From 676e4f29d908de2d55d537bef6823b2d6642d3ae Mon Sep 17 00:00:00 2001
From: YunaiV <zhijiantianya@gmail.com>
Date: Wed, 19 Jan 2022 01:00:59 +0800
Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=96=B0=E5=AE=9E=E7=8E=B0=E5=90=8E?=
 =?UTF-8?q?=E7=AB=AF=E7=9A=84=20bpm=20=E6=B5=81=E7=A8=8B=E5=9B=BE=E7=9A=84?=
 =?UTF-8?q?=E9=AB=98=E4=BA=AE=E6=8E=A5=E5=8F=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../task/BpmActivityController.java           |  40 +++++
 .../controller/task/BpmTaskController.java    |  12 +-
 .../bpm/controller/task/vo/task/FileResp.java |  24 ---
 .../bpm/enums/BpmErrorCodeConstants.java      |   3 +-
 .../bpm/service/task/BpmActivityService.java  |  25 ++++
 .../bpm/service/task/BpmTaskService.java      |  17 ++-
 .../task/impl/BpmActivityServiceImpl.java     |  78 ++++++++++
 .../service/task/impl/BpmTaskServiceImpl.java | 140 ++----------------
 .../bpm/service/task/package-info.java        |  12 ++
 9 files changed, 176 insertions(+), 175 deletions(-)
 create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmActivityController.java
 delete mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/FileResp.java
 create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmActivityService.java
 create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java
 create mode 100644 yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/package-info.java

diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmActivityController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmActivityController.java
new file mode 100644
index 000000000..15931ffaa
--- /dev/null
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmActivityController.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.controller.task;
+
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmActivityService;
+import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Api(tags = "流程活动实例")
+@RestController
+@RequestMapping("/bpm/activity")
+@Validated
+public class BpmActivityController {
+
+    @Resource
+    private BpmActivityService activityService;
+
+    // TODO 芋艿:注解、权限、validtion
+
+    @ApiOperation(value = "生成指定流程实例的高亮流程图",
+            notes = "只高亮进行中的任务。不过要注意,该接口暂时没用,通过前端的 ProcessViewer.vue 界面的 highlightDiagram 方法生成")
+    @GetMapping("/generate-highlight-diagram")
+    @ApiImplicitParam(name = "id", value = "流程实例的编号", required = true, dataTypeClass = String.class)
+    public void generateHighlightDiagram(@RequestParam("processInstanceId") String processInstanceId,
+                                         HttpServletResponse response) throws IOException {
+        byte[] bytes = activityService.generateHighlightDiagram(processInstanceId);
+        ServletUtils.writeAttachment(response, StrUtil.format("流程图-{}.svg", processInstanceId), bytes);
+    }
+
+}
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.java
index fdff560d0..5a0b6af4b 100644
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.java
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/BpmTaskController.java
@@ -20,7 +20,7 @@ import java.util.List;
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
 
-@Api(tags = "流程任务")
+@Api(tags = "流程任务实例")
 @RestController
 @RequestMapping("/bpm/task")
 @Validated
@@ -72,14 +72,4 @@ public class BpmTaskController {
         return success(taskService.getTaskListByProcessInstanceId(processInstanceId));
     }
 
