diff --git a/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue b/src/components/SimpleProcessDesignerV2/src/SimpleProcessDesigner.vue index a6c7a37e..1125d8e7 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() provide('processNodeTree', processNodeTree) @@ -113,70 +110,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) @@ -247,61 +188,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/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() }) 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/editor/index.vue b/src/views/bpm/model/editor/index.vue index 37eff739..101ea1b8 100644 --- a/src/views/bpm/model/editor/index.vue +++ b/src/views/bpm/model/editor/index.vue @@ -15,7 +15,7 @@ /> () @@ -51,10 +51,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 +66,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 +95,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 -})