From 221918bba28d2384d03c596a68256d7832e4a0e0 Mon Sep 17 00:00:00 2001
From: 潘志宝 <979469083@qq.com>
Date: 星期一, 06 一月 2025 13:30:50 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master'

---
 src/views/bpm/model/editor/index.vue |  258 ++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 204 insertions(+), 54 deletions(-)

diff --git a/src/views/bpm/model/editor/index.vue b/src/views/bpm/model/editor/index.vue
index 1a41a50..37eff73 100644
--- a/src/views/bpm/model/editor/index.vue
+++ b/src/views/bpm/model/editor/index.vue
@@ -3,7 +3,6 @@
     <!-- 流程设计器,负责绘制流程等 -->
     <MyProcessDesigner
       key="designer"
-      v-if="xmlString !== undefined"
       v-model="xmlString"
       :value="xmlString"
       v-bind="controlForm"
@@ -11,12 +10,14 @@
       ref="processDesigner"
       @init-finished="initModeler"
       :additionalModel="controlForm.additionalModel"
+      :model="model"
       @save="save"
     />
     <!-- 流程属性器,负责编辑每个流程节点的属性 -->
     <MyProcessPenal
+      v-if="isModelerReady && modeler"
       key="penal"
-      :bpmnModeler="modeler as any"
+      :bpmnModeler="modeler"
       :prefix="controlForm.prefix"
       class="process-panel"
       :model="model"
@@ -31,12 +32,17 @@
 // 自定义左侧菜单(修改 默认任务 为 用户任务)
 import CustomPaletteProvider from '@/components/bpmnProcessDesigner/package/designer/plugins/palette'
 import * as ModelApi from '@/api/bpm/model'
-import { getForm, FormVO } from '@/api/bpm/form'
 
 defineOptions({ name: 'BpmModelEditor' })
 
-const router = useRouter() // 路由
-const { query } = useRoute() // 路由的查询
+const props = defineProps<{
+  modelId?: string
+  modelKey?: string
+  modelName?: string
+  value?: string
+}>()
+
+const emit = defineEmits(['success', 'init-finished'])
 const message = useMessage() // 国际化
 
 // 表单信息
@@ -45,8 +51,10 @@
 provide('formFields', formFields)
 provide('formType', formType)
 
-const xmlString = ref(undefined) // BPMN XML
-const modeler = ref(null) // BPMN Modeler
+const xmlString = ref<string>('') // BPMN XML
+const modeler = shallowRef() // BPMN Modeler
+const processDesigner = ref()
+const isModelerReady = ref(false)
 const controlForm = ref({
   simulation: true,
   labelEditing: false,
@@ -57,73 +65,215 @@
 })
 const model = ref<ModelApi.ModelVO>() // 流程模型的信息
 
+// 初始化 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 = (item) => {
-  setTimeout(() => {
+const initModeler = async (item) => {
+  try {
     modeler.value = item
-  }, 10)
+    // 等待 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)
+  }
+}
+
+/** 获取默认的BPMN XML */
+const getDefaultBpmnXml = (key: string, name: string) => {
+  return `<?xml version="1.0" encoding="UTF-8"?>
+<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.activiti.org/processdef">
+  <process id="${key}" name="${name}" isExecutable="true" />
+  <bpmndi:BPMNDiagram id="BPMNDiagram">
+    <bpmndi:BPMNPlane id="${key}_di" bpmnElement="${key}" />
+  </bpmndi:BPMNDiagram>
+</definitions>`
 }
 
 /** 添加/修改模型 */
 const save = async (bpmnXml: string) => {
-  const data = {
-    ...model.value,
-    bpmnXml: bpmnXml // bpmnXml 只是初始化流程图,后续修改无法通过它获得
-  } as unknown as ModelApi.ModelVO
-  // 提交
-  if (data.id) {
-    await ModelApi.updateModelBpmn(data)
-    message.success('修改成功')
-  } else {
-    await ModelApi.updateModelBpmn(data)
-    message.success('新增成功')
+  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)
+    }
+  } catch (error) {
+    console.error('保存失败:', error)
+    message.error('保存失败')
   }
-  // 跳转回去
-  close()
 }
 
-/** 关闭按钮 */
-const close = () => {
-  router.push({ path: '/bpm/manager/model' })
+// 监听 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
+  if (w.bpmnInstances) {
+    w.bpmnInstances = null
+  }
+})
+
+/** 获取 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 }
+  }
 }
 
-/** 初始化 */
-onMounted(async () => {
-  const modelId = query.modelId as unknown as number
-  if (!modelId) {
-    message.error('缺少模型 modelId 编号')
-    return
+/** 获取SVG字符串 */
+const saveSVG = async () => {
+  if (!modeler.value) {
+    return { svg: undefined }
   }
-  // 查询模型
-  const data = await ModelApi.getModel(modelId)
-  if (!data.bpmnXml) {
-    // 首次创建的 Model 模型,它是没有 bpmnXml,此时需要给它一个默认的
-    data.bpmnXml = ` <?xml version="1.0" encoding="UTF-8"?>
-<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.activiti.org/processdef">
-  <process id="${data.key}" name="${data.name}" isExecutable="true" />
-  <bpmndi:BPMNDiagram id="BPMNDiagram">
-    <bpmndi:BPMNPlane id="${data.key}_di" bpmnElement="${data.key}" />
-  </bpmndi:BPMNDiagram>
-</definitions>`
+  try {
+    return await modeler.value.saveSVG()
+  } catch (error) {
+    console.error('获取SVG失败:', error)
+    return { svg: undefined }
   }
+}
 
-  formType.value = data.formType
-  if (data.formType === 10) {
-    const bpmnForm = (await getForm(data.formId)) as unknown as FormVO
-    formFields.value = bpmnForm?.fields
+/** 刷新视图 */
+const refresh = async () => {
+  if (processDesigner.value?.refresh && modeler.value) {
+    try {
+      await modeler.value.importXML(xmlString.value)
+      processDesigner.value.refresh()
+    } catch (error) {
+      console.error('刷新视图失败:', error)
+    }
   }
+}
 
-  model.value = {
-    ...data,
-    bpmnXml: undefined // 清空 bpmnXml 属性
-  }
-  xmlString.value = data.bpmnXml
+// 暴露必要的属性和方法给父组件
+defineExpose({
+  modeler,
+  isModelerReady,
+  saveXML,
+  saveSVG,
+  refresh
 })
 </script>
 <style lang="scss">
 .process-panel__container {
   position: absolute;
-  top: 90px;
-  right: 60px;
+  top: 172px;
+  right: 70px;
 }
 </style>

--
Gitblit v1.9.3