-    /**
-     * 返回高亮的流转图SVG
-     * @param processInstanceId 流程Id
-     */
-    @GetMapping("/process/highlight-img")
-    public void getHighlightImg(@RequestParam String processInstanceId, HttpServletResponse response) throws IOException {
-        FileResp fileResp = taskService.getHighlightImg(processInstanceId);
-        ServletUtils.writeAttachment(response, fileResp.getFileName(), fileResp.getFileByte());
-    }
-
 }
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/FileResp.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/FileResp.java
deleted file mode 100644
index fb9cbca2c..000000000
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/controller/task/vo/task/FileResp.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package cn.iocoder.yudao.adminserver.modules.bpm.controller.task.vo.task;
-
-import lombok.Data;
-
-// TODO @Li:1)改成 HighlightImgRespVO 吧。2)swagger 注解要补充;3)fileByte => fileContent
-/**
- * 文件输出类
- *
- * @author yunlongn
- */
-@Data
-public class FileResp {
-
-    /**
-     * 文件名字
-     */
-    private String fileName;
-
-    /**
-     * 文件输出流
-     */
-    private byte[] fileByte;
-
-}
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java
index ec2cafa7e..6f762f04f 100644
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/enums/BpmErrorCodeConstants.java
@@ -33,7 +33,8 @@ public interface BpmErrorCodeConstants {
     ErrorCode PROCESS_DEFINITION_KEY_NOT_MATCH = new ErrorCode(1009003000, "流程定义的标识期望是({}),当前是({}),请修改 BPMN 流程图");
     ErrorCode PROCESS_DEFINITION_NAME_NOT_MATCH = new ErrorCode(1009003001, "流程定义的名字期望是({}),当前是({}),请修改 BPMN 流程图");
     ErrorCode PROCESS_DEFINITION_NOT_EXISTS = new ErrorCode(1009003002, "流程定义不存在");
-    ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1009003002, "流程定义处于挂起状态");
+    ErrorCode PROCESS_DEFINITION_IS_SUSPENDED = new ErrorCode(1009003003, "流程定义处于挂起状态");
+    ErrorCode PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS = new ErrorCode(1009003004, "流程定义的模型不存在");
 
     // ========== 流程实例 1-009-004-000 ==========
     ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1009004000, "流程实例不存在");
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmActivityService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmActivityService.java
new file mode 100644
index 000000000..3fa4a5acc
--- /dev/null
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmActivityService.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.task;
+
+/**
+ * BPM 活动实例 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface BpmActivityService {
+
+    /**
+     * 生成指定流程实例的高亮流程图,只高亮进行中的任务
+     *
+     * 友情提示,非该方法的注释。如果想实现更高级的高亮流程图(当前节点红色 + 完成节点为绿色),可参考如下内容:
+     *      博客一:https://blog.csdn.net/qq_40109075/article/details/110939639
+     *      博客二:https://gitee.com/tony2y/RuoYi-flowable/blob/master/ruoyi-flowable/src/main/java/com/ruoyi/flowable/flow/CustomProcessDiagramGenerator.java
+     * 这里不实现的原理,需要自定义实现 ProcessDiagramGenerator 和 ProcessDiagramCanvas,代码量有点大
+     *
+     * 如果你想实现高亮已完成的任务,可参考 https://blog.csdn.net/qiuxinfa123/article/details/119579863 博客。不过测试下来,貌似不太对~
+     *
+     * @param processInstanceId 实例Id
+     * @return 图的字节数组
+     */
+    byte[] generateHighlightDiagram(String processInstanceId);
+
+}
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java
index a063bfeeb..383c124e4 100644
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/BpmTaskService.java
@@ -10,7 +10,7 @@ import java.util.List;
 import java.util.Map;
 
 /**
- * 流程任务 Service 接口
+ * 流程任务实例 Service 接口
  *
  * @author jason
  * @author 芋道源码
@@ -32,6 +32,14 @@ public interface BpmTaskService {
      */
     List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId);
 
+    /**
+     * 获得流程任务列表
+     *
+     * @param processInstanceId 流程实例的编号
+     * @return 流程任务列表
+     */
+    List<Task> getTasksByProcessInstanceId(String processInstanceId);
+
     /**
      * 获得流程任务列表
      *
@@ -101,13 +109,6 @@ public interface BpmTaskService {
      */
     void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
 
