fix(bpm): 完善流程实例打印字段展示
- Vben5 web-antd/web-ele/web-antdv-next 同步支持更多表单字段打印 - Vue3 + Element Plus 流程打印补齐字典、用户、部门、省市区、文件、图片、开关、富文本等字段展示 - 普通字段和流程记录改为安全文本渲染,保留富文本 HTML 展示 - 打印时间改为每次打开弹窗时刷新 - web-ele 补充 ElButton 显式导入,避免运行时组件解析风险pull/881/head
parent
595b8c5bb4
commit
ff3c7884cc
|
|
@ -1,10 +1,53 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
|
import * as ProcessInstanceApi from '@/api/bpm/processInstance'
|
||||||
|
import * as AreaApi from '@/api/system/area'
|
||||||
|
import * as DeptApi from '@/api/system/dept'
|
||||||
|
import * as UserApi from '@/api/system/user'
|
||||||
import { useUserStore } from '@/store/modules/user'
|
import { useUserStore } from '@/store/modules/user'
|
||||||
import { formatDate } from '@/utils/formatTime'
|
import { formatDate } from '@/utils/formatTime'
|
||||||
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
|
import {
|
||||||
|
DICT_TYPE,
|
||||||
|
getBoolDictOptions,
|
||||||
|
getDictLabel,
|
||||||
|
getDictOptions,
|
||||||
|
getIntDictOptions,
|
||||||
|
getStrDictOptions
|
||||||
|
} from '@/utils/dict'
|
||||||
import { decodeFields } from '@/utils/formCreate'
|
import { decodeFields } from '@/utils/formCreate'
|
||||||
|
|
||||||
|
interface FormFieldItem {
|
||||||
|
html: string
|
||||||
|
id: string
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface FormFieldOption {
|
||||||
|
label?: string
|
||||||
|
value?: unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
type FormFieldRule = Record<string, unknown> & {
|
||||||
|
field?: string
|
||||||
|
options?: FormFieldOption[]
|
||||||
|
props?: Record<string, unknown>
|
||||||
|
title?: string
|
||||||
|
type?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type PrintableRecord = Record<string, unknown>
|
||||||
|
|
||||||
|
interface AreaNode {
|
||||||
|
children?: AreaNode[]
|
||||||
|
id?: number
|
||||||
|
name: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PrintLookupMaps {
|
||||||
|
areaMap: Map<string, string>
|
||||||
|
deptMap: Map<string, string>
|
||||||
|
userMap: Map<string, string>
|
||||||
|
}
|
||||||
|
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
|
|
@ -13,15 +56,16 @@ const loading = ref(false)
|
||||||
const printData = ref()
|
const printData = ref()
|
||||||
const userName = computed(() => userStore.user.nickname ?? '')
|
const userName = computed(() => userStore.user.nickname ?? '')
|
||||||
const printTime = ref(formatDate(new Date(), 'YYYY-MM-DD HH:mm'))
|
const printTime = ref(formatDate(new Date(), 'YYYY-MM-DD HH:mm'))
|
||||||
const formFields = ref()
|
const formFields = ref<FormFieldItem[]>([])
|
||||||
const printDataMap = ref({})
|
const printDataMap = ref<Record<string, string>>({})
|
||||||
|
|
||||||
const open = async (id: string) => {
|
const open = async (id: string) => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
try {
|
try {
|
||||||
printData.value = await ProcessInstanceApi.getProcessInstancePrintData(id)
|
printData.value = await ProcessInstanceApi.getProcessInstancePrintData(id)
|
||||||
|
printTime.value = formatDate(new Date(), 'YYYY-MM-DD HH:mm')
|
||||||
initPrintDataMap()
|
initPrintDataMap()
|
||||||
parseFormFields()
|
await parseFormFields()
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
}
|
}
|
||||||
|
|
@ -29,82 +73,347 @@ const open = async (id: string) => {
|
||||||
}
|
}
|
||||||
defineExpose({ open })
|
defineExpose({ open })
|
||||||
|
|
||||||
const parseFormFields = () => {
|
const parseFormFields = async () => {
|
||||||
if (!printData.value) return
|
if (!printData.value) return
|
||||||
|
|
||||||
const formFieldsObj = decodeFields(
|
const formFieldsObj = decodeFields(
|
||||||
printData.value.processInstance.processDefinition?.formFields || []
|
printData.value.processInstance.processDefinition?.formFields || []
|
||||||
)
|
) as FormFieldRule[]
|
||||||
const processVariables = printData.value.processInstance.formVariables
|
const processVariables = printData.value.processInstance.formVariables ?? {}
|
||||||
let res: any = []
|
const lookupMaps = await loadPrintLookupMaps(formFieldsObj)
|
||||||
|
const res: FormFieldItem[] = []
|
||||||
|
|
||||||
for (const item of formFieldsObj) {
|
for (const item of formFieldsObj) {
|
||||||
const id = item['field']
|
const fieldKey = String(item.field ?? '')
|
||||||
const name = item['title']
|
const id = fieldKey
|
||||||
const variable = processVariables[item['field']]
|
const name = String(item.title ?? fieldKey)
|
||||||
let html = variable
|
const variable = processVariables[fieldKey]
|
||||||
switch (item['type']) {
|
const html = formatPrintField(item, variable, lookupMaps)
|
||||||
case 'UploadImg': {
|
|
||||||
let imgEl = document.createElement('img')
|
printDataMap.value[fieldKey] = html
|
||||||
imgEl.setAttribute('src', variable)
|
|
||||||
imgEl.setAttribute('style', 'max-width: 600px;')
|
|
||||||
html = imgEl.outerHTML
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'radio':
|
|
||||||
case 'checkbox':
|
|
||||||
case 'select': {
|
|
||||||
const options = item['options'] || []
|
|
||||||
const temp: any = []
|
|
||||||
if (Array.isArray(variable)) {
|
|
||||||
const labels = options.filter((o) => variable.includes(o.value)).map((o) => o.label)
|
|
||||||
temp.push(...labels)
|
|
||||||
} else {
|
|
||||||
const opt = options.find((o) => o.value === variable)
|
|
||||||
temp.push(opt.label)
|
|
||||||
}
|
|
||||||
html = temp.join(',')
|
|
||||||
}
|
|
||||||
// TODO 更多表单打印展示
|
|
||||||
}
|
|
||||||
printDataMap.value[item['field']] = html
|
|
||||||
res.push({ id, name, html })
|
res.push({ id, name, html })
|
||||||
}
|
}
|
||||||
formFields.value = res
|
formFields.value = res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getRuleProp = (rule: FormFieldRule, key: string) => {
|
||||||
|
return rule?.[key] ?? rule?.props?.[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
const isPrintableRecord = (value: unknown): value is PrintableRecord => {
|
||||||
|
return typeof value === 'object' && value !== null
|
||||||
|
}
|
||||||
|
|
||||||
|
const getRecordValue = (record: PrintableRecord, key: string) => {
|
||||||
|
return record[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
const isNotEmptyString = (value: string) => value.length > 0
|
||||||
|
|
||||||
|
const isEmptyValue = (value: unknown) => value === undefined || value === null || value === ''
|
||||||
|
|
||||||
|
const toValueArray = (value: unknown) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
if (isEmptyValue(value)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return [value]
|
||||||
|
}
|
||||||
|
|
||||||
|
const escapeHtml = (value: unknown) => {
|
||||||
|
return String(value)
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
}
|
||||||
|
|
||||||
|
const tryFormatDate = (value: unknown) => {
|
||||||
|
if (isEmptyValue(value)) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const formatted = formatDate(value as Date | number | string)
|
||||||
|
return formatted === 'Invalid Date' ? escapeHtml(value) : formatted
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatDateValue = (value: unknown) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.map((item) => tryFormatDate(item)).join(' ~ ')
|
||||||
|
}
|
||||||
|
return tryFormatDate(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatPrimitiveValue = (value: unknown): string => {
|
||||||
|
if (isEmptyValue(value)) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value
|
||||||
|
.map((item) => formatPrimitiveValue(item))
|
||||||
|
.filter((s) => isNotEmptyString(s))
|
||||||
|
.join(', ')
|
||||||
|
}
|
||||||
|
if (typeof value === 'boolean') {
|
||||||
|
return value ? '是' : '否'
|
||||||
|
}
|
||||||
|
if (isPrintableRecord(value)) {
|
||||||
|
const displayValue =
|
||||||
|
getRecordValue(value, 'label') ??
|
||||||
|
getRecordValue(value, 'name') ??
|
||||||
|
getRecordValue(value, 'url') ??
|
||||||
|
getRecordValue(value, 'value') ??
|
||||||
|
JSON.stringify(value)
|
||||||
|
return escapeHtml(displayValue)
|
||||||
|
}
|
||||||
|
return escapeHtml(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
const createImageHtml = (url: string) => {
|
||||||
|
const imgEl = document.createElement('img')
|
||||||
|
imgEl.setAttribute('src', url)
|
||||||
|
imgEl.setAttribute('style', 'max-width: 600px; max-height: 300px;')
|
||||||
|
return imgEl.outerHTML
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderImageListHtml = (value: unknown) => {
|
||||||
|
return toValueArray(value)
|
||||||
|
.map((item) => {
|
||||||
|
let url: string | undefined
|
||||||
|
if (typeof item === 'string') {
|
||||||
|
url = item
|
||||||
|
} else if (isPrintableRecord(item)) {
|
||||||
|
const recordUrl = getRecordValue(item, 'url')
|
||||||
|
url = recordUrl ? String(recordUrl) : undefined
|
||||||
|
}
|
||||||
|
return url ? createImageHtml(url) : ''
|
||||||
|
})
|
||||||
|
.filter((s) => isNotEmptyString(s))
|
||||||
|
.join('<br/>')
|
||||||
|
}
|
||||||
|
|
||||||
|
const createFileLinkHtml = (file: unknown) => {
|
||||||
|
const record = isPrintableRecord(file) ? file : undefined
|
||||||
|
const recordUrl = record ? getRecordValue(record, 'url') : undefined
|
||||||
|
const url = typeof file === 'string' ? file : String(recordUrl ?? '')
|
||||||
|
if (!url) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
const linkEl = document.createElement('a')
|
||||||
|
linkEl.setAttribute('href', url)
|
||||||
|
linkEl.setAttribute('target', '_blank')
|
||||||
|
linkEl.setAttribute('rel', 'noopener noreferrer')
|
||||||
|
const fallbackName = url.slice(Math.max(0, url.lastIndexOf('/') + 1)) || url
|
||||||
|
const recordName = record ? getRecordValue(record, 'name') : undefined
|
||||||
|
linkEl.textContent = recordName ? String(recordName) : fallbackName
|
||||||
|
return linkEl.outerHTML
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderFileListHtml = (value: unknown) => {
|
||||||
|
return toValueArray(value)
|
||||||
|
.map((item) => createFileLinkHtml(item))
|
||||||
|
.filter((s) => isNotEmptyString(s))
|
||||||
|
.join('<br/>')
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapValuesWithOptions = (value: unknown, options: FormFieldOption[] = []) => {
|
||||||
|
const values = toValueArray(value)
|
||||||
|
const labels = values
|
||||||
|
.map((item) => {
|
||||||
|
const matched = options.find(
|
||||||
|
(option) => option?.value === item || String(option?.value ?? '') === String(item)
|
||||||
|
)
|
||||||
|
return escapeHtml(matched?.label ?? String(item))
|
||||||
|
})
|
||||||
|
.filter((s) => isNotEmptyString(s))
|
||||||
|
return labels.join(', ')
|
||||||
|
}
|
||||||
|
|
||||||
|
const flattenAreaTree = (list: AreaNode[] = [], map: Map<string, string> = new Map()) => {
|
||||||
|
list.forEach((item) => {
|
||||||
|
if (item.id !== undefined) {
|
||||||
|
map.set(String(item.id), item.name)
|
||||||
|
}
|
||||||
|
if (Array.isArray(item.children) && item.children.length > 0) {
|
||||||
|
flattenAreaTree(item.children, map)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapValueWithLabelMap = (
|
||||||
|
value: unknown,
|
||||||
|
labelMap: Map<string, string>,
|
||||||
|
separator = ', '
|
||||||
|
) => {
|
||||||
|
const values = toValueArray(value)
|
||||||
|
const labels = values
|
||||||
|
.map((item) => escapeHtml(labelMap.get(String(item)) ?? String(item)))
|
||||||
|
.filter((s) => isNotEmptyString(s))
|
||||||
|
return labels.length > 0 ? labels.join(escapeHtml(separator)) : formatPrimitiveValue(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTypedDictOptions = (dictType: string, valueType: string) => {
|
||||||
|
switch (valueType) {
|
||||||
|
case 'bool':
|
||||||
|
case 'boolean':
|
||||||
|
return getBoolDictOptions(dictType)
|
||||||
|
case 'int':
|
||||||
|
case 'number':
|
||||||
|
return getIntDictOptions(dictType)
|
||||||
|
case 'str':
|
||||||
|
case 'string':
|
||||||
|
return getStrDictOptions(dictType)
|
||||||
|
default:
|
||||||
|
return getDictOptions(dictType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadPrintLookupMaps = async (formFieldsObj: FormFieldRule[]) => {
|
||||||
|
const hasAreaSelect = formFieldsObj.some((item) => item.type === 'AreaSelect')
|
||||||
|
const hasUserSelect = formFieldsObj.some((item) => item.type === 'UserSelect')
|
||||||
|
const hasDeptSelect = formFieldsObj.some((item) => item.type === 'DeptSelect')
|
||||||
|
|
||||||
|
const [areaList, userList, deptList] = await Promise.all([
|
||||||
|
hasAreaSelect ? AreaApi.getAreaTree() : Promise.resolve([]),
|
||||||
|
hasUserSelect ? UserApi.getSimpleUserList() : Promise.resolve([]),
|
||||||
|
hasDeptSelect ? DeptApi.getSimpleDeptList() : Promise.resolve([])
|
||||||
|
])
|
||||||
|
|
||||||
|
return {
|
||||||
|
areaMap: flattenAreaTree(areaList as AreaNode[]),
|
||||||
|
deptMap: new Map((deptList ?? []).map((item) => [String(item.id), item.name] as const)),
|
||||||
|
userMap: new Map(
|
||||||
|
(userList ?? []).map((item) => [String(item.id), item.nickname ?? item.username] as const)
|
||||||
|
)
|
||||||
|
} satisfies PrintLookupMaps
|
||||||
|
}
|
||||||
|
|
||||||
|
const formatPrintField = (
|
||||||
|
rule: FormFieldRule,
|
||||||
|
value: unknown,
|
||||||
|
lookupMaps: PrintLookupMaps
|
||||||
|
) => {
|
||||||
|
const type = String(rule.type ?? '')
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'AreaSelect': {
|
||||||
|
const separator = String(getRuleProp(rule, 'separator') || '/')
|
||||||
|
return mapValueWithLabelMap(value, lookupMaps.areaMap, separator)
|
||||||
|
}
|
||||||
|
case 'cascader':
|
||||||
|
case 'checkbox':
|
||||||
|
case 'radio':
|
||||||
|
case 'select':
|
||||||
|
case 'treeSelect': {
|
||||||
|
const options = getRuleProp(rule, 'options')
|
||||||
|
return Array.isArray(options) && options.length > 0
|
||||||
|
? mapValuesWithOptions(value, options as FormFieldOption[])
|
||||||
|
: formatPrimitiveValue(value)
|
||||||
|
}
|
||||||
|
case 'date':
|
||||||
|
case 'DatePicker':
|
||||||
|
case 'datePicker':
|
||||||
|
case 'daterange':
|
||||||
|
case 'datetime':
|
||||||
|
case 'datetimerange':
|
||||||
|
case 'month':
|
||||||
|
case 'monthrange':
|
||||||
|
case 'RangePicker':
|
||||||
|
case 'rangePicker':
|
||||||
|
case 'TimePicker':
|
||||||
|
case 'timePicker':
|
||||||
|
case 'TimeRangePicker':
|
||||||
|
case 'timeRangePicker':
|
||||||
|
return formatDateValue(value)
|
||||||
|
case 'DeptSelect': {
|
||||||
|
if (String(getRuleProp(rule, 'returnType')) === 'name') {
|
||||||
|
return formatPrimitiveValue(value)
|
||||||
|
}
|
||||||
|
return mapValueWithLabelMap(value, lookupMaps.deptMap)
|
||||||
|
}
|
||||||
|
case 'DictSelect': {
|
||||||
|
const dictType = getRuleProp(rule, 'dictType')
|
||||||
|
if (typeof dictType !== 'string' || !dictType) {
|
||||||
|
return formatPrimitiveValue(value)
|
||||||
|
}
|
||||||
|
const valueType = String(getRuleProp(rule, 'valueType') ?? '')
|
||||||
|
return mapValuesWithOptions(value, getTypedDictOptions(dictType, valueType))
|
||||||
|
}
|
||||||
|
case 'FileUpload':
|
||||||
|
case 'UploadFile':
|
||||||
|
return renderFileListHtml(value)
|
||||||
|
case 'IframeComponent': {
|
||||||
|
const propsObj = rule.props
|
||||||
|
const propsUrl = isPrintableRecord(propsObj) ? String(getRecordValue(propsObj, 'url') ?? '') : ''
|
||||||
|
const iframeUrl = isEmptyValue(value) ? propsUrl : String(value ?? '')
|
||||||
|
return iframeUrl ? createFileLinkHtml(iframeUrl) : ''
|
||||||
|
}
|
||||||
|
case 'ImagesUpload':
|
||||||
|
case 'ImageUpload':
|
||||||
|
case 'UploadImg':
|
||||||
|
case 'UploadImgs':
|
||||||
|
return renderImageListHtml(value)
|
||||||
|
case 'switch': {
|
||||||
|
if (isEmptyValue(value)) return '否'
|
||||||
|
const checkedVal = getRuleProp(rule, 'checkedValue') ?? getRuleProp(rule, 'activeValue')
|
||||||
|
const isChecked =
|
||||||
|
checkedVal !== undefined && checkedVal !== null ? value === checkedVal : Boolean(value)
|
||||||
|
return isChecked ? '是' : '否'
|
||||||
|
}
|
||||||
|
case 'Editor':
|
||||||
|
case 'Tinymce':
|
||||||
|
return isEmptyValue(value) ? '' : String(value)
|
||||||
|
case 'UserSelect': {
|
||||||
|
if (String(getRuleProp(rule, 'returnType')) === 'name') {
|
||||||
|
return formatPrimitiveValue(value)
|
||||||
|
}
|
||||||
|
return mapValueWithLabelMap(value, lookupMaps.userMap)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return formatPrimitiveValue(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const initPrintDataMap = () => {
|
const initPrintDataMap = () => {
|
||||||
printDataMap.value['startUser'] = printData.value.processInstance.startUser.nickname
|
if (!printData.value) return
|
||||||
printDataMap.value['startUserDept'] = printData.value.processInstance.startUser.deptName
|
|
||||||
|
printDataMap.value['startUser'] = printData.value.processInstance.startUser?.nickname || ''
|
||||||
|
printDataMap.value['startUserDept'] = printData.value.processInstance.startUser?.deptName || ''
|
||||||
printDataMap.value['processName'] = printData.value.processInstance.name
|
printDataMap.value['processName'] = printData.value.processInstance.name
|
||||||
printDataMap.value['processNum'] = printData.value.processInstance.id
|
printDataMap.value['processNum'] = String(printData.value.processInstance.id ?? '')
|
||||||
printDataMap.value['startTime'] = formatDate(printData.value.processInstance.startTime)
|
printDataMap.value['startTime'] = formatDate(printData.value.processInstance.startTime)
|
||||||
printDataMap.value['endTime'] = formatDate(printData.value.processInstance.endTime)
|
printDataMap.value['endTime'] = formatDate(printData.value.processInstance.endTime)
|
||||||
printDataMap.value['processStatus'] = getDictLabel(
|
printDataMap.value['processStatus'] = String(getDictLabel(
|
||||||
DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS,
|
DICT_TYPE.BPM_PROCESS_INSTANCE_STATUS,
|
||||||
printData.value.processInstance.status
|
printData.value.processInstance.status
|
||||||
)
|
) ?? '')
|
||||||
printDataMap.value['printUser'] = userName.value
|
printDataMap.value['printUser'] = userName.value
|
||||||
printDataMap.value['printTime'] = printTime.value
|
printDataMap.value['printTime'] = printTime.value
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPrintTemplateHTML = () => {
|
const getPrintTemplateHTML = () => {
|
||||||
|
if (!printData.value?.printTemplateHtml) return ''
|
||||||
|
|
||||||
const parser = new DOMParser()
|
const parser = new DOMParser()
|
||||||
let doc = parser.parseFromString(printData.value.printTemplateHtml, 'text/html')
|
const doc = parser.parseFromString(printData.value.printTemplateHtml, 'text/html')
|
||||||
// table 添加border
|
// table 添加border
|
||||||
let tables = doc.querySelectorAll('table')
|
const tables = doc.querySelectorAll('table')
|
||||||
tables.forEach((item) => {
|
tables.forEach((item) => {
|
||||||
item.setAttribute('border', '1')
|
item.setAttribute('border', '1')
|
||||||
item.setAttribute('style', (item.getAttribute('style') || '') + 'border-collapse:collapse;')
|
item.setAttribute('style', (item.getAttribute('style') || '') + 'border-collapse:collapse;')
|
||||||
})
|
})
|
||||||
// 替换 mentions
|
// 替换 mentions
|
||||||
let mentions = doc.querySelectorAll('[data-w-e-type="mention"]')
|
const mentions = doc.querySelectorAll('[data-w-e-type="mention"]')
|
||||||
mentions.forEach((item) => {
|
mentions.forEach((item) => {
|
||||||
const mentionId = JSON.parse(decodeURIComponent(item.getAttribute('data-info') ?? ''))['id']
|
const mentionId = JSON.parse(decodeURIComponent(item.getAttribute('data-info') ?? ''))['id']
|
||||||
item.innerHTML = printDataMap.value[mentionId] ?? ''
|
item.innerHTML = printDataMap.value[mentionId] ?? ''
|
||||||
})
|
})
|
||||||
// 替换流程记录
|
// 替换流程记录
|
||||||
let processRecords = doc.querySelectorAll('[data-w-e-type="process-record"]')
|
const processRecords = doc.querySelectorAll('[data-w-e-type="process-record"]')
|
||||||
let processRecordTable: Element = document.createElement('table')
|
const processRecordTable: Element = document.createElement('table')
|
||||||
if (processRecords.length > 0) {
|
if (processRecords.length > 0) {
|
||||||
// 构建流程记录html
|
// 构建流程记录html
|
||||||
processRecordTable.setAttribute('border', '1')
|
processRecordTable.setAttribute('border', '1')
|
||||||
|
|
@ -114,15 +423,15 @@ const getPrintTemplateHTML = () => {
|
||||||
headTd.setAttribute('colspan', '2')
|
headTd.setAttribute('colspan', '2')
|
||||||
headTd.setAttribute('width', 'auto')
|
headTd.setAttribute('width', 'auto')
|
||||||
headTd.setAttribute('style', 'text-align: center;')
|
headTd.setAttribute('style', 'text-align: center;')
|
||||||
headTd.innerHTML = '流程节点'
|
headTd.textContent = '流程节点'
|
||||||
headTr.appendChild(headTd)
|
headTr.appendChild(headTd)
|
||||||
processRecordTable.appendChild(headTr)
|
processRecordTable.appendChild(headTr)
|
||||||
printData.value.tasks.forEach((item) => {
|
printData.value.tasks.forEach((item) => {
|
||||||
const tr = document.createElement('tr')
|
const tr = document.createElement('tr')
|
||||||
const td1 = document.createElement('td')
|
const td1 = document.createElement('td')
|
||||||
td1.innerHTML = item.name
|
td1.textContent = item.name
|
||||||
const td2 = document.createElement('td')
|
const td2 = document.createElement('td')
|
||||||
td2.innerHTML = item.description
|
td2.textContent = item.description
|
||||||
tr.appendChild(td1)
|
tr.appendChild(td1)
|
||||||
tr.appendChild(td2)
|
tr.appendChild(td2)
|
||||||
processRecordTable.appendChild(tr)
|
processRecordTable.appendChild(tr)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue