Commit fedb9242b59b9846951d49e475b718c5a87a406e

Authored by YunaiV
1 parent 10d7cbb9

【代码评审】BPM:下一个审批人

yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java
@@ -58,7 +58,6 @@ public interface ErrorCodeConstants { @@ -58,7 +58,6 @@ public interface ErrorCodeConstants {
58 ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!"); 58 ErrorCode TASK_CREATE_FAIL_NO_CANDIDATE_USER = new ErrorCode(1_009_006_003, "操作失败,原因:找不到任务的审批人!");
59 ErrorCode TASK_SIGNATURE_NOT_EXISTS = new ErrorCode(1_009_005_015, "签名不能为空!"); 59 ErrorCode TASK_SIGNATURE_NOT_EXISTS = new ErrorCode(1_009_005_015, "签名不能为空!");
60 ErrorCode TASK_REASON_REQUIRE = new ErrorCode(1_009_005_016, "审批意见不能为空!"); 60 ErrorCode TASK_REASON_REQUIRE = new ErrorCode(1_009_005_016, "审批意见不能为空!");
61 - ErrorCode TASK_START_USER_SELECT_NODE_NOT_EXISTS = new ErrorCode(1_009_004_007, "({})不是下一个执行的流程节点!");  
62 61
63 // ========== 动态表单模块 1-009-010-000 ========== 62 // ========== 动态表单模块 1-009-010-000 ==========
64 ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在"); 63 ErrorCode FORM_NOT_EXISTS = new ErrorCode(1_009_010_000, "动态表单不存在");
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
@@ -25,6 +25,6 @@ public class BpmTaskApproveReqVO { @@ -25,6 +25,6 @@ public class BpmTaskApproveReqVO {
25 private Map<String, Object> variables; 25 private Map<String, Object> variables;
26 26
27 @Schema(description = "下一个节点审批人", example = "{nodeId:[1, 2]}") 27 @Schema(description = "下一个节点审批人", example = "{nodeId:[1, 2]}")
28 - private Map<String, List<Long>> nextAssignees; 28 + private Map<String, List<Long>> nextAssignees; // 为什么是 Map,而不是 List 呢?因为下一个节点可能是多个,例如说并行网关的情况
29 29
30 } 30 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/dept/BpmTaskCandidateStartUserSelectStrategy.java
@@ -2,24 +2,21 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.d @@ -2,24 +2,21 @@ package cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.d
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.lang.Assert; 4 import cn.hutool.core.lang.Assert;
5 -import cn.hutool.core.util.ObjectUtil;  
6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy; 5 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.user.BpmTaskCandidateUserStrategy;
7 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; 6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
8 -import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils;  
9 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; 7 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
10 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; 8 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
11 import com.google.common.collect.Sets; 9 import com.google.common.collect.Sets;
12 import jakarta.annotation.Resource; 10 import jakarta.annotation.Resource;
13 import org.flowable.bpmn.model.BpmnModel; 11 import org.flowable.bpmn.model.BpmnModel;
14 -import org.flowable.bpmn.model.ServiceTask;  
15 -import org.flowable.bpmn.model.Task;  
16 -import org.flowable.bpmn.model.UserTask;  
17 import org.flowable.engine.delegate.DelegateExecution; 12 import org.flowable.engine.delegate.DelegateExecution;
18 import org.flowable.engine.runtime.ProcessInstance; 13 import org.flowable.engine.runtime.ProcessInstance;
19 import org.springframework.context.annotation.Lazy; 14 import org.springframework.context.annotation.Lazy;
20 import org.springframework.stereotype.Component; 15 import org.springframework.stereotype.Component;
21 16
22 -import java.util.*; 17 +import java.util.LinkedHashSet;
  18 +import java.util.List;
  19 +import java.util.Map;
23 20
24 /** 21 /**
25 * 发起人自选 {@link BpmTaskCandidateUserStrategy} 实现类 22 * 发起人自选 {@link BpmTaskCandidateUserStrategy} 实现类
@@ -53,12 +50,9 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand @@ -53,12 +50,9 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand
53 Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance); 50 Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance);
54 Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空", 51 Assert.notNull(startUserSelectAssignees, "流程实例({}) 的发起人自选审批人不能为空",
55 execution.getProcessInstanceId()); 52 execution.getProcessInstanceId());
56 - // 获得审批人,如果不存在,则直接返回空,fix: 用于节点预测时,如果该节点不存在发起人自选审批人,类型转换异常 53 + // 获得审批人
57 List<Long> assignees = startUserSelectAssignees.get(execution.getCurrentActivityId()); 54 List<Long> assignees = startUserSelectAssignees.get(execution.getCurrentActivityId());
58 - if (CollUtil.isEmpty(assignees)){  
59 - return Sets.newLinkedHashSet();  
60 - }  
61 - return new LinkedHashSet<>(assignees); 55 + return CollUtil.isNotEmpty(assignees) ? new LinkedHashSet<>(assignees) : Sets.newLinkedHashSet();
62 } 56 }
63 57
64 @Override 58 @Override
@@ -71,33 +65,9 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand @@ -71,33 +65,9 @@ public class BpmTaskCandidateStartUserSelectStrategy extends AbstractBpmTaskCand
71 if (startUserSelectAssignees == null) { 65 if (startUserSelectAssignees == null) {
72 return Sets.newLinkedHashSet(); 66 return Sets.newLinkedHashSet();
73 } 67 }
74 - // 获得审批人,如果不存在,则直接返回空,fix: 用于节点预测时,如果该节点不存在发起人自选审批人,类型转换异常 68 + // 获得审批人
75 List<Long> assignees = startUserSelectAssignees.get(activityId); 69 List<Long> assignees = startUserSelectAssignees.get(activityId);
76 - if (CollUtil.isEmpty(assignees)){  
77 - return Sets.newLinkedHashSet();  
78 - }  
79 - return new LinkedHashSet<>(assignees);  
80 - }  
81 -  
82 - /**  
83 - * 获得发起人自选审批人或抄送人的 Task 列表  
84 - *  
85 - * @param bpmnModel BPMN 模型  
86 - * @return Task 列表  
87 - */  
88 - public static List<Task> getStartUserSelectTaskList(BpmnModel bpmnModel) {  
89 - if (bpmnModel == null) {  
90 - return Collections.emptyList();  
91 - }  
92 - List<Task> tasks = new ArrayList<>();  
93 - tasks.addAll(BpmnModelUtils.getBpmnModelElements(bpmnModel, UserTask.class));  
94 - tasks.addAll(BpmnModelUtils.getBpmnModelElements(bpmnModel, ServiceTask.class));  
95 - if (CollUtil.isEmpty(tasks)) {  
96 - return Collections.emptyList();  
97 - }  
98 - tasks.removeIf(task -> ObjectUtil.notEqual(BpmnModelUtils.parseCandidateStrategy(task),  
99 - BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy()));  
100 - return tasks; 70 + return CollUtil.isNotEmpty(assignees) ? new LinkedHashSet<>(assignees) : Sets.newLinkedHashSet();
101 } 71 }
102 72
103 } 73 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
@@ -809,8 +809,7 @@ public class BpmnModelUtils { @@ -809,8 +809,7 @@ public class BpmnModelUtils {
809 if (currentElement instanceof ExclusiveGateway) { 809 if (currentElement instanceof ExclusiveGateway) {
810 // 查找满足条件的 SequenceFlow 路径 810 // 查找满足条件的 SequenceFlow 路径
811 Gateway gateway = (Gateway) currentElement; 811 Gateway gateway = (Gateway) currentElement;
812 - // TODO @小北:当一个网关节点下存在多个满足的并行节点时,只查询一个节点流程流转会存在问题,需要优化,  
813 - // TODO 具体见issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/761 812 + // TODO @小北:当一个网关节点下存在多个满足的并行节点时,只查询一个节点流程流转会存在问题。需要优化,具体见issue:https://github.com/YunaiV/ruoyi-vue-pro/issues/761
814 SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), 813 SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(),
815 flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) 814 flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId())
816 && (evalConditionExpress(variables, flow.getConditionExpression()))); 815 && (evalConditionExpress(variables, flow.getConditionExpression())));
@@ -866,27 +865,27 @@ public class BpmnModelUtils { @@ -866,27 +865,27 @@ public class BpmnModelUtils {
866 * @param bpmnModel BPMN模型 865 * @param bpmnModel BPMN模型
867 * @param variables 流程变量 866 * @param variables 流程变量
868 */ 867 */
  868 + @SuppressWarnings("PatternVariableCanBeUsed")
869 public static List<FlowNode> getNextFlowNodes(FlowElement currentElement, BpmnModel bpmnModel, 869 public static List<FlowNode> getNextFlowNodes(FlowElement currentElement, BpmnModel bpmnModel,
870 Map<String, Object> variables){ 870 Map<String, Object> variables){
871 - // 下一个执行的流程节点集合  
872 - List<FlowNode> nextFlowNodes = new ArrayList<>();  
873 - // 当前执行节点的基本属性  
874 - FlowNode currentNode = (FlowNode) currentElement;  
875 - // 获取当前节点的关联节点  
876 - List<SequenceFlow> outgoingFlows = currentNode.getOutgoingFlows();  
877 - if (CollUtil.isEmpty(outgoingFlows)){ 871 + List<FlowNode> nextFlowNodes = new ArrayList<>(); // 下一个执行的流程节点集合
  872 + FlowNode currentNode = (FlowNode) currentElement; // 当前执行节点的基本属性
  873 + List<SequenceFlow> outgoingFlows = currentNode.getOutgoingFlows(); // 当前节点的关联节点
  874 + if (CollUtil.isEmpty(outgoingFlows)) {
878 log.warn("[getNextFlowNodes][当前节点({}) 的 outgoingFlows 为空]", currentNode.getId()); 875 log.warn("[getNextFlowNodes][当前节点({}) 的 outgoingFlows 为空]", currentNode.getId());
879 return nextFlowNodes; 876 return nextFlowNodes;
880 } 877 }
  878 +
881 // 遍历每个出口流 879 // 遍历每个出口流
882 for (SequenceFlow outgoingFlow : outgoingFlows) { 880 for (SequenceFlow outgoingFlow : outgoingFlows) {
883 // 获取目标节点的基本属性 881 // 获取目标节点的基本属性
884 FlowElement targetElement = bpmnModel.getFlowElement(outgoingFlow.getTargetRef()); 882 FlowElement targetElement = bpmnModel.getFlowElement(outgoingFlow.getTargetRef());
885 - if (targetElement == null){ 883 + if (targetElement == null) {
886 continue; 884 continue;
887 } 885 }
888 - if (targetElement instanceof Gateway gateway) {  
889 - // 处理不同类型的网关 886 + // 情况一:处理不同类型的网关
  887 + if (targetElement instanceof Gateway) {
  888 + Gateway gateway = (Gateway) targetElement;
890 if (gateway instanceof ExclusiveGateway) { 889 if (gateway instanceof ExclusiveGateway) {
891 handleExclusiveGateway(gateway, bpmnModel, variables, nextFlowNodes); 890 handleExclusiveGateway(gateway, bpmnModel, variables, nextFlowNodes);
892 } else if (gateway instanceof InclusiveGateway) { 891 } else if (gateway instanceof InclusiveGateway) {
@@ -895,7 +894,7 @@ public class BpmnModelUtils { @@ -895,7 +894,7 @@ public class BpmnModelUtils {
895 handleParallelGateway(gateway, bpmnModel, variables, nextFlowNodes); 894 handleParallelGateway(gateway, bpmnModel, variables, nextFlowNodes);
896 } 895 }
897 } else { 896 } else {
898 - // 如果不是网关,直接添加到下一个节点列表 897 + // 情况二:如果不是网关,直接添加到下一个节点列表
899 nextFlowNodes.add((FlowNode) targetElement); 898 nextFlowNodes.add((FlowNode) targetElement);
900 } 899 }
901 } 900 }
@@ -903,15 +902,17 @@ public class BpmnModelUtils { @@ -903,15 +902,17 @@ public class BpmnModelUtils {
903 } 902 }
904 903
905 /** 904 /**
906 - * 处理排他网关 905 + * 处理排它网关
907 * 906 *
908 * @param gateway 排他网关 907 * @param gateway 排他网关
909 * @param bpmnModel BPMN模型 908 * @param bpmnModel BPMN模型
910 * @param variables 流程变量 909 * @param variables 流程变量
911 * @param nextFlowNodes 下一个执行的流程节点集合 910 * @param nextFlowNodes 下一个执行的流程节点集合
912 */ 911 */
913 - private static void handleExclusiveGateway(Gateway gateway, BpmnModel bpmnModel, Map<String, Object> variables, List<FlowNode> nextFlowNodes) {  
914 - // TODO @小北: 这里和simulateNextFlowElements中有重复代码,是否重构??每个网关节点拆分出方法应该比较合理化,@芋道 912 + private static void handleExclusiveGateway(Gateway gateway, BpmnModel bpmnModel,
  913 + Map<String, Object> variables, List<FlowNode> nextFlowNodes) {
  914 + // TODO @小北: 这里和 simulateNextFlowElements 中有重复代码,是否重构??每个网关节点拆分出方法应该比较合理化,@芋艿
  915 + // TODO @小北:ok,把 simulateNextFlowElements 里面处理网关的,复用这个方法,可以么?
915 SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(), 916 SequenceFlow matchSequenceFlow = CollUtil.findOne(gateway.getOutgoingFlows(),
916 flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) 917 flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId())
917 && (evalConditionExpress(variables, flow.getConditionExpression()))); 918 && (evalConditionExpress(variables, flow.getConditionExpression())));
@@ -940,7 +941,8 @@ public class BpmnModelUtils { @@ -940,7 +941,8 @@ public class BpmnModelUtils {
940 * @param variables 流程变量 941 * @param variables 流程变量
941 * @param nextFlowNodes 下一个执行的流程节点集合 942 * @param nextFlowNodes 下一个执行的流程节点集合
942 */ 943 */
943 - private static void handleInclusiveGateway(Gateway gateway, BpmnModel bpmnModel, Map<String, Object> variables, List<FlowNode> nextFlowNodes) { 944 + private static void handleInclusiveGateway(Gateway gateway, BpmnModel bpmnModel,
  945 + Map<String, Object> variables, List<FlowNode> nextFlowNodes) {
944 Collection<SequenceFlow> matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(), 946 Collection<SequenceFlow> matchSequenceFlows = CollUtil.filterNew(gateway.getOutgoingFlows(),
945 flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId()) 947 flow -> ObjUtil.notEqual(gateway.getDefaultFlow(), flow.getId())
946 && evalConditionExpress(variables, flow.getConditionExpression())); 948 && evalConditionExpress(variables, flow.getConditionExpression()));
@@ -960,6 +962,7 @@ public class BpmnModelUtils { @@ -960,6 +962,7 @@ public class BpmnModelUtils {
960 } 962 }
961 }); 963 });
962 } 964 }
  965 +
