提交 | 用户 | 时间
|
3e359e
|
1 |
import { cloneDeep } from 'lodash-es' |
H |
2 |
import { TaskStatusEnum } from '@/api/bpm/task' |
|
3 |
import * as RoleApi from '@/api/system/role' |
|
4 |
import * as DeptApi from '@/api/system/dept' |
|
5 |
import * as PostApi from '@/api/system/post' |
|
6 |
import * as UserApi from '@/api/system/user' |
|
7 |
import * as UserGroupApi from '@/api/bpm/userGroup' |
|
8 |
import { |
|
9 |
SimpleFlowNode, |
|
10 |
CandidateStrategy, |
|
11 |
NodeType, |
|
12 |
ApproveMethodType, |
|
13 |
RejectHandlerType, |
|
14 |
NODE_DEFAULT_NAME, |
|
15 |
AssignStartUserHandlerType, |
|
16 |
AssignEmptyHandlerType, |
|
17 |
FieldPermissionType, |
|
18 |
ProcessVariableEnum |
|
19 |
} from './consts' |
|
20 |
import { parseFormFields } from '@/components/FormCreate/src/utils/index' |
|
21 |
export function useWatchNode(props: { flowNode: SimpleFlowNode }): Ref<SimpleFlowNode> { |
|
22 |
const node = ref<SimpleFlowNode>(props.flowNode) |
|
23 |
watch( |
|
24 |
() => props.flowNode, |
|
25 |
(newValue) => { |
|
26 |
node.value = newValue |
|
27 |
} |
|
28 |
) |
|
29 |
return node |
|
30 |
} |
|
31 |
|
|
32 |
// 解析 formCreate 所有表单字段, 并返回 |
|
33 |
const parseFormCreateFields = (formFields?: string[]) => { |
|
34 |
const result: Array<Record<string, any>> = [] |
|
35 |
if (formFields) { |
|
36 |
formFields.forEach((fieldStr: string) => { |
|
37 |
parseFormFields(JSON.parse(fieldStr), result) |
|
38 |
}) |
|
39 |
} |
|
40 |
// 固定添加发起人 ID 字段 |
|
41 |
result.unshift({ |
|
42 |
field: ProcessVariableEnum.START_USER_ID, |
|
43 |
title: '发起人', |
|
44 |
type: 'UserSelect', |
|
45 |
required: true |
|
46 |
}) |
|
47 |
return result |
|
48 |
} |
|
49 |
|
|
50 |
/** |
|
51 |
* @description 表单数据权限配置,用于发起人节点 、审批节点、抄送节点 |
|
52 |
*/ |
|
53 |
export function useFormFieldsPermission(defaultPermission: FieldPermissionType) { |
|
54 |
// 字段权限配置. 需要有 field, title, permissioin 属性 |
|
55 |
const fieldsPermissionConfig = ref<Array<Record<string, any>>>([]) |
|
56 |
|
|
57 |
const formType = inject<Ref<number>>('formType') // 表单类型 |
|
58 |
|
|
59 |
const formFields = inject<Ref<string[]>>('formFields') // 流程表单字段 |
|
60 |
|
|
61 |
const getNodeConfigFormFields = (nodeFormFields?: Array<Record<string, string>>) => { |
|
62 |
nodeFormFields = toRaw(nodeFormFields) |
|
63 |
fieldsPermissionConfig.value = |
|
64 |
cloneDeep(nodeFormFields) || getDefaultFieldsPermission(unref(formFields)) |
|
65 |
} |
|
66 |
// 默认的表单权限: 获取表单的所有字段,设置字段默认权限为只读 |
|
67 |
const getDefaultFieldsPermission = (formFields?: string[]) => { |
|
68 |
let defaultFieldsPermission: Array<Record<string, any>> = [] |
|
69 |
if (formFields) { |
|
70 |
defaultFieldsPermission = parseFormCreateFields(formFields).map((item) => { |
|
71 |
return { |
|
72 |
field: item.field, |
|
73 |
title: item.title, |
|
74 |
permission: defaultPermission |
|
75 |
} |
|
76 |
}) |
|
77 |
} |
|
78 |
return defaultFieldsPermission |
|
79 |
} |
|
80 |
|
|
81 |
// 获取表单的所有字段,作为下拉框选项 |
|
82 |
const formFieldOptions = parseFormCreateFields(unref(formFields)) |
|
83 |
|
|
84 |
return { |
|
85 |
formType, |
|
86 |
fieldsPermissionConfig, |
|
87 |
formFieldOptions, |
|
88 |
getNodeConfigFormFields |
|
89 |
} |
|
90 |
} |
|
91 |
/** |
|
92 |
* @description 获取表单的字段 |
|
93 |
*/ |
|
94 |
export function useFormFields() { |
|
95 |
const formFields = inject<Ref<string[]>>('formFields') // 流程表单字段 |
|
96 |
return parseFormCreateFields(unref(formFields)) |
|
97 |
} |
|
98 |
|
|
99 |
export type UserTaskFormType = { |
|
100 |
//candidateParamArray: any[] |
|
101 |
candidateStrategy: CandidateStrategy |
|
102 |
approveMethod: ApproveMethodType |
|
103 |
roleIds?: number[] // 角色 |
|
104 |
deptIds?: number[] // 部门 |
|
105 |
deptLevel?: number // 部门层级 |
|
106 |
userIds?: number[] // 用户 |
|
107 |
userGroups?: number[] // 用户组 |
|
108 |
postIds?: number[] // 岗位 |
|
109 |
expression?: string // 流程表达式 |
|
110 |
formUser?: string // 表单内用户字段 |
|
111 |
formDept?: string // 表单内部门字段 |
|
112 |
approveRatio?: number |
|
113 |
rejectHandlerType?: RejectHandlerType |
|
114 |
returnNodeId?: string |
|
115 |
timeoutHandlerEnable?: boolean |
|
116 |
timeoutHandlerType?: number |
|
117 |
assignEmptyHandlerType?: AssignEmptyHandlerType |
|
118 |
assignEmptyHandlerUserIds?: number[] |
|
119 |
assignStartUserHandlerType?: AssignStartUserHandlerType |
|
120 |
timeDuration?: number |
|
121 |
maxRemindCount?: number |
|
122 |
buttonsSetting: any[] |
|
123 |
} |
|
124 |
|
|
125 |
export type CopyTaskFormType = { |
|
126 |
// candidateParamArray: any[] |
|
127 |
candidateStrategy: CandidateStrategy |
|
128 |
roleIds?: number[] // 角色 |
|
129 |
deptIds?: number[] // 部门 |
|
130 |
deptLevel?: number // 部门层级 |
|
131 |
userIds?: number[] // 用户 |
|
132 |
userGroups?: number[] // 用户组 |
|
133 |
postIds?: number[] // 岗位 |
|
134 |
formUser?: string // 表单内用户字段 |
|
135 |
formDept?: string // 表单内部门字段 |
|
136 |
expression?: string // 流程表达式 |
|
137 |
} |
|
138 |
|
|
139 |
/** |
|
140 |
* @description 节点表单数据。 用于审批节点、抄送节点 |
|
141 |
*/ |
|
142 |
export function useNodeForm(nodeType: NodeType) { |
|
143 |
const roleOptions = inject<Ref<RoleApi.RoleVO[]>>('roleList') // 角色列表 |
|
144 |
const postOptions = inject<Ref<PostApi.PostVO[]>>('postList') // 岗位列表 |
|
145 |
const userOptions = inject<Ref<UserApi.UserVO[]>>('userList') // 用户列表 |
|
146 |
const deptOptions = inject<Ref<DeptApi.DeptVO[]>>('deptList') // 部门列表 |
|
147 |
const userGroupOptions = inject<Ref<UserGroupApi.UserGroupVO[]>>('userGroupList') // 用户组列表 |
|
148 |
const deptTreeOptions = inject('deptTree') // 部门树 |
|
149 |
const formFields = inject<Ref<string[]>>('formFields') // 流程表单字段 |
|
150 |
const configForm = ref<UserTaskFormType | CopyTaskFormType>() |
|
151 |
if (nodeType === NodeType.USER_TASK_NODE) { |
|
152 |
configForm.value = { |
|
153 |
candidateStrategy: CandidateStrategy.USER, |
|
154 |
approveMethod: ApproveMethodType.SEQUENTIAL_APPROVE, |
|
155 |
approveRatio: 100, |
|
156 |
rejectHandlerType: RejectHandlerType.FINISH_PROCESS, |
|
157 |
assignStartUserHandlerType: AssignStartUserHandlerType.START_USER_AUDIT, |
|
158 |
returnNodeId: '', |
|
159 |
timeoutHandlerEnable: false, |
|
160 |
timeoutHandlerType: 1, |
|
161 |
timeDuration: 6, // 默认 6小时 |
|
162 |
maxRemindCount: 1, // 默认 提醒 1次 |
|
163 |
buttonsSetting: [] |
|
164 |
} |
|
165 |
} else { |
|
166 |
configForm.value = { |
|
167 |
candidateStrategy: CandidateStrategy.USER |
|
168 |
} |
|
169 |
} |
|
170 |
|
|
171 |
const getShowText = (): string => { |
|
172 |
let showText = '' |
|
173 |
// 指定成员 |
|
174 |
if (configForm.value?.candidateStrategy === CandidateStrategy.USER) { |
|
175 |
if (configForm.value?.userIds!.length > 0) { |
|
176 |
const candidateNames: string[] = [] |
|
177 |
userOptions?.value.forEach((item) => { |
|
178 |
if (configForm.value?.userIds!.includes(item.id)) { |
|
179 |
candidateNames.push(item.nickname) |
|
180 |
} |
|
181 |
}) |
|
182 |
showText = `指定成员:${candidateNames.join(',')}` |
|
183 |
} |
|
184 |
} |
|
185 |
// 指定角色 |
|
186 |
if (configForm.value?.candidateStrategy === CandidateStrategy.ROLE) { |
|
187 |
if (configForm.value.roleIds!.length > 0) { |
|
188 |
const candidateNames: string[] = [] |
|
189 |
roleOptions?.value.forEach((item) => { |
|
190 |
if (configForm.value?.roleIds!.includes(item.id)) { |
|
191 |
candidateNames.push(item.name) |
|
192 |
} |
|
193 |
}) |
|
194 |
showText = `指定角色:${candidateNames.join(',')}` |
|
195 |
} |
|
196 |
} |
|
197 |
// 指定部门 |
|
198 |
if ( |
|
199 |
configForm.value?.candidateStrategy === CandidateStrategy.DEPT_MEMBER || |
|
200 |
configForm.value?.candidateStrategy === CandidateStrategy.DEPT_LEADER || |
|
201 |
configForm.value?.candidateStrategy === CandidateStrategy.MULTI_LEVEL_DEPT_LEADER |
|
202 |
) { |
|
203 |
if (configForm.value?.deptIds!.length > 0) { |
|
204 |
const candidateNames: string[] = [] |
|
205 |
deptOptions?.value.forEach((item) => { |
|
206 |
if (configForm.value?.deptIds!.includes(item.id!)) { |
|
207 |
candidateNames.push(item.name) |
|
208 |
} |
|
209 |
}) |
|
210 |
if (configForm.value.candidateStrategy === CandidateStrategy.DEPT_MEMBER) { |
|
211 |
showText = `部门成员:${candidateNames.join(',')}` |
|
212 |
} else if (configForm.value.candidateStrategy === CandidateStrategy.DEPT_LEADER) { |
|
213 |
showText = `部门的负责人:${candidateNames.join(',')}` |
|
214 |
} else { |
|
215 |
showText = `多级部门的负责人:${candidateNames.join(',')}` |
|
216 |
} |
|
217 |
} |
|
218 |
} |
|
219 |
|
|
220 |
// 指定岗位 |
|
221 |
if (configForm.value?.candidateStrategy === CandidateStrategy.POST) { |
|
222 |
if (configForm.value.postIds!.length > 0) { |
|
223 |
const candidateNames: string[] = [] |
|
224 |
postOptions?.value.forEach((item) => { |
|
225 |
if (configForm.value?.postIds!.includes(item.id!)) { |
|
226 |
candidateNames.push(item.name) |
|
227 |
} |
|
228 |
}) |
|
229 |
showText = `指定岗位: ${candidateNames.join(',')}` |
|
230 |
} |
|
231 |
} |
|
232 |
// 指定用户组 |
|
233 |
if (configForm.value?.candidateStrategy === CandidateStrategy.USER_GROUP) { |
|
234 |
if (configForm.value?.userGroups!.length > 0) { |
|
235 |
const candidateNames: string[] = [] |
|
236 |
userGroupOptions?.value.forEach((item) => { |
|
237 |
if (configForm.value?.userGroups!.includes(item.id)) { |
|
238 |
candidateNames.push(item.name) |
|
239 |
} |
|
240 |
}) |
|
241 |
showText = `指定用户组: ${candidateNames.join(',')}` |
|
242 |
} |
|
243 |
} |
|
244 |
|
|
245 |
// 表单内用户字段 |
|
246 |
if (configForm.value?.candidateStrategy === CandidateStrategy.FORM_USER) { |
|
247 |
const formFieldOptions = parseFormCreateFields(unref(formFields)) |
|
248 |
const item = formFieldOptions.find((item) => item.field === configForm.value?.formUser) |
|
249 |
showText = `表单用户:${item?.title}` |
|
250 |
} |
|
251 |
|
|
252 |
// 表单内部门负责人 |
|
253 |
if (configForm.value?.candidateStrategy === CandidateStrategy.FORM_DEPT_LEADER) { |
|
254 |
showText = `表单内部门负责人` |
|
255 |
} |
|
256 |
|
|
257 |
// 发起人自选 |
|
258 |
if (configForm.value?.candidateStrategy === CandidateStrategy.START_USER_SELECT) { |
|
259 |
showText = `发起人自选` |
|
260 |
} |
|
261 |
// 发起人自己 |
|
262 |
if (configForm.value?.candidateStrategy === CandidateStrategy.START_USER) { |
|
263 |
showText = `发起人自己` |
|
264 |
} |
|
265 |
// 发起人的部门负责人 |
|
266 |
if (configForm.value?.candidateStrategy === CandidateStrategy.START_USER_DEPT_LEADER) { |
|
267 |
showText = `发起人的部门负责人` |
|
268 |
} |
|
269 |
// 发起人的部门负责人 |
|
270 |
if ( |
|
271 |
configForm.value?.candidateStrategy === CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER |
|
272 |
) { |
|
273 |
showText = `发起人连续部门负责人` |
|
274 |
} |
|
275 |
// 流程表达式 |
|
276 |
if (configForm.value?.candidateStrategy === CandidateStrategy.EXPRESSION) { |
|
277 |
showText = `流程表达式:${configForm.value.expression}` |
|
278 |
} |
|
279 |
return showText |
|
280 |
} |
|
281 |
|
|
282 |
/** |
|
283 |
* 处理候选人参数的赋值 |
|
284 |
*/ |
|
285 |
const handleCandidateParam = () => { |
|
286 |
let candidateParam: undefined | string = undefined |
|
287 |
if (!configForm.value) { |
|
288 |
return candidateParam |
|
289 |
} |
|
290 |
switch (configForm.value.candidateStrategy) { |
|
291 |
case CandidateStrategy.USER: |
|
292 |
candidateParam = configForm.value.userIds!.join(',') |
|
293 |
break |
|
294 |
case CandidateStrategy.ROLE: |
|
295 |
candidateParam = configForm.value.roleIds!.join(',') |
|
296 |
break |
|
297 |
case CandidateStrategy.POST: |
|
298 |
candidateParam = configForm.value.postIds!.join(',') |
|
299 |
break |
|
300 |
case CandidateStrategy.USER_GROUP: |
|
301 |
candidateParam = configForm.value.userGroups!.join(',') |
|
302 |
break |
|
303 |
case CandidateStrategy.FORM_USER: |
|
304 |
candidateParam = configForm.value.formUser! |
|
305 |
break |
|
306 |
case CandidateStrategy.EXPRESSION: |
|
307 |
candidateParam = configForm.value.expression! |
|
308 |
break |
|
309 |
case CandidateStrategy.DEPT_MEMBER: |
|
310 |
case CandidateStrategy.DEPT_LEADER: |
|
311 |
candidateParam = configForm.value.deptIds!.join(',') |
|
312 |
break |
|
313 |
// 发起人部门负责人 |
|
314 |
case CandidateStrategy.START_USER_DEPT_LEADER: |
|
315 |
case CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER: |
|
316 |
candidateParam = configForm.value.deptLevel + '' |
|
317 |
break |
|
318 |
// 指定连续多级部门的负责人 |
|
319 |
case CandidateStrategy.MULTI_LEVEL_DEPT_LEADER: { |
|
320 |
// 候选人参数格式: | 分隔 。左边为部门(多个部门用 , 分隔)。 右边为部门层级 |
|
321 |
const deptIds = configForm.value.deptIds!.join(',') |
|
322 |
candidateParam = deptIds.concat('|' + configForm.value.deptLevel + '') |
|
323 |
break |
|
324 |
} |
|
325 |
// 表单内部门的负责人 |
|
326 |
case CandidateStrategy.FORM_DEPT_LEADER: { |
|
327 |
// 候选人参数格式: | 分隔 。左边为表单内部门字段。 右边为部门层级 |
|
328 |
const deptFieldOnForm = configForm.value.formDept! |
|
329 |
candidateParam = deptFieldOnForm.concat('|' + configForm.value.deptLevel + '') |
|
330 |
break |
|
331 |
} |
|
332 |
default: |
|
333 |
break |
|
334 |
} |
|
335 |
return candidateParam |
|
336 |
} |
|
337 |
/** |
|
338 |
* 解析候选人参数 |
|
339 |
*/ |
|
340 |
const parseCandidateParam = ( |
|
341 |
candidateStrategy: CandidateStrategy, |
|
342 |
candidateParam: string | undefined |
|
343 |
) => { |
|
344 |
if (!configForm.value || !candidateParam) { |
|
345 |
return |
|
346 |
} |
|
347 |
switch (candidateStrategy) { |
|
348 |
case CandidateStrategy.USER: { |
|
349 |
configForm.value.userIds = candidateParam.split(',').map((item) => +item) |
|
350 |
break |
|
351 |
} |
|
352 |
case CandidateStrategy.ROLE: |
|
353 |
configForm.value.roleIds = candidateParam.split(',').map((item) => +item) |
|
354 |
break |
|
355 |
case CandidateStrategy.POST: |
|
356 |
configForm.value.postIds = candidateParam.split(',').map((item) => +item) |
|
357 |
break |
|
358 |
case CandidateStrategy.USER_GROUP: |
|
359 |
configForm.value.userGroups = candidateParam.split(',').map((item) => +item) |
|
360 |
break |
|
361 |
case CandidateStrategy.FORM_USER: |
|
362 |
configForm.value.formUser = candidateParam |
|
363 |
break |
|
364 |
case CandidateStrategy.EXPRESSION: |
|
365 |
configForm.value.expression = candidateParam |
|
366 |
break |
|
367 |
case CandidateStrategy.DEPT_MEMBER: |
|
368 |
case CandidateStrategy.DEPT_LEADER: |
|
369 |
configForm.value.deptIds = candidateParam.split(',').map((item) => +item) |
|
370 |
break |
|
371 |
// 发起人部门负责人 |
|
372 |
case CandidateStrategy.START_USER_DEPT_LEADER: |
|
373 |
case CandidateStrategy.START_USER_MULTI_LEVEL_DEPT_LEADER: |
|
374 |
configForm.value.deptLevel = +candidateParam |
|
375 |
break |
|
376 |
// 指定连续多级部门的负责人 |
|
377 |
case CandidateStrategy.MULTI_LEVEL_DEPT_LEADER: { |
|
378 |
// 候选人参数格式: | 分隔 。左边为部门(多个部门用 , 分隔)。 右边为部门层级 |
|
379 |
const paramArray = candidateParam.split('|') |
|
380 |
configForm.value.deptIds = paramArray[0].split(',').map((item) => +item) |
|
381 |
configForm.value.deptLevel = +paramArray[1] |
|
382 |
break |
|
383 |
} |
|
384 |
// 表单内的部门负责人 |
|
385 |
case CandidateStrategy.FORM_DEPT_LEADER: { |
|
386 |
// 候选人参数格式: | 分隔 。左边为表单内的部门字段。 右边为部门层级 |
|
387 |
const paramArray = candidateParam.split('|') |
|
388 |
configForm.value.formDept = paramArray[0] |
|
389 |
configForm.value.deptLevel = +paramArray[1] |
|
390 |
break |
|
391 |
} |
|
392 |
default: |
|
393 |
break |
|
394 |
} |
|
395 |
} |
|
396 |
return { |
|
397 |
configForm, |
|
398 |
roleOptions, |
|
399 |
postOptions, |
|
400 |
userOptions, |
|
401 |
userGroupOptions, |
|
402 |
deptTreeOptions, |
|
403 |
handleCandidateParam, |
|
404 |
parseCandidateParam, |
|
405 |
getShowText |
|
406 |
} |
|
407 |
} |
|
408 |
|
|
409 |
/** |
|
410 |
* @description 抽屉配置 |
|
411 |
*/ |
|
412 |
export function useDrawer() { |
|
413 |
// 抽屉配置是否可见 |
|
414 |
const settingVisible = ref(false) |
|
415 |
// 关闭配置抽屉 |
|
416 |
const closeDrawer = () => { |
|
417 |
settingVisible.value = false |
|
418 |
} |
|
419 |
// 打开配置抽屉 |
|
420 |
const openDrawer = () => { |
|
421 |
settingVisible.value = true |
|
422 |
} |
|
423 |
return { |
|
424 |
settingVisible, |
|
425 |
closeDrawer, |
|
426 |
openDrawer |
|
427 |
} |
|
428 |
} |
|
429 |
|
|
430 |
/** |
|
431 |
* @description 节点名称配置 |
|
432 |
*/ |
|
433 |
export function useNodeName(nodeType: NodeType) { |
|
434 |
// 节点名称 |
|
435 |
const nodeName = ref<string>() |
|
436 |
// 节点名称输入框 |
|
437 |
const showInput = ref(false) |
|
438 |
// 点击节点名称编辑图标 |
|
439 |
const clickIcon = () => { |
|
440 |
showInput.value = true |
|
441 |
} |
|
442 |
// 节点名称输入框失去焦点 |
|
443 |
const blurEvent = () => { |
|
444 |
showInput.value = false |
|
445 |
nodeName.value = nodeName.value || (NODE_DEFAULT_NAME.get(nodeType) as string) |
|
446 |
} |
|
447 |
return { |
|
448 |
nodeName, |
|
449 |
showInput, |
|
450 |
clickIcon, |
|
451 |
blurEvent |
|
452 |
} |
|
453 |
} |
|
454 |
|
|
455 |
export function useNodeName2(node: Ref<SimpleFlowNode>, nodeType: NodeType) { |
|
456 |
// 显示节点名称输入框 |
|
457 |
const showInput = ref(false) |
|
458 |
// 节点名称输入框失去焦点 |
|
459 |
const blurEvent = () => { |
|
460 |
showInput.value = false |
|
461 |
node.value.name = node.value.name || (NODE_DEFAULT_NAME.get(nodeType) as string) |
|
462 |
} |
|
463 |
// 点击节点标题进行输入 |
|
464 |
const clickTitle = () => { |
|
465 |
showInput.value = true |
|
466 |
} |
|
467 |
return { |
|
468 |
showInput, |
|
469 |
clickTitle, |
|
470 |
blurEvent |
|
471 |
} |
|
472 |
} |
|
473 |
|
|
474 |
/** |
|
475 |
* @description 根据节点任务状态,获取节点任务状态样式 |
|
476 |
*/ |
|
477 |
export function useTaskStatusClass(taskStatus: TaskStatusEnum | undefined): string { |
|
478 |
if (!taskStatus) { |
|
479 |
return '' |
|
480 |
} |
|
481 |
if (taskStatus === TaskStatusEnum.APPROVE) { |
|
482 |
return 'status-pass' |
|
483 |
} |
|
484 |
if (taskStatus === TaskStatusEnum.RUNNING) { |
|
485 |
return 'status-running' |
|
486 |
} |
|
487 |
if (taskStatus === TaskStatusEnum.REJECT) { |
|
488 |
return 'status-reject' |
|
489 |
} |
|
490 |
if (taskStatus === TaskStatusEnum.CANCEL) { |
|
491 |
return 'status-cancel' |
|
492 |
} |
|
493 |
|
|
494 |
return '' |
|
495 |
} |