Эх сурвалжийг харах

bpm:优化 BpmnModelUtils

YunaiV 1 жил өмнө
parent
commit
83a133b344

+ 309 - 0
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/BpmnModelUtils.java

@@ -0,0 +1,309 @@
+package cn.iocoder.yudao.framework.flowable.core.util;
+
+import cn.hutool.core.collection.CollUtil;
+import org.flowable.bpmn.converter.BpmnXMLConverter;
+import org.flowable.bpmn.model.Process;
+import org.flowable.bpmn.model.*;
+
+import java.util.*;
+
+/**
+ * 流程模型转操作工具类
+ */
+public class BpmnModelUtils {
+
+    /**
+     * 根据节点,获取入口连线
+     *
+     * @param source 起始节点
+     * @return 入口连线列表
+     */
+    public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) {
+        if (source instanceof FlowNode) {
+            return ((FlowNode) source).getIncomingFlows();
+        }
+        return new ArrayList<>();
+    }
+
+    /**
+     * 根据节点,获取出口连线
+     *
+     * @param source 起始节点
+     * @return 出口连线列表
+     */
+    public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) {
+        if (source instanceof FlowNode) {
+            return ((FlowNode) source).getOutgoingFlows();
+        }
+        return new ArrayList<>();
+    }
+
+    /**
+     * 获取流程元素信息
+     *
+     * @param model         bpmnModel 对象
+     * @param flowElementId 元素 ID
+     * @return 元素信息
+     */
+    public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) {
+        Process process = model.getMainProcess();
+        return process.getFlowElement(flowElementId);
+    }
+
+    /**
+     * 获得 BPMN 流程中,指定的元素们
+     *
+     * @param model
+     * @param clazz 指定元素。例如说,{@link UserTask}、{@link Gateway} 等等
+     * @return 元素们
+     */
+    public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) {
+        List<T> result = new ArrayList<>();
+        model.getProcesses().forEach(process -> {
+            process.getFlowElements().forEach(flowElement -> {
+                if (flowElement.getClass().isAssignableFrom(clazz)) {
+                    result.add((T) flowElement);
+                }
+            });
+        });
+        return result;
+    }
+
+    /**
+     * 比较 两个bpmnModel 是否相同
+     * @param oldModel  老的bpmn model
+     * @param newModel 新的bpmn model
+     */
+    public static boolean equals(BpmnModel oldModel, BpmnModel newModel) {
+        // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较
+        return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel));
+    }
+
+    /**
+     * 把 bpmnModel 转换成 byte[]
+     * @param model  bpmnModel
+     */
+    public static byte[] getBpmnBytes(BpmnModel model) {
+        if (model == null) {
+            return new byte[0];
+        }
+        BpmnXMLConverter converter = new BpmnXMLConverter();
+        return converter.convertToXML(model);
+    }
+
+    // ========== 遍历相关的方法 ==========
+
+    /**
+     * 找到 source 节点之前的所有用户任务节点
+     *
+     * @param source          起始节点
+     * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
+     * @param userTaskList    已找到的用户任务节点
+     * @return 用户任务节点 数组
+     */
+    public static List<UserTask> getPreviousUserTaskList(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
+        userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+        // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
+        if (source instanceof StartEvent && source.getSubProcess() != null) {
+            userTaskList = getPreviousUserTaskList(source.getSubProcess(), hasSequenceFlow, userTaskList);
+        }
+
+        // 根据类型,获取入口连线
+        List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
+        if (sequenceFlows == null) {
+            return userTaskList;
+        }
+        // 循环找到目标元素
+        for (SequenceFlow sequenceFlow : sequenceFlows) {
+            // 如果发现连线重复,说明循环了,跳过这个循环
+            if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                continue;
+            }
+            // 添加已经走过的连线
+            hasSequenceFlow.add(sequenceFlow.getId());
+            // 类型为用户节点,则新增父级节点
+            if (sequenceFlow.getSourceFlowElement() instanceof UserTask) {
+                userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement());
+            }
+            // 类型为子流程,则添加子流程开始节点出口处相连的节点
+            if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) {
+                // 获取子流程用户任务节点
+                List<UserTask> childUserTaskList = findChildProcessUserTaskList((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null);
+                // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
+                if (CollUtil.isNotEmpty(childUserTaskList)) {
+                    userTaskList.addAll(childUserTaskList);
+                }
+            }
+            // 继续迭代
+            userTaskList = getPreviousUserTaskList(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList);
+        }
+        return userTaskList;
+    }
+
+    /**
+     * 迭代获取子流程用户任务节点
+     *
+     * @param source          起始节点
+     * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
+     * @param userTaskList    需要撤回的用户任务列表
+     * @return 用户任务节点
+     */
+    public static List<UserTask> findChildProcessUserTaskList(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+        userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
+
+        // 根据类型,获取出口连线
+        List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
+        if (sequenceFlows == null) {
+            return userTaskList;
+        }
+        // 循环找到目标元素
+        for (SequenceFlow sequenceFlow : sequenceFlows) {
+            // 如果发现连线重复,说明循环了,跳过这个循环
+            if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                continue;
+            }
+            // 添加已经走过的连线
+            hasSequenceFlow.add(sequenceFlow.getId());
+            // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
+            if (sequenceFlow.getTargetFlowElement() instanceof UserTask) {
+                userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
+                continue;
+            }
+            // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
+            if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
+                List<UserTask> childUserTaskList = findChildProcessUserTaskList((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null);
+                // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
+                if (CollUtil.isNotEmpty(childUserTaskList)) {
+                    userTaskList.addAll(childUserTaskList);
+                    continue;
+                }
+            }
+            // 继续迭代
+            userTaskList = findChildProcessUserTaskList(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList);
+        }
+        return userTaskList;
+    }
+
+
+    /**
+     * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行
+     * 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况
+     *
+     * @param source          起始节点
+     * @param target          目标节点
+     * @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复
+     * @return 结果
+     */
+    public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set<String> visitedElements) {
+        visitedElements = visitedElements == null ? new HashSet<>() : visitedElements;
+        // 不能是开始事件和子流程
+        if (source instanceof StartEvent && isInEventSubprocess(source)) {
+            return false;
+        }
+
+        // 根据类型,获取入口连线
+        List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
+        if (CollUtil.isEmpty(sequenceFlows)) {
+            return true;
+        }
+        // 循环找到目标元素
+        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;
+            }
+            // 否则就继续迭代
+            if (!isSequentialReachable(sourceFlowElement, target, visitedElements)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 判断当前节点是否属于不同的子流程
+     *
+     * @param flowElement 被判断的节点
+     * @return true 表示属于子流程
+     */
+    private 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;
+    }
+
+    /**
+     * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找
+     *
+     * @param source          起始节点
+     * @param runTaskKeyList  正在运行的任务 Key,用于校验任务节点是否是正在运行的节点
+     * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
+     * @param userTaskList    需要撤回的用户任务列表
+     * @return 子级任务节点列表
+     */
+    public static List<UserTask> iteratorFindChildUserTasks(FlowElement source, List<String> runTaskKeyList,
+                                                            Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
+        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
+        userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
+        // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
+        if (source instanceof StartEvent && source.getSubProcess() != null) {
+            userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList);
+        }
+
+        // 根据类型,获取出口连线
+        List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
+        if (sequenceFlows == null) {
+            return userTaskList;
+        }
+        // 循环找到目标元素
+        for (SequenceFlow sequenceFlow : sequenceFlows) {
+            // 如果发现连线重复,说明循环了,跳过这个循环
+            if (hasSequenceFlow.contains(sequenceFlow.getId())) {
+                continue;
+            }
+            // 添加已经走过的连线
+            hasSequenceFlow.add(sequenceFlow.getId());
+            // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
+            if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) {
+                userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
+                continue;
+            }
+            // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
+            if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
+                List<UserTask> childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null);
+                // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
+                if (CollUtil.isNotEmpty(childUserTaskList)) {
+                    userTaskList.addAll(childUserTaskList);
+                    continue;
+                }
+            }
+            // 继续迭代
+            userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList);
+        }
+        return userTaskList;
+    }
+
+}

