From 91f356fc741a1e17928b326069eda646e61ffc1c Mon Sep 17 00:00:00 2001 From: jason <2667446@qq.com> Date: Wed, 3 Jun 2026 14:39:35 +0800 Subject: [PATCH] fix: 自动去重,连续审批自动通过问题修复。https://gitee.com/zhijiantianya/yudao-cloud/issues/IE8CQN --- yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java | 46 ++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java | 13 +++++++++---- 2 files changed, 55 insertions(+), 4 deletions(-) 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 b624c53..041eceb 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 @@ -457,6 +457,52 @@ public class BpmnModelUtils { } /** + * 根据节点,递归获取上游 source 为 UserTask 的入口连线 + * + * 1. 如果当前节点的直接入口连线 source 就是 UserTask,则直接返回该连线 + * 2. 如果当前节点的直接入口连线 source 不是 UserTask,则继续向上递归查找 + * 3. 如果递归过程中遇到 StartEvent 或 SubProcess,则停止该分支继续向上查找 + * + * @param source 起始节点 + * @return 上游连接 UserTask 的入口连线列表 + */ + public static List getElementIncomingUserTaskFlows(FlowElement source) { + List result = new ArrayList<>(); + collectElementIncomingUserTaskFlows(source, new HashSet<>(), new HashSet<>(), result); + return result; + } + + private static void collectElementIncomingUserTaskFlows(FlowElement source, Set visitedSequenceFlowIds, + Set resultSequenceFlowIds, List result) { + // 如果是开始节点或子流程,则停止该分支向上查找 + if (source == null || source instanceof StartEvent || source instanceof SubProcess) { + return; + } + + List incomingFlows = getElementIncomingFlows(source); + if (CollUtil.isEmpty(incomingFlows)) { + return; + } + + for (SequenceFlow incomingFlow : incomingFlows) { + // 如果发现连线重复,说明连线已经走过。跳过 + if (incomingFlow == null || !visitedSequenceFlowIds.add(incomingFlow.getId())) { + continue; + } + FlowElement sourceFlowElement = incomingFlow.getSourceFlowElement(); + if (sourceFlowElement instanceof UserTask) { + if (resultSequenceFlowIds.add(incomingFlow.getId())) { + result.add(incomingFlow); + } + continue; + } + // 递归向上查找 UserTask + collectElementIncomingUserTaskFlows(sourceFlowElement, visitedSequenceFlowIds, + resultSequenceFlowIds, result); + } + } + + /** * 根据节点,获取出口连线 * * @param source 起始节点 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 952fa99..bafc72d 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 @@ -1475,25 +1475,30 @@ public class BpmTaskServiceImpl implements BpmTaskService { if (processDefinitionInfo.getAutoApprovalType() != null) { HistoricTaskInstanceQuery sameAssigneeQuery = historyService.createHistoricTaskInstanceQuery() .processInstanceId(task.getProcessInstanceId()) - .taskAssignee(task.getAssignee()) // 相同审批人 .taskVariableValueEquals(BpmnVariableConstants.TASK_VARIABLE_STATUS, BpmTaskStatusEnum.APPROVE.getStatus()) .finished(); if (BpmAutoApproveTypeEnum.APPROVE_ALL.getType().equals(processDefinitionInfo.getAutoApprovalType()) - && sameAssigneeQuery.count() > 0) { + && sameAssigneeQuery.taskAssignee(task.getAssignee()).count() > 0) { getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) .setReason(BpmAutoApproveTypeEnum.APPROVE_ALL.getName())); return; } + // 连续审批的节点自动通过 if (BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getType().equals(processDefinitionInfo.getAutoApprovalType())) { BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(processInstance.getProcessDefinitionId()); if (bpmnModel == null) { log.error("[processTaskAssigned][taskId({}) 没有找到流程模型({})]", task.getId(), task.getProcessDefinitionId()); return; } - List sourceTaskIds = convertList(BpmnModelUtils.getElementIncomingFlows( // 获取所有上一个节点 + List sourceTaskIds = convertList(BpmnModelUtils.getElementIncomingUserTaskFlows( // 获取所有的上一个 UserTask 节点连线 BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey())), SequenceFlow::getSourceRef); - if (sameAssigneeQuery.taskDefinitionKeys(sourceTaskIds).count() > 0) { + // 设置 taskIds, 并按创建时间倒序排序 + sameAssigneeQuery.taskDefinitionKeys(sourceTaskIds) + .orderByTaskCreateTime() + .desc(); + HistoricTaskInstance firstHisTask = CollUtil.getFirst(sameAssigneeQuery.list()); + if (firstHisTask != null && StrUtil.equals(firstHisTask.getAssignee(), task.getAssignee())) { getSelf().approveTask(Long.valueOf(task.getAssignee()), new BpmTaskApproveReqVO().setId(task.getId()) .setReason(BpmAutoApproveTypeEnum.APPROVE_SEQUENT.getName())); return; -- libgit2 0.21.4