mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-27 01:32:03 +08:00
fix:[工作流] 返回对应实例的流程图
This commit is contained in:
parent
abf2f697fb
commit
3c3f46ee4e
@ -9,6 +9,7 @@ import io.swagger.annotations.ApiOperation;
|
|||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -57,4 +58,15 @@ public class TaskController {
|
|||||||
return success(taskService.getHistorySteps(processInstanceId));
|
return success(taskService.getHistorySteps(processInstanceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回高亮的流转进程
|
||||||
|
* @param processInstanceId
|
||||||
|
*/
|
||||||
|
@GetMapping("/process/highlight-img/{id}")
|
||||||
|
public void getHighlightImg(@PathVariable("id") String processInstanceId, HttpServletResponse response) {
|
||||||
|
taskService.getHighlightImg(processInstanceId, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package cn.iocoder.yudao.adminserver.modules.activiti.service.workflow;
|
|||||||
import cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo.*;
|
import cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo.*;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
// TODO @芋艿:前缀,注释
|
// TODO @芋艿:前缀,注释
|
||||||
@ -23,4 +24,10 @@ public interface TaskService {
|
|||||||
|
|
||||||
TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery);
|
TodoTaskRespVO getTaskFormKey(TaskQueryReqVO taskQuery);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回高亮的流转进程
|
||||||
|
* @param processInstanceId
|
||||||
|
*/
|
||||||
|
void getHighlightImg(String processInstanceId, HttpServletResponse response);
|
||||||
}
|
}
|
||||||
|
@ -5,27 +5,43 @@ import cn.iocoder.yudao.adminserver.modules.activiti.controller.workflow.vo.*;
|
|||||||
import cn.iocoder.yudao.adminserver.modules.activiti.convert.workflow.TaskConvert;
|
import cn.iocoder.yudao.adminserver.modules.activiti.convert.workflow.TaskConvert;
|
||||||
import cn.iocoder.yudao.adminserver.modules.activiti.service.workflow.TaskService;
|
import cn.iocoder.yudao.adminserver.modules.activiti.service.workflow.TaskService;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.activiti.api.runtime.shared.query.Page;
|
import org.activiti.api.runtime.shared.query.Page;
|
||||||
import org.activiti.api.runtime.shared.query.Pageable;
|
import org.activiti.api.runtime.shared.query.Pageable;
|
||||||
import org.activiti.api.task.model.Task;
|
import org.activiti.api.task.model.Task;
|
||||||
import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder;
|
import org.activiti.api.task.model.builders.ClaimTaskPayloadBuilder;
|
||||||
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
|
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
|
||||||
import org.activiti.api.task.runtime.TaskRuntime;
|
import org.activiti.api.task.runtime.TaskRuntime;
|
||||||
|
import org.activiti.bpmn.model.BpmnModel;
|
||||||
|
import org.activiti.bpmn.model.FlowNode;
|
||||||
|
import org.activiti.bpmn.model.SequenceFlow;
|
||||||
import org.activiti.engine.HistoryService;
|
import org.activiti.engine.HistoryService;
|
||||||
import org.activiti.engine.RepositoryService;
|
import org.activiti.engine.RepositoryService;
|
||||||
|
import org.activiti.engine.RuntimeService;
|
||||||
import org.activiti.engine.history.HistoricActivityInstance;
|
import org.activiti.engine.history.HistoricActivityInstance;
|
||||||
|
import org.activiti.engine.history.HistoricProcessInstance;
|
||||||
import org.activiti.engine.repository.ProcessDefinition;
|
import org.activiti.engine.repository.ProcessDefinition;
|
||||||
|
import org.activiti.engine.runtime.ProcessInstance;
|
||||||
import org.activiti.engine.task.Comment;
|
import org.activiti.engine.task.Comment;
|
||||||
|
import org.activiti.image.ProcessDiagramGenerator;
|
||||||
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.ArrayList;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import java.util.List;
|
import java.io.IOException;
|
||||||
import java.util.Optional;
|
import java.io.InputStream;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class TaskServiceImpl implements TaskService {
|
public class TaskServiceImpl implements TaskService {
|
||||||
|
|
||||||
@ -41,6 +57,12 @@ public class TaskServiceImpl implements TaskService {
|
|||||||
@Resource
|
@Resource
|
||||||
private RepositoryService repositoryService;
|
private RepositoryService repositoryService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RuntimeService runtimeService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ProcessDiagramGenerator processDiagramGenerator;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<TodoTaskRespVO> getTodoTaskPage(TodoTaskPageReqVO pageReqVO) {
|
public PageResult<TodoTaskRespVO> getTodoTaskPage(TodoTaskPageReqVO pageReqVO) {
|
||||||
// TODO @jason:封装一个方法,用于转换成 activiti 的分页对象
|
// TODO @jason:封装一个方法,用于转换成 activiti 的分页对象
|
||||||
@ -201,4 +223,131 @@ public class TaskServiceImpl implements TaskService {
|
|||||||
// return highLightedFlows;
|
// return highLightedFlows;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void getHighlightImg(String processDefinitionId, HttpServletResponse response) {
|
||||||
|
// 查询历史
|
||||||
|
HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processDefinitionId).singleResult();
|
||||||
|
// 如果有结束时间
|
||||||
|
if (hpi == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 没有结束时间。说明流程在执行过程中
|
||||||
|
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processDefinitionId).singleResult();
|
||||||
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
|
||||||
|
List<String> highLightedActivities = new ArrayList<>();
|
||||||
|
|
||||||
|
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processDefinitionId)
|
||||||
|
.orderByHistoricActivityInstanceId().asc().list();
|
||||||
|
// 获取所有活动节点
|
||||||
|
List<HistoricActivityInstance> finishedInstances = historyService.createHistoricActivityInstanceQuery()
|
||||||
|
.processInstanceId(processDefinitionId).finished().list();
|
||||||
|
for (HistoricActivityInstance hai : finishedInstances) {
|
||||||
|
highLightedActivities.add(hai.getActivityId());
|
||||||
|
}
|
||||||
|
// 已完成的节点+当前节点
|
||||||
|
highLightedActivities.addAll(runtimeService.getActiveActivityIds(processDefinitionId));
|
||||||
|
|
||||||
|
// 经过的流
|
||||||
|
List<String> highLightedFlowIds = getHighLightedFlows(bpmnModel, historicActivityInstances);
|
||||||
|
|
||||||
|
//设置"宋体"
|
||||||
|
try (InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, highLightedFlowIds,
|
||||||
|
"宋体", "宋体", "宋体")){
|
||||||
|
String picName = hpi.getProcessDefinitionName()+".svg";
|
||||||
|
// 输出到浏览器
|
||||||
|
responseImage(response, inputStream, picName);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void responseImage(HttpServletResponse response, InputStream inputStream, String picName) throws IOException {
|
||||||
|
response.setContentType("application/octet-stream;charset=UTF-8");
|
||||||
|
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(picName, "UTF-8"));
|
||||||
|
byte[] b = new byte[1024];
|
||||||
|
int len = -1;
|
||||||
|
while ((len = inputStream.read(b, 0, 1024)) != -1) {
|
||||||
|
response.getOutputStream().write(b, 0, len);
|
||||||
|
}
|
||||||
|
response.flushBuffer();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取已经流转的线
|
||||||
|
* @see https://blog.csdn.net/qiuxinfa123/article/details/119579863
|
||||||
|
* @param bpmnModel model
|
||||||
|
* @param historicActivityInstances 高亮线条
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
|
||||||
|
// 高亮流程已发生流转的线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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FlowNode currentFlowNode;
|
||||||
|
FlowNode targetFlowNode;
|
||||||
|
// 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的
|
||||||
|
for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
|
||||||
|
// 获得当前活动对应的节点信息及outgoingFlows信息
|
||||||
|
currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
|
||||||
|
List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 遍历outgoingFlows并找到已流转的 满足如下条件认为已已流转:
|
||||||
|
* 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
|
||||||
|
* 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转
|
||||||
|
*/
|
||||||
|
if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
|
||||||
|
// 遍历历史活动节点,找到匹配流程目标节点的
|
||||||
|
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
||||||
|
targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
|
||||||
|
if (historicActivityNodes.contains(targetFlowNode)) {
|
||||||
|
highLightedFlowIds.add(targetFlowNode.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
List<Map<String, Object>> tempMapList = new ArrayList<>();
|
||||||
|
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
||||||
|
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
|
||||||
|
if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
|
||||||
|
Map<String, Object> map = new HashMap<>();
|
||||||
|
map.put("highLightedFlowId", sequenceFlow.getId());
|
||||||
|
map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
|
||||||
|
tempMapList.add(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CollectionUtils.isEmpty(tempMapList)) {
|
||||||
|
// 遍历匹配的集合,取得开始时间最早的一个
|
||||||
|
long earliestStamp = 0L;
|
||||||
|
String highLightedFlowId = null;
|
||||||
|
for (Map<String, Object> map : tempMapList) {
|
||||||
|
long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString());
|
||||||
|
if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) {
|
||||||
|
highLightedFlowId = map.get("highLightedFlowId").toString();
|
||||||
|
earliestStamp = highLightedFlowStartTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
highLightedFlowIds.add(highLightedFlowId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return highLightedFlowIds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,11 @@
|
|||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.activiti</groupId>
|
||||||
|
<artifactId>activiti-image-generator</artifactId>
|
||||||
|
<version>${activiti.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package cn.iocoder.yudao.framework.activiti.config;
|
package cn.iocoder.yudao.framework.activiti.config;
|
||||||
|
|
||||||
import org.activiti.api.runtime.shared.identity.UserGroupManager;
|
import org.activiti.api.runtime.shared.identity.UserGroupManager;
|
||||||
|
import org.activiti.image.ProcessDiagramGenerator;
|
||||||
|
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
|
||||||
import org.activiti.spring.SpringProcessEngineConfiguration;
|
import org.activiti.spring.SpringProcessEngineConfiguration;
|
||||||
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
|
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
|
||||||
import org.apache.ibatis.session.SqlSessionFactory;
|
import org.apache.ibatis.session.SqlSessionFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@ -12,7 +15,10 @@ public class YudaoActivitiConfiguration {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ProcessDiagramGenerator processDiagramGenerator (){
|
||||||
|
return new DefaultProcessDiagramGenerator();
|
||||||
|
}
|
||||||
@Component
|
@Component
|
||||||
public static class SqlSessionFactoryProcessEngineConfigurationConfigurer
|
public static class SqlSessionFactoryProcessEngineConfigurationConfigurer
|
||||||
implements ProcessEngineConfigurationConfigurer {
|
implements ProcessEngineConfigurationConfigurer {
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||||
|
cn.iocoder.yudao.framework.activiti.config.YudaoActivitiConfiguration
|
Loading…
Reference in New Issue
Block a user