adtec-core-package 3.0.8 → 3.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CLAUDE.md +1 -1
- package/package.json +1 -1
- package/src/api/workflow/workflowInstApi.ts +12 -0
- package/src/components/RichTextEditor/RichTextEditor.vue +15 -16
- package/src/components/RichTextEditor/richTextHtmlUtils.ts +63 -40
- package/src/interface/workflow/IWfNodeLastApprovalVo.ts +25 -0
- package/src/utils/AxiosConfig.ts +2 -2
package/AGENTS.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- gitnexus:start -->
|
|
2
2
|
# GitNexus — Code Intelligence
|
|
3
3
|
|
|
4
|
-
This project is indexed by GitNexus as **adtec-front-end-core-package** (
|
|
4
|
+
This project is indexed by GitNexus as **adtec-front-end-core-package** (6187 symbols, 9025 relationships, 155 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
|
|
5
5
|
|
|
6
6
|
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
|
|
7
7
|
|
package/CLAUDE.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<!-- gitnexus:start -->
|
|
2
2
|
# GitNexus — Code Intelligence
|
|
3
3
|
|
|
4
|
-
This project is indexed by GitNexus as **adtec-front-end-core-package** (
|
|
4
|
+
This project is indexed by GitNexus as **adtec-front-end-core-package** (6187 symbols, 9025 relationships, 155 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
|
|
5
5
|
|
|
6
6
|
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
|
|
7
7
|
|
package/package.json
CHANGED
|
@@ -4,6 +4,10 @@ import type { IWfProcessInstVo, IWfTaskVo } from '../../interface/workflow/IWfTa
|
|
|
4
4
|
import type { IWfTaskAskVo } from '../../interface/workflow/IWfTaskAskVo'
|
|
5
5
|
import type { IWfTaskUsersVo } from '../../interface/workflow/IWfTaskUsersVo'
|
|
6
6
|
import type { IWfReturnNodeVo } from '../../interface/workflow/IWfReturnNodeVo'
|
|
7
|
+
import type {
|
|
8
|
+
IWfNodeLastApprovalBatchVo,
|
|
9
|
+
IWfNodeLastApprovalQueryVo,
|
|
10
|
+
} from '../../interface/workflow/IWfNodeLastApprovalVo'
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
13
|
* 创建人:xux
|
|
@@ -72,4 +76,12 @@ export default {
|
|
|
72
76
|
getWfProcessInstByBusinessId(businessId: string) {
|
|
73
77
|
return request.get<IWfTaskVo>(baseUrl + '/getUserTaskInfo', { businessId })
|
|
74
78
|
},
|
|
79
|
+
/** 获取指定节点最后一轮审批人及审批意见(支持多节点,不限制流程是否结束) */
|
|
80
|
+
getLastNodeApprovalByBusinessId(businessId: string, nodeCodes: string | string[]) {
|
|
81
|
+
const query: IWfNodeLastApprovalQueryVo = {
|
|
82
|
+
businessId,
|
|
83
|
+
nodeCodes: Array.isArray(nodeCodes) ? nodeCodes : [nodeCodes],
|
|
84
|
+
}
|
|
85
|
+
return request.post<IWfNodeLastApprovalBatchVo>(baseUrl + '/lastNodeApproval', query)
|
|
86
|
+
},
|
|
75
87
|
}
|
|
@@ -217,9 +217,7 @@ async function remountEditor() {
|
|
|
217
217
|
if (remounting || !umoMountOptions.value) return
|
|
218
218
|
remounting = true
|
|
219
219
|
try {
|
|
220
|
-
const html = ready.value
|
|
221
|
-
? finalizeHtml(getRawHtml(), getRootElement())
|
|
222
|
-
: initHtml(model.value ?? '')
|
|
220
|
+
const html = ready.value ? getRawHtml() : (model.value ?? '')
|
|
223
221
|
ready.value = false
|
|
224
222
|
editorRef.value = null
|
|
225
223
|
umoMountOptions.value = null
|
|
@@ -286,7 +284,7 @@ async function ensureBlockImageNodeView() {
|
|
|
286
284
|
const editor = getEditorInstance()
|
|
287
285
|
if (editor?.setContent && ready.value) {
|
|
288
286
|
const html = initHtml(getRawHtml() || (model.value ?? ''))
|
|
289
|
-
editor.setContent(html, { emitUpdate: false })
|
|
287
|
+
editor.setContent(html, { emitUpdate: false, parseOptions: { preserveWhitespace: 'full' } })
|
|
290
288
|
await nextTick()
|
|
291
289
|
await waitEditorPaintFrames()
|
|
292
290
|
if (!usesPlainImageDom(rootRef.value)) {
|
|
@@ -296,7 +294,7 @@ async function ensureBlockImageNodeView() {
|
|
|
296
294
|
}
|
|
297
295
|
|
|
298
296
|
if (ready.value) {
|
|
299
|
-
publishModelFromEditor(
|
|
297
|
+
publishModelFromEditor()
|
|
300
298
|
}
|
|
301
299
|
await remountEditor()
|
|
302
300
|
await nextTick()
|
|
@@ -449,16 +447,15 @@ function applyEditorHtml(html: string, focus = false) {
|
|
|
449
447
|
editor?.setContent?.(initHtml(html), {
|
|
450
448
|
emitUpdate: false,
|
|
451
449
|
focusPosition: focus ? 'end' : false,
|
|
450
|
+
parseOptions: { preserveWhitespace: 'full' },
|
|
452
451
|
})
|
|
453
452
|
}
|
|
454
453
|
|
|
455
|
-
|
|
454
|
+
/** 将编辑器 HTML 同步到 v-model;始终使用 getRawHtml,不经 finalizeHtml(避免保存/blur 路径折叠空白) */
|
|
455
|
+
function publishModelFromEditor() {
|
|
456
456
|
const editor = getEditorInstance()
|
|
457
457
|
if (!editor) return
|
|
458
|
-
|
|
459
|
-
if (finalize) {
|
|
460
|
-
html = finalizeHtml(html, getRootElement())
|
|
461
|
-
}
|
|
458
|
+
const html = getRawHtml()
|
|
462
459
|
syncingContent.value = true
|
|
463
460
|
model.value = html
|
|
464
461
|
text.value = getPlainText()
|
|
@@ -498,11 +495,11 @@ async function onEditorCreated() {
|
|
|
498
495
|
|
|
499
496
|
function onEditorChanged() {
|
|
500
497
|
if (!ready.value || syncingContent.value) return
|
|
501
|
-
publishModelFromEditor(
|
|
498
|
+
publishModelFromEditor()
|
|
502
499
|
}
|
|
503
500
|
|
|
504
501
|
function onEditorBlur() {
|
|
505
|
-
publishModelFromEditor(
|
|
502
|
+
publishModelFromEditor()
|
|
506
503
|
emit('onBlur', { html: model.value ?? '', text: getPlainText() })
|
|
507
504
|
}
|
|
508
505
|
|
|
@@ -537,7 +534,7 @@ watch(editable, async (now, prev) => {
|
|
|
537
534
|
if (lastMountEditable.value === now) return
|
|
538
535
|
if (!umoMountOptions.value) return
|
|
539
536
|
if (ready.value) {
|
|
540
|
-
publishModelFromEditor(
|
|
537
|
+
publishModelFromEditor()
|
|
541
538
|
}
|
|
542
539
|
await remountEditor()
|
|
543
540
|
})
|
|
@@ -549,7 +546,7 @@ watch(
|
|
|
549
546
|
if (now === prev) return
|
|
550
547
|
if (!umoMountOptions.value) return
|
|
551
548
|
if (ready.value) {
|
|
552
|
-
publishModelFromEditor(
|
|
549
|
+
publishModelFromEditor()
|
|
553
550
|
}
|
|
554
551
|
await remountEditor()
|
|
555
552
|
},
|
|
@@ -573,9 +570,11 @@ watch(
|
|
|
573
570
|
)
|
|
574
571
|
|
|
575
572
|
defineExpose({
|
|
576
|
-
|
|
573
|
+
/** 默认返回编辑器原始 HTML(保留空白);导出/含图存档时传 { finalize: true } */
|
|
574
|
+
getHtml: (options?: { finalize?: boolean }) => {
|
|
577
575
|
if (!ready.value) return model.value ?? ''
|
|
578
|
-
|
|
576
|
+
const html = getRawHtml()
|
|
577
|
+
return options?.finalize ? finalizeHtml(html, getRootElement()) : html
|
|
579
578
|
},
|
|
580
579
|
getText: () => {
|
|
581
580
|
if (!ready.value) return text.value ?? ''
|
|
@@ -17,15 +17,23 @@ const fontSizes = [
|
|
|
17
17
|
{ name: '初号', pt: 42, px: 49 },
|
|
18
18
|
]
|
|
19
19
|
|
|
20
|
+
/** 纯字符串处理,避免 innerHTML 解析时合并连续空格 */
|
|
20
21
|
function setDefaultPx(html: string) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
return html.replace(/<p\b([^>]*)>/gi, (full, attrs: string) => {
|
|
23
|
+
const attrStr = attrs ?? ''
|
|
24
|
+
if (/style\s*=\s*["'][^"']*font-size\s*:/i.test(attrStr)) {
|
|
25
|
+
return full
|
|
26
|
+
}
|
|
27
|
+
if (/style\s*=\s*(["'])(.*?)\1/i.test(attrStr)) {
|
|
28
|
+
return full.replace(
|
|
29
|
+
/style\s*=\s*(["'])(.*?)\1/i,
|
|
30
|
+
(_m, quote: string, style: string) =>
|
|
31
|
+
`style=${quote}${normalizeStyleString(style)}font-size: 14px;${quote}`,
|
|
32
|
+
)
|
|
26
33
|
}
|
|
34
|
+
const trimmed = attrStr.trim()
|
|
35
|
+
return trimmed ? `<p ${trimmed} style="font-size: 14px;">` : '<p style="font-size: 14px;">'
|
|
27
36
|
})
|
|
28
|
-
return tempDiv.innerHTML
|
|
29
37
|
}
|
|
30
38
|
|
|
31
39
|
export function convertPxToPt(html: string) {
|
|
@@ -151,6 +159,45 @@ function srcMatchKey(src: string) {
|
|
|
151
159
|
return src.length > 100 ? src.substring(0, 100) : src
|
|
152
160
|
}
|
|
153
161
|
|
|
162
|
+
function upsertImgDimensionsInHtml(
|
|
163
|
+
html: string,
|
|
164
|
+
srcKey: string,
|
|
165
|
+
width: number,
|
|
166
|
+
height: number,
|
|
167
|
+
fallbackIndex: number,
|
|
168
|
+
): string {
|
|
169
|
+
if (!srcKey) return html
|
|
170
|
+
|
|
171
|
+
const imgTagPattern = /<img\b[^>]*\/?>/gi
|
|
172
|
+
const matches = [...html.matchAll(imgTagPattern)]
|
|
173
|
+
if (matches.length === 0) return html
|
|
174
|
+
|
|
175
|
+
let targetIndex = matches.findIndex((match) => {
|
|
176
|
+
const tag = match[0]
|
|
177
|
+
const srcMatch = tag.match(/\ssrc=(["'])(.*?)\1/i) ?? tag.match(/\ssrc=([^\s>]+)/i)
|
|
178
|
+
const src = srcMatch?.[2] ?? srcMatch?.[1] ?? ''
|
|
179
|
+
if (!src) return false
|
|
180
|
+
return src.startsWith(srcKey) || srcKey.startsWith(srcMatchKey(src))
|
|
181
|
+
})
|
|
182
|
+
if (targetIndex < 0) {
|
|
183
|
+
targetIndex = fallbackIndex < matches.length ? fallbackIndex : -1
|
|
184
|
+
}
|
|
185
|
+
if (targetIndex < 0) return html
|
|
186
|
+
|
|
187
|
+
const target = matches[targetIndex]
|
|
188
|
+
const start = target.index ?? 0
|
|
189
|
+
const end = start + target[0].length
|
|
190
|
+
let nextTag = target[0]
|
|
191
|
+
.replace(/\swidth=(["'])[^"']*\1/gi, '')
|
|
192
|
+
.replace(/\sheight=(["'])[^"']*\1/gi, '')
|
|
193
|
+
.replace(/\swidth=[^\s>]+/gi, '')
|
|
194
|
+
.replace(/\sheight=[^\s>]+/gi, '')
|
|
195
|
+
.replace(/\sstyle=(["'])[^"']*\1/gi, '')
|
|
196
|
+
nextTag = nextTag.replace(/\/?>$/, ` width="${width}" height="${height}">`)
|
|
197
|
+
|
|
198
|
+
return html.slice(0, start) + nextTag + html.slice(end)
|
|
199
|
+
}
|
|
200
|
+
|
|
154
201
|
/** 失焦/保存时把编辑器 DOM 中的图片尺寸写回 HTML(兜底 NodeView attrs 未同步) */
|
|
155
202
|
export function syncImageDimensions(html: string, root?: DomRoot) {
|
|
156
203
|
const domRoot = resolveDomRoot(root)
|
|
@@ -164,51 +211,26 @@ export function syncImageDimensions(html: string, root?: DomRoot) {
|
|
|
164
211
|
const liveImages = Array.from(contentRoot.querySelectorAll('img'))
|
|
165
212
|
if (liveImages.length === 0) return html
|
|
166
213
|
|
|
167
|
-
|
|
168
|
-
tempDiv.innerHTML = html
|
|
169
|
-
const htmlImages = Array.from(tempDiv.querySelectorAll('img'))
|
|
170
|
-
if (htmlImages.length === 0) return html
|
|
171
|
-
|
|
214
|
+
let result = html
|
|
172
215
|
liveImages.forEach((liveImg, index) => {
|
|
173
216
|
const width = Math.round(liveImg.offsetWidth)
|
|
174
217
|
const height = Math.round(liveImg.offsetHeight)
|
|
175
218
|
if (width <= 1 || height <= 1) return
|
|
176
219
|
|
|
177
220
|
const liveKey = srcMatchKey(liveImg.getAttribute('src') || liveImg.src || '')
|
|
178
|
-
|
|
179
|
-
htmlImages.find((img) => {
|
|
180
|
-
const src = img.getAttribute('src') || ''
|
|
181
|
-
if (!src || !liveKey) return false
|
|
182
|
-
return src.startsWith(liveKey) || liveKey.startsWith(srcMatchKey(src))
|
|
183
|
-
}) ?? htmlImages[index]
|
|
184
|
-
|
|
185
|
-
if (!htmlImg) return
|
|
186
|
-
|
|
187
|
-
htmlImg.setAttribute('width', String(width))
|
|
188
|
-
htmlImg.setAttribute('height', String(height))
|
|
189
|
-
htmlImg.removeAttribute('style')
|
|
221
|
+
result = upsertImgDimensionsInHtml(result, liveKey, width, height, index)
|
|
190
222
|
})
|
|
191
223
|
|
|
192
|
-
return
|
|
224
|
+
return result
|
|
193
225
|
}
|
|
194
226
|
|
|
195
227
|
function sanitizeBrokenImages(html: string) {
|
|
196
|
-
if (
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
const tempDiv = document.createElement('div')
|
|
204
|
-
tempDiv.innerHTML = html
|
|
205
|
-
tempDiv.querySelectorAll('img').forEach((img) => {
|
|
206
|
-
const src = (img.getAttribute('src') ?? '').trim()
|
|
207
|
-
if (!src || src === 'null' || src === 'undefined') {
|
|
208
|
-
img.remove()
|
|
209
|
-
}
|
|
210
|
-
})
|
|
211
|
-
return tempDiv.innerHTML
|
|
228
|
+
if (!html) return ''
|
|
229
|
+
// 仅用正则,避免 innerHTML 往返合并文本中的连续空格
|
|
230
|
+
return html
|
|
231
|
+
.replace(/<img\b[^>]*\ssrc=(["'])(null|undefined)\1[^>]*\/?>/gi, '')
|
|
232
|
+
.replace(/<img\b[^>]*\ssrc=(null|undefined)(?=\s|>|\/)[^>]*\/?>/gi, '')
|
|
233
|
+
.replace(/<img\b[^>]*\ssrc=(["'])\s*\1[^>]*\/?>/gi, '')
|
|
212
234
|
}
|
|
213
235
|
|
|
214
236
|
export function initHtml(html: string) {
|
|
@@ -219,6 +241,7 @@ export function initHtml(html: string) {
|
|
|
219
241
|
return convertPtToPx(html)
|
|
220
242
|
}
|
|
221
243
|
|
|
244
|
+
/** 导出/存档用:同步图片尺寸并将 px 字号转为 pt;全程正则/DOM 读尺寸,不经 innerHTML 文本往返 */
|
|
222
245
|
export function finalizeHtml(html: string, root?: DomRoot) {
|
|
223
246
|
let result = html || ''
|
|
224
247
|
result = calcImagesHeight(result, root)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { IWfTaskVo } from './IWfTaskVo'
|
|
2
|
+
|
|
3
|
+
/** 单个节点最后一轮审批信息 */
|
|
4
|
+
export interface IWfNodeLastApprovalVo {
|
|
5
|
+
/** BPMN 节点 id(taskDefKey) */
|
|
6
|
+
nodeCode?: string
|
|
7
|
+
/** 该节点最后一轮审批记录(会签时可能多条) */
|
|
8
|
+
approvalList?: IWfTaskVo[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** 多节点最后一轮审批查询入参 */
|
|
12
|
+
export interface IWfNodeLastApprovalQueryVo {
|
|
13
|
+
businessId?: string
|
|
14
|
+
nodeCodes?: string[]
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** 多节点最后一轮审批查询结果 */
|
|
18
|
+
export interface IWfNodeLastApprovalBatchVo {
|
|
19
|
+
businessId?: string
|
|
20
|
+
procInsId?: string
|
|
21
|
+
procEndTime?: string
|
|
22
|
+
/** 流程是否已结束(仅信息字段,不影响查询) */
|
|
23
|
+
finished?: boolean
|
|
24
|
+
nodeApprovalList?: IWfNodeLastApprovalVo[]
|
|
25
|
+
}
|
package/src/utils/AxiosConfig.ts
CHANGED
|
@@ -30,7 +30,7 @@ const request = axios.create({
|
|
|
30
30
|
})
|
|
31
31
|
function setHeaders(config: any) {
|
|
32
32
|
//数据防止篡改
|
|
33
|
-
const Authorization = sessionStorage.getItem('Authorization')
|
|
33
|
+
const Authorization = config.skipAuthorization ? '' : sessionStorage.getItem('Authorization')
|
|
34
34
|
const signa = 'F2E49299-D0D2-4AA1-87A3-270272EA3D6A'
|
|
35
35
|
let dataJson: string = ''
|
|
36
36
|
if (config.method === 'get') {
|
|
@@ -56,7 +56,7 @@ function setHeaders(config: any) {
|
|
|
56
56
|
// @ts-ignore
|
|
57
57
|
dataJson=dataJson.replace(/[^\u4E00-\u9FA5A-Za-z0-9]/g, '')
|
|
58
58
|
dataJson = dataJson.split('').sort().join('').trim()
|
|
59
|
-
config.headers.sessionId = sessionStorage.getItem('sessionId')
|
|
59
|
+
config.headers.sessionId = config.skipAuthorization ? '' : sessionStorage.getItem('sessionId')
|
|
60
60
|
config.headers.Authorization = Authorization
|
|
61
61
|
config.headers.signa = Md5.hashStr(Authorization + signa + dataJson)
|
|
62
62
|
config.headers.antiShakeKey = Md5.hashStr(dataJson)
|