+ 0 - 50
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/FlowableUtils.java

@@ -1,14 +1,7 @@
 package cn.iocoder.yudao.framework.flowable.core.util;
 
-import org.flowable.bpmn.converter.BpmnXMLConverter;
-import org.flowable.bpmn.model.BpmnModel;
-import org.flowable.bpmn.model.FlowElement;
 import org.flowable.common.engine.impl.identity.Authentication;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
 /**
  * Flowable 相关的工具方法
  *
@@ -26,49 +19,6 @@ public class FlowableUtils {
         Authentication.setAuthenticatedUserId(null);
     }
 
-    // ========== BPMN 相关的工具方法 ==========
-
-    /**
-     * 获得 BPMN 流程中,指定的元素们
-     *
-     * @param model
-     * @param clazz 指定元素。例如说,{@link org.flowable.bpmn.model.UserTask}、{@link org.flowable.bpmn.model.Gateway} 等等
-     * @return 元素们
-     */
-    public static <T extends FlowElement> List<T> getBpmnModelElements(BpmnModel model, Class<T> clazz) {
-        List<T> result = new ArrayList<>();
-        model.getProcesses().forEach(process -> {
-            process.getFlowElements().forEach(flowElement -> {
-                if (flowElement.getClass().isAssignableFrom(clazz)) {
-                    result.add((T) flowElement);
-                }
-            });
-        });
-        return result;
-    }
-
-    /**
-     * 比较 两个bpmnModel 是否相同
-     * @param oldModel  老的bpmn model
-     * @param newModel 新的bpmn model
-     */
-    public static boolean equals(BpmnModel oldModel, BpmnModel newModel) {
-        // 由于 BpmnModel 未提供 equals 方法,所以只能转成字节数组,进行比较
-        return Arrays.equals(getBpmnBytes(oldModel), getBpmnBytes(newModel));
-    }
-
-    /**
-     * 把 bpmnModel 转换成 byte[]
-     * @param model  bpmnModel
-     */
-    public  static byte[] getBpmnBytes(BpmnModel model) {
-        if (model == null) {
-            return new byte[0];
-        }
-        BpmnXMLConverter converter = new BpmnXMLConverter();
-        return converter.convertToXML(model);
-    }
-
     // ========== Execution 相关的工具方法 ==========
 
     public static String formatCollectionVariable(String activityId) {

+ 0 - 272
yudao-framework/yudao-spring-boot-starter-flowable/src/main/java/cn/iocoder/yudao/framework/flowable/core/util/ModelUtils.java

@@ -1,272 +0,0 @@
-package cn.iocoder.yudao.framework.flowable.core.util;
-
-import org.flowable.bpmn.model.Process;
-import org.flowable.bpmn.model.*;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * 流程模型转操作工具类
- */
-public class ModelUtils {
-
-    /**
-     * 根据节点,获取入口连线
-     *
-     * @param source 起始节点
-     * @return 入口连线列表
-     */
-    public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) {
-        List<SequenceFlow> sequenceFlows = new ArrayList<>();
-        if (source instanceof FlowNode) {
-            sequenceFlows = ((FlowNode) source).getIncomingFlows();
-        }
-        return sequenceFlows;
-    }
-
-
-    /**
-     * 根据节点,获取出口连线
-     *
-     * @param source 起始节点
-     * @return 出口连线列表
-     */
-    public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) {
-        List<SequenceFlow> sequenceFlows = new ArrayList<>();
-        if (source instanceof FlowNode) {
-            sequenceFlows = ((FlowNode) source).getOutgoingFlows();
-        }
-        return sequenceFlows;
-    }
-
-
-    /**
-     * 获取流程元素信息
-     *
-     * @param model         bpmnModel对象
-     * @param flowElementId 元素ID
-     * @return 元素信息
-     */
-    public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) {
-        Process process = model.getMainProcess();
-        return process.getFlowElement(flowElementId);
-    }
-
-    /**
-     * 找到 source 节点之前的所有用户任务节点
-     *
-     * @param source          起始节点
-     * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
-     * @param userTaskList    已找到的用户任务节点
-     * @return
-     */
-    public static List<UserTask> getPreUserTaskList(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
-        userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
-        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
-
-        // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
-        if (source instanceof StartEvent && source.getSubProcess() != null) {
-            userTaskList = getPreUserTaskList(source.getSubProcess(), hasSequenceFlow, userTaskList);
-        }
-
-        // 根据类型,获取入口连线
-        List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
-
-        if (sequenceFlows != null) {
-            // 循环找到目标元素
-            for (SequenceFlow sequenceFlow : sequenceFlows) {
-                // 如果发现连线重复,说明循环了,跳过这个循环
-                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
-                    continue;
-                }
-                // 添加已经走过的连线
-                hasSequenceFlow.add(sequenceFlow.getId());
-                // 类型为用户节点,则新增父级节点
-                if (sequenceFlow.getSourceFlowElement() instanceof UserTask) {
-                    userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement());
-                }
-                // 类型为子流程,则添加子流程开始节点出口处相连的节点
-                if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) {
-                    // 获取子流程用户任务节点
-                    List<UserTask> childUserTaskList = findChildProcessUserTasks((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null);
-                    // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
-                    if (childUserTaskList != null && childUserTaskList.size() > 0) {
-                        userTaskList.addAll(childUserTaskList);
-                    }
-                }
-                // 继续迭代
-                userTaskList = getPreUserTaskList(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList);
-            }
-        }
-        return userTaskList;
-    }
-
-    /**
-     * 迭代获取子流程用户任务节点
-     *
-     * @param source          起始节点
-     * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
-     * @param userTaskList    需要撤回的用户任务列表
-     * @return
-     */
-    public static List<UserTask> findChildProcessUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
-        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
-        userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
-
-        // 根据类型,获取出口连线
-        List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
-
-        if (sequenceFlows != null) {
-            // 循环找到目标元素
-            for (SequenceFlow sequenceFlow : sequenceFlows) {
-                // 如果发现连线重复,说明循环了,跳过这个循环
-                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
-                    continue;
-                }
-                // 添加已经走过的连线
-                hasSequenceFlow.add(sequenceFlow.getId());
-                // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
-                if (sequenceFlow.getTargetFlowElement() instanceof UserTask) {
-                    userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
-                    continue;
-                }
-                // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
-                if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
-                    List<UserTask> childUserTaskList = findChildProcessUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null);
-                    // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
-                    if (childUserTaskList != null && childUserTaskList.size() > 0) {
-                        userTaskList.addAll(childUserTaskList);
-                        continue;
-                    }
-                }
-                // 继续迭代
-                userTaskList = findChildProcessUserTasks(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList);
-            }
-        }
-        return userTaskList;
-    }
-
-
-    /**
-     * 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行
-     * 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况
-     *
-     * @param source          起始节点
-     * @param target          目标节点
-     * @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复
-     * @return 结果
-     */
-    public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set<String> visitedElements) {
-        visitedElements = visitedElements == null ? new HashSet<>() : visitedElements;
-        //不能是开始事件和子流程
-        if (source instanceof StartEvent && isInEventSubprocess(source)) {
-            return false;
-        }
-
-        // 根据类型,获取入口连线
-        List<SequenceFlow> 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;
-    }
-
-    /**
-     * 判断当前节点是否属于不同的子流程
-     *
-     * @param flowElement 被判断的节点
-     * @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;
-    }
-
-
-    /**
-     * 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找
-     *
-     * @param source          起始节点
-     * @param runTaskKeyList  正在运行的任务 Key,用于校验任务节点是否是正在运行的节点
-     * @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
-     * @param userTaskList    需要撤回的用户任务列表
-     * @return
-     */
-    public static List<UserTask> iteratorFindChildUserTasks(FlowElement source, List<String> runTaskKeyList, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
-        hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow;
-        userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList;
-
-        // 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
-        if (source instanceof StartEvent && source.getSubProcess() != null) {
-            userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList);
-        }
-
-        // 根据类型,获取出口连线
-        List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
-
-        if (sequenceFlows != null) {
-            // 循环找到目标元素
-            for (SequenceFlow sequenceFlow : sequenceFlows) {
-                // 如果发现连线重复,说明循环了,跳过这个循环
-                if (hasSequenceFlow.contains(sequenceFlow.getId())) {
-                    continue;
-                }
-                // 添加已经走过的连线
-                hasSequenceFlow.add(sequenceFlow.getId());
-                // 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
-                if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) {
-                    userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement());
-                    continue;
-                }
-                // 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
-                if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) {
-                    List<UserTask> childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null);
-                    // 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
-                    if (childUserTaskList != null && childUserTaskList.size() > 0) {
-                        userTaskList.addAll(childUserTaskList);
-                        continue;
-                    }
-                }
-                // 继续迭代
-                userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList);
-            }
-        }
-        return userTaskList;
-    }
-}

