perf: bpm 流程模型表单代码优化. 去掉大量watch 代码. 用依赖注入替换props 传递流程数据. 增加导入导出
parent
49fc9b5412
commit
3d8f1290c3
|
@ -40,7 +40,7 @@ defineOptions({
|
||||||
name: 'SimpleProcessDesigner'
|
name: 'SimpleProcessDesigner'
|
||||||
})
|
})
|
||||||
|
|
||||||
const emits = defineEmits(['success', 'init-finished']) // 保存成功事件
|
const emits = defineEmits(['success']) // 保存成功事件
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelId: {
|
modelId: {
|
||||||
|
@ -59,13 +59,12 @@ const props = defineProps({
|
||||||
startUserIds : {
|
startUserIds : {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false
|
required: false
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: [String, Object],
|
|
||||||
required: false
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const processData = inject('processData') as Ref
|
||||||
|
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const formFields = ref<string[]>([])
|
const formFields = ref<string[]>([])
|
||||||
const formType = ref(20)
|
const formType = ref(20)
|
||||||
|
@ -76,9 +75,6 @@ const deptOptions = ref<DeptApi.DeptVO[]>([]) // 部门列表
|
||||||
const deptTreeOptions = ref()
|
const deptTreeOptions = ref()
|
||||||
const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]) // 用户组列表
|
const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]) // 用户组列表
|
||||||
|
|
||||||
// 添加当前值的引用
|
|
||||||
const currentValue = ref<SimpleFlowNode | undefined>()
|
|
||||||
|
|
||||||
provide('formFields', formFields)
|
provide('formFields', formFields)
|
||||||
provide('formType', formType)
|
provide('formType', formType)
|
||||||
provide('roleList', roleOptions)
|
provide('roleList', roleOptions)
|
||||||
|
@ -88,7 +84,8 @@ provide('deptList', deptOptions)
|
||||||
provide('userGroupList', userGroupOptions)
|
provide('userGroupList', userGroupOptions)
|
||||||
provide('deptTree', deptTreeOptions)
|
provide('deptTree', deptTreeOptions)
|
||||||
provide('startUserIds', props.startUserIds)
|
provide('startUserIds', props.startUserIds)
|
||||||
|
provide('tasks', [])
|
||||||
|
provide('processInstance', {})
|
||||||
const message = useMessage() // 国际化
|
const message = useMessage() // 国际化
|
||||||
const processNodeTree = ref<SimpleFlowNode | undefined>()
|
const processNodeTree = ref<SimpleFlowNode | undefined>()
|
||||||
const errorDialogVisible = ref(false)
|
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) => {
|
const saveSimpleFlowModel = async (simpleModelNode: SimpleFlowNode) => {
|
||||||
if (!simpleModelNode) {
|
if (!simpleModelNode) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验节点
|
|
||||||
errorNodes = []
|
|
||||||
validateNode(simpleModelNode, errorNodes)
|
|
||||||
if (errorNodes.length > 0) {
|
|
||||||
errorDialogVisible.value = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (props.modelId) {
|
processData.value = simpleModelNode
|
||||||
// 编辑模式
|
|
||||||
const data = {
|
|
||||||
id: props.modelId,
|
|
||||||
simpleModel: simpleModelNode
|
|
||||||
}
|
|
||||||
await updateBpmSimpleModel(data)
|
|
||||||
}
|
|
||||||
// 无论是编辑还是新建模式,都更新当前值并触发事件
|
|
||||||
currentValue.value = simpleModelNode
|
|
||||||
emits('success', simpleModelNode)
|
emits('success', simpleModelNode)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存失败:', error)
|
console.error('保存失败:', error)
|
||||||
|
@ -246,61 +187,20 @@ onMounted(async () => {
|
||||||
deptTreeOptions.value = handleTree(deptOptions.value as DeptApi.DeptVO[], 'id')
|
deptTreeOptions.value = handleTree(deptOptions.value as DeptApi.DeptVO[], 'id')
|
||||||
// 获取用户组列表
|
// 获取用户组列表
|
||||||
userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
|
userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
|
||||||
|
|
||||||
// 加载流程数据
|
// 加载流程数据
|
||||||
if (props.modelId) {
|
if (processData.value) {
|
||||||
// 获取 SIMPLE 设计器模型
|
processNodeTree.value = processData?.value
|
||||||
const result = await getBpmSimpleModel(props.modelId)
|
|
||||||
if (result) {
|
|
||||||
await loadProcessData(result)
|
|
||||||
} else {
|
|
||||||
updateModel()
|
|
||||||
}
|
|
||||||
} else if (props.value) {
|
|
||||||
await loadProcessData(props.value)
|
|
||||||
} else {
|
} else {
|
||||||
updateModel()
|
updateModel()
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
emits('init-finished')
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const simpleProcessModelRef = ref()
|
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({
|
defineExpose({
|
||||||
getCurrentFlowData,
|
|
||||||
updateModel,
|
|
||||||
loadProcessData,
|
|
||||||
refresh
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -3,11 +3,31 @@
|
||||||
<div class="position-absolute top-0px right-0px bg-#fff">
|
<div class="position-absolute top-0px right-0px bg-#fff">
|
||||||
<el-row type="flex" justify="end">
|
<el-row type="flex" justify="end">
|
||||||
<el-button-group key="scale-control" size="default">
|
<el-button-group key="scale-control" size="default">
|
||||||
|
<el-button size="default" @click="exportJson()"><Icon icon="ep:download" />导出</el-button>
|
||||||
|
<el-button size="default" @click="importJson()"><Icon icon="ep:upload" />导入</el-button>
|
||||||
|
<!-- 用于打开本地文件-->
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
id="files"
|
||||||
|
ref="refFile"
|
||||||
|
style="display: none"
|
||||||
|
accept=".json"
|
||||||
|
@change="importLocalFile"
|
||||||
|
/>
|
||||||
<el-button size="default" :icon="ScaleToOriginal" @click="processReZoom()" />
|
<el-button size="default" :icon="ScaleToOriginal" @click="processReZoom()" />
|
||||||
<el-button size="default" :plain="true" :icon="ZoomOut" @click="zoomOut()" />
|
<el-button size="default" :plain="true" :icon="ZoomOut" @click="zoomOut()" />
|
||||||
<el-button size="default" class="w-80px"> {{ scaleValue }}% </el-button>
|
<el-button size="default" class="w-80px"> {{ scaleValue }}% </el-button>
|
||||||
<el-button size="default" :plain="true" :icon="ZoomIn" @click="zoomIn()" />
|
<el-button size="default" :plain="true" :icon="ZoomIn" @click="zoomIn()" />
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
|
<!-- <el-button-->
|
||||||
|
<!-- v-if="!readonly"-->
|
||||||
|
<!-- size="default"-->
|
||||||
|
<!-- class="ml-4px"-->
|
||||||
|
<!-- type="primary"-->
|
||||||
|
<!-- :icon="Select"-->
|
||||||
|
<!-- @click="saveSimpleFlowModel"-->
|
||||||
|
<!-- >保存模型</el-button-->
|
||||||
|
<!-- >-->
|
||||||
</el-row>
|
</el-row>
|
||||||
</div>
|
</div>
|
||||||
<div class="simple-process-model" :style="`transform: scale(${scaleValue / 100});`">
|
<div class="simple-process-model" :style="`transform: scale(${scaleValue / 100});`">
|
||||||
|
@ -33,7 +53,8 @@
|
||||||
import ProcessNodeTree from './ProcessNodeTree.vue'
|
import ProcessNodeTree from './ProcessNodeTree.vue'
|
||||||
import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT } from './consts'
|
import { SimpleFlowNode, NodeType, NODE_DEFAULT_TEXT } from './consts'
|
||||||
import { useWatchNode } from './node'
|
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({
|
defineOptions({
|
||||||
name: 'SimpleProcessModel'
|
name: 'SimpleProcessModel'
|
||||||
|
@ -85,6 +106,16 @@ const processReZoom = () => {
|
||||||
const errorDialogVisible = ref(false)
|
const errorDialogVisible = ref(false)
|
||||||
let errorNodes: SimpleFlowNode[] = []
|
let errorNodes: SimpleFlowNode[] = []
|
||||||
|
|
||||||
|
const saveSimpleFlowModel = async () => {
|
||||||
|
errorNodes = []
|
||||||
|
validateNode(processNodeTree.value, errorNodes)
|
||||||
|
if (errorNodes.length > 0) {
|
||||||
|
errorDialogVisible.value = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
emits('save', processNodeTree.value)
|
||||||
|
}
|
||||||
|
|
||||||
// 校验节点设置。 暂时以 showText 为空 未节点错误配置
|
// 校验节点设置。 暂时以 showText 为空 未节点错误配置
|
||||||
const validateNode = (node: SimpleFlowNode | undefined, errorNodes: SimpleFlowNode[]) => {
|
const validateNode = (node: SimpleFlowNode | undefined, errorNodes: SimpleFlowNode[]) => {
|
||||||
if (node) {
|
if (node) {
|
||||||
|
@ -143,6 +174,36 @@ const getCurrentFlowData = async () => {
|
||||||
defineExpose({
|
defineExpose({
|
||||||
getCurrentFlowData
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|
|
@ -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)
|
provide('configGlobal', props)
|
||||||
let bpmnModeler: any = null
|
let bpmnModeler: any = null
|
||||||
const defaultZoom = ref(1)
|
const defaultZoom = ref(1)
|
||||||
|
@ -480,6 +458,7 @@ const initModelListeners = () => {
|
||||||
emit('commandStack-changed', event)
|
emit('commandStack-changed', event)
|
||||||
emit('input', xml)
|
emit('input', xml)
|
||||||
emit('change', xml)
|
emit('change', xml)
|
||||||
|
emit('save', xml)
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error(`[Process Designer Warn]: ${e.message || e}`)
|
console.error(`[Process Designer Warn]: ${e.message || e}`)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<!-- 流程设计器,负责绘制流程等 -->
|
<!-- 流程设计器,负责绘制流程等 -->
|
||||||
<MyProcessDesigner
|
<MyProcessDesigner
|
||||||
key="designer"
|
key="designer"
|
||||||
|
v-if="xmlString != undefined"
|
||||||
v-model="xmlString"
|
v-model="xmlString"
|
||||||
:value="xmlString"
|
:value="xmlString"
|
||||||
v-bind="controlForm"
|
v-bind="controlForm"
|
||||||
|
@ -15,7 +16,7 @@
|
||||||
/>
|
/>
|
||||||
<!-- 流程属性器,负责编辑每个流程节点的属性 -->
|
<!-- 流程属性器,负责编辑每个流程节点的属性 -->
|
||||||
<MyProcessPenal
|
<MyProcessPenal
|
||||||
v-if="isModelerReady && modeler"
|
v-if="modeler"
|
||||||
key="penal"
|
key="penal"
|
||||||
:bpmnModeler="modeler"
|
:bpmnModeler="modeler"
|
||||||
:prefix="controlForm.prefix"
|
:prefix="controlForm.prefix"
|
||||||
|
@ -37,8 +38,8 @@ defineOptions({ name: 'BpmModelEditor' })
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
modelId?: string
|
modelId?: string
|
||||||
modelKey?: string
|
modelKey: string
|
||||||
modelName?: string
|
modelName: string
|
||||||
value?: string
|
value?: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
|
@ -51,10 +52,11 @@ const formType = ref(20)
|
||||||
provide('formFields', formFields)
|
provide('formFields', formFields)
|
||||||
provide('formType', formType)
|
provide('formType', formType)
|
||||||
|
|
||||||
const xmlString = ref<string>('') // BPMN XML
|
//注入 流程数据
|
||||||
|
const xmlString = inject('processData') as Ref
|
||||||
|
|
||||||
const modeler = shallowRef() // BPMN Modeler
|
const modeler = shallowRef() // BPMN Modeler
|
||||||
const processDesigner = ref()
|
const processDesigner = ref()
|
||||||
const isModelerReady = ref(false)
|
|
||||||
const controlForm = ref({
|
const controlForm = ref({
|
||||||
simulation: true,
|
simulation: true,
|
||||||
labelEditing: false,
|
labelEditing: false,
|
||||||
|
@ -65,154 +67,27 @@ const controlForm = ref({
|
||||||
})
|
})
|
||||||
const model = ref<ModelApi.ModelVO>() // 流程模型的信息
|
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 */
|
/** 初始化 modeler */
|
||||||
const initModeler = async (item) => {
|
const initModeler = async (item) => {
|
||||||
try {
|
modeler.value = item
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取默认的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 save = async (bpmnXml: string) => {
|
||||||
try {
|
try {
|
||||||
xmlString.value = bpmnXml
|
xmlString.value = bpmnXml
|
||||||
if (props.modelId) {
|
emit('success', bpmnXml)
|
||||||
// 编辑模式
|
|
||||||
const data = {
|
|
||||||
...model.value,
|
|
||||||
bpmnXml: bpmnXml
|
|
||||||
} as unknown as ModelApi.ModelVO
|
|
||||||
await ModelApi.updateModelBpmn(data)
|
|
||||||
emit('success')
|
|
||||||
} else {
|
|
||||||
// 新建模式,直接返回XML
|
|
||||||
emit('success', bpmnXml)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存失败:', error)
|
console.error('保存失败:', error)
|
||||||
message.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(() => {
|
onBeforeUnmount(() => {
|
||||||
isModelerReady.value = false
|
|
||||||
modeler.value = null
|
modeler.value = null
|
||||||
// 清理全局实例
|
// 清理全局实例
|
||||||
const w = window as any
|
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
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.process-panel__container {
|
.process-panel__container {
|
||||||
|
|
|
@ -144,10 +144,6 @@ import { DICT_TYPE, getBoolDictOptions, getIntDictOptions } from '@/utils/dict'
|
||||||
import { UserVO } from '@/api/system/user'
|
import { UserVO } from '@/api/system/user'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
categoryList: {
|
categoryList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true
|
required: true
|
||||||
|
@ -158,8 +154,6 @@ const props = defineProps({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
|
||||||
|
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
const selectedStartUsers = ref<UserVO[]>([])
|
const selectedStartUsers = ref<UserVO[]>([])
|
||||||
const selectedManagerUsers = ref<UserVO[]>([])
|
const selectedManagerUsers = ref<UserVO[]>([])
|
||||||
|
@ -177,27 +171,30 @@ const rules = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建本地数据副本
|
// 创建本地数据副本
|
||||||
const modelData = computed({
|
const modelData = defineModel<any>()
|
||||||
get: () => props.modelValue,
|
|
||||||
set: (val) => emit('update:modelValue', val)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 初始化选中的用户
|
// 初始化选中的用户
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => modelData.value,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
if (newVal.startUserIds?.length) {
|
if (newVal.startUserIds?.length) {
|
||||||
selectedStartUsers.value = props.userList.filter((user: UserVO) =>
|
selectedStartUsers.value = props.userList.filter((user: UserVO) =>
|
||||||
newVal.startUserIds.includes(user.id)
|
newVal.startUserIds.includes(user.id)
|
||||||
) as UserVO[]
|
) as UserVO[]
|
||||||
|
} else {
|
||||||
|
selectedStartUsers.value = []
|
||||||
}
|
}
|
||||||
if (newVal.managerUserIds?.length) {
|
if (newVal.managerUserIds?.length) {
|
||||||
selectedManagerUsers.value = props.userList.filter((user: UserVO) =>
|
selectedManagerUsers.value = props.userList.filter((user: UserVO) =>
|
||||||
newVal.managerUserIds.includes(user.id)
|
newVal.managerUserIds.includes(user.id)
|
||||||
) as UserVO[]
|
) as UserVO[]
|
||||||
|
} else {
|
||||||
|
selectedManagerUsers.value = []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
/** 打开发起人选择 */
|
/** 打开发起人选择 */
|
||||||
|
@ -215,58 +212,52 @@ const openManagerUserSelect = () => {
|
||||||
/** 处理用户选择确认 */
|
/** 处理用户选择确认 */
|
||||||
const handleUserSelectConfirm = (_, users: UserVO[]) => {
|
const handleUserSelectConfirm = (_, users: UserVO[]) => {
|
||||||
if (currentSelectType.value === 'start') {
|
if (currentSelectType.value === 'start') {
|
||||||
selectedStartUsers.value = users
|
modelData.value = {
|
||||||
emit('update:modelValue', {
|
|
||||||
...modelData.value,
|
...modelData.value,
|
||||||
startUserIds: users.map((u) => u.id)
|
startUserIds: users.map((u) => u.id)
|
||||||
})
|
}
|
||||||
} else {
|
} else {
|
||||||
selectedManagerUsers.value = users
|
modelData.value = {
|
||||||
emit('update:modelValue', {
|
|
||||||
...modelData.value,
|
...modelData.value,
|
||||||
managerUserIds: users.map((u) => u.id)
|
managerUserIds: users.map((u) => u.id)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理发起人类型变化 */
|
/** 处理发起人类型变化 */
|
||||||
const handleStartUserTypeChange = (value: number) => {
|
const handleStartUserTypeChange = (value: number) => {
|
||||||
if (value !== 1) {
|
if (value !== 1) {
|
||||||
selectedStartUsers.value = []
|
modelData.value = {
|
||||||
emit('update:modelValue', {
|
|
||||||
...modelData.value,
|
...modelData.value,
|
||||||
startUserIds: []
|
startUserIds: []
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理管理员类型变化 */
|
/** 处理管理员类型变化 */
|
||||||
const handleManagerUserTypeChange = (value: number) => {
|
const handleManagerUserTypeChange = (value: number) => {
|
||||||
if (value !== 1) {
|
if (value !== 1) {
|
||||||
selectedManagerUsers.value = []
|
modelData.value = {
|
||||||
emit('update:modelValue', {
|
|
||||||
...modelData.value,
|
...modelData.value,
|
||||||
managerUserIds: []
|
managerUserIds: []
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 移除发起人 */
|
/** 移除发起人 */
|
||||||
const handleRemoveStartUser = (user: UserVO) => {
|
const handleRemoveStartUser = (user: UserVO) => {
|
||||||
selectedStartUsers.value = selectedStartUsers.value.filter((u) => u.id !== user.id)
|
modelData.value = {
|
||||||
emit('update:modelValue', {
|
|
||||||
...modelData.value,
|
...modelData.value,
|
||||||
startUserIds: modelData.value.startUserIds.filter((id: number) => id !== user.id)
|
startUserIds: modelData.value.startUserIds.filter((id: number) => id !== user.id)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 移除管理员 */
|
/** 移除管理员 */
|
||||||
const handleRemoveManagerUser = (user: UserVO) => {
|
const handleRemoveManagerUser = (user: UserVO) => {
|
||||||
selectedManagerUsers.value = selectedManagerUsers.value.filter((u) => u.id !== user.id)
|
modelData.value = {
|
||||||
emit('update:modelValue', {
|
|
||||||
...modelData.value,
|
...modelData.value,
|
||||||
managerUserIds: modelData.value.managerUserIds.filter((id: number) => id !== user.id)
|
managerUserIds: modelData.value.managerUserIds.filter((id: number) => id !== user.id)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 表单校验 */
|
/** 表单校验 */
|
||||||
|
|
|
@ -70,25 +70,16 @@ import * as FormApi from '@/api/bpm/form'
|
||||||
import { setConfAndFields2 } from '@/utils/formCreate'
|
import { setConfAndFields2 } from '@/utils/formCreate'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
formList: {
|
formList: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
|
||||||
|
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
|
|
||||||
// 创建本地数据副本
|
// 创建本地数据副本
|
||||||
const modelData = computed({
|
const modelData = defineModel<any>()
|
||||||
get: () => props.modelValue,
|
|
||||||
set: (val) => emit('update:modelValue', val)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 表单预览数据
|
// 表单预览数据
|
||||||
const formPreview = ref({
|
const formPreview = ref({
|
||||||
|
|
|
@ -6,10 +6,7 @@
|
||||||
:model-id="modelData.id"
|
:model-id="modelData.id"
|
||||||
:model-key="modelData.key"
|
:model-key="modelData.key"
|
||||||
:model-name="modelData.name"
|
:model-name="modelData.name"
|
||||||
:value="currentBpmnXml"
|
|
||||||
ref="bpmnEditorRef"
|
|
||||||
@success="handleDesignSuccess"
|
@success="handleDesignSuccess"
|
||||||
@init-finished="handleEditorInit"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -21,10 +18,7 @@
|
||||||
:model-key="modelData.key"
|
:model-key="modelData.key"
|
||||||
:model-name="modelData.name"
|
:model-name="modelData.name"
|
||||||
:start-user-ids="modelData.startUserIds"
|
:start-user-ids="modelData.startUserIds"
|
||||||
:value="currentSimpleModel"
|
|
||||||
ref="simpleEditorRef"
|
|
||||||
@success="handleDesignSuccess"
|
@success="handleDesignSuccess"
|
||||||
@init-finished="handleEditorInit"
|
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
@ -34,137 +28,16 @@ import { BpmModelType } from '@/utils/constants'
|
||||||
import BpmModelEditor from '../editor/index.vue'
|
import BpmModelEditor from '../editor/index.vue'
|
||||||
import SimpleModelDesign from '../../simple/SimpleModelDesign.vue'
|
import SimpleModelDesign from '../../simple/SimpleModelDesign.vue'
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue', 'success'])
|
|
||||||
|
|
||||||
const bpmnEditorRef = ref()
|
|
||||||
const simpleEditorRef = ref()
|
|
||||||
const isEditorInitialized = ref(false)
|
|
||||||
|
|
||||||
// 创建本地数据副本
|
// 创建本地数据副本
|
||||||
const modelData = computed({
|
const modelData = defineModel<any>()
|
||||||
get: () => props.modelValue,
|
|
||||||
set: (val) => emit('update:modelValue', val)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 保存当前的流程XML或数据
|
const processData = inject('processData') as Ref
|
||||||
const currentBpmnXml = ref('')
|
|
||||||
const currentSimpleModel = ref('')
|
|
||||||
|
|
||||||
// 初始化或更新当前的XML数据
|
|
||||||
const initOrUpdateXmlData = () => {
|
|
||||||
if (modelData.value) {
|
|
||||||
if (modelData.value.type === BpmModelType.BPMN) {
|
|
||||||
currentBpmnXml.value = modelData.value.bpmnXml || ''
|
|
||||||
} else {
|
|
||||||
currentSimpleModel.value = modelData.value.simpleModel || ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听modelValue的变化,更新数据
|
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(newVal) => {
|
|
||||||
if (newVal) {
|
|
||||||
if (newVal.type === BpmModelType.BPMN) {
|
|
||||||
if (newVal.bpmnXml && newVal.bpmnXml !== currentBpmnXml.value) {
|
|
||||||
currentBpmnXml.value = newVal.bpmnXml
|
|
||||||
// 如果编辑器已经初始化,刷新视图
|
|
||||||
if (isEditorInitialized.value && bpmnEditorRef.value?.refresh) {
|
|
||||||
nextTick(() => {
|
|
||||||
bpmnEditorRef.value.refresh()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (newVal.simpleModel && newVal.simpleModel !== currentSimpleModel.value) {
|
|
||||||
currentSimpleModel.value = newVal.simpleModel
|
|
||||||
// 如果编辑器已经初始化,刷新视图
|
|
||||||
if (isEditorInitialized.value && simpleEditorRef.value?.refresh) {
|
|
||||||
nextTick(() => {
|
|
||||||
simpleEditorRef.value.refresh()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true, deep: true }
|
|
||||||
)
|
|
||||||
|
|
||||||
/** 编辑器初始化完成的回调 */
|
|
||||||
const handleEditorInit = async () => {
|
|
||||||
isEditorInitialized.value = true
|
|
||||||
|
|
||||||
// 等待下一个tick,确保编辑器已经准备好
|
|
||||||
await nextTick()
|
|
||||||
|
|
||||||
// 初始化完成后,设置初始值
|
|
||||||
if (modelData.value.type === BpmModelType.BPMN) {
|
|
||||||
if (modelData.value.bpmnXml) {
|
|
||||||
currentBpmnXml.value = modelData.value.bpmnXml
|
|
||||||
if (bpmnEditorRef.value?.refresh) {
|
|
||||||
await nextTick()
|
|
||||||
bpmnEditorRef.value.refresh()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (modelData.value.simpleModel) {
|
|
||||||
currentSimpleModel.value = modelData.value.simpleModel
|
|
||||||
if (simpleEditorRef.value?.refresh) {
|
|
||||||
await nextTick()
|
|
||||||
simpleEditorRef.value.refresh()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 获取当前流程数据 */
|
|
||||||
const getProcessData = async () => {
|
|
||||||
try {
|
|
||||||
if (modelData.value.type === BpmModelType.BPMN) {
|
|
||||||
if (!bpmnEditorRef.value || !isEditorInitialized.value) {
|
|
||||||
return currentBpmnXml.value || undefined
|
|
||||||
}
|
|
||||||
const { xml } = await bpmnEditorRef.value.saveXML()
|
|
||||||
if (xml) {
|
|
||||||
currentBpmnXml.value = xml
|
|
||||||
return xml
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!simpleEditorRef.value || !isEditorInitialized.value) {
|
|
||||||
return currentSimpleModel.value || undefined
|
|
||||||
}
|
|
||||||
const flowData = await simpleEditorRef.value.getCurrentFlowData()
|
|
||||||
if (flowData) {
|
|
||||||
currentSimpleModel.value = flowData
|
|
||||||
return flowData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return modelData.value.type === BpmModelType.BPMN
|
|
||||||
? currentBpmnXml.value
|
|
||||||
: currentSimpleModel.value
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取流程数据失败:', error)
|
|
||||||
return modelData.value.type === BpmModelType.BPMN
|
|
||||||
? currentBpmnXml.value
|
|
||||||
: currentSimpleModel.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 表单校验 */
|
/** 表单校验 */
|
||||||
const validate = async () => {
|
const validate = async () => {
|
||||||
try {
|
try {
|
||||||
// 获取最新的流程数据
|
// 获取最新的流程数据
|
||||||
const processData = await getProcessData()
|
if (!processData.value) {
|
||||||
if (!processData) {
|
|
||||||
throw new Error('请设计流程')
|
throw new Error('请设计流程')
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
@ -172,27 +45,19 @@ const validate = async () => {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理设计器保存成功 */
|
/** 处理设计器保存成功 */
|
||||||
const handleDesignSuccess = async (data?: any) => {
|
const handleDesignSuccess = async (data?: any) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
if (modelData.value.type === BpmModelType.BPMN) {
|
|
||||||
currentBpmnXml.value = data
|
|
||||||
} else {
|
|
||||||
currentSimpleModel.value = data
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建新的对象以触发响应式更新
|
// 创建新的对象以触发响应式更新
|
||||||
const newModelData = {
|
const newModelData = {
|
||||||
...modelData.value,
|
...modelData.value,
|
||||||
bpmnXml: modelData.value.type === BpmModelType.BPMN ? data : null,
|
bpmnXml: modelData.value.type === BpmModelType.BPMN ? data : null,
|
||||||
simpleModel: modelData.value.type === BpmModelType.BPMN ? null : data
|
simpleModel: modelData.value.type === BpmModelType.BPMN ? null : data
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用emit更新父组件的数据
|
// 使用emit更新父组件的数据
|
||||||
await nextTick()
|
await nextTick()
|
||||||
emit('update:modelValue', newModelData)
|
//更新表单的模型数据部分
|
||||||
emit('success', data)
|
modelData.value = newModelData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,33 +68,14 @@ const showDesigner = computed(() => {
|
||||||
|
|
||||||
// 组件创建时初始化数据
|
// 组件创建时初始化数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initOrUpdateXmlData()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 组件卸载前保存数据
|
// 组件卸载前保存数据
|
||||||
onBeforeUnmount(async () => {
|
onBeforeUnmount(async () => {
|
||||||
try {
|
|
||||||
// 获取并保存最新的流程数据
|
|
||||||
const data = await getProcessData()
|
|
||||||
if (data) {
|
|
||||||
// 创建新的对象以触发响应式更新
|
|
||||||
const newModelData = {
|
|
||||||
...modelData.value,
|
|
||||||
bpmnXml: modelData.value.type === BpmModelType.BPMN ? data : null,
|
|
||||||
simpleModel: modelData.value.type === BpmModelType.BPMN ? null : data
|
|
||||||
}
|
|
||||||
|
|
||||||
// 使用emit更新父组件的数据
|
|
||||||
await nextTick()
|
|
||||||
emit('update:modelValue', newModelData)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('保存数据失败:', error)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
validate,
|
validate
|
||||||
getProcessData
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -71,7 +71,6 @@
|
||||||
v-if="currentStep === 2"
|
v-if="currentStep === 2"
|
||||||
v-model="formData"
|
v-model="formData"
|
||||||
ref="processDesignRef"
|
ref="processDesignRef"
|
||||||
@success="handleDesignSuccess"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -118,7 +117,8 @@ const validateProcess = async () => {
|
||||||
await processDesignRef.value?.validate()
|
await processDesignRef.value?.validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentStep = ref(0) // 步骤控制
|
const currentStep = ref(-1) // 步骤控制 一开始全部不展示等当前页面数据初始化完成
|
||||||
|
|
||||||
const steps = [
|
const steps = [
|
||||||
{ title: '基本信息', validator: validateBasic },
|
{ title: '基本信息', validator: validateBasic },
|
||||||
{ title: '表单设计', validator: validateForm },
|
{ title: '表单设计', validator: validateForm },
|
||||||
|
@ -145,17 +145,24 @@ const formData: any = ref({
|
||||||
managerUserIds: []
|
managerUserIds: []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
//流程数据
|
||||||
|
const processData = ref<any>()
|
||||||
|
|
||||||
|
provide("processData", processData)
|
||||||
|
|
||||||
// 数据列表
|
// 数据列表
|
||||||
const formList = ref([])
|
const formList = ref([])
|
||||||
const categoryList = ref([])
|
const categoryList = ref([])
|
||||||
const userList = ref<UserApi.UserVO[]>([])
|
const userList = ref<UserApi.UserVO[]>([])
|
||||||
|
|
||||||
|
|
||||||
/** 初始化数据 */
|
/** 初始化数据 */
|
||||||
const initData = async () => {
|
const initData = async () => {
|
||||||
const modelId = route.params.id as string
|
const modelId = route.params.id as string
|
||||||
if (modelId) {
|
if (modelId) {
|
||||||
// 修改场景
|
// 修改场景
|
||||||
formData.value = await ModelApi.getModel(modelId)
|
formData.value = await ModelApi.getModel(modelId)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// 新增场景
|
// 新增场景
|
||||||
formData.value.managerUserIds.push(userStore.getUser.id)
|
formData.value.managerUserIds.push(userStore.getUser.id)
|
||||||
|
@ -167,59 +174,49 @@ const initData = async () => {
|
||||||
categoryList.value = await CategoryApi.getCategorySimpleList()
|
categoryList.value = await CategoryApi.getCategorySimpleList()
|
||||||
// 获取用户列表
|
// 获取用户列表
|
||||||
userList.value = await UserApi.getSimpleUserList()
|
userList.value = await UserApi.getSimpleUserList()
|
||||||
|
|
||||||
|
currentStep.value = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//根据类型切换流程数据
|
||||||
|
watch(async () => formData.value.type, (newValue, oldValue) => {
|
||||||
|
if (formData.value.type === BpmModelType.BPMN) {
|
||||||
|
processData.value = formData.value.bpmnXml
|
||||||
|
} else if (formData.value.type === BpmModelType.SIMPLE) {
|
||||||
|
processData.value = formData.value.simpleModel
|
||||||
|
}
|
||||||
|
console.log('加载流程数据', processData.value)
|
||||||
|
}, {
|
||||||
|
immediate: true,
|
||||||
|
})
|
||||||
|
|
||||||
/** 校验所有步骤数据是否完整 */
|
/** 校验所有步骤数据是否完整 */
|
||||||
const validateAllSteps = async () => {
|
const validateAllSteps = async () => {
|
||||||
try {
|
try {
|
||||||
// 基本信息校验
|
// 基本信息校验
|
||||||
await basicInfoRef.value?.validate()
|
try {
|
||||||
if (!formData.value.key || !formData.value.name || !formData.value.category) {
|
await validateBasic()
|
||||||
|
} catch (error) {
|
||||||
currentStep.value = 0
|
currentStep.value = 0
|
||||||
throw new Error('请完善基本信息')
|
throw new Error('请完善基本信息')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 表单设计校验
|
// 表单设计校验
|
||||||
await formDesignRef.value?.validate()
|
try {
|
||||||
if (formData.value.formType === 10 && !formData.value.formId) {
|
await validateForm()
|
||||||
currentStep.value = 1
|
} catch (error) {
|
||||||
throw new Error('请选择流程表单')
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
formData.value.formType === 20 &&
|
|
||||||
(!formData.value.formCustomCreatePath || !formData.value.formCustomViewPath)
|
|
||||||
) {
|
|
||||||
currentStep.value = 1
|
currentStep.value = 1
|
||||||
throw new Error('请完善自定义表单信息')
|
throw new Error('请完善自定义表单信息')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 流程设计校验
|
// 流程设计校验
|
||||||
// 如果已经有流程数据,则不需要重新校验
|
|
||||||
if (!formData.value.bpmnXml && !formData.value.simpleModel) {
|
|
||||||
// 如果当前不在第三步,需要先保存当前步骤数据
|
|
||||||
if (currentStep.value !== 2) {
|
|
||||||
await steps[currentStep.value].validator()
|
|
||||||
// 切换到第三步
|
|
||||||
currentStep.value = 2
|
|
||||||
// 等待组件渲染完成
|
|
||||||
await nextTick()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 校验流程设计
|
// 表单设计校验
|
||||||
await processDesignRef.value?.validate()
|
try {
|
||||||
const processData = await processDesignRef.value?.getProcessData()
|
await validateProcess()
|
||||||
if (!processData) {
|
} catch (error) {
|
||||||
throw new Error('请设计流程')
|
currentStep.value = 2
|
||||||
}
|
throw new Error('请设计流程')
|
||||||
|
|
||||||
// 保存流程数据
|
|
||||||
if (formData.value.type === BpmModelType.BPMN) {
|
|
||||||
formData.value.bpmnXml = processData
|
|
||||||
formData.value.simpleModel = null
|
|
||||||
} else {
|
|
||||||
formData.value.bpmnXml = null
|
|
||||||
formData.value.simpleModel = processData
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
@ -239,20 +236,6 @@ const handleSave = async () => {
|
||||||
...formData.value
|
...formData.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果当前在第三步,获取最新的流程设计数据
|
|
||||||
if (currentStep.value === 2) {
|
|
||||||
const processData = await processDesignRef.value?.getProcessData()
|
|
||||||
if (processData) {
|
|
||||||
if (formData.value.type === BpmModelType.BPMN) {
|
|
||||||
modelData.bpmnXml = processData
|
|
||||||
modelData.simpleModel = null
|
|
||||||
} else {
|
|
||||||
modelData.bpmnXml = null
|
|
||||||
modelData.simpleModel = processData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formData.value.id) {
|
if (formData.value.id) {
|
||||||
// 修改场景
|
// 修改场景
|
||||||
await ModelApi.updateModel(modelData)
|
await ModelApi.updateModel(modelData)
|
||||||
|
@ -308,20 +291,6 @@ const handleDeploy = async () => {
|
||||||
...formData.value
|
...formData.value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果当前在第三步,获取最新的流程设计数据
|
|
||||||
if (currentStep.value === 2) {
|
|
||||||
const processData = await processDesignRef.value?.getProcessData()
|
|
||||||
if (processData) {
|
|
||||||
if (formData.value.type === BpmModelType.BPMN) {
|
|
||||||
modelData.bpmnXml = processData
|
|
||||||
modelData.simpleModel = null
|
|
||||||
} else {
|
|
||||||
modelData.bpmnXml = null
|
|
||||||
modelData.simpleModel = processData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 先保存所有数据
|
// 先保存所有数据
|
||||||
if (formData.value.id) {
|
if (formData.value.id) {
|
||||||
await ModelApi.updateModel(modelData)
|
await ModelApi.updateModel(modelData)
|
||||||
|
@ -344,59 +313,26 @@ const handleDeploy = async () => {
|
||||||
/** 步骤切换处理 */
|
/** 步骤切换处理 */
|
||||||
const handleStepClick = async (index: number) => {
|
const handleStepClick = async (index: number) => {
|
||||||
try {
|
try {
|
||||||
// 如果是切换到第三步(流程设计),需要校验key和name
|
console.log('index', index);
|
||||||
if (index === 2) {
|
if (index !== 0) {
|
||||||
if (!formData.value.key || !formData.value.name) {
|
await validateBasic()
|
||||||
message.warning('请先填写流程标识和流程名称')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (index !== 1) {
|
||||||
// 保存当前步骤的数据
|
await validateForm()
|
||||||
if (currentStep.value === 2) {
|
}
|
||||||
const processData = await processDesignRef.value?.getProcessData()
|
if (index !== 2) {
|
||||||
if (processData) {
|
await validateProcess()
|
||||||
if (formData.value.type === BpmModelType.BPMN) {
|
|
||||||
formData.value.bpmnXml = processData
|
|
||||||
formData.value.simpleModel = null
|
|
||||||
} else {
|
|
||||||
formData.value.bpmnXml = null
|
|
||||||
formData.value.simpleModel = processData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 只有在向后切换时才进行校验
|
|
||||||
if (index > currentStep.value) {
|
|
||||||
if (typeof steps[currentStep.value].validator === 'function') {
|
|
||||||
await steps[currentStep.value].validator()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换步骤
|
// 切换步骤
|
||||||
currentStep.value = index
|
currentStep.value = index
|
||||||
|
|
||||||
// 如果切换到流程设计步骤,等待组件渲染完成后刷新设计器
|
|
||||||
if (index === 2) {
|
|
||||||
await nextTick()
|
|
||||||
// 等待更长时间确保组件完全初始化
|
|
||||||
await new Promise(resolve => setTimeout(resolve, 200))
|
|
||||||
if (processDesignRef.value?.refresh) {
|
|
||||||
await processDesignRef.value.refresh()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('步骤切换失败:', error)
|
console.error('步骤切换失败:', error)
|
||||||
message.warning('请先完善当前步骤必填信息')
|
message.warning('请先完善当前步骤必填信息')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理设计器保存成功 */
|
|
||||||
const handleDesignSuccess = (bpmnXml?: string) => {
|
|
||||||
if (bpmnXml) {
|
|
||||||
formData.value.bpmnXml = bpmnXml
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 返回列表页 */
|
/** 返回列表页 */
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
:model-id="modelId"
|
:model-id="modelId"
|
||||||
:model-key="modelKey"
|
:model-key="modelKey"
|
||||||
:model-name="modelName"
|
:model-name="modelName"
|
||||||
:value="currentValue"
|
|
||||||
@success="handleSuccess"
|
@success="handleSuccess"
|
||||||
@init-finished="handleInit"
|
|
||||||
:start-user-ids="startUserIds"
|
:start-user-ids="startUserIds"
|
||||||
ref="designerRef"
|
ref="designerRef"
|
||||||
/>
|
/>
|
||||||
|
@ -23,133 +21,30 @@ const props = defineProps<{
|
||||||
modelId?: string
|
modelId?: string
|
||||||
modelKey?: string
|
modelKey?: string
|
||||||
modelName?: string
|
modelName?: string
|
||||||
value?: string
|
|
||||||
startUserIds?: number[]
|
startUserIds?: number[]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits(['success', 'init-finished'])
|
const emit = defineEmits(['success'])
|
||||||
const designerRef = ref()
|
const designerRef = ref()
|
||||||
const isInitialized = ref(false)
|
|
||||||
const currentValue = ref('')
|
|
||||||
|
|
||||||
// 初始化或更新当前值
|
|
||||||
const initOrUpdateValue = async () => {
|
|
||||||
console.log('initOrUpdateValue', props.value)
|
|
||||||
if (props.value) {
|
|
||||||
currentValue.value = props.value
|
|
||||||
// 如果设计器已经初始化,立即加载数据
|
|
||||||
if (isInitialized.value && designerRef.value) {
|
|
||||||
try {
|
|
||||||
await designerRef.value.loadProcessData(props.value)
|
|
||||||
await nextTick()
|
|
||||||
if (designerRef.value.refresh) {
|
|
||||||
await designerRef.value.refresh()
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('加载流程数据失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听属性变化
|
|
||||||
watch(
|
|
||||||
[() => props.modelKey, () => props.modelName, () => props.value],
|
|
||||||
async ([newKey, newName, newValue], [oldKey, oldName, oldValue]) => {
|
|
||||||
if (designerRef.value && isInitialized.value) {
|
|
||||||
try {
|
|
||||||
if (newKey && newName && (newKey !== oldKey || newName !== oldName)) {
|
|
||||||
await designerRef.value.updateModel(newKey, newName)
|
|
||||||
}
|
|
||||||
if (newValue && newValue !== oldValue) {
|
|
||||||
currentValue.value = newValue
|
|
||||||
await designerRef.value.loadProcessData(newValue)
|
|
||||||
await nextTick()
|
|
||||||
if (designerRef.value.refresh) {
|
|
||||||
await designerRef.value.refresh()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('更新流程数据失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ deep: true, immediate: true }
|
|
||||||
)
|
|
||||||
|
|
||||||
// 初始化完成回调
|
|
||||||
const handleInit = async () => {
|
|
||||||
try {
|
|
||||||
isInitialized.value = true
|
|
||||||
emit('init-finished')
|
|
||||||
|
|
||||||
// 等待下一个tick,确保设计器已经准备好
|
|
||||||
await nextTick()
|
|
||||||
|
|
||||||
// 初始化完成后,设置初始值
|
|
||||||
if (props.modelKey && props.modelName) {
|
|
||||||
await designerRef.value.updateModel(props.modelKey, props.modelName)
|
|
||||||
}
|
|
||||||
if (props.value) {
|
|
||||||
currentValue.value = props.value
|
|
||||||
await designerRef.value.loadProcessData(props.value)
|
|
||||||
// 再次刷新确保数据正确加载
|
|
||||||
await nextTick()
|
|
||||||
if (designerRef.value.refresh) {
|
|
||||||
await designerRef.value.refresh()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('初始化流程数据失败:', error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 修改成功回调
|
// 修改成功回调
|
||||||
const handleSuccess = (data?: any) => {
|
const handleSuccess = (data?: any) => {
|
||||||
console.warn('handleSuccess', data)
|
console.info('handleSuccess', data)
|
||||||
if (data && data !== currentValue.value) {
|
if (data) {
|
||||||
currentValue.value = data
|
|
||||||
emit('success', data)
|
emit('success', data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取当前流程数据 */
|
|
||||||
const getCurrentFlowData = async () => {
|
|
||||||
try {
|
|
||||||
if (designerRef.value) {
|
|
||||||
const data = await designerRef.value.getCurrentFlowData()
|
|
||||||
if (data) {
|
|
||||||
currentValue.value = data
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
return currentValue.value || undefined
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取流程数据失败:', error)
|
|
||||||
return currentValue.value || undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 组件创建时初始化数据
|
// 组件创建时初始化数据
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initOrUpdateValue()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 组件卸载前保存数据
|
// 组件卸载前保存数据
|
||||||
onBeforeUnmount(async () => {
|
onBeforeUnmount(async () => {
|
||||||
try {
|
|
||||||
const data = await getCurrentFlowData()
|
|
||||||
if (data) {
|
|
||||||
emit('success', data)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('保存数据失败:', error)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
getCurrentFlowData,
|
|
||||||
refresh: () => designerRef.value?.refresh?.()
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|
Loading…
Reference in New Issue