diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/utils/ModelUtils.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/utils/ModelUtils.java index e552ea8e..7f1980fa 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/utils/ModelUtils.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/utils/ModelUtils.java @@ -310,4 +310,64 @@ public class ModelUtils { } return userTaskList; } + + /** + * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行 + * 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况 + * @param source 起始节点 + * @param target 目标节点 + * @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复 + * @return 结果 + */ + public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set visitedElements) { + visitedElements = visitedElements == null ? new HashSet<>() : visitedElements; + if (source instanceof StartEvent && isInEventSubprocess(source)) { + return false; + } + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + if (sequenceFlows != null && sequenceFlows.size() > 0) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow: sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (visitedElements.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + visitedElements.add(sequenceFlow.getId()); + FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement(); + // 这条线路存在目标节点,这条线路完成,进入下个线路 + if (target.getId().equals(sourceFlowElement.getId())) { + continue; + } + // 如果目标节点为并行网关,则不继续 + if (sourceFlowElement instanceof ParallelGateway) { + return false; + } + // 否则就继续迭代 + boolean isSequential = isSequentialReachable(sourceFlowElement, target, visitedElements); + if (!isSequential) { + return false; + } + } + } + return true; + } + + protected static boolean isInEventSubprocess(FlowElement flowElement) { + FlowElementsContainer flowElementsContainer = flowElement.getParentContainer(); + while (flowElementsContainer != null) { + if (flowElementsContainer instanceof EventSubProcess) { + return true; + } + + if (flowElementsContainer instanceof FlowElement) { + flowElementsContainer = ((FlowElement) flowElementsContainer).getParentContainer(); + } else { + flowElementsContainer = null; + } + } + return false; + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java index 55ed5cb7..27c53f9f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/IWfTaskService.java @@ -1,7 +1,7 @@ package com.ruoyi.workflow.service; import com.ruoyi.workflow.domain.bo.WfTaskBo; -import org.flowable.bpmn.model.UserTask; +import org.flowable.bpmn.model.FlowElement; import org.flowable.engine.runtime.ProcessInstance; import java.io.InputStream; @@ -42,7 +42,7 @@ public interface IWfTaskService { * @param bo * @return */ - List findReturnTaskList(WfTaskBo bo); + List findReturnTaskList(WfTaskBo bo); /** * 删除任务 diff --git a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java index 5496016f..be5ffa30 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/workflow/service/impl/WfTaskServiceImpl.java @@ -167,36 +167,18 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ } // 获取流程定义信息 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); - // 获取所有节点信息 - Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); - // 获取全部节点列表,包含子节点 - Collection allElements = FlowableUtils.getAllElements(process.getFlowElements(), null); + // 获取流程模型信息 + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); // 获取当前任务节点元素 - FlowElement source = null; + FlowElement source = ModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); // 获取跳转的节点元素 - FlowElement target = null; - if (allElements != null) { - for (FlowElement flowElement : allElements) { - // 当前任务节点元素 - if (flowElement.getId().equals(task.getTaskDefinitionKey())) { - source = flowElement; - } - // 跳转的节点元素 - if (flowElement.getId().equals(bo.getTargetKey())) { - target = flowElement; - } - } - } - - // 从当前节点向前扫描 - // 如果存在路线上不存在目标节点,说明目标节点是在网关上或非同一路线上,不可跳转 - // 否则目标节点相对于当前节点,属于串行 - Boolean isSequential = FlowableUtils.iteratorCheckSequentialReferTarget(source, bo.getTargetKey(), null, null); + FlowElement target = ModelUtils.getFlowElementById(bpmnModel, bo.getTargetKey()); + // 从当前节点向前扫描,判断当前节点与目标节点是否属于串行,若目标节点是在并行网关上或非同一路线上,不可跳转 + boolean isSequential = ModelUtils.isSequentialReachable(source, target, new HashSet<>()); if (!isSequential) { throw new RuntimeException("当前节点相对于目标节点,不属于串行关系,无法回退"); } - // 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务 List runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list(); List runTaskKeyList = new ArrayList<>(); @@ -245,38 +227,36 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ * @return */ @Override - public List findReturnTaskList(WfTaskBo bo) { + public List findReturnTaskList(WfTaskBo bo) { // 当前任务 task Task task = taskService.createTaskQuery().taskId(bo.getTaskId()).singleResult(); // 获取流程定义信息 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); - // 获取所有节点信息,暂不考虑子流程情况 - Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); - Collection flowElements = process.getFlowElements(); + // 获取流程模型信息 + BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); + // 查询历史节点实例 + List activityInstanceList = historyService.createHistoricActivityInstanceQuery() + .processInstanceId(task.getProcessInstanceId()) + .activityType(BpmnXMLConstants.ELEMENT_TASK_USER) + .finished() + .orderByHistoricActivityInstanceEndTime().asc() + .list(); + List activityIdList = activityInstanceList.stream() + .map(HistoricActivityInstance::getActivityId) + .filter(activityId -> !StringUtils.equals(activityId, task.getTaskDefinitionKey())) + .distinct() + .collect(Collectors.toList()); // 获取当前任务节点元素 - UserTask source = null; - if (flowElements != null) { - for (FlowElement flowElement : flowElements) { - // 类型为用户节点 - if (flowElement.getId().equals(task.getTaskDefinitionKey())) { - source = (UserTask) flowElement; - } + FlowElement source = ModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); + List elementList = new ArrayList<>(); + for (String activityId : activityIdList) { + FlowElement target = ModelUtils.getFlowElementById(bpmnModel, activityId); + boolean isSequential = ModelUtils.isSequentialReachable(source, target, new HashSet<>()); + if (isSequential) { + elementList.add(target); } } - // 获取节点的所有路线 - List> roads = FlowableUtils.findRoad(source, null, null, null); - // 可回退的节点列表 - List userTaskList = new ArrayList<>(); - for (List road : roads) { - if (userTaskList.size() == 0) { - // 还没有可回退节点直接添加 - userTaskList = road; - } else { - // 如果已有回退节点,则比对取交集部分 - userTaskList.retainAll(road); - } - } - return userTaskList; + return elementList; } /**