houzhongjian
2024-12-03 874287a4c02d0a980d8b97c4a691b4f37ec5e812
提交 | 用户 | 时间
e7c126 1 package com.iailab.module.bpm.framework.flowable.core.candidate;
H 2
3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.util.StrUtil;
6 import com.iailab.framework.common.enums.CommonStatusEnum;
7 import com.iailab.framework.datapermission.core.annotation.DataPermission;
8 import com.iailab.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
9 import com.iailab.module.bpm.framework.flowable.core.util.BpmnModelUtils;
10 import com.iailab.module.system.api.user.AdminUserApi;
11 import com.iailab.module.system.api.user.dto.AdminUserRespDTO;
12 import com.google.common.annotations.VisibleForTesting;
13 import lombok.extern.slf4j.Slf4j;
14 import org.flowable.bpmn.model.BpmnModel;
15 import org.flowable.bpmn.model.UserTask;
16 import org.flowable.engine.delegate.DelegateExecution;
17
18 import java.util.HashMap;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 import static com.iailab.framework.common.exception.util.ServiceExceptionUtil.exception;
24 import static com.iailab.module.bpm.enums.ErrorCodeConstants.MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG;
25 import static com.iailab.module.bpm.enums.ErrorCodeConstants.TASK_CREATE_FAIL_NO_CANDIDATE_USER;
26
27 /**
28  * {@link BpmTaskCandidateStrategy} 的调用者,用于调用对应的策略,实现任务的候选人的计算
29  *
30  * @author iailab
31  */
32 @Slf4j
33 public class BpmTaskCandidateInvoker {
34
35     private final Map<BpmTaskCandidateStrategyEnum, BpmTaskCandidateStrategy> strategyMap = new HashMap<>();
36
37     private final AdminUserApi adminUserApi;
38
39     public BpmTaskCandidateInvoker(List<BpmTaskCandidateStrategy> strategyList,
40                                    AdminUserApi adminUserApi) {
41         strategyList.forEach(strategy -> {
42             BpmTaskCandidateStrategy oldStrategy = strategyMap.put(strategy.getStrategy(), strategy);
43             Assert.isNull(oldStrategy, "策略(%s) 重复", strategy.getStrategy());
44         });
45         this.adminUserApi = adminUserApi;
46     }
47
48     /**
49      * 校验流程模型的任务分配规则全部都配置了
50      * 目的:如果有规则未配置,会导致流程任务找不到负责人,进而流程无法进行下去!
51      *
52      * @param bpmnBytes BPMN XML
53      */
54     public void validateBpmnConfig(byte[] bpmnBytes) {
55         BpmnModel bpmnModel = BpmnModelUtils.getBpmnModel(bpmnBytes);
56         assert bpmnModel != null;
57         List<UserTask> userTaskList = BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class);
58         // 遍历所有的 UserTask,校验审批人配置
59         userTaskList.forEach(userTask -> {
60             // 1. 非空校验
61             Integer strategy = BpmnModelUtils.parseCandidateStrategy(userTask);
62             String param = BpmnModelUtils.parseCandidateParam(userTask);
63             if (strategy == null) {
64                 throw exception(MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG, userTask.getName());
65             }
66             BpmTaskCandidateStrategy candidateStrategy = getCandidateStrategy(strategy);
67             if (candidateStrategy.isParamRequired() && StrUtil.isBlank(param)) {
68                 throw exception(MODEL_DEPLOY_FAIL_TASK_CANDIDATE_NOT_CONFIG, userTask.getName());
69             }
70             // 2. 具体策略校验
71             getCandidateStrategy(strategy).validateParam(param);
72         });
73     }
74
75     /**
76      * 计算任务的候选人
77      *
78      * @param execution 执行任务
79      * @return 用户编号集合
80      */
81     @DataPermission(enable = false) // 忽略数据权限,避免因为过滤,导致找不到候选人
82     public Set<Long> calculateUsers(DelegateExecution execution) {
83         Integer strategy = BpmnModelUtils.parseCandidateStrategy(execution.getCurrentFlowElement());
84         String param = BpmnModelUtils.parseCandidateParam(execution.getCurrentFlowElement());
85         // 1.1 计算任务的候选人
86         Set<Long> userIds = getCandidateStrategy(strategy).calculateUsers(execution, param);
87         // 1.2 移除被禁用的用户
88         removeDisableUsers(userIds);
89
90         // 2. 校验是否有候选人
91         if (CollUtil.isEmpty(userIds)) {
92             log.error("[calculateUsers][流程任务({}/{}/{}) 任务规则({}/{}) 找不到候选人]", execution.getId(),
93                     execution.getProcessDefinitionId(), execution.getCurrentActivityId(), strategy, param);
94             throw exception(TASK_CREATE_FAIL_NO_CANDIDATE_USER);
95         }
96         return userIds;
97     }
98
99     @VisibleForTesting
100     void removeDisableUsers(Set<Long> assigneeUserIds) {
101         if (CollUtil.isEmpty(assigneeUserIds)) {
102             return;
103         }
104         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assigneeUserIds);
105         assigneeUserIds.removeIf(id -> {
106             AdminUserRespDTO user = userMap.get(id);
107             return user == null || !CommonStatusEnum.ENABLE.getStatus().equals(user.getStatus());
108         });
109     }
110
111     private BpmTaskCandidateStrategy getCandidateStrategy(Integer strategy) {
112         BpmTaskCandidateStrategyEnum strategyEnum = BpmTaskCandidateStrategyEnum.valueOf(strategy);
113         Assert.notNull(strategyEnum, "策略(%s) 不存在", strategy);
114         BpmTaskCandidateStrategy strategyObj = strategyMap.get(strategyEnum);
115         Assert.notNull(strategyObj, "策略(%s) 不存在", strategy);
116         return strategyObj;
117     }
118
119 }