mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 20:28:44 +08:00 
			
		
		
		
	重新实现后端的 bpm 流程图的高亮接口
This commit is contained in:
		@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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, "流程实例不存在");
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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 拓展表相关 ==========
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -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();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
		Reference in New Issue
	
	Block a user