From 3d8f1290c3c023f34567978d8eebb9985881dc98 Mon Sep 17 00:00:00 2001 From: zws <447643445@qq.com> Date: Tue, 14 Jan 2025 08:46:08 +0800 Subject: [PATCH 1/5] =?UTF-8?q?perf:=20bpm=20=E6=B5=81=E7=A8=8B=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=E8=A1=A8=E5=8D=95=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= =?UTF-8?q?.=20=E5=8E=BB=E6=8E=89=E5=A4=A7=E9=87=8Fwatch=20=E4=BB=A3?= =?UTF-8?q?=E7=A0=81.=20=E7=94=A8=E4=BE=9D=E8=B5=96=E6=B3=A8=E5=85=A5?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2props=20=E4=BC=A0=E9=80=92=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E6=95=B0=E6=8D=AE.=20=E5=A2=9E=E5=8A=A0=E5=AF=BC=E5=85=A5?= =?UTF-8?q?=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/SimpleProcessDesigner.vue | 118 +---------- .../src/SimpleProcessModel.vue | 63 +++++- .../package/designer/ProcessDesigner.vue | 23 +-- src/views/bpm/model/editor/index.vue | 190 +----------------- src/views/bpm/model/form/BasicInfo.vue | 51 ++--- src/views/bpm/model/form/FormDesign.vue | 11 +- src/views/bpm/model/form/ProcessDesign.vue | 166 +-------------- src/views/bpm/model/form/index.vue | 150 ++++---------- src/views/bpm/simple/SimpleModelDesign.vue | 113 +---------- 9 files changed, 156 insertions(+), 729 deletions(-) diff --git a/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue b/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue index 22e6073f..ad42696b 100644 --- a/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue +++ b/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue @@ -40,7 +40,7 @@ defineOptions({ name: 'SimpleProcessDesigner' }) -const emits = defineEmits(['success', 'init-finished']) // 保存成功事件 +const emits = defineEmits(['success']) // 保存成功事件 const props = defineProps({ modelId: { @@ -59,13 +59,12 @@ const props = defineProps({ startUserIds : { type: Array, required: false - }, - value: { - type: [String, Object], - required: false } }) +const processData = inject('processData') as Ref + + const loading = ref(false) const formFields = ref([]) const formType = ref(20) @@ -76,9 +75,6 @@ const deptOptions = ref([]) // 部门列表 const deptTreeOptions = ref() const userGroupOptions = ref([]) // 用户组列表 -// 添加当前值的引用 -const currentValue = ref() - provide('formFields', formFields) provide('formType', formType) provide('roleList', roleOptions) @@ -88,7 +84,8 @@ provide('deptList', deptOptions) provide('userGroupList', userGroupOptions) provide('deptTree', deptTreeOptions) provide('startUserIds', props.startUserIds) - +provide('tasks', []) +provide('processInstance', {}) const message = useMessage() // 国际化 const processNodeTree = ref() const errorDialogVisible = ref(false) @@ -112,70 +109,14 @@ const updateModel = () => { } } -// 加载流程数据 -const loadProcessData = async (data: any) => { - try { - if (data) { - const parsedData = typeof data === 'string' ? JSON.parse(data) : data - processNodeTree.value = parsedData - currentValue.value = parsedData - // 确保数据加载后刷新视图 - await nextTick() - if (simpleProcessModelRef.value?.refresh) { - await simpleProcessModelRef.value.refresh() - } - } - } catch (error) { - console.error('加载流程数据失败:', error) - } -} - -// 监听属性变化 -watch( - () => props.value, - async (newValue, oldValue) => { - if (newValue && newValue !== oldValue) { - await loadProcessData(newValue) - } - }, - { immediate: true, deep: true } -) - -// 监听流程节点树变化,自动保存 -watch( - () => processNodeTree.value, - async (newValue, oldValue) => { - if (newValue && oldValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) { - await saveSimpleFlowModel(newValue) - } - }, - { deep: true } -) const saveSimpleFlowModel = async (simpleModelNode: SimpleFlowNode) => { if (!simpleModelNode) { return } - // 校验节点 - errorNodes = [] - validateNode(simpleModelNode, errorNodes) - if (errorNodes.length > 0) { - errorDialogVisible.value = true - return - } - try { - if (props.modelId) { - // 编辑模式 - const data = { - id: props.modelId, - simpleModel: simpleModelNode - } - await updateBpmSimpleModel(data) - } - // 无论是编辑还是新建模式,都更新当前值并触发事件 - currentValue.value = simpleModelNode + processData.value = simpleModelNode emits('success', simpleModelNode) } catch (error) { console.error('保存失败:', error) @@ -246,61 +187,20 @@ onMounted(async () => { deptTreeOptions.value = handleTree(deptOptions.value as DeptApi.DeptVO[], 'id') // 获取用户组列表 userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList() - // 加载流程数据 - if (props.modelId) { - // 获取 SIMPLE 设计器模型 - const result = await getBpmSimpleModel(props.modelId) - if (result) { - await loadProcessData(result) - } else { - updateModel() - } - } else if (props.value) { - await loadProcessData(props.value) + if (processData.value) { + processNodeTree.value = processData?.value } else { updateModel() } } finally { loading.value = false - emits('init-finished') } }) const simpleProcessModelRef = ref() -/** 获取当前流程数据 */ -const getCurrentFlowData = async () => { - try { - if (simpleProcessModelRef.value) { - const data = await simpleProcessModelRef.value.getCurrentFlowData() - if (data) { - currentValue.value = data - return data - } - } - return currentValue.value - } catch (error) { - console.error('获取流程数据失败:', error) - return currentValue.value - } -} - -// 刷新方法 -const refresh = async () => { - try { - if (currentValue.value) { - await loadProcessData(currentValue.value) - } - } catch (error) { - console.error('刷新失败:', error) - } -} defineExpose({ - getCurrentFlowData, - updateModel, - loadProcessData, - refresh }) diff --git a/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue b/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue index ccd1f10d..b9a26475 100644 --- a/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue +++ b/src/components/SimpleProcessDesignerV2/src/SimpleProcessModel.vue @@ -3,11 +3,31 @@
+ 导出 + 导入 + + {{ scaleValue }}% + + + + + + + + +
@@ -33,7 +53,8 @@ import ProcessNodeTree from './ProcessNodeTree.vue' import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT } from './consts' import { useWatchNode } from './node' -import { ZoomOut, ZoomIn, ScaleToOriginal } from '@element-plus/icons-vue' +import { ZoomOut, ZoomIn, ScaleToOriginal, Select } from '@element-plus/icons-vue' +import { isString } from '@/utils/is' defineOptions({ name: 'SimpleProcessModel' @@ -85,6 +106,16 @@ const processReZoom = () => { const errorDialogVisible = ref(false) let errorNodes: SimpleFlowNode[] = [] +const saveSimpleFlowModel = async () => { + errorNodes = [] + validateNode(processNodeTree.value, errorNodes) + if (errorNodes.length > 0) { + errorDialogVisible.value = true + return + } + emits('save', processNodeTree.value) +} + // 校验节点设置。 暂时以 showText 为空 未节点错误配置 const validateNode = (node: SimpleFlowNode | undefined, errorNodes: SimpleFlowNode[]) => { if (node) { @@ -143,6 +174,36 @@ const getCurrentFlowData = async () => { defineExpose({ getCurrentFlowData }) + +const exportJson = () => { + const blob = new Blob([JSON.stringify(processNodeTree.value)]); + const tempLink = document.createElement('a'); // 创建a标签 + const href = window.URL.createObjectURL(blob); // 创建下载的链接 + //filename + const fileName = `model.json`; + tempLink.href = href; + tempLink.target = '_blank'; + tempLink.download = fileName; + document.body.appendChild(tempLink); + tempLink.click(); // 点击下载 + document.body.removeChild(tempLink); // 下载完成移除元素 + window.URL.revokeObjectURL(href); // 释放掉blob对象 +} +const importJson = () => { + refFile.value.click() +} +const refFile = ref() +// 加载本地文件 +const importLocalFile = () => { + const file = refFile.value.files[0] + const reader = new FileReader() + reader.readAsText(file) + reader.onload = function () { + if (isString(this.result)) { + processNodeTree.value = JSON.parse(this.result) + } + } +} diff --git a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue index 9d2fa5ba..5b3d14f4 100644 --- a/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue +++ b/src/components/bpmnProcessDesigner/package/designer/ProcessDesigner.vue @@ -308,28 +308,6 @@ const props = defineProps({ } }) -// 监听value变化,重新加载流程图 -watch( - () => props.value, - (newValue) => { - if (newValue && bpmnModeler) { - createNewDiagram(newValue) - } - }, - { immediate: true } -) - -// 监听processId和processName变化 -watch( - [() => props.processId, () => props.processName], - ([newId, newName]) => { - if (newId && newName && !props.value) { - createNewDiagram(null) - } - }, - { immediate: true } -) - provide('configGlobal', props) let bpmnModeler: any = null const defaultZoom = ref(1) @@ -480,6 +458,7 @@ const initModelListeners = () => { emit('commandStack-changed', event) emit('input', xml) emit('change', xml) + emit('save', xml) } catch (e: any) { console.error(`[Process Designer Warn]: ${e.message || e}`) } diff --git a/src/views/bpm/model/editor/index.vue b/src/views/bpm/model/editor/index.vue index 37eff739..512eb152 100644 --- a/src/views/bpm/model/editor/index.vue +++ b/src/views/bpm/model/editor/index.vue @@ -3,6 +3,7 @@ () @@ -51,10 +52,11 @@ const formType = ref(20) provide('formFields', formFields) provide('formType', formType) -const xmlString = ref('') // BPMN XML +//注入 流程数据 +const xmlString = inject('processData') as Ref + const modeler = shallowRef() // BPMN Modeler const processDesigner = ref() -const isModelerReady = ref(false) const controlForm = ref({ simulation: true, labelEditing: false, @@ -65,154 +67,27 @@ const controlForm = ref({ }) const model = ref() // 流程模型的信息 -// 初始化 bpmnInstances -const initBpmnInstances = () => { - if (!modeler.value) return false - try { - const instances = { - modeler: modeler.value, - modeling: modeler.value.get('modeling'), - moddle: modeler.value.get('moddle'), - eventBus: modeler.value.get('eventBus'), - bpmnFactory: modeler.value.get('bpmnFactory'), - elementFactory: modeler.value.get('elementFactory'), - elementRegistry: modeler.value.get('elementRegistry'), - replace: modeler.value.get('replace'), - selection: modeler.value.get('selection') - } - - // 检查所有实例是否都存在 - return Object.values(instances).every((instance) => instance) - } catch (error) { - console.error('初始化 bpmnInstances 失败:', error) - return false - } -} /** 初始化 modeler */ const initModeler = async (item) => { - try { - modeler.value = item - // 等待 modeler 初始化完成 - await nextTick() - - // 确保 modeler 的所有实例都已经准备好 - if (initBpmnInstances()) { - isModelerReady.value = true - emit('init-finished') - - // 初始化完成后,设置初始值 - if (props.modelId) { - // 编辑模式 - const data = await ModelApi.getModel(props.modelId) - model.value = { - ...data, - bpmnXml: undefined // 清空 bpmnXml 属性 - } - xmlString.value = data.bpmnXml || getDefaultBpmnXml(data.key, data.name) - } else if (props.modelKey && props.modelName) { - // 新建模式 - xmlString.value = props.value || getDefaultBpmnXml(props.modelKey, props.modelName) - model.value = { - key: props.modelKey, - name: props.modelName - } as ModelApi.ModelVO - } - - // 导入XML并刷新视图 - await nextTick() - try { - await modeler.value.importXML(xmlString.value) - if (processDesigner.value?.refresh) { - processDesigner.value.refresh() - } - } catch (error) { - console.error('导入XML失败:', error) - } - } else { - console.error('modeler 实例未完全初始化') - } - } catch (error) { - console.error('初始化 modeler 失败:', error) - } + modeler.value = item } -/** 获取默认的BPMN XML */ -const getDefaultBpmnXml = (key: string, name: string) => { - return ` - - - - - -` -} /** 添加/修改模型 */ const save = async (bpmnXml: string) => { try { xmlString.value = bpmnXml - if (props.modelId) { - // 编辑模式 - const data = { - ...model.value, - bpmnXml: bpmnXml - } as unknown as ModelApi.ModelVO - await ModelApi.updateModelBpmn(data) - emit('success') - } else { - // 新建模式,直接返回XML - emit('success', bpmnXml) - } + emit('success', bpmnXml) } catch (error) { console.error('保存失败:', error) message.error('保存失败') } } -// 监听 key、name 和 value 的变化 -watch( - [() => props.modelKey, () => props.modelName, () => props.value], - async ([newKey, newName, newValue]) => { - if (!props.modelId && isModelerReady.value) { - let shouldRefresh = false - - if (newKey && newName) { - const newXml = newValue || getDefaultBpmnXml(newKey, newName) - if (newXml !== xmlString.value) { - xmlString.value = newXml - shouldRefresh = true - } - model.value = { - ...model.value, - key: newKey, - name: newName - } as ModelApi.ModelVO - } else if (newValue && newValue !== xmlString.value) { - xmlString.value = newValue - shouldRefresh = true - } - - if (shouldRefresh) { - // 确保更新后重新渲染 - await nextTick() - if (processDesigner.value?.refresh) { - try { - await modeler.value?.importXML(xmlString.value) - processDesigner.value.refresh() - } catch (error) { - console.error('导入XML失败:', error) - } - } - } - } - }, - { deep: true } -) // 在组件卸载时清理 onBeforeUnmount(() => { - isModelerReady.value = false modeler.value = null // 清理全局实例 const w = window as any @@ -221,54 +96,7 @@ onBeforeUnmount(() => { } }) -/** 获取 XML 字符串 */ -const saveXML = async () => { - if (!modeler.value) { - return { xml: xmlString.value } - } - try { - const result = await modeler.value.saveXML({ format: true }) - xmlString.value = result.xml - return result - } catch (error) { - console.error('获取XML失败:', error) - return { xml: xmlString.value } - } -} -/** 获取SVG字符串 */ -const saveSVG = async () => { - if (!modeler.value) { - return { svg: undefined } - } - try { - return await modeler.value.saveSVG() - } catch (error) { - console.error('获取SVG失败:', error) - return { svg: undefined } - } -} - -/** 刷新视图 */ -const refresh = async () => { - if (processDesigner.value?.refresh && modeler.value) { - try { - await modeler.value.importXML(xmlString.value) - processDesigner.value.refresh() - } catch (error) { - console.error('刷新视图失败:', error) - } - } -} - -// 暴露必要的属性和方法给父组件 -defineExpose({ - modeler, - isModelerReady, - saveXML, - saveSVG, - refresh -}) From 4fe158b2ec5d03bf5ca206c9e04e85bc1aa38bc7 Mon Sep 17 00:00:00 2001 From: zws <447643445@qq.com> Date: Tue, 14 Jan 2025 12:00:08 +0800 Subject: [PATCH 2/5] =?UTF-8?q?perf:=20bpm=20=E4=BF=AE=E5=A4=8Dbpmn?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1=E5=99=A8=E4=B8=8D=E6=98=BE=E7=A4=BA=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/bpm/model/editor/index.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/src/views/bpm/model/editor/index.vue b/src/views/bpm/model/editor/index.vue index 512eb152..101ea1b8 100644 --- a/src/views/bpm/model/editor/index.vue +++ b/src/views/bpm/model/editor/index.vue @@ -3,7 +3,6 @@ Date: Wed, 15 Jan 2025 14:54:23 +0800 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=9C=A8keepAlive=E4=B8=8B=E5=88=B7=E6=96=B0=E4=B8=8D=E8=A7=A6?= =?UTF-8?q?=E5=8F=91onActivated=E9=92=A9=E5=AD=90=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layout/components/TagsView/src/TagsView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/layout/components/TagsView/src/TagsView.vue b/src/layout/components/TagsView/src/TagsView.vue index dcbb90fd..3bfb69df 100644 --- a/src/layout/components/TagsView/src/TagsView.vue +++ b/src/layout/components/TagsView/src/TagsView.vue @@ -243,7 +243,7 @@ const move = (to: number) => { start() } -onMounted(() => { +onBeforeMount(() => { initTags() addTags() }) From 8df285aefb5abfbc1573988dc03da5718008738f Mon Sep 17 00:00:00 2001 From: zws <447643445@qq.com> Date: Wed, 15 Jan 2025 14:57:23 +0800 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20bpm=20=E7=94=A8onActivated=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2onMounted=20=E8=A7=A3=E5=86=B3=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E8=BF=94=E5=9B=9E=E5=90=8E=E4=B8=8D=E5=88=B7?= =?UTF-8?q?=E6=96=B0=E6=96=B0=E7=9A=84=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/views/bpm/model/index.vue | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/views/bpm/model/index.vue b/src/views/bpm/model/index.vue index c7d94170..8132bf73 100644 --- a/src/views/bpm/model/index.vue +++ b/src/views/bpm/model/index.vue @@ -207,6 +207,8 @@ const getList = async () => { /** 初始化 **/ onMounted(() => { +}) +onActivated(()=>{ getList() }) From b1174313185998677be5a7142a0f716563e0b478 Mon Sep 17 00:00:00 2001 From: zws <447643445@qq.com> Date: Wed, 15 Jan 2025 15:04:23 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20bpm=20=E6=B7=BB=E5=8A=A0=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=E6=A8=A1=E5=9E=8B=E5=A4=8D=E5=88=B6=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/router/modules/remaining.ts | 2 +- src/views/bpm/model/CategoryDraggableModel.vue | 11 ++++++++++- src/views/bpm/model/form/index.vue | 5 ++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 806f954d..34466079 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -344,7 +344,7 @@ const remainingRouter: AppRouteRecordRaw[] = [ } }, { - path: 'manager/model/update/:id', + path: 'manager/model/:type/:id', component: () => import('@/views/bpm/model/form/index.vue'), name: 'BpmModelUpdate', meta: { diff --git a/src/views/bpm/model/CategoryDraggableModel.vue b/src/views/bpm/model/CategoryDraggableModel.vue index f3b5a422..8fe6e14d 100644 --- a/src/views/bpm/model/CategoryDraggableModel.vue +++ b/src/views/bpm/model/CategoryDraggableModel.vue @@ -163,6 +163,15 @@ > 修改 + + 复制 + { } else { push({ name: 'BpmModelUpdate', - params: { id } + params: { id, type } }) } } diff --git a/src/views/bpm/model/form/index.vue b/src/views/bpm/model/form/index.vue index 3a45e716..6c5cb21a 100644 --- a/src/views/bpm/model/form/index.vue +++ b/src/views/bpm/model/form/index.vue @@ -162,7 +162,10 @@ const initData = async () => { if (modelId) { // 修改场景 formData.value = await ModelApi.getModel(modelId) - + // 复制场景 + if (route.params.type === 'copy') { + delete formData.value.id + } } else { // 新增场景 formData.value.managerUserIds.push(userStore.getUser.id)