mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-30 11:11:55 +08:00
fix: 代码 review 修改
This commit is contained in:
parent
fef0562523
commit
0ff7f2ef74
@ -4,6 +4,7 @@ import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*;
|
|||||||
import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.TaskService;
|
import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.TaskService;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
|
||||||
import io.swagger.annotations.Api;
|
import io.swagger.annotations.Api;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@ -11,6 +12,7 @@ import org.springframework.web.bind.annotation.*;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
||||||
@ -63,8 +65,9 @@ public class TaskController {
|
|||||||
* @param processInstanceId
|
* @param processInstanceId
|
||||||
*/
|
*/
|
||||||
@GetMapping("/process/highlight-img/{id}")
|
@GetMapping("/process/highlight-img/{id}")
|
||||||
public void getHighlightImg(@PathVariable("id") String processInstanceId, HttpServletResponse response) {
|
public void getHighlightImg(@PathVariable("id") String processInstanceId, HttpServletResponse response) throws IOException {
|
||||||
taskService.getHighlightImg(processInstanceId, response);
|
FileResp fileResp = taskService.getHighlightImg(processInstanceId);
|
||||||
|
ServletUtils.writeAttachment(response, fileResp.getFileName(), fileResp.getFileByte());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件输出类
|
||||||
|
* @author yunlongn
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class FileResp {
|
||||||
|
/**
|
||||||
|
* 文件名字
|
||||||
|
*/
|
||||||
|
private String fileName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件输出流
|
||||||
|
*/
|
||||||
|
private byte[] fileByte;
|
||||||
|
}
|
@ -16,4 +16,7 @@ public interface OAErrorCodeConstants {
|
|||||||
ErrorCode DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1003001005, "部门的部门经理不存在");
|
ErrorCode DEPART_BM_POST_NOT_EXISTS = new ErrorCode(1003001005, "部门的部门经理不存在");
|
||||||
ErrorCode HR_POST_NOT_EXISTS = new ErrorCode(1003001006, "HR岗位未设置");
|
ErrorCode HR_POST_NOT_EXISTS = new ErrorCode(1003001006, "HR岗位未设置");
|
||||||
ErrorCode DAY_LEAVE_ERROR = new ErrorCode(1003001007, "请假天数必须大于0");
|
ErrorCode DAY_LEAVE_ERROR = new ErrorCode(1003001007, "请假天数必须大于0");
|
||||||
|
|
||||||
|
ErrorCode PROCESS_INSTANCE_NOT_EXISTS = new ErrorCode(1003001008, "流程实例不存在");
|
||||||
|
ErrorCode HIGHLIGHT_IMG_ERROR = new ErrorCode(1003001009, "获取高亮流程图异常");
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,6 @@ public interface TaskService {
|
|||||||
/**
|
/**
|
||||||
* 返回高亮的流转进程
|
* 返回高亮的流转进程
|
||||||
* @param processInstanceId 实例Id
|
* @param processInstanceId 实例Id
|
||||||
* @param response 响应
|
|
||||||
*/
|
*/
|
||||||
void getHighlightImg(String processInstanceId, HttpServletResponse response);
|
FileResp getHighlightImg(String processInstanceId);
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.impl;
|
package cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.impl;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.io.IoUtil;
|
||||||
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*;
|
import cn.iocoder.yudao.adminserver.modules.bpm.controller.workflow.vo.*;
|
||||||
import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.TaskConvert;
|
import cn.iocoder.yudao.adminserver.modules.bpm.convert.workflow.TaskConvert;
|
||||||
import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.TaskService;
|
import cn.iocoder.yudao.adminserver.modules.bpm.service.workflow.TaskService;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
|
||||||
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.activiti.api.runtime.shared.query.Page;
|
import org.activiti.api.runtime.shared.query.Page;
|
||||||
@ -13,6 +16,7 @@ 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.constants.BpmnXMLConstants;
|
||||||
import org.activiti.bpmn.model.BpmnModel;
|
import org.activiti.bpmn.model.BpmnModel;
|
||||||
import org.activiti.bpmn.model.FlowNode;
|
import org.activiti.bpmn.model.FlowNode;
|
||||||
import org.activiti.bpmn.model.SequenceFlow;
|
import org.activiti.bpmn.model.SequenceFlow;
|
||||||
@ -28,17 +32,19 @@ import org.activiti.image.ProcessDiagramGenerator;
|
|||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
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 javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.adminserver.modules.bpm.enums.oa.OAErrorCodeConstants.*;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
public class TaskServiceImpl implements TaskService {
|
public class TaskServiceImpl implements TaskService {
|
||||||
@ -171,69 +177,60 @@ public class TaskServiceImpl implements TaskService {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getHighlightImg(String processInstanceId, HttpServletResponse response) {
|
public FileResp getHighlightImg(String processInstanceId) {
|
||||||
// 查询历史
|
// 查询历史
|
||||||
//TODO 云扬四海 貌似流程结束后,点击审批进度会报错
|
//TODO 云扬四海 貌似流程结束后,点击审批进度会报错
|
||||||
// TODO @Li:一些 historyService 的查询,貌似比较通用,是不是抽一些小方法出来
|
// TODO @Li:一些 historyService 的查询,貌似比较通用,是不是抽一些小方法出来
|
||||||
HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||||
// 如果有结束时间 TODO @Li:如果查询不到,是不是抛出一个业务异常比较好哈?
|
// 如果不存在实例。 说明数据异常
|
||||||
if (hpi == null) {
|
if (hpi == null) {
|
||||||
return;
|
throw ServiceExceptionUtil.exception(PROCESS_INSTANCE_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
// 没有结束时间。说明流程在执行过程中
|
// 没有结束时间。说明流程在执行过程中
|
||||||
// TODO @Li:一些 runtimeService 的查询,貌似比较通用,是不是抽一些小方法出来
|
// TODO @Li:一些 runtimeService 的查询,貌似比较通用,是不是抽一些小方法出来
|
||||||
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId()); // TODO @Li:这块和下面的逻辑比较相关,可以在后面一点查询。
|
|
||||||
List<String> highLightedActivities = new ArrayList<>();
|
|
||||||
|
|
||||||
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
|
List<String> highLightedActivities = new ArrayList<>();
|
||||||
.orderByHistoricActivityInstanceId().asc().list(); // TODO @Li:这块和下面的逻辑比较相关,可以在后面一点查询。
|
|
||||||
// 获取所有活动节点
|
// 获取所有活动节点
|
||||||
List<HistoricActivityInstance> finishedInstances = historyService.createHistoricActivityInstanceQuery()
|
List<HistoricActivityInstance> finishedInstances = historyService.createHistoricActivityInstanceQuery()
|
||||||
.processInstanceId(processInstanceId).finished().list();
|
.processInstanceId(processInstanceId).finished().list();
|
||||||
// TODO @Li:highLightedActivities 结果,可以使用 CollUtils.buildList() 方法。即使不用,也应该用 stream。简洁很重要。
|
// TODO @Li:highLightedActivities 结果,可以使用 CollUtils.buildList() 方法。即使不用,也应该用 stream。简洁很重要。
|
||||||
for (HistoricActivityInstance hai : finishedInstances) {
|
finishedInstances.stream()
|
||||||
highLightedActivities.add(hai.getActivityId());
|
.map(HistoricActivityInstance::getActivityId)
|
||||||
}
|
.forEach(highLightedActivities::add);
|
||||||
// 已完成的节点+当前节点
|
// 已完成的节点+当前节点
|
||||||
highLightedActivities.addAll(runtimeService.getActiveActivityIds(processInstanceId));
|
highLightedActivities.addAll(runtimeService.getActiveActivityIds(processInstanceId));
|
||||||
|
|
||||||
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
|
||||||
// 经过的流
|
// 经过的流
|
||||||
List<String> highLightedFlowIds = getHighLightedFlows(bpmnModel, historicActivityInstances);
|
List<String> highLightedFlowIds = getHighLightedFlows(bpmnModel, processInstanceId);
|
||||||
|
|
||||||
//设置"宋体"
|
//设置"宋体"
|
||||||
// TODO @Li:Service 返回 bytes,最终 Controller 去写
|
|
||||||
try (InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, highLightedFlowIds,
|
try (InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, highLightedActivities, highLightedFlowIds,
|
||||||
"宋体", "宋体", "宋体")){
|
"宋体", "宋体", "宋体")){
|
||||||
String picName = hpi.getProcessDefinitionName()+".svg";
|
FileResp fileResp = new FileResp();
|
||||||
// 输出到浏览器
|
String picName = hpi.getProcessDefinitionName() + ".svg";
|
||||||
responseImage(response, inputStream, picName);
|
fileResp.setFileName(picName);
|
||||||
|
fileResp.setFileByte(IoUtil.readBytes(inputStream));
|
||||||
|
return fileResp;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error(ExceptionUtils.getStackTrace(e));
|
log.error(ExceptionUtils.getStackTrace(e));
|
||||||
|
throw ServiceExceptionUtil.exception(HIGHLIGHT_IMG_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO @Li:参考 ServletUtils 方法。如果没有满足的,可以在写一个。
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO @Li:这个方法的可读性还有一定的优化空间,可以思考下哈。
|
// TODO @Li:这个方法的可读性还有一定的优化空间,可以思考下哈。
|
||||||
/**
|
/**
|
||||||
* 获取已经流转的线 https://blog.csdn.net/qiuxinfa123/article/details/119579863
|
* 获取指定 processInstanceId 已经高亮的Flows
|
||||||
* @see
|
* 获取已经流转的线 参考: https://blog.csdn.net/qiuxinfa123/article/details/119579863
|
||||||
* @param bpmnModel model
|
* @param bpmnModel model
|
||||||
* @param historicActivityInstances 高亮线条
|
* @param processInstanceId 流程实例Id
|
||||||
* @return
|
* @return 获取已经流转的列表
|
||||||
*/
|
*/
|
||||||
private List<String> getHighLightedFlows(BpmnModel bpmnModel, List<HistoricActivityInstance> historicActivityInstances) {
|
private List<String> getHighLightedFlows(BpmnModel bpmnModel, String processInstanceId) {
|
||||||
|
// 获取所有的线条
|
||||||
|
List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId)
|
||||||
|
.orderByHistoricActivityInstanceId().asc().list();
|
||||||
// 高亮流程已发生流转的线id集合
|
// 高亮流程已发生流转的线id集合
|
||||||
List<String> highLightedFlowIds = new ArrayList<>();
|
List<String> highLightedFlowIds = new ArrayList<>();
|
||||||
// 全部活动节点
|
// 全部活动节点
|
||||||
@ -249,57 +246,43 @@ public class TaskServiceImpl implements TaskService {
|
|||||||
finishedActivityInstances.add(historicActivityInstance);
|
finishedActivityInstances.add(historicActivityInstance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 提取活动id 是唯一的。塞入Map
|
||||||
// TODO @Li:这两个变量,直接放到循环里。这种优化一般不需要做的,对性能影响超级小。
|
Map<String, HistoricActivityInstance> historicActivityInstanceMap = CollectionUtils.convertMap(historicActivityInstances, HistoricActivityInstance::getActivityId);
|
||||||
FlowNode currentFlowNode;
|
|
||||||
FlowNode targetFlowNode;
|
|
||||||
// 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的
|
// 遍历已完成的活动实例,从每个实例的outgoingFlows中找到已执行的
|
||||||
for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
|
for (HistoricActivityInstance currentActivityInstance : finishedActivityInstances) {
|
||||||
// 获得当前活动对应的节点信息及outgoingFlows信息
|
// 获得当前活动对应的节点信息及outgoingFlows信息
|
||||||
currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
|
FlowNode currentFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currentActivityInstance.getActivityId(), true);
|
||||||
List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();
|
List<SequenceFlow> sequenceFlows = currentFlowNode.getOutgoingFlows();
|
||||||
|
|
||||||
// 遍历outgoingFlows并找到已流转的 满足如下条件认为已已流转:
|
// 遍历outgoingFlows并找到已流转的 满足如下条件认为已已流转:
|
||||||
// 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
|
// 1.当前节点是并行网关或兼容网关,则通过outgoingFlows能够在历史活动中找到的全部节点均为已流转
|
||||||
// 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转
|
// 2.当前节点是以上两种类型之外的,通过outgoingFlows查找到的时间最早的流转节点视为有效流转
|
||||||
// TODO @Li:“parallelGateway” 和 "inclusiveGateway",有对应的枚举么?如果木有,可以自己枚举哈
|
if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(currentActivityInstance.getActivityType())
|
||||||
if ("parallelGateway".equals(currentActivityInstance.getActivityType()) || "inclusiveGateway".equals(currentActivityInstance.getActivityType())) {
|
|| BpmnXMLConstants.ELEMENT_GATEWAY_INCLUSIVE.equals(currentActivityInstance.getActivityType())) {
|
||||||
// 遍历历史活动节点,找到匹配流程目标节点的
|
// 遍历历史活动节点,找到匹配流程目标节点的
|
||||||
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
||||||
targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
|
FlowNode targetFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(sequenceFlow.getTargetRef(), true);
|
||||||
if (historicActivityNodes.contains(targetFlowNode)) {
|
if (historicActivityNodes.contains(targetFlowNode)) {
|
||||||
highLightedFlowIds.add(targetFlowNode.getId());
|
highLightedFlowIds.add(targetFlowNode.getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO @Li:如果是为了获取到时间更早的一个,是不是遍历的过程中,就可以解决
|
long earliestStamp = 0L;
|
||||||
List<Map<String, Object>> tempMapList = new ArrayList<>();
|
String highLightedFlowId = null;
|
||||||
|
// 循环流出的流
|
||||||
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
||||||
for (HistoricActivityInstance historicActivityInstance : historicActivityInstances) {
|
HistoricActivityInstance historicActivityInstance = historicActivityInstanceMap.get(sequenceFlow.getTargetRef());
|
||||||
if (historicActivityInstance.getActivityId().equals(sequenceFlow.getTargetRef())) {
|
if (historicActivityInstance == null) {
|
||||||
Map<String, Object> map = new HashMap<>();
|
continue;
|
||||||
map.put("highLightedFlowId", sequenceFlow.getId());
|
|
||||||
map.put("highLightedFlowStartTime", historicActivityInstance.getStartTime().getTime());
|
|
||||||
tempMapList.add(map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
final long startTime = historicActivityInstance.getStartTime().getTime();
|
||||||
|
|
||||||
if (!CollectionUtils.isEmpty(tempMapList)) {
|
|
||||||
// 遍历匹配的集合,取得开始时间最早的一个
|
// 遍历匹配的集合,取得开始时间最早的一个
|
||||||
long earliestStamp = 0L;
|
if (earliestStamp == 0 || earliestStamp >= startTime) {
|
||||||
String highLightedFlowId = null;
|
highLightedFlowId = sequenceFlow.getId();
|
||||||
for (Map<String, Object> map : tempMapList) {
|
earliestStamp = startTime;
|
||||||
// TODO @Li:可以使用 MapUtil 去 get 值
|
|
||||||
long highLightedFlowStartTime = Long.valueOf(map.get("highLightedFlowStartTime").toString());
|
|
||||||
if (earliestStamp == 0 || earliestStamp >= highLightedFlowStartTime) {
|
|
||||||
highLightedFlowId = map.get("highLightedFlowId").toString();
|
|
||||||
earliestStamp = highLightedFlowStartTime;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
highLightedFlowIds.add(highLightedFlowId);
|
|
||||||
}
|
}
|
||||||
|
highLightedFlowIds.add(highLightedFlowId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user