diff --git a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/flow/FlowableUtils.java b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/flow/FlowableUtils.java index 3018def7..80b7ca59 100644 --- a/ruoyi-flowable/src/main/java/com/ruoyi/flowable/flow/FlowableUtils.java +++ b/ruoyi-flowable/src/main/java/com/ruoyi/flowable/flow/FlowableUtils.java @@ -1,5 +1,7 @@ package com.ruoyi.flowable.flow; +import cn.hutool.core.util.ObjectUtil; +import com.ruoyi.common.exception.ServiceException; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.*; import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; @@ -586,4 +588,117 @@ public class FlowableUtils { log.info("清洗后的历史节点数据:" + lastHistoricTaskInstanceList); return lastHistoricTaskInstanceList; } + + /** + * 深搜递归获取流程未通过的节点 + * @param bpmnModel 流程模型 + * @param unfinishedTaskSet 未结束的任务节点 + * @param finishedSequenceFlowSet 已经完成的连线 + * @param finishedTaskSet 已完成的任务节点 + * @return + */ + public static Set dfsFindRejects(BpmnModel bpmnModel, Set unfinishedTaskSet, Set finishedSequenceFlowSet, Set finishedTaskSet) { + if (ObjectUtil.isNull(bpmnModel)) { + throw new ServiceException("流程模型不存在"); + } + Collection allElements = getAllElements(bpmnModel.getMainProcess().getFlowElements(), null); + Set rejectedSet = new HashSet<>(); + for (FlowElement flowElement : allElements) { + // 用户节点且未结束元素 + if (flowElement instanceof UserTask && unfinishedTaskSet.contains(flowElement.getId())) { + List hasSequenceFlow = iteratorFindFinishes(flowElement, null); + List rejects = iteratorFindRejects(flowElement, finishedSequenceFlowSet, finishedTaskSet, hasSequenceFlow, null); + rejectedSet.addAll(rejects); + } + } + return rejectedSet; + } + + /** + * 迭代获取父级节点列表,向前找 + * @param source 起始节点 + * @param hasSequenceFlow 已经经过的连线的ID,用于判断线路是否重复 + * @return + */ + public static List iteratorFindFinishes(FlowElement source, List hasSequenceFlow) { + hasSequenceFlow = hasSequenceFlow == null ? new ArrayList<>() : hasSequenceFlow; + + // 根据类型,获取入口连线 + List sequenceFlows = getElementIncomingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow: sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + FlowElement finishedElement = sequenceFlow.getSourceFlowElement(); + // 类型为子流程,则添加子流程开始节点出口处相连的节点 + if (finishedElement instanceof SubProcess) { + FlowElement firstElement = (StartEvent) ((SubProcess) finishedElement).getFlowElements().toArray()[0]; + // 获取子流程的连线 + hasSequenceFlow.addAll(iteratorFindFinishes(firstElement, null)); + } + // 继续迭代 + hasSequenceFlow = iteratorFindFinishes(finishedElement, hasSequenceFlow); + } + } + return hasSequenceFlow; + } + + /** + * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找 + * @param source 起始节点 + * @param finishedSequenceFlowSet 已经完成的连线 + * @param finishedTaskSet 已经完成的任务节点 + * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 + * @param rejectedList 未通过的元素 + * @return + */ + public static List iteratorFindRejects(FlowElement source, Set finishedSequenceFlowSet, Set finishedTaskSet + , List hasSequenceFlow, List rejectedList) { + hasSequenceFlow = hasSequenceFlow == null ? new ArrayList<>() : hasSequenceFlow; + rejectedList = rejectedList == null ? new ArrayList<>() : rejectedList; + + // 根据类型,获取出口连线 + List sequenceFlows = getElementOutgoingFlows(source); + + if (sequenceFlows != null) { + // 循环找到目标元素 + for (SequenceFlow sequenceFlow: sequenceFlows) { + // 如果发现连线重复,说明循环了,跳过这个循环 + if (hasSequenceFlow.contains(sequenceFlow.getId())) { + continue; + } + // 添加已经走过的连线 + hasSequenceFlow.add(sequenceFlow.getId()); + FlowElement targetElement = sequenceFlow.getTargetFlowElement(); + // 添加未完成的节点 + if (finishedTaskSet.contains(targetElement.getId())) { + rejectedList.add(targetElement.getId()); + } + // 添加未完成的连线 + if (finishedSequenceFlowSet.contains(sequenceFlow.getId())) { + rejectedList.add(sequenceFlow.getId()); + } + // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取 + if (targetElement instanceof SubProcess) { + FlowElement firstElement = (FlowElement) (((SubProcess) targetElement).getFlowElements().toArray()[0]); + List childList = iteratorFindRejects(firstElement, finishedSequenceFlowSet, finishedTaskSet, hasSequenceFlow, null); + // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续 + if (childList != null && childList.size() > 0) { + rejectedList.addAll(childList); + continue; + } + } + // 继续迭代 + rejectedList = iteratorFindRejects(targetElement, finishedSequenceFlowSet, finishedTaskSet, hasSequenceFlow, rejectedList); + } + } + return rejectedList; + } + } 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 9d5be68f..3d01b9a3 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 @@ -2,7 +2,6 @@ package com.ruoyi.workflow.service.impl; import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -726,26 +725,6 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ // 获取流程发布Id信息 String processDefinitionId = allActivityInstanceList.get(0).getProcessDefinitionId(); BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); - if (ObjectUtil.isNull(bpmnModel)) { - throw new ServiceException("流程模型不存在"); - } - Map> sequenceElementMap = new HashMap<>(); - Map sequenceFlowMap = new HashMap<>(); - Collection flowElements = bpmnModel.getMainProcess().getFlowElements(); - for (FlowElement flowElement : flowElements) { - if (flowElement instanceof SequenceFlow) { - SequenceFlow sequenceFlow = (SequenceFlow) flowElement; - String sourceRef = sequenceFlow.getSourceRef(); - String targetRef = sequenceFlow.getTargetRef(); - List targetRefList = sequenceElementMap.get(sourceRef); - if (CollUtil.isEmpty(targetRefList)) { - sequenceElementMap.put(sourceRef, ListUtil.toList(targetRef)); - } else { - targetRefList.add(targetRef); - } - sequenceFlowMap.put(sourceRef + targetRef, sequenceFlow.getId()); - } - } // 查询所有已完成的元素 List finishedElementList = allActivityInstanceList.stream() .filter(item -> ObjectUtil.isNotNull(item.getEndTime())).collect(Collectors.toList()); @@ -765,30 +744,9 @@ public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskServ .filter(item -> ObjectUtil.isNull(item.getEndTime())) .map(HistoricActivityInstance::getActivityId) .collect(Collectors.toSet()); - - Set rejectedTaskSet = new LinkedHashSet<>(); - Set sourceTaskSet = unfinishedTaskSet; - while (CollUtil.isNotEmpty(sourceTaskSet)) { - Set nextIdSet = new HashSet<>(); - for (String previousId : sourceTaskSet) { - List nextIdList = sequenceElementMap.get(previousId); - if (CollUtil.isEmpty(nextIdList)) { - continue; - } - nextIdList.forEach(nextId -> { - if (finishedTaskSet.contains(nextId)) { - nextIdSet.add(nextId); - String rejectedSequenceFlow = sequenceFlowMap.get(previousId + nextId); - if (finishedSequenceFlowSet.contains(rejectedSequenceFlow)) { - nextIdSet.add(rejectedSequenceFlow); - } - } - }); - } - rejectedTaskSet.addAll(nextIdSet); - sourceTaskSet = nextIdSet; - } - return new WfViewerVo(finishedTaskSet, finishedSequenceFlowSet, unfinishedTaskSet, rejectedTaskSet); + // DFS 查询未通过的元素集合 + Set rejectedSet = FlowableUtils.dfsFindRejects(bpmnModel, unfinishedTaskSet, finishedSequenceFlowSet, finishedTaskSet); + return new WfViewerVo(finishedTaskSet, finishedSequenceFlowSet, unfinishedTaskSet, rejectedSet); } /**