提交 | 用户 | 时间
820397 1 <template>
9259c2 2   <el-form label-width="120px">
820397 3     <el-form-item label="规则类型" prop="candidateStrategy">
H 4       <el-select
5         v-model="userTaskForm.candidateStrategy"
6         clearable
7         style="width: 100%"
8         @change="changeCandidateStrategy"
9       >
10         <el-option
9259c2 11           v-for="(dict, index) in CANDIDATE_STRATEGY"
H 12           :key="index"
820397 13           :label="dict.label"
H 14           :value="dict.value"
15         />
16       </el-select>
17     </el-form-item>
18     <el-form-item
9259c2 19       v-if="userTaskForm.candidateStrategy == CandidateStrategy.ROLE"
820397 20       label="指定角色"
H 21       prop="candidateParam"
22     >
23       <el-select
24         v-model="userTaskForm.candidateParam"
25         clearable
26         multiple
27         style="width: 100%"
28         @change="updateElementTask"
29       >
30         <el-option v-for="item in roleOptions" :key="item.id" :label="item.name" :value="item.id" />
31       </el-select>
32     </el-form-item>
33     <el-form-item
9259c2 34       v-if="
H 35         userTaskForm.candidateStrategy == CandidateStrategy.DEPT_MEMBER ||
36         userTaskForm.candidateStrategy == CandidateStrategy.DEPT_LEADER ||
37         userTaskForm.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER
38       "
820397 39       label="指定部门"
H 40       prop="candidateParam"
41       span="24"
42     >
43       <el-tree-select
44         ref="treeRef"
45         v-model="userTaskForm.candidateParam"
46         :data="deptTreeOptions"
47         :props="defaultProps"
48         empty-text="加载中,请稍后"
49         multiple
50         node-key="id"
51         show-checkbox
52         @change="updateElementTask"
53       />
54     </el-form-item>
55     <el-form-item
9259c2 56       v-if="userTaskForm.candidateStrategy == CandidateStrategy.POST"
820397 57       label="指定岗位"
H 58       prop="candidateParam"
59       span="24"
60     >
61       <el-select
62         v-model="userTaskForm.candidateParam"
63         clearable
64         multiple
65         style="width: 100%"
66         @change="updateElementTask"
67       >
68         <el-option v-for="item in postOptions" :key="item.id" :label="item.name" :value="item.id" />
69       </el-select>
70     </el-form-item>
71     <el-form-item
9259c2 72       v-if="userTaskForm.candidateStrategy == CandidateStrategy.USER"
820397 73       label="指定用户"
H 74       prop="candidateParam"
75       span="24"
76     >
77       <el-select
78         v-model="userTaskForm.candidateParam"
79         clearable
80         multiple
81         style="width: 100%"
82         @change="updateElementTask"
83       >
84         <el-option
85           v-for="item in userOptions"
86           :key="item.id"
87           :label="item.nickname"
88           :value="item.id"
89         />
90       </el-select>
91     </el-form-item>
92     <el-form-item
9259c2 93       v-if="userTaskForm.candidateStrategy === CandidateStrategy.USER_GROUP"
820397 94       label="指定用户组"
H 95       prop="candidateParam"
96     >
97       <el-select
98         v-model="userTaskForm.candidateParam"
99         clearable
100         multiple
101         style="width: 100%"
102         @change="updateElementTask"
103       >
104         <el-option
105           v-for="item in userGroupOptions"
106           :key="item.id"
107           :label="item.name"
108           :value="item.id"
109         />
110       </el-select>
111     </el-form-item>
112     <el-form-item
9259c2 113       v-if="userTaskForm.candidateStrategy === CandidateStrategy.FORM_USER"
H 114       label="表单内用户字段"
115       prop="formUser"
116     >
117       <el-select
118         v-model="userTaskForm.candidateParam"
119         clearable
120         style="width: 100%"
121         @change="handleFormUserChange"
122       >
123         <el-option
124           v-for="(item, idx) in userFieldOnFormOptions"
125           :key="idx"
126           :label="item.title"
127           :value="item.field"
128           :disabled="!item.required"
129         />
130       </el-select>
131     </el-form-item>
132     <el-form-item
133       v-if="userTaskForm.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER"
134       label="表单内部门字段"
135       prop="formDept"
136     >
137       <el-select
138         v-model="userTaskForm.candidateParam"
139         clearable
140         style="width: 100%"
141         @change="updateElementTask"
142       >
143         <el-option
144           v-for="(item, idx) in deptFieldOnFormOptions"
145           :key="idx"
146           :label="item.title"
147           :value="item.field"
148           :disabled="!item.required"
149         />
150       </el-select>
151     </el-form-item>
152     <el-form-item
153       v-if="
154         userTaskForm.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
155         userTaskForm.candidateStrategy == CandidateStrategy.START_USER_DEPT_LEADER ||
156         userTaskForm.candidateStrategy == CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER ||
157         userTaskForm.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
158       "
159       :label="deptLevelLabel!"
160       prop="deptLevel"
161       span="24"
162     >
163       <el-select v-model="deptLevel" clearable @change="updateElementTask">
164         <el-option
165           v-for="(item, index) in MULTI_LEVEL_DEPT"
166           :key="index"
167           :label="item.label"
168           :value="item.value"
169         />
170       </el-select>
171     </el-form-item>
172     <el-form-item
173       v-if="userTaskForm.candidateStrategy === CandidateStrategy.EXPRESSION"
820397 174       label="流程表达式"
H 175       prop="candidateParam"
176     >
177       <el-input
178         type="textarea"
179         v-model="userTaskForm.candidateParam[0]"
180         clearable
9259c2 181         style="width: 100%"
820397 182         @change="updateElementTask"
H 183       />
9259c2 184       <XButton
H 185         class="!w-1/1 mt-5px"
186         type="success"
187         preIcon="ep:select"
188         title="选择表达式"
189         size="small"
190         @click="openProcessExpressionDialog"
191       />
820397 192       <!-- 选择弹窗 -->
H 193       <ProcessExpressionDialog ref="processExpressionDialogRef" @select="selectProcessExpression" />
194     </el-form-item>
195   </el-form>
196 </template>
197
198 <script lang="ts" setup>
9259c2 199 import {
H 200   CANDIDATE_STRATEGY,
201   CandidateStrategy,
202   FieldPermissionType,
203   MULTI_LEVEL_DEPT
204 } from '@/components/SimpleProcessDesignerV2/src/consts'
820397 205 import { defaultProps, handleTree } from '@/utils/tree'
H 206 import * as RoleApi from '@/api/system/role'
207 import * as DeptApi from '@/api/system/dept'
208 import * as PostApi from '@/api/system/post'
209 import * as UserApi from '@/api/system/user'
210 import * as UserGroupApi from '@/api/bpm/userGroup'
211 import ProcessExpressionDialog from './ProcessExpressionDialog.vue'
212 import { ProcessExpressionVO } from '@/api/bpm/processExpression'
9259c2 213 import { useFormFieldsPermission } from '@/components/SimpleProcessDesignerV2/src/node'
820397 214
H 215 defineOptions({ name: 'UserTask' })
216 const props = defineProps({
217   id: String,
218   type: String
219 })
9259c2 220 const prefix = inject('prefix')
820397 221 const userTaskForm = ref({
H 222   candidateStrategy: undefined, // 分配规则
223   candidateParam: [] // 分配选项
224 })
225 const bpmnElement = ref()
226 const bpmnInstances = () => (window as any)?.bpmnInstances
227
228 const roleOptions = ref<RoleApi.RoleVO[]>([]) // 角色列表
229 const deptTreeOptions = ref() // 部门树
230 const postOptions = ref<PostApi.PostVO[]>([]) // 岗位列表
231 const userOptions = ref<UserApi.UserVO[]>([]) // 用户列表
232 const userGroupOptions = ref<UserGroupApi.UserGroupVO[]>([]) // 用户组列表
233
9259c2 234 const { formFieldOptions } = useFormFieldsPermission(FieldPermissionType.READ)
H 235 // 表单内用户字段选项, 必须是必填和用户选择器
236 const userFieldOnFormOptions = computed(() => {
237   return formFieldOptions.filter((item) => item.type === 'UserSelect')
238 })
239 // 表单内部门字段选项, 必须是必填和部门选择器
240 const deptFieldOnFormOptions = computed(() => {
241   return formFieldOptions.filter((item) => item.type === 'DeptSelect')
242 })
243
244 const deptLevel = ref(1)
245 const deptLevelLabel = computed(() => {
246   let label = '部门负责人来源'
247   if (userTaskForm.value.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER) {
248     label = label + '(指定部门向上)'
249   } else if (userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER) {
250     label = label + '(表单内部门向上)'
251   } else {
252     label = label + '(发起人部门向上)'
253   }
254   return label
255 })
256
257 const otherExtensions = ref()
258
820397 259 const resetTaskForm = () => {
H 260   const businessObject = bpmnElement.value.businessObject
261   if (!businessObject) {
262     return
263   }
9259c2 264
H 265   const extensionElements =
266     businessObject?.extensionElements ??
267     bpmnInstances().moddle.create('bpmn:ExtensionElements', { values: [] })
268   userTaskForm.value.candidateStrategy = extensionElements.values?.filter(
269     (ex) => ex.$type === `${prefix}:CandidateStrategy`
270   )?.[0]?.value
271   const candidateParamStr = extensionElements.values?.filter(
272     (ex) => ex.$type === `${prefix}:CandidateParam`
273   )?.[0]?.value
274   if (candidateParamStr && candidateParamStr.length > 0) {
275     if (userTaskForm.value.candidateStrategy === CandidateStrategy.EXPRESSION) {
276       // 特殊:流程表达式,只有一个 input 输入框
277       userTaskForm.value.candidateParam = [candidateParamStr]
278     } else if (userTaskForm.value.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER) {
279       // 特殊:多级不部门负责人,需要通过'|'分割
280       userTaskForm.value.candidateParam = candidateParamStr
281         .split('|')[0]
282         .split(',')
283         .map((item) => {
284           // 如果数字超出了最大安全整数范围,则将其作为字符串处理
285           let num = Number(item)
286           return num > Number.MAX_SAFE_INTEGER || num < -Number.MAX_SAFE_INTEGER ? item : num
287         })
288       deptLevel.value = +candidateParamStr.split('|')[1]
289     } else if (
290       userTaskForm.value.candidateStrategy == CandidateStrategy.START_USER_DEPT_LEADER ||
291       userTaskForm.value.candidateStrategy == CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
292     ) {
293       userTaskForm.value.candidateParam = +candidateParamStr
294       deptLevel.value = +candidateParamStr
295     } else if (userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER) {
296       userTaskForm.value.candidateParam = candidateParamStr.split('|')[0]
297       deptLevel.value = +candidateParamStr.split('|')[1]
298     } else {
299       userTaskForm.value.candidateParam = candidateParamStr.split(',').map((item) => {
300         // 如果数字超出了最大安全整数范围,则将其作为字符串处理
301         let num = Number(item)
302         return num > Number.MAX_SAFE_INTEGER || num < -Number.MAX_SAFE_INTEGER ? item : num
303       })
304     }
305   } else {
306     userTaskForm.value.candidateParam = []
307   }
308
309   otherExtensions.value =
310     extensionElements.values?.filter(
311       (ex) => ex.$type !== `${prefix}:CandidateStrategy` && ex.$type !== `${prefix}:CandidateParam`
312     ) ?? []
313
314   // 改用通过extensionElements来存储数据
315   return
820397 316   if (businessObject.candidateStrategy != undefined) {
H 317     userTaskForm.value.candidateStrategy = parseInt(businessObject.candidateStrategy) as any
318   } else {
319     userTaskForm.value.candidateStrategy = undefined
320   }
321   if (businessObject.candidateParam && businessObject.candidateParam.length > 0) {
322     if (userTaskForm.value.candidateStrategy === 60) {
323       // 特殊:流程表达式,只有一个 input 输入框
324       userTaskForm.value.candidateParam = [businessObject.candidateParam]
325     } else {
326       userTaskForm.value.candidateParam = businessObject.candidateParam
327         .split(',')
9259c2 328         .map((item) => item)
820397 329     }
H 330   } else {
331     userTaskForm.value.candidateParam = []
332   }
333 }
334
335 /** 更新 candidateStrategy 字段时,需要清空 candidateParam,并触发 bpmn 图更新 */
336 const changeCandidateStrategy = () => {
337   userTaskForm.value.candidateParam = []
9259c2 338   deptLevel.value = 1
H 339   if (userTaskForm.value.candidateStrategy === CandidateStrategy.FORM_USER) {
340     // 特殊处理表单内用户字段,当只有发起人选项时应选中发起人
341     if (!userFieldOnFormOptions.value || userFieldOnFormOptions.value.length <= 1) {
342       userTaskForm.value.candidateStrategy = CandidateStrategy.START_USER
343     }
344   }
820397 345   updateElementTask()
H 346 }
347
348 /** 选中某个 options 时候,更新 bpmn 图  */
349 const updateElementTask = () => {
9259c2 350   let candidateParam =
H 351     userTaskForm.value.candidateParam instanceof Array
352       ? userTaskForm.value.candidateParam.join(',')
353       : userTaskForm.value.candidateParam
354
355   // 特殊处理多级部门情况
356   if (
357     userTaskForm.value.candidateStrategy == CandidateStrategy.MULTI_LEVEL_DEPT_LEADER ||
358     userTaskForm.value.candidateStrategy == CandidateStrategy.FORM_DEPT_LEADER
359   ) {
360     candidateParam += '|' + deptLevel.value
361   }
362   // 特殊处理发起人部门负责人、发起人连续部门负责人
363   if (
364     userTaskForm.value.candidateStrategy == CandidateStrategy.START_USER_DEPT_LEADER ||
365     userTaskForm.value.candidateStrategy == CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER
366   ) {
367     candidateParam = deptLevel.value + ''
368   }
369
370   const extensions = bpmnInstances().moddle.create('bpmn:ExtensionElements', {
371     values: [
372       ...otherExtensions.value,
373       bpmnInstances().moddle.create(`${prefix}:CandidateStrategy`, {
374         value: userTaskForm.value.candidateStrategy
375       }),
376       bpmnInstances().moddle.create(`${prefix}:CandidateParam`, {
377         value: candidateParam
378       })
379     ]
380   })
381   bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
382     extensionElements: extensions
383   })
384
385   // 改用通过extensionElements来存储数据
386   return
820397 387   bpmnInstances().modeling.updateProperties(toRaw(bpmnElement.value), {
H 388     candidateStrategy: userTaskForm.value.candidateStrategy,
389     candidateParam: userTaskForm.value.candidateParam.join(',')
390   })
391 }
392
393 // 打开监听器弹窗
394 const processExpressionDialogRef = ref()
395 const openProcessExpressionDialog = async () => {
396   processExpressionDialogRef.value.open()
397 }
398 const selectProcessExpression = (expression: ProcessExpressionVO) => {
399   userTaskForm.value.candidateParam = [expression.expression]
400   updateElementTask()
401 }
402
9259c2 403 const handleFormUserChange = (e) => {
H 404   if (e === 'PROCESS_START_USER_ID') {
405     userTaskForm.value.candidateParam = []
406     userTaskForm.value.candidateStrategy = CandidateStrategy.START_USER
407   }
408   updateElementTask()
409 }
410
820397 411 watch(
H 412   () => props.id,
413   () => {
414     bpmnElement.value = bpmnInstances().bpmnElement
415     nextTick(() => {
416       resetTaskForm()
417     })
418   },
419   { immediate: true }
420 )
421
422 onMounted(async () => {
423   // 获得角色列表
424   roleOptions.value = await RoleApi.getSimpleRoleList()
425   // 获得部门列表
426   const deptOptions = await DeptApi.getSimpleDeptList()
427   deptTreeOptions.value = handleTree(deptOptions, 'id')
428   // 获得岗位列表
429   postOptions.value = await PostApi.getSimplePostList()
430   // 获得用户列表
431   userOptions.value = await UserApi.getSimpleUserList()
432   // 获得用户组列表
433   userGroupOptions.value = await UserGroupApi.getUserGroupSimpleList()
434 })
435
436 onBeforeUnmount(() => {
437   bpmnElement.value = null
438 })
439 </script>