+ 2 - 2
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java

@@ -5,7 +5,7 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
-import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils;
+import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionListReqVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageItemRespVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process.BpmProcessDefinitionPageReqVO;
@@ -200,7 +200,7 @@ public class BpmProcessDefinitionServiceImpl implements BpmProcessDefinitionServ
         BpmnModel newModel = buildBpmnModel(createReqDTO.getBpmnBytes());
         BpmnModel oldModel = getBpmnModel(oldProcessDefinition.getId());
         // 对比字节变化
-        if (!FlowableUtils.equals(oldModel, newModel)) {
+        if (!BpmnModelUtils.equals(oldModel, newModel)) {
             return false;
         }
         // 最终发现都一致,则返回 true

+ 2 - 2
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmTaskAssignRuleServiceImpl.java

@@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
 import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
-import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils;
+import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleCreateReqVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleRespVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.rule.BpmTaskAssignRuleUpdateReqVO;
@@ -114,7 +114,7 @@ public class BpmTaskAssignRuleServiceImpl implements BpmTaskAssignRuleService {
             return Collections.emptyList();
         }
         // 获得用户任务,只有用户任务才可以设置分配规则
-        List<UserTask> userTasks = FlowableUtils.getBpmnModelElements(model, UserTask.class);
+        List<UserTask> userTasks = BpmnModelUtils.getBpmnModelElements(model, UserTask.class);
         if (CollUtil.isEmpty(userTasks)) {
             return Collections.emptyList();
         }

+ 16 - 15
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java

@@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 import cn.iocoder.yudao.framework.common.util.object.PageUtils;
-import cn.iocoder.yudao.framework.flowable.core.util.ModelUtils;
+import cn.iocoder.yudao.framework.flowable.core.util.BpmnModelUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
 import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
@@ -61,22 +61,23 @@ public class BpmTaskServiceImpl implements BpmTaskService {
     private TaskService taskService;
     @Resource
     private HistoryService historyService;
+    @Resource
+    private RuntimeService runtimeService;
 
     @Resource
     private BpmProcessInstanceService processInstanceService;
     @Resource
-    private AdminUserApi adminUserApi;
-    @Resource
-    private DeptApi deptApi;
-    @Resource
-    private BpmTaskExtMapper taskExtMapper;
+    private BpmModelService bpmModelService;
     @Resource
     private BpmMessageService messageService;
+
     @Resource
-    private BpmModelService bpmModelService;
+    private AdminUserApi adminUserApi;
     @Resource
-    private RuntimeService runtimeService;
+    private DeptApi deptApi;
 
+    @Resource
+    private BpmTaskExtMapper taskExtMapper;
 
     @Override
     public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
@@ -351,18 +352,18 @@ public class BpmTaskServiceImpl implements BpmTaskService {
             throw exception(TASK_NOT_EXISTS);
         }
         BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId());
-        FlowElement source = ModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
+        FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
         if (source == null) {
             throw exception(TASK_NOT_EXISTS);
         }
 
         // 2.1 查询该任务的前置任务节点的 key 集合
-        List<UserTask> previousUserList = ModelUtils.getPreUserTaskList(source, null, null);
+        List<UserTask> previousUserList = BpmnModelUtils.getPreviousUserTaskList(source, null, null);
         if (CollUtil.isEmpty(previousUserList)) {
             return Collections.emptyList();
         }
         // 2.2 过滤:只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回
-        previousUserList.removeIf(userTask -> !ModelUtils.isSequentialReachable(source, userTask, null));
+        previousUserList.removeIf(userTask -> !BpmnModelUtils.isSequentialReachable(source, userTask, null));
         return BpmTaskConvert.INSTANCE.convertList(previousUserList);
     }
 