-    /**
-     * 返回高亮的流转进程
-     * @param processInstanceId 实例Id
-     * @return {@link FileResp} 返回文件
-     */
-    FileResp getHighlightImg(String processInstanceId);
-
     // ========== Task 拓展表相关 ==========
 
     /**
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java
new file mode 100644
index 000000000..299b4a980
--- /dev/null
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmActivityServiceImpl.java
@@ -0,0 +1,78 @@
+package cn.iocoder.yudao.adminserver.modules.bpm.service.task.impl;
+
+import cn.hutool.core.io.IoUtil;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.definition.BpmProcessDefinitionService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmActivityService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmProcessInstanceService;
+import cn.iocoder.yudao.adminserver.modules.bpm.service.task.BpmTaskService;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.activiti.bpmn.model.BpmnModel;
+import org.activiti.engine.HistoryService;
+import org.activiti.engine.RepositoryService;
+import org.activiti.engine.RuntimeService;
+import org.activiti.engine.history.HistoricProcessInstance;
+import org.activiti.engine.task.Task;
+import org.activiti.image.ProcessDiagramGenerator;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.List;
+
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS;
+import static cn.iocoder.yudao.adminserver.modules.bpm.enums.BpmErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS;
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+
+/**
+ * BPM 活动实例 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Slf4j
+@Validated
+public class BpmActivityServiceImpl implements BpmActivityService {
+
+    private static final String FONT_NAME = "宋体";
+
+    @Resource
+    private ProcessDiagramGenerator processDiagramGenerator;
+
+    @Resource
+    private BpmProcessInstanceService processInstanceService;
+    @Resource
+    private BpmProcessDefinitionService processDefinitionService;
+    @Resource
+    private BpmTaskService taskService;
+
+    @Override
+    public byte[] generateHighlightDiagram(String processInstanceId) {
+        // 获得流程实例
+        HistoricProcessInstance processInstance = processInstanceService.getHistoricProcessInstance(processInstanceId);
+        if (processInstance == null) {
+            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
+        }
+        // 获得流程定义的 BPMN 模型
+        BpmnModel bpmnModel = processDefinitionService.getBpmnModel(processInstance.getProcessDefinitionId());
+        if (bpmnModel == null) {
+            throw exception(PROCESS_DEFINITION_BPMN_MODEL_NOT_EXISTS);
+        }
+
+        // 如果流程已经结束,则无进行中的任务,无法高亮
+        // 如果流程未结束,才需要高亮
+        List<String> highLightedActivities = Collections.emptyList();
+        if (processInstance.getEndTime() == null) {
+            List<Task> tasks = taskService.getTasksByProcessInstanceId(processInstanceId);
+            highLightedActivities = CollectionUtils.convertList(tasks, Task::getTaskDefinitionKey);
+        }
+
+        // 生成高亮流程图
+        InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, Collections.emptyList(),
+                FONT_NAME, FONT_NAME, FONT_NAME);
+        return IoUtil.readBytes(inputStream);
+    }
+
+}
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java
index 351ff80fa..e199eba63 100644
--- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/impl/BpmTaskServiceImpl.java
@@ -54,7 +54,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 
 /**
- * 流程任务 Service 实现类
+ * 流程任务实例 Service 实现类
  *
  * @author jason
  * @author 芋道源码
@@ -66,14 +66,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
     @Resource
     private TaskService taskService;
     @Resource
-    private RuntimeService runtimeService;
-    @Resource
     private HistoryService  historyService;
-    @Resource
-    private RepositoryService repositoryService;
-
-    @Resource
-    private ProcessDiagramGenerator processDiagramGenerator;
 
     @Resource
     private SysUserService userService;
@@ -118,6 +111,14 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         return BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap);
     }
 
+    @Override
+    public List<Task> getTasksByProcessInstanceId(String processInstanceId) {
+        if (StrUtil.isEmpty(processInstanceId)) {
+            return Collections.emptyList();
+        }
+        return taskService.createTaskQuery().processInstanceId(processInstanceId).list();
+    }
+
     @Override
     public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
         if (CollUtil.isEmpty(processInstanceIds)) {
@@ -270,129 +271,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 //        taskService.addComment(task.getId(), task.getProcessInstanceId(), reqVO.getComment());
     }
 
-    @Override
-    public FileResp getHighlightImg(String processInstanceId) {
-        // 查询历史
-        //TODO 云扬四海 貌似流程结束后,点击审批进度会报错
-        // TODO @Li:一些 historyService 的查询,貌似比较通用,是不是抽一些小方法出来
-        HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
-        // 如果不存在实例。 说明数据异常
-        if (hpi == null) {
-//            throw exception(PROCESS_INSTANCE_NOT_EXISTS);
-            throw new RuntimeException("不存在");
-        }
-        // 如果有结束时间 返回model的流程图
-        if (!ObjectUtils.isEmpty(hpi.getEndTime())) {
-            ProcessDefinition pd = repositoryService.createProcessDefinitionQuery().processDefinitionId(hpi.getProcessDefinitionId()).singleResult();
-            String resourceName = Optional.ofNullable(pd.getDiagramResourceName()).orElse(pd.getResourceName());
-            BpmnModel bpmnModel = repositoryService.getBpmnModel(pd.getId());
-            InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, new ArrayList<>(1), new ArrayList<>(1),
-                    "宋体", "宋体", "宋体");
-            FileResp fileResp = new FileResp();
-            fileResp.setFileName( resourceName + ".svg");
-            fileResp.setFileByte(IoUtil.readBytes(inputStream));
-            return fileResp;
-        }
-        // 没有结束时间。说明流程在执行过程中
-        // TODO @Li:一些 runtimeService 的查询,貌似比较通用,是不是抽一些小方法出来
-        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
-
-        List<String> highLightedActivities = new ArrayList<>();
-        // 获取所有活动节点
-        List<HistoricActivityInstance> finishedInstances = historyService.createHistoricActivityInstanceQuery()
-                .processInstanceId(processInstanceId).finished().list();
-        finishedInstances.stream().map(HistoricActivityInstance::getActivityId)
-                .forEach(highLightedActivities::add);
-        // 已完成的节点+当前节点
-        highLightedActivities.addAll(runtimeService.getActiveActivityIds(processInstanceId));
-
-        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
-        // 经过的流
-        List<String> highLightedFlowIds = getHighLightedFlows(bpmnModel, processInstanceId);
-
-        //设置"宋体"
-        try (InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, highLightedFlowIds,
-                "宋体", "宋体", "宋体")){
-            FileResp fileResp = new FileResp();
-            fileResp.setFileName( hpi.getProcessDefinitionName() + ".svg");
-            fileResp.setFileByte(IoUtil.readBytes(inputStream));
-            return fileResp;
-        } catch (IOException e) {
-            log.error("[getHighlightImg][流程({}) 生成图表失败]", processInstanceId, e);
-            throw exception(HIGHLIGHT_IMG_ERROR);
-        }
-    }
-
-    // TODO @Li:这个方法的可读性还有一定的优化空间,可以思考下哈。
-    /**
-     * 获取指定 processInstanceId 已经高亮的Flows
-     * 获取已经流转的线 参考: https://blog.csdn.net/qiuxinfa123/article/details/119579863
-     * @param bpmnModel model
-     * @param processInstanceId 流程实例Id
-     * @return 获取已经流转的列表
-     */
-    private List<String> getHighLightedFlows(BpmnModel bpmnModel, String processInstanceId) {
-        // 获取所有的线条
-        List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
-                .orderByHistoricActivityInstanceId().asc().list();
-        // 高亮流程已发生流转的线id集合
-        List<String> highLightedFlowIds = new ArrayList<>();
-        // 全部活动节点
-        List<FlowNode> historicActivityNodes = new ArrayList<>();
-        // 已完成的历史活动节点
-        List<HistoricActivityInstance> finishedActivityInstances = new ArrayList<>();
-
-        for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
-            FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(historicActivityInstance.getActivityId(), true);
-            historicActivityNodes.add(flowNode);
-            // 结束时间不为空,则是已完成节点
-            if (historicActivityInstance.getEndTime() != null) {
-                finishedActivityInstances.add(historicActivityInstance);
-            }
-        }
-        // 提取活动id 是唯一的。塞入Map
-        Map<String, HistoricActivityInstance> historicActivityInstanceMap = CollectionUtils.convertMap(historicActivityInstances, HistoricActivityInstance::getActivityId);
-        // 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的
-        for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
-            // 获得当前活动对应的节点信息及outgoingFlows信息
-            FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
-            List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();
-
-            // 遍历outgoingFlows并找到已流转的 满足如下条件认为已已流转:
-            // 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
-            // 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转
-            if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(currentActivityInstance.getActivityType())
-                    || BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE.equals(currentActivityInstance.getActivityType())) {
-                // 遍历历史活动节点,找到匹配流程目标节点的
-                for (SequenceFlow sequenceFlow : sequenceFlows) {
-                    FlowNode targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
-                    if (historicActivityNodes.contains(targetFlowNode)) {
-                        highLightedFlowIds.add(targetFlowNode.getId());
-                    }
-                }
-            } else {
-                long earliestStamp = 0L;
-                String highLightedFlowId = null;
-                // 循环流出的流
-                for (SequenceFlow sequenceFlow : sequenceFlows) {
-                    HistoricActivityInstance historicActivityInstance = historicActivityInstanceMap.get(sequenceFlow.getTargetRef());
-                    if (historicActivityInstance == null) {
-                        continue;
-                    }
-                    final long startTime = historicActivityInstance.getStartTime().getTime();
-                    // 遍历匹配的集合,取得开始时间最早的一个
-                    if (earliestStamp == 0 || earliestStamp >= startTime) {
-                        highLightedFlowId = sequenceFlow.getId();
-                        earliestStamp = startTime;
-                    }
-                }
-                highLightedFlowIds.add(highLightedFlowId);
-            }
-
-        }
-        return highLightedFlowIds;
-    }
-
     private Task getTask(String id) {
         return taskService.createTaskQuery().taskId(id).singleResult();
     }
diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/package-info.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/package-info.java
new file mode 100644
index 000000000..01ecbf3a2
--- /dev/null
+++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/bpm/service/task/package-info.java
@@ -0,0 +1,12 @@
+/**
+ * task 包下,存放的都是 xxx 实例。例如说:
+ * 1. ProcessInstance 是 ProcessDefinition 创建而来的实例;
+ * 2. TaskInstance 是 TaskDefinition 创建而来的实例;
+ * 3. ActivityInstance 是 BPMN 流程图的每个元素创建的实例;
+ *
+ * 考虑到 Task 和 Activity 可以比较明确表示名字,所以对应的 Service 就没有使用 Instance 后缀~
+ * 嘿嘿,其实也是实现到比较后面的阶段,所以就暂时没去统一和修改了~
+ *
+ * @author 芋道源码
+ */
+package cn.iocoder.yudao.adminserver.modules.bpm.service.task;