From 64eea34a63fc977855588aadb315f3ec5e4dafce Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 31 May 2026 18:22:15 +0800 Subject: [PATCH] =?UTF-8?q?fix(bpm):=20=E5=AE=8C=E5=96=84=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E5=AE=9E=E4=BE=8B=E6=89=93=E5=8D=B0=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Vben5 web-antd/web-ele/web-antdv-next 同步支持更多表单字段打印 - Vue3 + Element Plus 流程打印补齐字典、用户、部门、省市区、文件、图片、开关、富文本等字段展示 - 普通字段和流程记录改为安全文本渲染,保留富文本 HTML 展示 - 打印时间改为每次打开弹窗时刷新 - web-ele 补充 ElButton 显式导入,避免运行时组件解析风险 --- .../detail/modules/process-print.vue | 46 +- .../detail/modules/process-print.vue | 423 +++++++++++++++--- 2 files changed, 403 insertions(+), 66 deletions(-) diff --git a/apps/web-antd/src/views/bpm/processInstance/detail/modules/process-print.vue b/apps/web-antd/src/views/bpm/processInstance/detail/modules/process-print.vue index 3f4dec119..3d487af22 100644 --- a/apps/web-antd/src/views/bpm/processInstance/detail/modules/process-print.vue +++ b/apps/web-antd/src/views/bpm/processInstance/detail/modules/process-print.vue @@ -90,6 +90,7 @@ const [Modal, modalApi] = useVbenModal({ /** 获取打印数据 */ async function fetchPrintData(id: string) { printData.value = await getProcessInstancePrintData(id); + printTime.value = formatDate(new Date(), 'YYYY-MM-DD HH:mm'); initPrintDataMap(); await parseFormFields(); } @@ -154,7 +155,7 @@ function tryFormatDate(value: unknown) { return ''; } const formatted = formatDate(value as Date | number | string); - return formatted === 'Invalid Date' ? String(value) : formatted; + return formatted === 'Invalid Date' ? escapeHtml(value) : formatted; } function formatDateValue(value: unknown) { @@ -164,6 +165,15 @@ function formatDateValue(value: unknown) { return tryFormatDate(value); } +function escapeHtml(value: unknown) { + return String(value) + .replaceAll('&', '&') + .replaceAll('<', '<') + .replaceAll('>', '>') + .replaceAll('"', '"') + .replaceAll("'", '''); +} + function formatPrimitiveValue(value: unknown): string { if (isEmptyValue(value)) { return ''; @@ -185,9 +195,9 @@ function formatPrimitiveValue(value: unknown): string { getRecordValue(record, 'url') ?? getRecordValue(record, 'value') ?? JSON.stringify(value); - return String(displayValue); + return escapeHtml(displayValue); } - return String(value); + return escapeHtml(value); } function createImageHtml(url: string) { @@ -248,7 +258,7 @@ function mapValuesWithOptions( (option) => option?.value === item || String(option?.value ?? '') === String(item), ); - return matched?.label ?? String(item); + return escapeHtml(matched?.label ?? String(item)); }) .filter((s) => isNotEmptyString(s)); return labels.join(', '); @@ -276,9 +286,11 @@ function mapValueWithLabelMap( ) { const values = toValueArray(value); const labels = values - .map((item) => labelMap.get(String(item)) ?? String(item)) + .map((item) => escapeHtml(labelMap.get(String(item)) ?? String(item))) .filter((s) => isNotEmptyString(s)); - return labels.length > 0 ? labels.join(separator) : formatPrimitiveValue(values); + return labels.length > 0 + ? labels.join(escapeHtml(separator)) + : formatPrimitiveValue(values); } /** @@ -380,7 +392,12 @@ function formatPrintField( const options = getDictOptions(dictType, valueType); return mapValuesWithOptions(value, options); } - case 'FileUpload': { + case 'Editor': + case 'Tinymce': { + return isEmptyValue(value) ? '' : String(value); + } + case 'FileUpload': + case 'UploadFile': { return renderFileListHtml(value); } case 'IframeComponent': { @@ -394,21 +411,20 @@ function formatPrintField( } case 'ImagesUpload': case 'ImageUpload': - case 'UploadImg': { + case 'UploadImg': + case 'UploadImgs': { return renderImageListHtml(value); } case 'switch': { if (isEmptyValue(value)) return '否'; - const checkedVal = getRuleProp(rule, 'checkedValue'); + const checkedVal = + getRuleProp(rule, 'checkedValue') ?? getRuleProp(rule, 'activeValue'); const isChecked = checkedVal !== undefined && checkedVal !== null ? value === checkedVal : Boolean(value); return isChecked ? '是' : '否'; } - case 'Tinymce': { - return isEmptyValue(value) ? '' : String(value); - } case 'UserSelect': { if (String(getRuleProp(rule, 'returnType')) === 'name') { return formatPrimitiveValue(value); @@ -481,7 +497,7 @@ function getPrintTemplateHTML() { const headTd = document.createElement('td'); headTd.setAttribute('colspan', '2'); headTd.setAttribute('class', 'border border-black p-1.5 text-center'); - headTd.innerHTML = '流程记录'; + headTd.textContent = '流程记录'; headTr.append(headTd); processRecordTable.append(headTr); @@ -489,10 +505,10 @@ function getPrintTemplateHTML() { const tr = document.createElement('tr'); const td1 = document.createElement('td'); td1.setAttribute('class', 'border border-black p-1.5'); - td1.innerHTML = item.name; + td1.textContent = item.name; const td2 = document.createElement('td'); td2.setAttribute('class', 'border border-black p-1.5'); - td2.innerHTML = item.description; + td2.textContent = item.description; tr.append(td1); tr.append(td2); processRecordTable.append(tr); diff --git a/apps/web-ele/src/views/bpm/processInstance/detail/modules/process-print.vue b/apps/web-ele/src/views/bpm/processInstance/detail/modules/process-print.vue index e385e933e..1853f187c 100644 --- a/apps/web-ele/src/views/bpm/processInstance/detail/modules/process-print.vue +++ b/apps/web-ele/src/views/bpm/processInstance/detail/modules/process-print.vue @@ -1,27 +1,59 @@