@@ -395,15 +396,15 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         // 1.1 获取流程模型信息
         BpmnModel bpmnModel = bpmModelService.getBpmnModelByDefinitionId(processDefinitionId);
         // 1.3 获取当前任务节点元素
-        FlowElement source = ModelUtils.getFlowElementById(bpmnModel, sourceKey);
+        FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, sourceKey);
         // 1.3 获取跳转的节点元素
-        FlowElement target = ModelUtils.getFlowElementById(bpmnModel, targetKey);
+        FlowElement target = BpmnModelUtils.getFlowElementById(bpmnModel, targetKey);
         if (target == null) {
             throw exception(TASK_TARGET_NODE_NOT_EXISTS);
         }
 
         // 2.2 只有串行可到达的节点,才可以回退。类似非串行、子流程无法退回
-        if (!ModelUtils.isSequentialReachable(source, target, null)) {
+        if (!BpmnModelUtils.isSequentialReachable(source, target, null)) {
             throw exception(TASK_RETURN_FAIL_SOURCE_TARGET_ERROR);
         }
         return target;
@@ -423,7 +424,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         List<String> runTaskKeyList = convertList(taskList, Task::getTaskDefinitionKey);
         // 1.2 通过 targetElement 的出口连线,计算在 runTaskKeyList 有哪些 key 需要被撤回
         // 为什么不直接使用 runTaskKeyList 呢?因为可能存在多个审批分支,例如说:A -> B -> C 和 D -> F,而只要 C 撤回到 A,需要排除掉 F
-        List<UserTask> returnUserTaskList = ModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null);
+        List<UserTask> returnUserTaskList = BpmnModelUtils.iteratorFindChildUserTasks(targetElement, runTaskKeyList, null, null);
         List<String> returnTaskKeyList = convertList(returnUserTaskList, UserTask::getId);
 
         // 2. 给当前要被回退的 task 数组,设置回退意见