963 /** 966 /**
964 * 处理并行网关 967 * 处理并行网关
965 * 968 *
@@ -968,7 +971,8 @@ public class BpmnModelUtils { @@ -968,7 +971,8 @@ public class BpmnModelUtils {
968 * @param variables 流程变量 971 * @param variables 流程变量
969 * @param nextFlowNodes 下一个执行的流程节点集合 972 * @param nextFlowNodes 下一个执行的流程节点集合
970 */ 973 */
971 - private static void handleParallelGateway(Gateway gateway, BpmnModel bpmnModel, Map<String, Object> variables, List<FlowNode> nextFlowNodes) { 974 + private static void handleParallelGateway(Gateway gateway, BpmnModel bpmnModel,
  975 + Map<String, Object> variables, List<FlowNode> nextFlowNodes) {
972 // 并行网关,遍历所有出口路径,获取目标节点 976 // 并行网关,遍历所有出口路径,获取目标节点
973 gateway.getOutgoingFlows().forEach(flow -> { 977 gateway.getOutgoingFlows().forEach(flow -> {
974 FlowElement targetElement = bpmnModel.getFlowElement(flow.getTargetRef()); 978 FlowElement targetElement = bpmnModel.getFlowElement(flow.getTargetRef());
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
@@ -175,9 +175,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -175,9 +175,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
175 } 175 }
176 startUserId = Long.valueOf(historicProcessInstance.getStartUserId()); 176 startUserId = Long.valueOf(historicProcessInstance.getStartUserId());
177 processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance); 177 processInstanceStatus = FlowableUtils.getProcessInstanceStatus(historicProcessInstance);
178 - // 如果流程变量不为空,则用前端传递的新变量值覆盖历史的流程变量 178 + // 合并 DB 和前端传递的流量变量,以前端的为主
179 Map<String, Object> historicVariables = historicProcessInstance.getProcessVariables(); 179 Map<String, Object> historicVariables = historicProcessInstance.getProcessVariables();
180 - if (null != processVariables) { 180 + if (CollUtil.isNotEmpty(processVariables)) {
181 historicVariables.putAll(processVariables); 181 historicVariables.putAll(processVariables);
182 } 182 }
183 processVariables = historicVariables; 183 processVariables = historicVariables;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -11,13 +11,10 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils; @@ -11,13 +11,10 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
11 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; 11 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
12 import cn.iocoder.yudao.framework.common.util.object.PageUtils; 12 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
13 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; 13 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
14 -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailReqVO;  
15 -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmApprovalDetailRespVO;  
16 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; 14 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
17 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; 15 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
18 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; 16 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO;
19 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; 17 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
20 -import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants;  
21 import cn.iocoder.yudao.module.bpm.enums.definition.*; 18 import cn.iocoder.yudao.module.bpm.enums.definition.*;
22 import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; 19 import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum;
23 import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; 20 import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum;
@@ -63,7 +60,6 @@ import org.springframework.transaction.support.TransactionSynchronization; @@ -63,7 +60,6 @@ import org.springframework.transaction.support.TransactionSynchronization;
63 import org.springframework.transaction.support.TransactionSynchronizationManager; 60 import org.springframework.transaction.support.TransactionSynchronizationManager;
64 61
65 import java.util.*; 62 import java.util.*;
66 -import java.util.stream.Collectors;  
67 import java.util.stream.Stream; 63 import java.util.stream.Stream;
68 64
69 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 65 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -535,9 +531,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -535,9 +531,15 @@ public class BpmTaskServiceImpl implements BpmTaskService {
535 Map<String, Object> variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables()); 531 Map<String, Object> variables = FlowableUtils.filterTaskFormVariable(reqVO.getVariables());
536 // 校验传递的参数中是否为下一个将要执行的任务节点 532 // 校验传递的参数中是否为下一个将要执行的任务节点
537 validateNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), bpmnModel, reqVO.getNextAssignees(), instance); 533 validateNextAssignees(task.getTaskDefinitionKey(), reqVO.getVariables(), bpmnModel, reqVO.getNextAssignees(), instance);
538 - // 下个节点审批人如果不存在,则由前端传递 534 + // 如果有下一个审批人,则设置到流程变量中
  535 + // TODO @小北:validateNextAssignees 升级成 validateAndSetNextAssignees,然后里面吧下面这一小段逻辑,抽进去如何?
539 if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) { 536 if (CollUtil.isNotEmpty(reqVO.getNextAssignees())) {
540 // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖 537 // 获取实例中的全部节点数据,避免后续节点的审批人被覆盖
  538 + // TODO @小北:这里有个需要讨论的点,微信哈;
  539 + // TODO 因为 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES 定位是发起人,那么审批人选择的,放在 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES。目前想到两个方案:
  540 + // TODO 方案一:增加一个 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES,然后设置到这里面。然后,BpmTaskCandidateStartUserSelectStrategy 也从这里读
  541 + // TODO 方案二:也是增加一个 PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES,根据节点审批人类型,放到 PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES、PROCESS_INSTANCE_VARIABLE_APPROVE_USER_SELECT_ASSIGNEES
  542 + // TODO 方案三:融合成 PROCESS_INSTANCE_VARIABLE_USER_SELECT_ASSIGNEES,不再区分是发起人选择、还是审批人选择。
541 Map<String, List<Long>> hisProcessVariables = FlowableUtils.getStartUserSelectAssignees(instance.getProcessVariables()); 543 Map<String, List<Long>> hisProcessVariables = FlowableUtils.getStartUserSelectAssignees(instance.getProcessVariables());
542 hisProcessVariables.putAll(reqVO.getNextAssignees()); 544 hisProcessVariables.putAll(reqVO.getNextAssignees());
543 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, hisProcessVariables); 545 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, hisProcessVariables);
@@ -554,45 +556,52 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -554,45 +556,52 @@ public class BpmTaskServiceImpl implements BpmTaskService {
554 556
555 557
556 /** 558 /**
557 - * 校验传递的参数中是否为下一个将要执行的任务节点 559 + * 校验选择的下一个节点的审批人,是否合法
558 * 560 *
559 - * @param taskDefinitionKey 当前任务节点id 561 + * 1. 是否有漏选:没有选择审批人
  562 + * 2. 是否有多选:非下一个节点
  563 + *
  564 + * @param taskDefinitionKey 当前任务节点标识
560 * @param variables 流程变量 565 * @param variables 流程变量
561 * @param bpmnModel 流程模型 566 * @param bpmnModel 流程模型
562 - * @param nextActivityNodes 下一个节点审批人集合(参数) 567 + * @param nextAssignees 下一个节点审批人集合(参数)
  568 + * @param processInstance 流程实例
563 */ 569 */
564 private void validateNextAssignees(String taskDefinitionKey, Map<String, Object> variables, BpmnModel bpmnModel, 570 private void validateNextAssignees(String taskDefinitionKey, Map<String, Object> variables, BpmnModel bpmnModel,
565 - Map<String, List<Long>> nextActivityNodes,ProcessInstance processInstance){  
566 - // 1、获取当前任务节点的信息 571 + Map<String, List<Long>> nextAssignees, ProcessInstance processInstance) {
  572 + // 1. 获取当前任务节点的信息
567 FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); 573 FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey);
568 - // 2、获取下一个将要执行的节点集合 574 + // 2. 获取下一个将要执行的节点集合
569 List<FlowNode> nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); 575 List<FlowNode> nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables);
570 - // 3、循环下一个将要执行的节点集合 576 +
  577 + // 3. 循环下一个将要执行的节点集合
