From d9b320f29fd8b7978b338c86594405c9a472a8d5 Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Sat, 20 Jun 2026 10:20:25 +0800 Subject: [PATCH] fix: 条件分支、并行分支下,审核人自选问题修复,https://wx.zsxq.com/group/88858522214142/topic/2852142228215121 --- yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java | 2 +- yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java | 6 ++---- yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 4 ++-- 4 files changed, 82 insertions(+), 9 deletions(-) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java index 2a45e3a..15d3505 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmTaskCandidateStrategyEnum.java @@ -24,7 +24,7 @@ public enum BpmTaskCandidateStrategyEnum implements ArrayValuable { MULTI_DEPT_LEADER_MULTI(23, "连续多级部门的负责人"), POST(22, "岗位"), USER(30, "用户"), - APPROVE_USER_SELECT(34, "审批人自身"), // 当前审批人,可在审批时,选择下一个节点的审批人 + APPROVE_USER_SELECT(34, "审批人自选"), // 当前审批人,可在审批时,选择下一个节点的审批人 START_USER_SELECT(35, "发起人自选"), // 申请人自己,可在提交申请时,选择此节点的审批人 START_USER(36, "发起人自己"), // 申请人自己, 一般紧挨开始节点,常用于发起人信息审核场景 START_USER_DEPT_LEADER(37, "发起人部门负责人"), diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java index 17051c7..fbaefd1 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java @@ -958,13 +958,88 @@ public class BpmnModelUtils { } /** - * 查找起始节点下一个用户任务列表列表 + * 查找起始节点下一个用户任务列表, 该方法会递归向下查找:跳过非 UserTask 节点, 支持网关条件判断 + * + * + * + * @param currentElement 当前节点 + * @param bpmnModel BPMN 模型 + * @param variables 流程变量(用于网关条件判断) + * @return 下一个用户任务节点列表 + */ + public static List getNextUserTasks(FlowElement currentElement, BpmnModel bpmnModel, + Map variables) { + return getNextUserTasks(currentElement, bpmnModel, variables, new HashSet<>(), new ArrayList<>()); + } + + private static List getNextUserTasks(FlowElement currentElement, BpmnModel bpmnModel, + Map variables, + Set hasSequenceFlow, List userTaskList) { + // 1. 根据节点类型决定要遍历的出口连线 + // 网关需要根据条件表达式筛选;其它节点直接取所有 outgoing flows + List outgoingFlows; + if (currentElement instanceof Gateway) { + outgoingFlows = getGatewayOutgoingFlows((Gateway) currentElement, variables); + } else { + outgoingFlows = getElementOutgoingFlows(currentElement); + } + if (CollUtil.isEmpty(outgoingFlows)) { + return userTaskList; + } + // 2. 遍历出口连线,递归查找用户任务 + for (SequenceFlow outgoingFlow : outgoingFlows) { + // 防止连线成环导致死循环 + if (hasSequenceFlow.contains(outgoingFlow.getId())) { + continue; + } + hasSequenceFlow.add(outgoingFlow.getId()); + + FlowElement targetElement = bpmnModel.getFlowElement(outgoingFlow.getTargetRef()); + if (targetElement == null || targetElement instanceof EndEvent) { + continue; + } + if (targetElement instanceof UserTask) { + // 找到用户任务:加入结果 + userTaskList.add((UserTask) targetElement); + } else { + // 非用户任务(网关、服务任务、中间事件等):继续递归向下查找 + getNextUserTasks(targetElement, bpmnModel, variables, hasSequenceFlow, userTaskList); + } + } + return userTaskList; + } + + /** + * 根据网关类型与流程变量,筛选网关的出口连线 + * + * @param gateway 网关节点 + * @param variables 流程变量 + * @return 命中的出口连线列表 + */ + private static List getGatewayOutgoingFlows(Gateway gateway, Map variables) { + if (gateway instanceof ExclusiveGateway) { + SequenceFlow matchFlow = findMatchSequenceFlowByExclusiveGateway(gateway, variables); + return matchFlow == null ? Collections.emptyList() : Collections.singletonList(matchFlow); + } + if (gateway instanceof InclusiveGateway) { + return new ArrayList<>(findMatchSequenceFlowsByInclusiveGateway(gateway, variables)); + } + // 默认(并行网关等):走所有出口 + return gateway.getOutgoingFlows(); + } + + /** + * 查找起始节点下一个用户任务列表列表, 不判断网关条件 * * @param source 起始节点 * @return 结果 */ public static List getNextUserTasks(FlowElement source) { - return getNextUserTasks(source, null, null); + return getNextUserTasks(source, new HashSet<>(), new ArrayList<>()); } /** diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 1205bb1..760dca0 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -7,7 +7,6 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.*; import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; @@ -279,9 +278,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService // 3. 获取下一个将要执行的节点集合 FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey()); - List nextFlowNodes = BpmnModelUtils.getNextFlowNodes(flowElement, bpmnModel, processVariables); - // 仅仅获取 UserTask 节点 TODO add from jason:如果网关节点和网关节点相连,获取下个 UserTask. 貌似有点不准。 - List nextUserTaskList = CollectionUtils.filterList(nextFlowNodes, node -> node instanceof UserTask); + // 获取 UserTask 节点 + List nextUserTaskList = BpmnModelUtils.getNextUserTasks(flowElement, bpmnModel, processVariables); List nextActivityNodes = convertList(nextUserTaskList, node -> new ActivityNode().setId(node.getId()) .setName(node.getName()).setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()) .setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index b31b8a0..f95b824 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -669,10 +669,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { } // 1. 获取下一个将要执行的节点集合 FlowElement flowElement = bpmnModel.getFlowElement(taskDefinitionKey); - List nextFlowNodes = getNextFlowNodes(flowElement, bpmnModel, variables); + List nextFlowNodes = getNextUserTasks(flowElement, bpmnModel, variables); // 2. 校验选择的下一个节点的审批人,是否合法 - for (FlowNode nextFlowNode : nextFlowNodes) { + for (UserTask nextFlowNode : nextFlowNodes) { Integer candidateStrategy = parseCandidateStrategy(nextFlowNode); // 2.1 情况一:如果节点中的审批人策略为 发起人自选 if (ObjUtil.equals(candidateStrategy, BpmTaskCandidateStrategyEnum.START_USER_SELECT.getStrategy())) { -- libgit2 0.21.4