fix(ts): 修复 BPMN 设计器类型错误

- 设计器/预览补 DOM 空值保护与局部 service 类型(canvas/elementRegistry)
- UserTaskCustomConfig/ElementForm/ElementMultiInstance 等补 ref/数组/element 类型
- ProcessListener/Expression Dialog 补声明实际已 emit 的 select 事件
- UserTask 删除 return 后不可达旧代码
- ElementMultiInstance:loopCharacteristics 按需写入,不影响 ApproveMethod 扩展保存
- 运行时:keyboard 配置 { bindTo: document } → { bind: true },适配 diagram-js 15
master
YunaiV 2026-06-20 19:43:55 -07:00
parent cb9400e93d
commit 3f779091be
9 changed files with 85 additions and 46 deletions

View File

@ -405,7 +405,10 @@ console.log(additionalModules, 'additionalModules()')
console.log(moddleExtensions, 'moddleExtensions()') console.log(moddleExtensions, 'moddleExtensions()')
const initBpmnModeler = () => { const initBpmnModeler = () => {
if (bpmnModeler) return if (bpmnModeler) return
let data = document.getElementById('bpmnCanvas') const data = document.getElementById('bpmnCanvas')
if (!data) {
return
}
console.log(data, 'data') console.log(data, 'data')
console.log(props.keyboard, 'props.keyboard') console.log(props.keyboard, 'props.keyboard')
console.log(additionalModules, 'additionalModules()') console.log(additionalModules, 'additionalModules()')
@ -422,9 +425,9 @@ const initBpmnModeler = () => {
// propertiesPanel: { // propertiesPanel: {
// parent: '#js-properties-panel' // parent: '#js-properties-panel'
// }, // },
keyboard: props.keyboard ? { bindTo: document } : null, keyboard: props.keyboard ? { bind: true } : null,
// additionalModules: additionalModules.value, // additionalModules: additionalModules.value,
additionalModules: additionalModules.value, additionalModules: additionalModules.value as any[],
moddleExtensions: moddleExtensions.value moddleExtensions: moddleExtensions.value
// additionalModules: [ // additionalModules: [

View File

@ -140,6 +140,8 @@
import '../theme/index.scss' import '../theme/index.scss'
import BpmnViewer from 'bpmn-js/lib/Viewer' import BpmnViewer from 'bpmn-js/lib/Viewer'
import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas' import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'
import type Canvas from 'diagram-js/lib/core/Canvas'
import type ElementRegistry from 'diagram-js/lib/core/ElementRegistry'
import { ZoomOut, ZoomIn, ScaleToOriginal } from '@element-plus/icons-vue' import { ZoomOut, ZoomIn, ScaleToOriginal } from '@element-plus/icons-vue'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter, formatPast2 } from '@/utils/formatTime' import { dateFormatter, formatPast2 } from '@/utils/formatTime'
@ -170,10 +172,18 @@ const dialogTitle = ref<string | undefined>(undefined) // 弹窗标题
const selectActivityType = ref<string | undefined>(undefined) // Task const selectActivityType = ref<string | undefined>(undefined) // Task
const selectTasks = ref<any[]>([]) // const selectTasks = ref<any[]>([]) //
type BpmnCanvas = Omit<Canvas, 'zoom'> & {
_svg?: SVGSVGElement
zoom: (newScale?: number | 'fit-viewport', center?: 'auto' | { x: number; y: number }) => number
}
const getCanvas = () => bpmnViewer.value?.get<BpmnCanvas>('canvas')
const getElementRegistry = () => bpmnViewer.value?.get<ElementRegistry>('elementRegistry')
/** Zoom恢复 */ /** Zoom恢复 */
const processReZoom = () => { const processReZoom = () => {
defaultZoom.value = 1 defaultZoom.value = 1
bpmnViewer.value?.get('canvas').zoom('fit-viewport', 'auto') getCanvas()?.zoom('fit-viewport', 'auto')
} }
let resizeObserver: ResizeObserver | null = null let resizeObserver: ResizeObserver | null = null
@ -218,7 +228,7 @@ const processZoomIn = (zoomStep = 0.1) => {
throw new Error('[Process Designer Warn ]: The zoom ratio cannot be greater than 4') throw new Error('[Process Designer Warn ]: The zoom ratio cannot be greater than 4')
} }
defaultZoom.value = newZoom defaultZoom.value = newZoom
bpmnViewer.value?.get('canvas').zoom(defaultZoom.value) getCanvas()?.zoom(defaultZoom.value)
} }
/** Zoom缩小 */ /** Zoom缩小 */
@ -228,7 +238,7 @@ const processZoomOut = (zoomStep = 0.1) => {
throw new Error('[Process Designer Warn ]: The zoom ratio cannot be less than 0.2') throw new Error('[Process Designer Warn ]: The zoom ratio cannot be less than 0.2')
} }
defaultZoom.value = newZoom defaultZoom.value = newZoom
bpmnViewer.value?.get('canvas').zoom(defaultZoom.value) getCanvas()?.zoom(defaultZoom.value)
} }
/** 流程图预览清空 */ /** 流程图预览清空 */
@ -249,9 +259,9 @@ const addCustomDefs = () => {
if (!bpmnViewer.value) { if (!bpmnViewer.value) {
return return
} }
const canvas = bpmnViewer.value?.get('canvas') const canvas = getCanvas()
const svg = canvas?._svg const svg = canvas?._svg
svg.appendChild(customDefs.value) svg?.appendChild(customDefs.value)
} }
/** 节点选中 */ /** 节点选中 */
@ -340,8 +350,11 @@ const setProcessStatus = (view: any) => {
finishedSequenceFlowActivityIds, finishedSequenceFlowActivityIds,
rejectedTaskActivityIds rejectedTaskActivityIds
} = view } = view
const canvas = bpmnViewer.value.get('canvas') const canvas = getCanvas()
const elementRegistry = bpmnViewer.value.get('elementRegistry') const elementRegistry = getElementRegistry()
if (!canvas || !elementRegistry) {
return
}
// //
if (Array.isArray(finishedSequenceFlowActivityIds)) { if (Array.isArray(finishedSequenceFlowActivityIds)) {
@ -349,7 +362,7 @@ const setProcessStatus = (view: any) => {
if (item != null) { if (item != null) {
canvas.addMarker(item, 'success') canvas.addMarker(item, 'success')
const element = elementRegistry.get(item) const element = elementRegistry.get(item)
const conditionExpression = element.businessObject.conditionExpression const conditionExpression = element?.businessObject.conditionExpression
if (conditionExpression) { if (conditionExpression) {
canvas.addMarker(item, 'condition-expression') canvas.addMarker(item, 'condition-expression')
} }

View File

@ -101,7 +101,7 @@ const maxRemindCount = ref(1)
const elExtensionElements = ref() const elExtensionElements = ref()
const otherExtensions = ref() const otherExtensions = ref()
const configExtensions = ref([]) const configExtensions = ref<any[]>([])
const eventDefinition = ref() const eventDefinition = ref()
const resetElement = () => { const resetElement = () => {

View File

@ -215,6 +215,18 @@ import * as UserApi from '@/api/system/user'
import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node' import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node'
import { BpmModelFormType } from '@/utils/constants' import { BpmModelFormType } from '@/utils/constants'
type BpmnElement = {
id: string
type: string
businessObject: Record<string, any>
source?: BpmnElement
target?: BpmnElement
}
type ReturnTask = Record<string, any> & {
id: string
name?: string
}
defineOptions({ name: 'ElementCustomConfig4UserTask' }) defineOptions({ name: 'ElementCustomConfig4UserTask' })
const props = defineProps({ const props = defineProps({
id: String, id: String,
@ -231,16 +243,16 @@ const rejectHandlerTypeEl = ref()
const rejectHandlerType = ref() const rejectHandlerType = ref()
const returnNodeIdEl = ref() const returnNodeIdEl = ref()
const returnNodeId = ref() const returnNodeId = ref()
const returnTaskList = ref([]) const returnTaskList = ref<ReturnTask[]>([])
// //
const assignEmptyHandlerTypeEl = ref() const assignEmptyHandlerTypeEl = ref()
const assignEmptyHandlerType = ref() const assignEmptyHandlerType = ref()
const assignEmptyUserIdsEl = ref() const assignEmptyUserIdsEl = ref()
const assignEmptyUserIds = ref() const assignEmptyUserIds = ref<Array<string | number>>([])
// //
const buttonsSettingEl = ref() const buttonsSettingEl = ref<any[]>([])
const { btnDisplayNameEdit, changeBtnDisplayName } = useButtonsSetting() const { btnDisplayNameEdit, changeBtnDisplayName } = useButtonsSetting()
const btnDisplayNameBlurEvent = (index: number) => { const btnDisplayNameBlurEvent = (index: number) => {
btnDisplayNameEdit.value[index] = false btnDisplayNameEdit.value[index] = false
@ -250,7 +262,7 @@ const btnDisplayNameBlurEvent = (index: number) => {
} }
// //
const fieldsPermissionEl = ref([]) const fieldsPermissionEl = ref<any[]>([])
const { formType, fieldsPermissionConfig, getNodeConfigFormFields } = useFormFieldsPermission( const { formType, fieldsPermissionConfig, getNodeConfigFormFields } = useFormFieldsPermission(
FieldPermissionType.READ FieldPermissionType.READ
) )
@ -451,18 +463,20 @@ watch(
{ immediate: true } { immediate: true }
) )
function findAllPredecessorsExcludingStart(elementId, modeler) { function findAllPredecessorsExcludingStart(elementId: string, modeler: any) {
const elementRegistry = modeler.get('elementRegistry') const elementRegistry = modeler.get('elementRegistry')
const allConnections = elementRegistry.filter((element) => element.type === 'bpmn:SequenceFlow') const allConnections = elementRegistry.filter(
const predecessors = new Set() // 使 Set (element: BpmnElement) => element.type === 'bpmn:SequenceFlow'
const visited = new Set() // 访 )
const predecessors = new Set<Record<string, any>>() // 使 Set
const visited = new Set<BpmnElement>() // 访
// //
function isStartEvent(element) { function isStartEvent(element: BpmnElement) {
return element.type === 'bpmn:StartEvent' return element.type === 'bpmn:StartEvent'
} }
function findPredecessorsRecursively(element) { function findPredecessorsRecursively(element: BpmnElement) {
// 访 // 访
if (visited.has(element)) { if (visited.has(element)) {
return return
@ -472,10 +486,15 @@ function findAllPredecessorsExcludingStart(elementId, modeler) {
visited.add(element) visited.add(element)
// //
const incomingConnections = allConnections.filter((connection) => connection.target === element) const incomingConnections = allConnections.filter(
(connection: BpmnElement) => connection.target === element
)
incomingConnections.forEach((connection) => { incomingConnections.forEach((connection: BpmnElement) => {
const source = connection.source // const source = connection.source //
if (!source) {
return
}
// //
if (!isStartEvent(source)) { if (!isStartEvent(source)) {
@ -491,7 +510,7 @@ function findAllPredecessorsExcludingStart(elementId, modeler) {
findPredecessorsRecursively(targetElement) findPredecessorsRecursively(targetElement)
} }
return Array.from(predecessors) // return Array.from(predecessors) as ReturnTask[] //
} }
function useButtonsSetting() { function useButtonsSetting() {

View File

@ -236,7 +236,7 @@ const props = defineProps({
}) })
const prefix = inject('prefix') const prefix = inject('prefix')
const formKey = ref(undefined) const formKey = ref<number | undefined>()
const bpmnELement = ref() const bpmnELement = ref()
const elExtensionElements = ref() const elExtensionElements = ref()
const formData = ref() const formData = ref()
@ -282,10 +282,10 @@ const updateElementExtensions = () => {
}) })
} }
const formList = ref([]) // const formList = ref<Array<{ id: number; name: string }>>([]) //
onMounted(async () => { onMounted(async () => {
formList.value = await FormApi.getFormSimpleList() formList.value = await FormApi.getFormSimpleList()
formKey.value = parseInt(formKey.value) formKey.value = formKey.value != null ? Number(formKey.value) : undefined
}) })
watch( watch(

View File

@ -76,8 +76,8 @@ const getList = async () => {
} }
/** 提交表单 */ /** 提交表单 */
const emit = defineEmits(['success']) // success const emit = defineEmits(['success', 'select']) // success/select
const select = async (row) => { const select = async (row: ProcessListenerVO) => {
dialogVisible.value = false dialogVisible.value = false
// //
emit('select', row) emit('select', row)

View File

@ -117,8 +117,8 @@ const props = defineProps({
const prefix = inject('prefix') const prefix = inject('prefix')
const loopCharacteristics = ref('') const loopCharacteristics = ref('')
const loopInstanceForm = ref<any>({}) const loopInstanceForm = ref<any>({})
const bpmnElement = ref(null) const bpmnElement = ref<any | null>(null)
const multiLoopInstance = ref(null) const multiLoopInstance = ref<any | null>(null)
const bpmnInstances = () => (window as any)?.bpmnInstances const bpmnInstances = () => (window as any)?.bpmnInstances
const changeLoopCharacteristicsType = (type) => { const changeLoopCharacteristicsType = (type) => {
@ -261,7 +261,7 @@ const approveMethod = ref()
const approveRatio = ref(100) const approveRatio = ref(100)
const otherExtensions = ref() const otherExtensions = ref()
const getElementLoopNew = () => { const getElementLoopNew = () => {
if (props.type === 'UserTask') { if (props.type === 'UserTask' && bpmnElement.value) {
const extensionElements = const extensionElements =
bpmnElement.value.businessObject?.extensionElements ?? bpmnElement.value.businessObject?.extensionElements ??
bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] }) bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
@ -286,6 +286,9 @@ const onApproveRatioChange = () => {
updateLoopCharacteristics() updateLoopCharacteristics()
} }
const updateLoopCharacteristics = () => { const updateLoopCharacteristics = () => {
if (!bpmnElement.value) {
return
}
// ApproveMethodmultiInstanceLoopCharacteristics // ApproveMethodmultiInstanceLoopCharacteristics
if (approveMethod.value === ApproveMethodType.RANDOM_SELECT_ONE_APPROVE) { if (approveMethod.value === ApproveMethodType.RANDOM_SELECT_ONE_APPROVE) {
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), { bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
@ -334,9 +337,11 @@ const updateLoopCharacteristics = () => {
} }
) )
} }
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), { if (multiLoopInstance.value) {
loopCharacteristics: toRaw(multiLoopInstance.value) bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
}) loopCharacteristics: toRaw(multiLoopInstance.value)
})
}
} }
// ApproveMethodExtensionElements // ApproveMethodExtensionElements

View File

@ -61,8 +61,8 @@ const getList = async () => {
} }
/** 提交表单 */ /** 提交表单 */
const emit = defineEmits(['success']) // success const emit = defineEmits(['success', 'select']) // success/select
const select = async (row) => { const select = async (row: ProcessExpressionVO) => {
dialogVisible.value = false dialogVisible.value = false
// //
emit('select', row) emit('select', row)

View File

@ -233,7 +233,13 @@ const props = defineProps({
type: String type: String
}) })
const prefix = inject('prefix') const prefix = inject('prefix')
const userTaskForm = ref({ type CandidateParam = Array<string | number> | string | number
type UserTaskForm = {
candidateStrategy?: CandidateStrategy
candidateParam: CandidateParam
skipExpression: string
}
const userTaskForm = ref<UserTaskForm>({
candidateStrategy: undefined, // candidateStrategy: undefined, //
candidateParam: [], // candidateParam: [], //
skipExpression: '' // skipExpression: '' //
@ -405,13 +411,6 @@ const updateElementTask = () => {
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), { bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
extensionElements: extensions extensionElements: extensions
}) })
// extensionElements
return
bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
candidateStrategy: userTaskForm.value.candidateStrategy,
candidateParam: userTaskForm.value.candidateParam.join(',')
})
} }
const updateSkipExpression = () => { const updateSkipExpression = () => {