mirror of
https://github.com/dromara/RuoYi-Vue-Plus.git
synced 2025-09-30 15:16:41 +08:00
add 添加通过流程实例id获取历史流程图,添加flowable配置,调整流程办理
This commit is contained in:
parent
e69e9d3087
commit
fa3e9f82bd
@ -15,4 +15,9 @@ public interface FlowConstant {
|
|||||||
|
|
||||||
String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人";
|
String MESSAGE_CURRENT_TASK_IS_NULL = "当前任务不存在或你不是任务办理人";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 连线
|
||||||
|
*/
|
||||||
|
String SEQUENCE_FLOW = "sequenceFlow";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package org.dromara.workflow.controller;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import jakarta.validation.constraints.NotBlank;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.dromara.common.web.core.BaseController;
|
||||||
|
import org.dromara.workflow.service.IActProcessInstanceService;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例管理 控制层
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
*/
|
||||||
|
@Validated
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/workflow/processInstance")
|
||||||
|
public class ActProcessInstanceController extends BaseController {
|
||||||
|
|
||||||
|
private final IActProcessInstanceService iActProcessInstanceService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过流程实例id获取历史流程图
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @param response 响应
|
||||||
|
*/
|
||||||
|
@GetMapping("/getHistoryProcessImage/{processInstanceId}")
|
||||||
|
public void getHistoryProcessImage(@NotBlank(message = "流程实例id不能为空") @PathVariable String processInstanceId,
|
||||||
|
HttpServletResponse response) {
|
||||||
|
iActProcessInstanceService.getHistoryProcessImage(processInstanceId, response);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,108 @@
|
|||||||
|
package org.dromara.workflow.flowable;
|
||||||
|
|
||||||
|
import org.flowable.bpmn.model.AssociationDirection;
|
||||||
|
import org.flowable.image.impl.DefaultProcessDiagramCanvas;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.geom.Line2D;
|
||||||
|
import java.awt.geom.RoundRectangle2D;
|
||||||
|
|
||||||
|
public class CustomDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
|
||||||
|
//设置高亮线的颜色 这里我设置成绿色
|
||||||
|
protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN;
|
||||||
|
|
||||||
|
public CustomDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
|
||||||
|
super(width, height, minX, minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 画线颜色设置
|
||||||
|
*/
|
||||||
|
public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType,
|
||||||
|
AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {
|
||||||
|
|
||||||
|
Paint originalPaint = g.getPaint();
|
||||||
|
Stroke originalStroke = g.getStroke();
|
||||||
|
|
||||||
|
g.setPaint(CONNECTION_COLOR);
|
||||||
|
if (connectionType.equals("association")) {
|
||||||
|
g.setStroke(ASSOCIATION_STROKE);
|
||||||
|
} else if (highLighted) {
|
||||||
|
//设置线的颜色
|
||||||
|
g.setPaint(HIGHLIGHT_SEQUENCEFLOW_COLOR);
|
||||||
|
g.setStroke(HIGHLIGHT_FLOW_STROKE);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 1; i < xPoints.length; i++) {
|
||||||
|
Integer sourceX = xPoints[i - 1];
|
||||||
|
Integer sourceY = yPoints[i - 1];
|
||||||
|
Integer targetX = xPoints[i];
|
||||||
|
Integer targetY = yPoints[i];
|
||||||
|
Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
|
||||||
|
g.draw(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDefault) {
|
||||||
|
Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
|
||||||
|
drawDefaultSequenceFlowIndicator(line, scaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conditional) {
|
||||||
|
Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
|
||||||
|
drawConditionalSequenceFlowIndicator(line, scaleFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) {
|
||||||
|
Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
|
||||||
|
drawArrowHead(line, scaleFactor);
|
||||||
|
}
|
||||||
|
if (associationDirection == AssociationDirection.BOTH) {
|
||||||
|
Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
|
||||||
|
drawArrowHead(line, scaleFactor);
|
||||||
|
}
|
||||||
|
g.setPaint(originalPaint);
|
||||||
|
g.setStroke(originalStroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 高亮节点设置
|
||||||
|
*/
|
||||||
|
public void drawHighLight(int x, int y, int width, int height) {
|
||||||
|
Paint originalPaint = g.getPaint();
|
||||||
|
Stroke originalStroke = g.getStroke();
|
||||||
|
//设置高亮节点的颜色
|
||||||
|
g.setPaint(HIGHLIGHT_COLOR);
|
||||||
|
g.setStroke(THICK_TASK_BORDER_STROKE);
|
||||||
|
|
||||||
|
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
|
||||||
|
g.draw(rect);
|
||||||
|
|
||||||
|
g.setPaint(originalPaint);
|
||||||
|
g.setStroke(originalStroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 高亮节点红色
|
||||||
|
* @param: x
|
||||||
|
* @param: y
|
||||||
|
* @param: width
|
||||||
|
* @param: height
|
||||||
|
* @return: void
|
||||||
|
* @author: gssong
|
||||||
|
* @date: 2022/4/12
|
||||||
|
*/
|
||||||
|
public void drawHighLightRed(int x, int y, int width, int height) {
|
||||||
|
Paint originalPaint = g.getPaint();
|
||||||
|
Stroke originalStroke = g.getStroke();
|
||||||
|
//设置高亮节点的颜色
|
||||||
|
g.setPaint(Color.green);
|
||||||
|
g.setStroke(THICK_TASK_BORDER_STROKE);
|
||||||
|
|
||||||
|
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
|
||||||
|
g.draw(rect);
|
||||||
|
|
||||||
|
g.setPaint(originalPaint);
|
||||||
|
g.setStroke(originalStroke);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,20 @@
|
|||||||
|
package org.dromara.workflow.flowable.config;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
|
import org.flowable.spring.SpringProcessEngineConfiguration;
|
||||||
|
import org.flowable.spring.boot.EngineConfigurationConfigurer;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* flowable配置
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
|
||||||
|
processEngineConfiguration.setIdGenerator(IdWorker::getIdStr);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package org.dromara.workflow.service;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例 服务层
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
*/
|
||||||
|
public interface IActProcessInstanceService {
|
||||||
|
/**
|
||||||
|
* 通过流程实例id获取历史流程图
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @param response 响应
|
||||||
|
*/
|
||||||
|
void getHistoryProcessImage(String processInstanceId, HttpServletResponse response);
|
||||||
|
}
|
@ -0,0 +1,132 @@
|
|||||||
|
package org.dromara.workflow.service.impl;
|
||||||
|
|
||||||
|
import jakarta.servlet.ServletOutputStream;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.dromara.workflow.common.constant.FlowConstant;
|
||||||
|
import org.dromara.workflow.flowable.CustomDefaultProcessDiagramGenerator;
|
||||||
|
import org.dromara.workflow.service.IActProcessInstanceService;
|
||||||
|
import org.flowable.bpmn.model.BpmnModel;
|
||||||
|
import org.flowable.engine.HistoryService;
|
||||||
|
import org.flowable.engine.RepositoryService;
|
||||||
|
import org.flowable.engine.RuntimeService;
|
||||||
|
import org.flowable.engine.history.HistoricActivityInstance;
|
||||||
|
import org.flowable.engine.history.HistoricProcessInstance;
|
||||||
|
import org.flowable.engine.runtime.ProcessInstance;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程实例 服务层实现
|
||||||
|
*
|
||||||
|
* @author may
|
||||||
|
*/
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Service
|
||||||
|
public class ActProcessInstanceServiceImpl implements IActProcessInstanceService {
|
||||||
|
|
||||||
|
private final RepositoryService repositoryService;
|
||||||
|
private final RuntimeService runtimeService;
|
||||||
|
private final HistoryService historyService;
|
||||||
|
|
||||||
|
@Value("${flowable.activity-font-name}")
|
||||||
|
private String activityFontName;
|
||||||
|
|
||||||
|
@Value("${flowable.label-font-name}")
|
||||||
|
private String labelFontName;
|
||||||
|
|
||||||
|
@Value("${flowable.annotation-font-name}")
|
||||||
|
private String annotationFontName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过流程实例id获取历史流程图
|
||||||
|
*
|
||||||
|
* @param processInstanceId 流程实例id
|
||||||
|
* @param response 响应
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void getHistoryProcessImage(String processInstanceId, HttpServletResponse response) {
|
||||||
|
// 设置页面不缓存
|
||||||
|
response.setHeader("Pragma", "no-cache");
|
||||||
|
response.addHeader("Cache-Control", "must-revalidate");
|
||||||
|
response.addHeader("Cache-Control", "no-cache");
|
||||||
|
response.addHeader("Cache-Control", "no-store");
|
||||||
|
response.setDateHeader("Expires", 0);
|
||||||
|
InputStream inputStream = null;
|
||||||
|
try {
|
||||||
|
String processDefinitionId;
|
||||||
|
// 获取当前的流程实例
|
||||||
|
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||||
|
// 如果流程已经结束,则得到结束节点
|
||||||
|
if (Objects.isNull(processInstance)) {
|
||||||
|
HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||||
|
processDefinitionId = pi.getProcessDefinitionId();
|
||||||
|
} else {
|
||||||
|
// 根据流程实例ID获得当前处于活动状态的ActivityId合集
|
||||||
|
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
|
||||||
|
processDefinitionId = pi.getProcessDefinitionId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获得活动的节点
|
||||||
|
List<HistoricActivityInstance> highLightedFlowList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
|
||||||
|
|
||||||
|
List<String> highLightedFlows = new ArrayList<>();
|
||||||
|
List<String> highLightedNodes = new ArrayList<>();
|
||||||
|
//高亮
|
||||||
|
for (HistoricActivityInstance tempActivity : highLightedFlowList) {
|
||||||
|
if (FlowConstant.SEQUENCE_FLOW.equals(tempActivity.getActivityType())) {
|
||||||
|
//高亮线
|
||||||
|
highLightedFlows.add(tempActivity.getActivityId());
|
||||||
|
} else {
|
||||||
|
//高亮节点
|
||||||
|
if (tempActivity.getEndTime() == null) {
|
||||||
|
highLightedNodes.add(Color.RED.toString() + tempActivity.getActivityId());
|
||||||
|
} else {
|
||||||
|
highLightedNodes.add(tempActivity.getActivityId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> highLightedNodeList = new ArrayList<>();
|
||||||
|
//运行中的节点
|
||||||
|
List<String> redNodeCollect = highLightedNodes.stream().filter(e -> e.contains(Color.RED.toString())).collect(Collectors.toList());
|
||||||
|
//排除与运行中相同的节点
|
||||||
|
for (String nodeId : highLightedNodes) {
|
||||||
|
if (!nodeId.contains(Color.RED.toString()) && !redNodeCollect.contains(Color.RED + nodeId)) {
|
||||||
|
highLightedNodeList.add(nodeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
highLightedNodeList.addAll(redNodeCollect);
|
||||||
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
||||||
|
CustomDefaultProcessDiagramGenerator diagramGenerator = new CustomDefaultProcessDiagramGenerator();
|
||||||
|
inputStream = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodeList, highLightedFlows, activityFontName, labelFontName, annotationFontName, null, 1.0, true);
|
||||||
|
// 响应相关图片
|
||||||
|
response.setContentType("image/png");
|
||||||
|
|
||||||
|
byte[] bytes = IOUtils.toByteArray(inputStream);
|
||||||
|
ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
outputStream.write(bytes);
|
||||||
|
outputStream.flush();
|
||||||
|
outputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} finally {
|
||||||
|
if (inputStream != null) {
|
||||||
|
try {
|
||||||
|
inputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -53,6 +53,7 @@ public class ActTaskServiceImpl implements IActTaskService {
|
|||||||
* @param startProcessBo 启动流程参数
|
* @param startProcessBo 启动流程参数
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Map<String, Object> startWorkFlow(StartProcessBo startProcessBo) {
|
public Map<String, Object> startWorkFlow(StartProcessBo startProcessBo) {
|
||||||
Map<String, Object> map = new HashMap<>();
|
Map<String, Object> map = new HashMap<>();
|
||||||
if (StringUtils.isBlank(startProcessBo.getBusinessKey())) {
|
if (StringUtils.isBlank(startProcessBo.getBusinessKey())) {
|
||||||
@ -74,12 +75,7 @@ public class ActTaskServiceImpl implements IActTaskService {
|
|||||||
Map<String, Object> variables = startProcessBo.getVariables();
|
Map<String, Object> variables = startProcessBo.getVariables();
|
||||||
// 启动跳过表达式
|
// 启动跳过表达式
|
||||||
variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
|
variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true);
|
||||||
ProcessInstance pi;
|
ProcessInstance pi = runtimeService.startProcessInstanceByKeyAndTenantId(startProcessBo.getProcessKey(), startProcessBo.getBusinessKey(), variables, TenantHelper.getTenantId());
|
||||||
if (CollUtil.isNotEmpty(variables)) {
|
|
||||||
pi = runtimeService.startProcessInstanceByKeyAndTenantId(startProcessBo.getProcessKey(), startProcessBo.getBusinessKey(), variables, TenantHelper.getTenantId());
|
|
||||||
} else {
|
|
||||||
pi = runtimeService.startProcessInstanceByKeyAndTenantId(startProcessBo.getProcessKey(), startProcessBo.getBusinessKey(), TenantHelper.getTenantId());
|
|
||||||
}
|
|
||||||
// 将流程定义名称 作为 流程实例名称
|
// 将流程定义名称 作为 流程实例名称
|
||||||
runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName());
|
runtimeService.setProcessInstanceName(pi.getProcessInstanceId(), pi.getProcessDefinitionName());
|
||||||
// 申请人执行流程
|
// 申请人执行流程
|
||||||
@ -116,10 +112,10 @@ public class ActTaskServiceImpl implements IActTaskService {
|
|||||||
if (task == null) {
|
if (task == null) {
|
||||||
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
|
throw new ServiceException(FlowConstant.MESSAGE_CURRENT_TASK_IS_NULL);
|
||||||
}
|
}
|
||||||
//办理任务
|
|
||||||
taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables());
|
|
||||||
//办理意见
|
//办理意见
|
||||||
taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "同意" : completeTaskBo.getMessage());
|
taskService.addComment(completeTaskBo.getTaskId(), task.getProcessInstanceId(), StringUtils.isBlank(completeTaskBo.getMessage()) ? "同意" : completeTaskBo.getMessage());
|
||||||
|
//办理任务
|
||||||
|
taskService.complete(completeTaskBo.getTaskId(), completeTaskBo.getVariables());
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ServiceException(e.getMessage());
|
throw new ServiceException(e.getMessage());
|
||||||
|
Loading…
Reference in New Issue
Block a user