潘志宝
3 天以前 221918bba28d2384d03c596a68256d7832e4a0e0
提交 | 用户 | 时间
3e359e 1 <template>
H 2   <div v-loading="loading" class="overflow-auto">
3     <SimpleProcessModel
c9a6f7 4       ref="simpleProcessModelRef"
3e359e 5       v-if="processNodeTree"
H 6       :flow-node="processNodeTree"
7       :readonly="false"
8       @save="saveSimpleFlowModel"
9     />
10     <Dialog v-model="errorDialogVisible" title="保存失败" width="400" :fullscreen="false">
11       <div class="mb-2">以下节点内容不完善,请修改后保存</div>
12       <div
13         class="mb-3 b-rounded-1 bg-gray-100 p-2 line-height-normal"
14         v-for="(item, index) in errorNodes"
15         :key="index"
16       >
17         {{ item.name }} : {{ NODE_DEFAULT_TEXT.get(item.type) }}
18       </div>
19       <template #footer>
20         <el-button type="primary" @click="errorDialogVisible = false">知道了</el-button>
21       </template>
22     </Dialog>
23   </div>
24 </template>
25
26 <script setup lang="ts">
27 import SimpleProcessModel from './SimpleProcessModel.vue'
28 import { updateBpmSimpleModel, getBpmSimpleModel } from '@/api/bpm/simple'
29 import { SimpleFlowNode, NodeType, NodeId, NODE_DEFAULT_TEXT } from './consts'
30 import { getModel } from '@/api/bpm/model'
31 import { getForm, FormVO } from '@/api/bpm/form'
32 import { handleTree } from '@/utils/tree'
33 import * as RoleApi from '@/api/system/role'
34 import * as DeptApi from '@/api/system/dept'
35 import * as PostApi from '@/api/system/post'
36 import * as UserApi from '@/api/system/user'
37 import * as UserGroupApi from '@/api/bpm/userGroup'
38
39 defineOptions({
40   name: 'SimpleProcessDesigner'
41 })
c9a6f7 42
H 43 const emits = defineEmits(['success', 'init-finished']) // 保存成功事件
3e359e 44
H 45 const props = defineProps({
46   modelId: {
47     type: String,
c9a6f7 48     required: false
H 49   },
50   modelKey: {
51     type: String,
52     required: false
53   },
54   modelName: {
55     type: String,
56     required: false
57   },
58   // 可发起流程的人员编号
59   startUserIds : {
60     type: Array,
61     required: false
62   },
63   value: {
64     type: [String, Object],
65     required: false
3e359e 66   }
H 67 })
68
69 const loading = ref(false)
70 const formFields = ref<string[]>([])
71 const formType = ref(20)
72 const roleOptions = ref<RoleApi.RoleVO[]>([]) // 角色列表
73 const postOptions = ref<PostApi.PostVO[]>([]) // 岗位列表
74 const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
75 const deptOptions = ref<DeptApi.DeptVO[]>([]) // 部门列表
76 const deptTreeOptions = ref()
77 const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]) // 用户组列表
c9a6f7 78
H 79 // 添加当前值的引用
80 const currentValue = ref<SimpleFlowNode | undefined>()
81
3e359e 82 provide('formFields', formFields)
H 83 provide('formType', formType)
84 provide('roleList', roleOptions)
85 provide('postList', postOptions)
86 provide('userList', userOptions)
87 provide('deptList', deptOptions)
88 provide('userGroupList', userGroupOptions)
89 provide('deptTree', deptTreeOptions)
c9a6f7 90 provide('startUserIds', props.startUserIds)
3e359e 91
H 92 const message = useMessage() // 国际化
93 const processNodeTree = ref<SimpleFlowNode | undefined>()
94 const errorDialogVisible = ref(false)
95 let errorNodes: SimpleFlowNode[] = []
c9a6f7 96
H 97 // 添加更新模型的方法
98 const updateModel = () => {
99   if (!processNodeTree.value) {
100     processNodeTree.value = {
101       name: '发起人',
102       type: NodeType.START_USER_NODE,
103       id: NodeId.START_USER_NODE_ID,
104       childNode: {
105         id: NodeId.END_EVENT_NODE_ID,
106         name: '结束',
107         type: NodeType.END_EVENT_NODE
108       }
3e359e 109     }
c9a6f7 110     // 初始化时也触发一次保存
H 111     saveSimpleFlowModel(processNodeTree.value)
3e359e 112   }
H 113 }
c9a6f7 114
H 115 // 加载流程数据
116 const loadProcessData = async (data: any) => {
117   try {
118     if (data) {
119       const parsedData = typeof data === 'string' ? JSON.parse(data) : data
120       processNodeTree.value = parsedData
121       currentValue.value = parsedData
122       // 确保数据加载后刷新视图
123       await nextTick()
124       if (simpleProcessModelRef.value?.refresh) {
125         await simpleProcessModelRef.value.refresh()
126       }
127     }
128   } catch (error) {
129     console.error('加载流程数据失败:', error)
130   }
131 }
132
133 // 监听属性变化
134 watch(
135   () => props.value,
136   async (newValue, oldValue) => {
137     if (newValue && newValue !== oldValue) {
138       await loadProcessData(newValue)
139     }
140   },
141   { immediate: true, deep: true }
142 )
143
144 // 监听流程节点树变化,自动保存
145 watch(
146   () => processNodeTree.value,
147   async (newValue, oldValue) => {
148     if (newValue && oldValue && JSON.stringify(newValue) !== JSON.stringify(oldValue)) {
149       await saveSimpleFlowModel(newValue)
150     }
151   },
152   { deep: true }
153 )
154
155 const saveSimpleFlowModel = async (simpleModelNode: SimpleFlowNode) => {
156   if (!simpleModelNode) {
157     return
158   }
159
160   // 校验节点
161   errorNodes = []
162   validateNode(simpleModelNode, errorNodes)
163   if (errorNodes.length > 0) {
164     errorDialogVisible.value = true
165     return
166   }
167
168   try {
169     if (props.modelId) {
170       // 编辑模式
171       const data = {
172         id: props.modelId,
173         simpleModel: simpleModelNode
174       }
175       await updateBpmSimpleModel(data)
176     }
177     // 无论是编辑还是新建模式,都更新当前值并触发事件
178     currentValue.value = simpleModelNode
179     emits('success', simpleModelNode)
180   } catch (error) {
181     console.error('保存失败:', error)
182   }
183 }
184
3e359e 185 // 校验节点设置。 暂时以 showText 为空 未节点错误配置
H 186 const validateNode = (node: SimpleFlowNode | undefined, errorNodes: SimpleFlowNode[]) => {
187   if (node) {
188     const { type, showText, conditionNodes } = node
189     if (type == NodeType.END_EVENT_NODE) {
190       return
191     }
192     if (type == NodeType.START_USER_NODE) {
193       // 发起人节点暂时不用校验,直接校验孩子节点
194       validateNode(node.childNode, errorNodes)
195     }
196
197     if (
198       type === NodeType.USER_TASK_NODE ||
199       type === NodeType.COPY_TASK_NODE ||
200       type === NodeType.CONDITION_NODE
201     ) {
202       if (!showText) {
203         errorNodes.push(node)
204       }
205       validateNode(node.childNode, errorNodes)
206     }
207
208     if (
209       type == NodeType.CONDITION_BRANCH_NODE ||
210       type == NodeType.PARALLEL_BRANCH_NODE ||
211       type == NodeType.INCLUSIVE_BRANCH_NODE
212     ) {
213       // 分支节点
214       // 1. 先校验各个分支
215       conditionNodes?.forEach((item) => {
216         validateNode(item, errorNodes)
217       })
218       // 2. 校验孩子节点
219       validateNode(node.childNode, errorNodes)
220     }
221   }
222 }
223
224 onMounted(async () => {
225   try {
226     loading.value = true
227     // 获取表单字段
c9a6f7 228     if (props.modelId) {
H 229       const bpmnModel = await getModel(props.modelId)
230       if (bpmnModel) {
231         formType.value = bpmnModel.formType
232         if (formType.value === 10) {
233           const bpmnForm = (await getForm(bpmnModel.formId)) as unknown as FormVO
234           formFields.value = bpmnForm?.fields
235         }
3e359e 236       }
H 237     }
238     // 获得角色列表
239     roleOptions.value = await RoleApi.getSimpleRoleList()
240     // 获得岗位列表
241     postOptions.value = await PostApi.getSimplePostList()
242     // 获得用户列表
243     userOptions.value = await UserApi.getSimpleUserList()
244     // 获得部门列表
245     deptOptions.value = await DeptApi.getSimpleDeptList()
246     deptTreeOptions.value = handleTree(deptOptions.value as DeptApi.DeptVO[], 'id')
247     // 获取用户组列表
248     userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
249
c9a6f7 250     // 加载流程数据
H 251     if (props.modelId) {
252       // 获取 SIMPLE 设计器模型
253       const result = await getBpmSimpleModel(props.modelId)
254       if (result) {
255         await loadProcessData(result)
256       } else {
257         updateModel()
3e359e 258       }
c9a6f7 259     } else if (props.value) {
H 260       await loadProcessData(props.value)
261     } else {
262       updateModel()
3e359e 263     }
H 264   } finally {
265     loading.value = false
c9a6f7 266     emits('init-finished')
3e359e 267   }
H 268 })
c9a6f7 269
H 270 const simpleProcessModelRef = ref()
271
272 /** 获取当前流程数据 */
273 const getCurrentFlowData = async () => {
274   try {
275     if (simpleProcessModelRef.value) {
276       const data = await simpleProcessModelRef.value.getCurrentFlowData()
277       if (data) {
278         currentValue.value = data
279         return data
280       }
281     }
282     return currentValue.value
283   } catch (error) {
284     console.error('获取流程数据失败:', error)
285     return currentValue.value
286   }
287 }
288
289 // 刷新方法
290 const refresh = async () => {
291   try {
292     if (currentValue.value) {
293       await loadProcessData(currentValue.value)
294     }
295   } catch (error) {
296     console.error('刷新失败:', error)
297   }
298 }
299
300 defineExpose({
301   getCurrentFlowData,
302   updateModel,
303   loadProcessData,
304   refresh
305 })
3e359e 306 </script>