571 for (FlowNode nextFlowNode : nextFlowNodes) { 578 for (FlowNode nextFlowNode : nextFlowNodes) {
572 - // 3.1、获取下一个将要执行节点的属性(是否为自选审批人等) 579 + // 3.1 获取下一个将要执行节点的属性(是否为自选审批人等)
  580 + // TODO @小北:public static Integer parseCandidateStrategy(FlowElement userTask) 使用这个工具方法哈。
573 Map<String, List<ExtensionElement>> extensionElements = nextFlowNode.getExtensionElements(); 581 Map<String, List<ExtensionElement>> extensionElements = nextFlowNode.getExtensionElements();
574 List<ExtensionElement> elements = extensionElements.get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY); 582 List<ExtensionElement> elements = extensionElements.get(BpmnModelConstants.USER_TASK_CANDIDATE_STRATEGY);
575 - if (CollUtil.isEmpty(elements)){ 583 + if (CollUtil.isEmpty(elements)) {
576 continue; 584 continue;
577 } 585 }
578 - // 3.2、获取节点中的审批人策略 586 + // 3.2 获取节点中的审批人策略
579 Integer candidateStrategy = Integer.valueOf(elements.get(0).getElementText()); 587 Integer candidateStrategy = Integer.valueOf(elements.get(0).getElementText());
580 - // 3.3、获取流程实例中的发起人自选审批人 588 + // 3.3 获取流程实例中的发起人自选审批人
581 Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables()); 589 Map<String, List<Long>> startUserSelectAssignees = FlowableUtils.getStartUserSelectAssignees(processInstance.getProcessVariables());
582 List<Long> startUserSelectAssignee = startUserSelectAssignees.get(nextFlowNode.getId()); 590 List<Long> startUserSelectAssignee = startUserSelectAssignees.get(nextFlowNode.getId());
583 - // 3.4、如果节点中的审批人策略为 发起人自选,并且该节点的审批人为空 591 + // 3.4 如果节点中的审批人策略为 发起人自选,并且该节点的审批人为空
584 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy()) && CollUtil.isEmpty(startUserSelectAssignee)) { 592 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy()) && CollUtil.isEmpty(startUserSelectAssignee)) {
585 // 先判断前端传递的参数节点节点是否为将要执行的节点 593 // 先判断前端传递的参数节点节点是否为将要执行的节点
586 - if (!nextActivityNodes.containsKey(nextFlowNode.getId())){ 594 + // TODO @小北:!nextAssignees.containsKey(nextFlowNode.getId())、和 CollUtil.isEmpty(nextAssignees.get(nextFlowNode.getId()))) 是不是等价的?
  595 + if (!nextAssignees.containsKey(nextFlowNode.getId())) {
587 throw exception(TASK_TARGET_NODE_NOT_EXISTS, nextFlowNode.getName()); 596 throw exception(TASK_TARGET_NODE_NOT_EXISTS, nextFlowNode.getName());
588 } 597 }
589 - // 如果节点存在,则获取节点中的审批人  
590 - List<Long> nextAssignees = nextActivityNodes.get(nextFlowNode.getId());  
591 // 如果前端传递的节点为空,则抛出异常 598 // 如果前端传递的节点为空,则抛出异常
592 - if (CollUtil.isEmpty(nextAssignees)) { 599 + // TODO @小北:换一个错误码哈。
  600 + if (CollUtil.isEmpty(nextAssignees.get(nextFlowNode.getId()))) {
593 throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName()); 601 throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, nextFlowNode.getName());
594 } 602 }
595 } 603 }
  604 + // TODO @小北:加一个“审批人选择”的校验;
596 } 605 }
597 } 606 }
598 607