处理提交

This commit is contained in:
2025-06-30 16:05:44 +08:00
commit ec57cf8a74
399 changed files with 111158 additions and 0 deletions

69
JeeThink-activiti/pom.xml Normal file
View File

@ -0,0 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>jeethink</artifactId>
<groupId>com.jeethink</groupId>
<version>3.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jeethink-activiti</artifactId>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-rest-api</artifactId>
<version>${activiti.version}</version>
</dependency>
<dependency>
<groupId>com.jeethink</groupId>
<artifactId>jeethink-framework</artifactId>
</dependency>
<dependency>
<groupId>com.jeethink</groupId>
<artifactId>jeethink-system</artifactId>
</dependency>
<dependency>
<groupId>com.jeethink</groupId>
<artifactId>jeethink-common</artifactId>
</dependency>
<!--activiti modeler 5.22 start-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>6.0.0</version>
<exclusions>
<exclusion>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- xml解析依赖-->
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-codec</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-css</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svg-dom</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-svggen</artifactId>
<version>1.7</version>
</dependency>
<!-- xml解析依赖-->
<!--activiti modeler 5.22 end-->
</dependencies>
</project>

View File

@ -0,0 +1,26 @@
package com.jeethink.activiti.config;
import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ActivitiConfig implements ProcessEngineConfigurationConfigurer {
@Autowired
private ICustomProcessDiagramGenerator customProcessDiagramGenerator;
/**
* 解決工作流生成图片乱码问题
*
* @param processEngineConfiguration
*/
@Override
public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
processEngineConfiguration.setActivityFontName("宋体");
processEngineConfiguration.setAnnotationFontName("宋体");
processEngineConfiguration.setLabelFontName("宋体");
processEngineConfiguration.setProcessDiagramGenerator(customProcessDiagramGenerator);
}
}

View File

@ -0,0 +1,245 @@
package com.jeethink.activiti.config;
import org.activiti.bpmn.model.AssociationDirection;
import org.activiti.bpmn.model.GraphicInfo;
import org.activiti.image.exception.ActivitiImageException;
import org.activiti.image.impl.DefaultProcessDiagramCanvas;
import org.activiti.image.util.ReflectUtil;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
protected static Color LABEL_COLOR = new Color(0, 0, 0);
//font
protected String activityFontName = "宋体";
protected String labelFontName = "宋体";
protected String annotationFontName = "宋体";
private static volatile boolean flag = false;
public CustomProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType) {
super(width, height, minX, minY, imageType);
}
public CustomProcessDiagramCanvas(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 drawHighLight(boolean isStartOrEnd, int x, int y, int width, int height, Color color) {
Paint originalPaint = g.getPaint();
Stroke originalStroke = g.getStroke();
g.setPaint(color);
g.setStroke(MULTI_INSTANCE_STROKE);
if (isStartOrEnd) {// 开始、结束节点画圆
g.drawOval(x, y, width, height);
} else {// 非开始、结束节点画圆角矩形
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 5, 5);
g.draw(rect);
}
g.setPaint(originalPaint);
g.setStroke(originalStroke);
}
public void drawSequenceflow(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault,
boolean highLighted, double scaleFactor, Color color) {
drawConnection(xPoints, yPoints, conditional, isDefault, "sequenceFlow", AssociationDirection.ONE, highLighted,
scaleFactor, color);
}
public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault,
String connectionType, AssociationDirection associationDirection, boolean highLighted, double scaleFactor,
Color color) {
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(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.equals(AssociationDirection.ONE)
|| associationDirection.equals(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.equals(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 drawLabel(boolean highLighted, String text, GraphicInfo graphicInfo, boolean centered) {
float interline = 1.0f;
// text
if (text != null && text.length() > 0) {
Paint originalPaint = g.getPaint();
Font originalFont = g.getFont();
if (highLighted) {
g.setPaint(WorkflowConstants.COLOR_NORMAL);
} else {
g.setPaint(LABEL_COLOR);
}
g.setFont(new Font(labelFontName, Font.BOLD, 10));
int wrapWidth = 100;
int textY = (int) graphicInfo.getY();
// TODO: use drawMultilineText()
AttributedString as = new AttributedString(text);
as.addAttribute(TextAttribute.FOREGROUND, g.getPaint());
as.addAttribute(TextAttribute.FONT, g.getFont());
AttributedCharacterIterator aci = as.getIterator();
FontRenderContext frc = new FontRenderContext(null, true, false);
LineBreakMeasurer lbm = new LineBreakMeasurer(aci, frc);
while (lbm.getPosition() < text.length()) {
TextLayout tl = lbm.nextLayout(wrapWidth);
textY += tl.getAscent();
Rectangle2D bb = tl.getBounds();
double tX = graphicInfo.getX();
if (centered) {
tX += (int) (graphicInfo.getWidth() / 2 - bb.getWidth() / 2);
}
tl.draw(g, (float) tX, textY);
textY += tl.getDescent() + tl.getLeading() + (interline - 1.0f) * tl.getAscent();
}
// restore originals
g.setFont(originalFont);
g.setPaint(originalPaint);
}
}
@Override
public BufferedImage generateBufferedImage(String imageType) {
if (closed) {
throw new ActivitiImageException("ProcessDiagramGenerator already closed");
}
// Try to remove white space
minX = (minX <= WorkflowConstants.PROCESS_PADDING) ? WorkflowConstants.PROCESS_PADDING : minX;
minY = (minY <= WorkflowConstants.PROCESS_PADDING) ? WorkflowConstants.PROCESS_PADDING : minY;
BufferedImage imageToSerialize = processDiagram;
if (minX >= 0 && minY >= 0) {
imageToSerialize = processDiagram.getSubimage(
minX - WorkflowConstants.PROCESS_PADDING,
minY - WorkflowConstants.PROCESS_PADDING,
canvasWidth - minX + WorkflowConstants.PROCESS_PADDING,
canvasHeight - minY + WorkflowConstants.PROCESS_PADDING);
}
return imageToSerialize;
}
@Override
public void initialize(String imageType) {
this.processDiagram = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_ARGB);
this.g = processDiagram.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setPaint(Color.black);
Font font = new Font(activityFontName, Font.BOLD, FONT_SIZE);
g.setFont(font);
this.fontMetrics = g.getFontMetrics();
LABEL_FONT = new Font(labelFontName, Font.ITALIC, 10);
ANNOTATION_FONT = new Font(annotationFontName, Font.PLAIN, FONT_SIZE);
//优化加载速度
if(flag) {
return;
}
try {
USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/userTask.png", customClassLoader));
SCRIPTTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/scriptTask.png", customClassLoader));
SERVICETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/serviceTask.png", customClassLoader));
RECEIVETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/receiveTask.png", customClassLoader));
SENDTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/sendTask.png", customClassLoader));
MANUALTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/manualTask.png", customClassLoader));
BUSINESS_RULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/businessRuleTask.png", customClassLoader));
SHELL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/shellTask.png", customClassLoader));
CAMEL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/camelTask.png", customClassLoader));
MULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/muleTask.png", customClassLoader));
TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/timer.png", customClassLoader));
COMPENSATE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/compensate-throw.png", customClassLoader));
COMPENSATE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/compensate.png", customClassLoader));
ERROR_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/error-throw.png", customClassLoader));
ERROR_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/error.png", customClassLoader));
MESSAGE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/message-throw.png", customClassLoader));
MESSAGE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/message.png", customClassLoader));
SIGNAL_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/signal-throw.png", customClassLoader));
SIGNAL_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/activiti/icons/signal.png", customClassLoader));
/* String baseUrl = Thread.currentThread().getContextClassLoader().getResource("static/img/activiti/").getPath();
SCRIPTTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"scriptTask.png"));
USERTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"userTask.png"));
SERVICETASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"serviceTask.png"));
RECEIVETASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"receiveTask.png"));
SENDTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"sendTask.png"));
MANUALTASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"manualTask.png"));
BUSINESS_RULE_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"businessRuleTask.png"));
SHELL_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"shellTask.png"));
CAMEL_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"camelTask.png"));
MULE_TASK_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"muleTask.png"));
TIMER_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"timer.png"));
COMPENSATE_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"compensate-throw.png"));
COMPENSATE_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"compensate.png"));
ERROR_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"error-throw.png"));
ERROR_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"error.png"));
MESSAGE_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"message-throw.png"));
MESSAGE_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"message.png"));
SIGNAL_THROW_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"signal-throw.png"));
SIGNAL_CATCH_IMAGE = ImageIO.read(new FileInputStream(baseUrl+"signal.png"));*/
flag = true;
} catch (IOException e) {
flag = false;
LOGGER.warn("Could not load image for process diagram creation: {}", e.getMessage());
}
}
}

View File

@ -0,0 +1,361 @@
package com.jeethink.activiti.config;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@Component
public class CustomProcessDiagramGenerator extends DefaultProcessDiagramGenerator implements ICustomProcessDiagramGenerator{
//预初始化流程图绘制,大大提升了系统启动后首次查看流程图的速度
static {
new CustomProcessDiagramCanvas(10,10,0,0,"png", "宋体","宋体","宋体",null);
}
public CustomProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType,
List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName,
String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor,
Color[] colors, Set<String> currIds) {
if(null == highLightedActivities) {
highLightedActivities = Collections.<String>emptyList();
}
if(null == highLightedFlows) {
highLightedFlows = Collections.<String>emptyList();
}
prepareBpmnModel(bpmnModel);
CustomProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
// Draw pool shape, if process is participant in collaboration
for (Pool pool : bpmnModel.getPools()) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
processDiagramCanvas.drawPoolOrLane(pool.getName(), graphicInfo);
}
// Draw lanes
for (Process process : bpmnModel.getProcesses()) {
for (Lane lane : process.getLanes()) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(lane.getId());
processDiagramCanvas.drawPoolOrLane(lane.getName(), graphicInfo);
}
}
// Draw activities and their sequence-flows
for (Process process: bpmnModel.getProcesses()) {
List<FlowNode> flowNodeList= process.findFlowElementsOfType(FlowNode.class);
for (FlowNode flowNode : flowNodeList) {
drawActivity(processDiagramCanvas, bpmnModel, flowNode, highLightedActivities, highLightedFlows, scaleFactor, colors, currIds);
}
}
// Draw artifacts
for (Process process : bpmnModel.getProcesses()) {
for (Artifact artifact : process.getArtifacts()) {
drawArtifact(processDiagramCanvas, bpmnModel, artifact);
}
List<SubProcess> subProcesses = process.findFlowElementsOfType(SubProcess.class, true);
if (subProcesses != null) {
for (SubProcess subProcess : subProcesses) {
for (Artifact subProcessArtifact : subProcess.getArtifacts()) {
drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact);
}
}
}
}
return processDiagramCanvas;
}
protected void drawActivity(CustomProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, FlowNode flowNode,
List<String> highLightedActivities, List<String> highLightedFlows, double scaleFactor, Color[] colors, Set<String> currIds) {
ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass());
if (drawInstruction != null) {
drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode);
// Gather info on the multi instance marker
boolean multiInstanceSequential = false, multiInstanceParallel = false, collapsed = false;
if (flowNode instanceof Activity) {
Activity activity = (Activity) flowNode;
MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = activity.getLoopCharacteristics();
if (multiInstanceLoopCharacteristics != null) {
multiInstanceSequential = multiInstanceLoopCharacteristics.isSequential();
multiInstanceParallel = !multiInstanceSequential;
}
}
// Gather info on the collapsed marker
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
if (flowNode instanceof SubProcess) {
collapsed = graphicInfo.getExpanded() != null && !graphicInfo.getExpanded();
} else if (flowNode instanceof CallActivity) {
collapsed = true;
}
if (scaleFactor == 1.0) {
// Actually draw the markers
processDiagramCanvas.drawActivityMarkers((int) graphicInfo.getX(), (int) graphicInfo.getY(),(int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(),
multiInstanceSequential, multiInstanceParallel, collapsed);
}
// Draw highlighted activities
if (highLightedActivities.contains(flowNode.getId())) {
if(!CollectionUtils.isEmpty(currIds)
&&currIds.contains(flowNode.getId())
&& !(flowNode instanceof Gateway)) {//非结束节点,并且是当前节点
drawHighLight((flowNode instanceof StartEvent), processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[1]);
}else {//普通节点
drawHighLight((flowNode instanceof StartEvent)||(flowNode instanceof EndEvent),processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId()), colors[0]);
}
}
}
// Outgoing transitions of activity
for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
String flowId = sequenceFlow.getId();
boolean highLighted = (highLightedFlows.contains(flowId));
String defaultFlow = null;
if (flowNode instanceof Activity) {
defaultFlow = ((Activity) flowNode).getDefaultFlow();
} else if (flowNode instanceof Gateway) {
defaultFlow = ((Gateway) flowNode).getDefaultFlow();
}
boolean isDefault = false;
if (defaultFlow != null && defaultFlow.equalsIgnoreCase(flowId)) {
isDefault = true;
}
// boolean drawConditionalIndicator = sequenceFlow.getConditionExpression() != null && !(flowNode instanceof Gateway);
String sourceRef = sequenceFlow.getSourceRef();
String targetRef = sequenceFlow.getTargetRef();
FlowElement sourceElement = bpmnModel.getFlowElement(sourceRef);
FlowElement targetElement = bpmnModel.getFlowElement(targetRef);
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(flowId);
if (graphicInfoList != null && graphicInfoList.size() > 0) {
graphicInfoList = connectionPerfectionizer(processDiagramCanvas, bpmnModel, sourceElement, targetElement, graphicInfoList);
int xPoints[]= new int[graphicInfoList.size()];
int yPoints[]= new int[graphicInfoList.size()];
for (int i=1; i<graphicInfoList.size(); i++) {
GraphicInfo graphicInfo = graphicInfoList.get(i);
GraphicInfo previousGraphicInfo = graphicInfoList.get(i-1);
if (i == 1) {
xPoints[0] = (int) previousGraphicInfo.getX();
yPoints[0] = (int) previousGraphicInfo.getY();
}
xPoints[i] = (int) graphicInfo.getX();
yPoints[i] = (int) graphicInfo.getY();
}
//画高亮线
processDiagramCanvas.drawSequenceflow(xPoints, yPoints, false, isDefault, highLighted, scaleFactor, colors[0]);
// Draw sequenceflow label
// GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(flowId);
// if (labelGraphicInfo != null) {
// processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false);
// }else {//解决流程图连线名称不显示的BUG
GraphicInfo lineCenter = getLineCenter(graphicInfoList);
processDiagramCanvas.drawLabel(highLighted, sequenceFlow.getName(), lineCenter, Math.abs(xPoints[1]-xPoints[0]) >= 5);
// }
}
}
// Nested elements
if (flowNode instanceof FlowElementsContainer) {
for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) {
if (nestedFlowElement instanceof FlowNode) {
drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement,
highLightedActivities, highLightedFlows, scaleFactor);
}
}
}
}
protected void drawHighLight(boolean isStartOrEnd, CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo, Color color) {
processDiagramCanvas.drawHighLight(isStartOrEnd, (int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight(), color);
}
protected static CustomProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType,
String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
// We need to calculate maximum values to know how big the image will be in its entirety
double minX = Double.MAX_VALUE;
double maxX = 0;
double minY = Double.MAX_VALUE;
double maxY = 0;
for (Pool pool : bpmnModel.getPools()) {
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(pool.getId());
minX = graphicInfo.getX();
maxX = graphicInfo.getX() + graphicInfo.getWidth();
minY = graphicInfo.getY();
maxY = graphicInfo.getY() + graphicInfo.getHeight();
}
List<FlowNode> flowNodes = gatherAllFlowNodes(bpmnModel);
for (FlowNode flowNode : flowNodes) {
GraphicInfo flowNodeGraphicInfo = bpmnModel.getGraphicInfo(flowNode.getId());
// width
if (flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth() > maxX) {
maxX = flowNodeGraphicInfo.getX() + flowNodeGraphicInfo.getWidth();
}
if (flowNodeGraphicInfo.getX() < minX) {
minX = flowNodeGraphicInfo.getX();
}
// height
if (flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight() > maxY) {
maxY = flowNodeGraphicInfo.getY() + flowNodeGraphicInfo.getHeight();
}
if (flowNodeGraphicInfo.getY() < minY) {
minY = flowNodeGraphicInfo.getY();
}
for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) {
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId());
if (graphicInfoList != null) {
for (GraphicInfo graphicInfo : graphicInfoList) {
// width
if (graphicInfo.getX() > maxX) {
maxX = graphicInfo.getX();
}
if (graphicInfo.getX() < minX) {
minX = graphicInfo.getX();
}
// height
if (graphicInfo.getY() > maxY) {
maxY = graphicInfo.getY();
}
if (graphicInfo.getY()< minY) {
minY = graphicInfo.getY();
}
}
}
}
}
List<Artifact> artifacts = gatherAllArtifacts(bpmnModel);
for (Artifact artifact : artifacts) {
GraphicInfo artifactGraphicInfo = bpmnModel.getGraphicInfo(artifact.getId());
if (artifactGraphicInfo != null) {
// width
if (artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth() > maxX) {
maxX = artifactGraphicInfo.getX() + artifactGraphicInfo.getWidth();
}
if (artifactGraphicInfo.getX() < minX) {
minX = artifactGraphicInfo.getX();
}
// height
if (artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight() > maxY) {
maxY = artifactGraphicInfo.getY() + artifactGraphicInfo.getHeight();
}
if (artifactGraphicInfo.getY() < minY) {
minY = artifactGraphicInfo.getY();
}
}
List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(artifact.getId());
if (graphicInfoList != null) {
for (GraphicInfo graphicInfo : graphicInfoList) {
// width
if (graphicInfo.getX() > maxX) {
maxX = graphicInfo.getX();
}
if (graphicInfo.getX() < minX) {
minX = graphicInfo.getX();
}
// height
if (graphicInfo.getY() > maxY) {
maxY = graphicInfo.getY();
}
if (graphicInfo.getY()< minY) {
minY = graphicInfo.getY();
}
}
}
}
int nrOfLanes = 0;
for (Process process : bpmnModel.getProcesses()) {
for (Lane l : process.getLanes()) {
nrOfLanes++;
GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(l.getId());
// // width
if (graphicInfo.getX() + graphicInfo.getWidth() > maxX) {
maxX = graphicInfo.getX() + graphicInfo.getWidth();
}
if (graphicInfo.getX() < minX) {
minX = graphicInfo.getX();
}
// height
if (graphicInfo.getY() + graphicInfo.getHeight() > maxY) {
maxY = graphicInfo.getY() + graphicInfo.getHeight();
}
if (graphicInfo.getY() < minY) {
minY = graphicInfo.getY();
}
}
}
// Special case, see https://activiti.atlassian.net/browse/ACT-1431
if (flowNodes.isEmpty() && bpmnModel.getPools().isEmpty() && nrOfLanes == 0) {
// Nothing to show
minX = 0;
minY = 0;
}
return new CustomProcessDiagramCanvas((int) maxX + 10,(int) maxY + 10, (int) minX, (int) minY,
imageType, activityFontName, labelFontName, annotationFontName, customClassLoader);
}
@Override
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities,
List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName,
ClassLoader customClassLoader, double scaleFactor, Color[] colors, Set<String> currIds) {
CustomProcessDiagramCanvas customProcessDiagramCanvas = generateProcessDiagram(bpmnModel, imageType, highLightedActivities, highLightedFlows,
activityFontName, labelFontName, annotationFontName, customClassLoader, scaleFactor,colors, currIds);
BufferedImage bufferedImage = customProcessDiagramCanvas.generateBufferedImage(imageType);
ByteArrayOutputStream bs = new ByteArrayOutputStream();
ImageOutputStream imOut;
try {
imOut = ImageIO.createImageOutputStream(bs);
ImageIO.write(bufferedImage, "PNG", imOut);
} catch (IOException e) {
e.printStackTrace();
}
InputStream is = new ByteArrayInputStream(bs.toByteArray());
return is;
}
@Override
public InputStream generateDiagram(BpmnModel bpmnModel, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) {
return generateDiagram(bpmnModel, imageType, Collections.<String>emptyList(), Collections.<String>emptyList(),
activityFontName, labelFontName, annotationFontName, customClassLoader, 1.0, new Color[] {Color.BLACK, Color.BLACK}, null);
}
}

View File

@ -0,0 +1,15 @@
package com.jeethink.activiti.config;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.image.ProcessDiagramGenerator;
import java.awt.*;
import java.io.InputStream;
import java.util.List;
import java.util.Set;
public interface ICustomProcessDiagramGenerator extends ProcessDiagramGenerator {
InputStream generateDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities,
List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName,
ClassLoader customClassLoader, double scaleFactor, Color[] colors, Set<String> currIds);
}

View File

@ -0,0 +1,136 @@
package com.jeethink.activiti.config;
import java.awt.*;
/**
* 常量类
*@author jjd
**/
public final class WorkflowConstants {
/**businessKey**/
public static final String WORKLOW_BUSINESS_KEY = "businessKey";
/**按钮网关**/
public static final String WAY_TYPE = "wayType";
/**按钮网关**/
public static final String WAY_TYPE_PREFIX = "way_type_";
/**项目id**/
public static final String PROJECT_ID = "projectId";
/**核心企业Id变量**/
public static final String CORE_ENTERPRISE_ID="coreEnterpriseId";
/**链属企业Id变量**/
public static final String CHAIN_ENTERPRISE_ID="chainEnterpriseId";
/**银行企业Id变量**/
public static final String BANK_ENTERPRISE_ID="bankEnterpriseId";
/**保理公司Id变量**/
public static final String BAOLI_ENTERPRISE_ID="baoliEnterpriseId";
/**立账开立企业Id变量**/
public static final String START_ENTERPRISE_ID="startEnterpriseId";
/**立账合作企业Id变量**/
public static final String PARTNER_ENTERPRISE_ID="partnerEnterpriseId";
/**母公司企业id**/
public static final String PARENT_ENTERPRISE_ID="parentEnterpriseId";
/**指定签收企业id**/
public static final String RECEIVE_ENTERPRISE_ID ="receiveEnterpriseId";
/**转出方企业Id变量**/
public static final String TRANSFER_ENTERPRISE_ID="transEnterpriseId";
/**指定签收企业id**/
public static final String AC_TASK_ID ="acTaskId";
/**企业所有角色**/
public static final String ENT_ALL_ROLE ="all";
/**运营所有角色**/
public static final String OPER_ALL_ROLE ="oper";
/**流程定义缓存时间**/
public static final int PROCESS_DEFINITION_CACHE = 60;
/**流程实例激活**/
public static final int PROCESS_INSTANCE_ACTIVE = 1;
/**流程实例挂起**/
public static final int PROCESS_INSTANCE_SUSPEND = 0;
/**读取图片**/
public static final String READ_IMAGE = "image";
/**读取xml**/
public static final String READ_XML = "xml";
/**流程激活**/
public static final Integer ACTIVE_PROCESSDEFINITION = 1;
/**流程挂起**/
public static final Integer SUSPEND_PROCESSDEFINITION = 2;
/**流程状态0-全部1-正常2-已挂起**/
public static final int QUERY_ALL = 0;
public static final int QUERY_NORMAL = 1;
public static final int QUERY_SUSPENDED = 2;
/**流程实例状态0-全部1-正常2-已删除**/
public static final int INSTANCE_ALL = 0;
public static final int INSTANCE_NOT_DELETED = 1;
public static final int INSTANCE_DELETED = 2;
/** 系统管理员ID **/
public static final String INTERFACE_SYSTEM_ID = "-1";
/** 系统管理员名称 **/
public static final String INTERFACE_SYSTEM_NAME = "系统操作";
/** 流程部署类型:1-启动并激活2-启动即挂起 **/
public static final int PROCESS_START_ACTIVE = 1;
public static final int PROCESS_START_SUSPEND = 2;
/** 用于标识流程项目配置信息校验结果1新流程2新版本 3流程类别有误 **/
public static final int CHECK_NEW_PROCESS = 1;
public static final int CHECK_NEW_VERSION = 2;
public static final int CHECK_ERROR_PROCESS_TYPE = 3;
/** 默认网关条件值 **/
public static final Integer default_GATEWAY_CONDITION_VALUE = 1;
/** 工作流-业务状态表数据类型1-工作流状态2-业务状态 **/
public static final Integer PROCESS_STATUS = 1;
public static final Integer BIZNESS_STATUS = 2;
/** 新增流程时标识1-直接保存2-提示覆盖 **/
public static final Integer PROCESS_STATUS_SAVE = 1;
public static final Integer BIZNESS_STATUS_WARN = 2;
/** 模板类型标识1-新创建或直接导入的模板2-默认模板生成 **/
public static final Integer MODEL_TYPE_1 = 1;
public static final Integer MODEL_TYPE_2 = 2;
/** 查询流程定义标识1-查询最新版本流程定义2-查询所有版本 **/
public static final Integer QUERY_PROCESS_LATEST_VERSION = 1;
public static final Integer QUERY_PROCESS_ALL_VERSION = 2;
/** 按钮网关 通过1 */
public static final String WAY_TYPE_PASS = "1";
/** 按钮网关 驳回或结束0 */
public static final String WAY_TYPE_REJECT = "0";
/** 按钮网关 退回2 */
public static final String WAY_TYPE_BACK = "2";
/**任务参数为空**/
public static final int TASK_CHECK_PARAM_NULL = -1;
/**任务已办理**/
public static final int TASK_CHECK_COMPLETED = 1;
/**无权限办理**/
public static final int TASK_CHECK_NO_PERMISSIONS= 2;
/**任务校验通过**/
public static final int TASK_CHECK_PASS = 0;
/** 动态流程图颜色定义 **/
public static final Color COLOR_NORMAL = new Color(0, 205, 0);
public static final Color COLOR_CURRENT = new Color(255, 0, 0);
/** 定义生成流程图时的边距(像素) **/
public static final int PROCESS_PADDING = 5;
/** 定义新版业务进度查询包含的流程类型 **/
// public static final List<ProcessTypeEnum> INCLUDE_PROCEE_TYPE = Lists.newArrayList(
// ProcessTypeEnum.BUILD_ACCOUNT_APPLY,
// ProcessTypeEnum.CREDIT_LETTER_APPLY,
// ProcessTypeEnum.CREDIT_LETTER_TRANSFER,
// ProcessTypeEnum.CREDIT_LETTER_CASH);
}

View File

@ -0,0 +1,71 @@
package com.jeethink.activiti.controller;
import com.github.pagehelper.Page;
import com.jeethink.activiti.domain.ActIdGroup;
import com.jeethink.common.core.controller.BaseController;
import com.jeethink.common.core.page.PageDomain;
import com.jeethink.common.core.page.TableDataInfo;
import com.jeethink.common.core.page.TableSupport;
import com.jeethink.common.utils.StringUtils;
import org.activiti.engine.IdentityService;
import org.activiti.engine.identity.Group;
import org.activiti.engine.identity.GroupQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
/**
* 流程用户组Controller
*
* @author Xianlu Tech
* @date 2019-10-02
*/
@Controller
@RequestMapping("/activiti/actIdGroup")
public class ActIdGroupController extends BaseController
{
@Autowired
private IdentityService identityService;
/**
* 查询流程用户组列表
*/
@GetMapping("/list")
@ResponseBody
public TableDataInfo list(ActIdGroup query)
{
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
GroupQuery groupQuery = identityService.createGroupQuery();
if (StringUtils.isNotBlank(query.getId())) {
groupQuery.groupId(query.getId());
}
if (StringUtils.isNotBlank(query.getName())) {
groupQuery.groupNameLike("%" + query.getName() + "%");
}
List<Group> groupList = groupQuery.listPage((pageNum - 1) * pageSize, pageSize);
Page<ActIdGroup> list = new Page<>();
list.setTotal(groupQuery.count());
list.setPageNum(pageNum);
list.setPageSize(pageSize);
for (Group group: groupList) {
ActIdGroup idGroup = new ActIdGroup();
idGroup.setId(group.getId());
idGroup.setName(group.getName());
list.add(idGroup);
}
return getDataTable(list);
}
}

View File

@ -0,0 +1,96 @@
package com.jeethink.activiti.controller;
import com.github.pagehelper.Page;
import com.jeethink.activiti.domain.ActIdUser;
import com.jeethink.common.core.controller.BaseController;
import com.jeethink.common.core.domain.entity.SysUser;
import com.jeethink.common.core.page.PageDomain;
import com.jeethink.common.core.page.TableDataInfo;
import com.jeethink.common.core.page.TableSupport;
import com.jeethink.common.utils.StringUtils;
import com.jeethink.system.service.ISysUserService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.identity.User;
import org.activiti.engine.identity.UserQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.List;
/**
* 流程用户Controller
*
* @author Xianlu Tech
* @date 2019-10-02
*/
@Controller
@RequestMapping("/activiti/actIdUser")
public class ActIdUserController extends BaseController {
@Autowired
private IdentityService identityService;
@Autowired
private ISysUserService userService;
/**
* 查询流程用户列表
*/
@GetMapping("/list")
@ResponseBody
public TableDataInfo list(ActIdUser query)
{
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
UserQuery userQuery = identityService.createUserQuery();
if (StringUtils.isNotBlank(query.getId())) {
userQuery.userId(query.getId());
}
if (StringUtils.isNotBlank(query.getFirst())) {
userQuery.userFirstNameLike("%" + query.getFirst() + "%");
}
if (StringUtils.isNotBlank(query.getEmail())) {
userQuery.userEmailLike("%" + query.getEmail() + "%");
}
List<User> userList = userQuery.listPage((pageNum - 1) * pageSize, pageSize);
Page<ActIdUser> list = new Page<>();
list.setTotal(userQuery.count());
list.setPageNum(pageNum);
list.setPageSize(pageSize);
for (User user: userList) {
ActIdUser idUser = new ActIdUser();
idUser.setId(user.getId());
idUser.setFirst(user.getFirstName());
idUser.setEmail(user.getEmail());
list.add(idUser);
}
return getDataTable(list);
}
// /**
// * 选择系统用户
// */
// @GetMapping("/authUser/selectUser")
// public String selectUser(String taskId, ModelMap mmap) {
// mmap.put("taskId", taskId);
// return prefix + "/selectUser";
// }
@PostMapping("/systemUserList")
@ResponseBody
public TableDataInfo systemUserList(SysUser user) {
startPage();
List<SysUser> list = userService.selectUserList(user);
return getDataTable(list);
}
}

View File

@ -0,0 +1,301 @@
package com.jeethink.activiti.controller;
import com.jeethink.activiti.config.ICustomProcessDiagramGenerator;
import com.jeethink.activiti.config.WorkflowConstants;
import com.jeethink.activiti.domain.ActivitiBaseEntity;
import com.jeethink.activiti.domain.HistoricActivity;
import com.jeethink.activiti.service.IProcessService;
import com.jeethink.common.core.controller.BaseController;
import com.jeethink.common.core.domain.AjaxResult;
import com.jeethink.common.core.page.TableDataInfo;
import com.jeethink.common.utils.SecurityUtils;
import com.jeethink.common.utils.StringUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowNode;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/process")
public class ProcessController extends BaseController {
@Autowired
private RepositoryService repositoryService;
@Autowired
private HistoryService historyService;
@Autowired
private ProcessEngine processEngine;
@Autowired
private IProcessService processService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
/**
* 审批历史列表
* @param instanceId
* @return
*/
// @RequiresPermissions("process:leave:list")
@GetMapping("/listHistory/{instanceId}")
@ResponseBody
public TableDataInfo listHistory(@PathVariable String instanceId, HistoricActivity historicActivity) {
startPage();
List<HistoricActivity> list = processService.selectHistoryList(instanceId, historicActivity);
return getDataTable(list);
}
@RequestMapping(value = "/read-resource")
public void readResource(String pProcessInstanceId, HttpServletResponse response)
throws Exception {
String processDefinitionId = "";
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(pProcessInstanceId).singleResult();
if(processInstance == null) {
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(pProcessInstanceId).singleResult();
processDefinitionId = historicProcessInstance.getProcessDefinitionId();
} else {
processDefinitionId = processInstance.getProcessDefinitionId();
}
ProcessDefinitionQuery pdq = repositoryService.createProcessDefinitionQuery();
ProcessDefinition pd = pdq.processDefinitionId(processDefinitionId).singleResult();
String resourceName = pd.getDiagramResourceName();
if(resourceName.endsWith(".png") && StringUtils.isEmpty(pProcessInstanceId) == false)
{
getActivitiProccessImage(pProcessInstanceId,response);
//ProcessDiagramGenerator.generateDiagram(pde, "png", getRuntimeService().getActiveActivityIds(processInstanceId));
}
else
{
// 通过接口读取
InputStream resourceAsStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), resourceName);
// 输出资源内容到相应对象
byte[] b = new byte[1024];
int len = -1;
while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
response.getOutputStream().write(b, 0, len);
}
}
}
/**
* 获取流程图像,已执行节点和流程线高亮显示
*/
public void getActivitiProccessImage(String pProcessInstanceId, HttpServletResponse response) {
//logger.info("[开始]-获取流程图图像");
try {
// 获取历史流程实例
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(pProcessInstanceId).singleResult();
if (historicProcessInstance == null) {
//throw new BusinessException("获取流程实例ID[" + pProcessInstanceId + "]对应的历史流程实例失败!");
}
else {
// 获取流程定义
ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
.getDeployedProcessDefinition(historicProcessInstance.getProcessDefinitionId());
// 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(pProcessInstanceId).orderByHistoricActivityInstanceId().asc().list();
// 已执行的节点ID集合
List<String> executedActivityIdList = new ArrayList<String>();
int index = 1;
//logger.info("获取已经执行的节点ID");
for (HistoricActivityInstance activityInstance : historicActivityInstanceList) {
executedActivityIdList.add(activityInstance.getActivityId());
//logger.info("第[" + index + "]个已执行节点=" + activityInstance.getActivityId() + " : " +activityInstance.getActivityName());
index++;
}
BpmnModel bpmnModel = repositoryService.getBpmnModel(historicProcessInstance.getProcessDefinitionId());
// 已执行的线集合
List<String> flowIds = new ArrayList<String>();
// 获取流程走过的线 (getHighLightedFlows是下面的方法)
flowIds = getHighLightedFlows(bpmnModel,processDefinition, historicActivityInstanceList);
// // 获取流程图图像字符流
// ProcessDiagramGenerator pec = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
// //配置字体
// InputStream imageStream = pec.generateDiagram(bpmnModel, "png", executedActivityIdList, flowIds,"宋体","微软雅黑","黑体",null,2.0);
Set<String> currIds = runtimeService.createExecutionQuery().processInstanceId(pProcessInstanceId).list()
.stream().map(e->e.getActivityId()).collect(Collectors.toSet());
ICustomProcessDiagramGenerator diagramGenerator = (ICustomProcessDiagramGenerator) processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
InputStream imageStream = diagramGenerator.generateDiagram(bpmnModel, "png", executedActivityIdList,
flowIds, "宋体", "宋体", "宋体", null, 1.0, new Color[] { WorkflowConstants.COLOR_NORMAL, WorkflowConstants.COLOR_CURRENT }, currIds);
response.setContentType("image/png");
OutputStream os = response.getOutputStream();
int bytesRead = 0;
byte[] buffer = new byte[8192];
while ((bytesRead = imageStream.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
imageStream.close();
}
//logger.info("[完成]-获取流程图图像");
} catch (Exception e) {
System.out.println(e.getMessage());
//logger.error("【异常】-获取流程图失败!" + e.getMessage());
//throw new BusinessException("获取流程图失败!" + e.getMessage());
}
}
private List<String> getHighLightedFlows(BpmnModel bpmnModel,ProcessDefinitionEntity processDefinitionEntity,List<HistoricActivityInstance> historicActivityInstances) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //24小时制
List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId
for (int i = 0; i < historicActivityInstances.size() - 1; i++) {
// 对历史流程节点进行遍历
// 得到节点定义的详细信息
FlowNode activityImpl = (FlowNode)bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(i).getActivityId());
List<FlowNode> sameStartTimeNodes = new ArrayList<FlowNode>();// 用以保存后续开始时间相同的节点
FlowNode sameActivityImpl1 = null;
HistoricActivityInstance activityImpl_ = historicActivityInstances.get(i);// 第一个节点
HistoricActivityInstance activityImp2_ ;
for(int k = i + 1 ; k <= historicActivityInstances.size() - 1; k++) {
activityImp2_ = historicActivityInstances.get(k);// 后续第1个节点
if ( activityImpl_.getActivityType().equals("userTask") && activityImp2_.getActivityType().equals("userTask") &&
df.format(activityImpl_.getStartTime()).equals(df.format(activityImp2_.getStartTime())) ) //都是usertask且主节点与后续节点的开始时间相同说明不是真实的后继节点
{
}
else {
sameActivityImpl1 = (FlowNode)bpmnModel.getMainProcess().getFlowElement(historicActivityInstances.get(k).getActivityId());//找到紧跟在后面的一个节点
break;
}
}
sameStartTimeNodes.add(sameActivityImpl1); // 将后面第一个节点放在时间相同节点的集合里
for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第一个节点
HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 后续第二个节点
if (df.format(activityImpl1.getStartTime()).equals(df.format(activityImpl2.getStartTime())) )
{// 如果第一个节点和第二个节点开始时间相同保存
FlowNode sameActivityImpl2 = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityImpl2.getActivityId());
sameStartTimeNodes.add(sameActivityImpl2);
}
else
{// 有不相同跳出循环
break;
}
}
List<SequenceFlow> pvmTransitions = activityImpl.getOutgoingFlows() ; // 取出节点的所有出去的线
for (SequenceFlow pvmTransition : pvmTransitions)
{// 对所有的线进行遍历
FlowNode pvmActivityImpl = (FlowNode)bpmnModel.getMainProcess().getFlowElement( pvmTransition.getTargetRef());// 如果取出的线的目标节点存在时间相同的节点里保存该线的id进行高亮显示
if (sameStartTimeNodes.contains(pvmActivityImpl)) {
highFlows.add(pvmTransition.getId());
}
}
}
return highFlows;
}
@PostMapping("/delegate")
@ResponseBody
public AjaxResult delegate(String taskId, String delegateToUser) {
processService.delegate(taskId, SecurityUtils.getUsername(), delegateToUser);
return AjaxResult.success();
}
@PostMapping( "/cancelApply/{instanceId}")
@ResponseBody
public AjaxResult cancelApply(@PathVariable String instanceId) {
processService.cancelApply(instanceId, "用户撤销");
return AjaxResult.success();
}
@PostMapping( "/suspendOrActiveApply")
@ResponseBody
public AjaxResult suspendOrActiveApply(@RequestBody ActivitiBaseEntity activitiBaseEntity) {
processService.suspendOrActiveApply(activitiBaseEntity.getInstanceId(), activitiBaseEntity.getSuspendState());
return AjaxResult.success();
}
@GetMapping("/showVerifyDialog/{taskId}")
public AjaxResult showVerifyDialog(@PathVariable("taskId") String taskId) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
String verifyName = task.getTaskDefinitionKey().substring(0, 1).toUpperCase() + task.getTaskDefinitionKey().substring(1);
return AjaxResult.success(verifyName);
}
/**
* 完成任务
*
* @return
*/
@PostMapping(value = "/complete")
@ResponseBody
public AjaxResult complete( @RequestBody ActivitiBaseEntity activitiBaseEntity) {
List<Task> taskList = taskService.createTaskQuery()
.processInstanceId(activitiBaseEntity.getInstanceId())
// .singleResult();
.list();
if (!CollectionUtils.isEmpty(taskList)) {
TaskEntityImpl task = (TaskEntityImpl) taskList.get(0);
activitiBaseEntity.setTaskId(task.getId());
}
processService.complete(activitiBaseEntity,"leave");
return AjaxResult.success("任务已完成");
}
}

View File

@ -0,0 +1,189 @@
package com.jeethink.activiti.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jeethink.activiti.domain.ProcessDefinition;
import com.jeethink.activiti.service.ProcessDefinitionService;
import com.jeethink.common.annotation.Log;
import com.jeethink.common.config.JeeThinkConfig;
import com.jeethink.common.constant.Constants;
import com.jeethink.common.core.controller.BaseController;
import com.jeethink.common.core.domain.AjaxResult;
import com.jeethink.common.core.page.TableDataInfo;
import com.jeethink.common.enums.BusinessType;
import com.jeethink.common.utils.StringUtils;
import com.jeethink.common.utils.file.FileUploadUtils;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Param;
import org.aspectj.weaver.loadtime.Aj;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.List;
@Controller
@RequestMapping("/definition")
public class ProcessDefinitionController extends BaseController {
private static final Logger log = LoggerFactory.getLogger(ProcessDefinitionController.class);
private String prefix = "definition";
@Autowired
private ProcessDefinitionService processDefinitionService;
@Autowired
private RepositoryService repositoryService;
@GetMapping("/list")
@ResponseBody
public TableDataInfo list(ProcessDefinition processDefinition) {
List<ProcessDefinition> list = processDefinitionService.listProcessDefinition(processDefinition);
return getDataTable(list);
}
/**
* 部署流程定义
*/
@Log(title = "流程定义", businessType = BusinessType.INSERT)
@PostMapping("/upload")
@ResponseBody
public AjaxResult upload(MultipartFile file) {
try {
if (!file.isEmpty()) {
String extensionName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf('.') + 1);
if (!"bpmn".equalsIgnoreCase(extensionName)
&& !"zip".equalsIgnoreCase(extensionName)
&& !"bar".equalsIgnoreCase(extensionName)) {
return AjaxResult.error("流程定义文件仅支持 bpmn, zip 和 bar 格式!");
}
// p.s. 此时 FileUploadUtils.upload() 返回字符串 fileName 前缀为 Constants.RESOURCE_PREFIX需剔除
// 详见: FileUploadUtils.getPathFileName(...)
String fileName = FileUploadUtils.upload(JeeThinkConfig.getProfile()+ "/processDefiniton", file);
if (StringUtils.isNotBlank(fileName)) {
String realFilePath = JeeThinkConfig.getProfile()+ fileName.substring(Constants.RESOURCE_PREFIX.length());
processDefinitionService.deployProcessDefinition(realFilePath);
return AjaxResult.success();
}
}
return AjaxResult.error("不允许上传空文件!");
}
catch (Exception e) {
log.error("上传流程定义文件失败!", e);
return AjaxResult.error(e.getMessage());
}
}
@Log(title = "流程定义", businessType = BusinessType.DELETE)
@DeleteMapping("/remove/{ids}")
@ResponseBody
public AjaxResult remove(String ids) {
try {
return toAjax(processDefinitionService.deleteProcessDeploymentByIds(ids));
}
catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
// @Log(title = "流程定义", businessType = BusinessType.EXPORT)
// @PostMapping("/export")
// @ResponseBody
// public AjaxResult export() {
// List<ProcessDefinition> list = processDefinitionService.listProcessDefinition(new ProcessDefinition());
// ExcelUtil<ProcessDefinition> util = new ExcelUtil<>(ProcessDefinition.class);
// return util.exportExcel(list, "流程定义数据");
// }
@PostMapping( "/suspendOrActiveApply")
@ResponseBody
public AjaxResult suspendOrActiveApply(@RequestBody ProcessDefinition processDefinition) {
processDefinitionService.suspendOrActiveApply(processDefinition.getId(), processDefinition.getSuspendState());
return AjaxResult.success();
}
/**
* 读取流程资源
*
* @param processDefinitionId 流程定义ID
* @param resourceName 资源名称
*/
@RequestMapping(value = "/readResource")
public void readResource(@RequestParam("processDefinitionId") String processDefinitionId, @RequestParam("resourceName") String resourceName, HttpServletResponse response)
throws Exception {
ProcessDefinitionQuery pdq = repositoryService.createProcessDefinitionQuery();
org.activiti.engine.repository.ProcessDefinition pd = pdq.processDefinitionId(processDefinitionId).singleResult();
// 通过接口读取
InputStream resourceAsStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), resourceName);
// 输出资源内容到相应对象
byte[] b = new byte[1024];
int len = -1;
while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
response.getOutputStream().write(b, 0, len);
}
}
/**
* 转换流程定义为模型
* @param processDefinitionId
* @return
* @throws UnsupportedEncodingException
* @throws XMLStreamException
*/
@PostMapping(value = "/convert2Model")
@ResponseBody
public AjaxResult convertToModel(@RequestBody String processDefinitionId)
throws UnsupportedEncodingException, XMLStreamException {
org.activiti.engine.repository.ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(processDefinitionId).singleResult();
InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
processDefinition.getResourceName());
XMLInputFactory xif = XMLInputFactory.newInstance();
InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
XMLStreamReader xtr = xif.createXMLStreamReader(in);
BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
BpmnJsonConverter converter = new BpmnJsonConverter();
ObjectNode modelNode = converter.convertToJson(bpmnModel);
Model modelData = repositoryService.newModel();
modelData.setKey(processDefinition.getKey());
modelData.setName(processDefinition.getResourceName());
modelData.setCategory(processDefinition.getDeploymentId());
ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
modelData.setMetaInfo(modelObjectNode.toString());
repositoryService.saveModel(modelData);
repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
return AjaxResult.success();
}
}

View File

@ -0,0 +1,100 @@
package com.jeethink.activiti.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.jeethink.common.annotation.Excel;
import com.jeethink.common.core.domain.BaseEntity;
/**
* 流程用户组对象 act_id_group
*
* @author Xianlu Tech
* @date 2019-10-02
*/
public class ActIdGroup extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
@Excel(name = "组ID")
private String id;
/** 版本 */
private Long rev;
/** 名称 */
@Excel(name = "名称")
private String name;
/** 类型 */
private String type;
private String[] userIds;
/** 用户是否存在此用户组标识 默认不存在 */
private boolean flag = false;
public void setId(String id)
{
this.id = id;
}
public String getId()
{
return id;
}
public void setRev(Long rev)
{
this.rev = rev;
}
public Long getRev()
{
return rev;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setType(String type)
{
this.type = type;
}
public String getType()
{
return type;
}
public String[] getUserIds() {
return userIds;
}
public void setUserIds(String[] userIds) {
this.userIds = userIds;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("rev", getRev())
.append("name", getName())
.append("type", getType())
.toString();
}
}

View File

@ -0,0 +1,141 @@
package com.jeethink.activiti.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.jeethink.common.annotation.Excel;
import com.jeethink.common.core.domain.BaseEntity;
/**
* 流程用户对象 act_id_user
*
* @author Xianlu Tech
* @date 2019-10-02
*/
public class ActIdUser extends BaseEntity
{
private static final long serialVersionUID = 1L;
/** 主键ID */
@Excel(name = "用户ID")
private String id;
/** 版本 */
private Long rev;
/** 名字 */
@Excel(name = "名字")
private String first;
/** 姓氏 */
private String last;
/** 邮箱 */
@Excel(name = "邮箱")
private String email;
/** 密码 */
private String pwd;
/** 头像 */
private String pictureId;
/** 用户组 */
private String[] groupIds;
/** 用户组是否存在此用户标识 默认不存在 */
private boolean flag = false;
public void setId(String id)
{
this.id = id;
}
public String getId()
{
return id;
}
public void setRev(Long rev)
{
this.rev = rev;
}
public Long getRev()
{
return rev;
}
public void setFirst(String first)
{
this.first = first;
}
public String getFirst()
{
return first;
}
public void setLast(String last)
{
this.last = last;
}
public String getLast()
{
return last;
}
public void setEmail(String email)
{
this.email = email;
}
public String getEmail()
{
return email;
}
public void setPwd(String pwd)
{
this.pwd = pwd;
}
public String getPwd()
{
return pwd;
}
public void setPictureId(String pictureId)
{
this.pictureId = pictureId;
}
public String getPictureId()
{
return pictureId;
}
public String[] getGroupIds() {
return groupIds;
}
public void setGroupIds(String[] groupIds) {
this.groupIds = groupIds;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("rev", getRev())
.append("first", getFirst())
.append("last", getLast())
.append("email", getEmail())
.append("pwd", getPwd())
.append("pictureId", getPictureId())
.toString();
}
}

View File

@ -0,0 +1,131 @@
package com.jeethink.activiti.domain;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.jeethink.common.annotation.Excel;
import com.jeethink.common.core.domain.BaseEntity;
public class ActivitiBaseEntity extends BaseEntity {
/** 流程实例ID */
@Excel(name = "流程实例ID")
private String instanceId;
/** 申请人姓名 */
private String applyUserName;
/** 标题 */
@Excel(name = "标题")
private String title;
/** 原因 */
@Excel(name = "原因")
private String reason;
/** 任务ID */
private String taskId;
/** 任务名称 */
private String taskName;
/** 办理时间 */
private Date doneTime;
/** 创建人 */
private String createUserName;
/** 流程实例状态 1 激活 2 挂起 */
private String suspendState;
private Map<String, Object> processParams;
public String getApplyUserName() {
return applyUserName;
}
public void setApplyUserName(String applyUserName) {
this.applyUserName = applyUserName;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public Date getDoneTime() {
return doneTime;
}
public void setDoneTime(Date doneTime) {
this.doneTime = doneTime;
}
public String getCreateUserName() {
return createUserName;
}
public void setCreateUserName(String createUserName) {
this.createUserName = createUserName;
}
public String getSuspendState() {
return suspendState;
}
public void setSuspendState(String suspendState) {
this.suspendState = suspendState;
}
public void setInstanceId(String instanceId)
{
this.instanceId = instanceId;
}
public String getInstanceId()
{
return instanceId;
}
public void setTitle(String title)
{
this.title = title;
}
public String getTitle()
{
return title;
}
public void setReason(String reason)
{
this.reason = reason;
}
public String getReason()
{
return reason;
}
public Map<String, Object> getProcessParams() {
if (processParams == null)
{
processParams = new HashMap<>();
}
return processParams;
}
public void setProcessParams(Map<String, Object> processParams) {
this.processParams = processParams;
}
}

View File

@ -0,0 +1,218 @@
package com.jeethink.activiti.domain;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.jeethink.common.annotation.Excel;
import com.jeethink.common.core.domain.BaseEntity;
import java.util.Date;
/**
* 待办事项对象 biz_todo_item
*
* @author Xianlu Tech
* @date 2019-11-08
*/
public class BizTodoItem extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 主键 ID */
private Long id;
/** 事项标题 */
@Excel(name = "事项标题")
private String itemName;
/** 事项内容 */
@Excel(name = "事项内容")
private String itemContent;
/** 模块名称 (必须以 uri 一致) */
@Excel(name = "模块名称")
private String module;
/** 任务 ID */
@Excel(name = "任务 ID")
private String taskId;
/** 流程实例 ID */
@Excel(name = "流程实例 ID")
private String instanceId;
/** 任务名称 (必须以表单页面名称一致) */
@Excel(name = "任务名称")
private String taskName;
/** 节点名称 */
@Excel(name = "节点名称")
private String nodeName;
/** 是否查看 default 0 (0 否 1 是) */
@Excel(name = "是否查看")
private String isView;
/** 是否处理 default 0 (0 否 1 是) */
@Excel(name = "是否处理")
private String isHandle;
/** 待办人 ID */
@Excel(name = "待办人 ID")
private String todoUserId;
/** 待办人名称 */
@Excel(name = "待办人名称")
private String todoUserName;
/** 处理人 ID */
@Excel(name = "处理人 ID")
private String handleUserId;
/** 处理人名称 */
@Excel(name = "处理人名称")
private String handleUserName;
/** 通知时间 */
@Excel(name = "通知时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date todoTime;
/** 处理时间 */
@Excel(name = "处理时间", width = 30, dateFormat = "yyyy-MM-dd")
private Date handleTime;
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getItemName() {
return itemName;
}
public void setItemContent(String itemContent) {
this.itemContent = itemContent;
}
public String getItemContent() {
return itemContent;
}
public void setModule(String module) {
this.module = module;
}
public String getModule() {
return module;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getTaskId() {
return taskId;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public String getTaskName() {
return taskName;
}
public void setIsView(String isView) {
this.isView = isView;
}
public String getIsView() {
return isView;
}
public void setIsHandle(String isHandle) {
this.isHandle = isHandle;
}
public String getIsHandle() {
return isHandle;
}
public void setTodoUserId(String todoUserId) {
this.todoUserId = todoUserId;
}
public String getTodoUserId() {
return todoUserId;
}
public void setTodoUserName(String todoUserName) {
this.todoUserName = todoUserName;
}
public String getTodoUserName() {
return todoUserName;
}
public void setHandleUserId(String handleUserId) {
this.handleUserId = handleUserId;
}
public String getHandleUserId() {
return handleUserId;
}
public void setHandleUserName(String handleUserName) {
this.handleUserName = handleUserName;
}
public String getHandleUserName() {
return handleUserName;
}
public void setTodoTime(Date todoTime) {
this.todoTime = todoTime;
}
public Date getTodoTime() {
return todoTime;
}
public void setHandleTime(Date handleTime) {
this.handleTime = handleTime;
}
public Date getHandleTime() {
return handleTime;
}
public String getInstanceId() {
return instanceId;
}
public void setInstanceId(String instanceId) {
this.instanceId = instanceId;
}
@Override
public String toString() {
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
.append("id", getId())
.append("itemName", getItemName())
.append("itemContent", getItemContent())
.append("module", getModule())
.append("instanceId", getInstanceId())
.append("taskId", getTaskId())
.append("taskName", getTaskName())
.append("isView", getIsView())
.append("isHandle", getIsHandle())
.append("todoUserId", getTodoUserId())
.append("todoUserName", getTodoUserName())
.append("handleUserId", getHandleUserId())
.append("handleUserName", getHandleUserName())
.append("todoTime", getTodoTime())
.append("handleTime", getHandleTime())
.toString();
}
}

View File

@ -0,0 +1,29 @@
package com.jeethink.activiti.domain;
import org.activiti.engine.impl.persistence.entity.HistoricActivityInstanceEntityImpl;
public class HistoricActivity extends HistoricActivityInstanceEntityImpl {
/** 审批批注 */
private String comment;
/** 办理人姓名 */
private String assigneeName;
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getAssigneeName() {
return assigneeName;
}
public void setAssigneeName(String assigneeName) {
this.assigneeName = assigneeName;
}
}

View File

@ -0,0 +1,39 @@
package com.jeethink.activiti.domain;
import com.jeethink.common.core.domain.BaseEntity;
/**
* 汇讯数码科技(深圳)有限公司
* 创建日期:2020/9/14-13:57
* 版本 开发者 日期
* 1.0 Danny 2020/9/14
*/
public class ModelerVo {
private String name;
private String key;
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -0,0 +1,140 @@
package com.jeethink.activiti.domain;
import java.util.Date;
import com.jeethink.common.annotation.Excel;
import com.jeethink.common.core.domain.BaseEntity;
public class ProcessDefinition extends BaseEntity {
private static final long serialVersionUID = 1L;
private String id;
@Excel(name = "流程名称")
private String name;
@Excel(name = "流程KEY")
private String key;
@Excel(name = "流程版本")
private int version;
@Excel(name = "所属分类")
private String category;
@Excel(name = "流程描述")
private String description;
private String deploymentId;
@Excel(name = "部署时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
private Date deploymentTime;
@Excel(name = "流程图")
private String diagramResourceName;
@Excel(name = "流程定义")
private String resourceName;
/** 流程实例状态 1 激活 2 挂起 */
private String suspendState;
private String suspendStateName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getDeploymentId() {
return deploymentId;
}
public void setDeploymentId(String deploymentId) {
this.deploymentId = deploymentId;
}
public Date getDeploymentTime() {
return deploymentTime;
}
public void setDeploymentTime(Date deploymentTime) {
this.deploymentTime = deploymentTime;
}
public String getDiagramResourceName() {
return diagramResourceName;
}
public void setDiagramResourceName(String diagramResourceName) {
this.diagramResourceName = diagramResourceName;
}
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
public String getSuspendState() {
return suspendState;
}
public void setSuspendState(String suspendState) {
this.suspendState = suspendState;
}
public String getSuspendStateName() {
return suspendStateName;
}
public void setSuspendStateName(String suspendStateName) {
this.suspendStateName = suspendStateName;
}
}

View File

@ -0,0 +1,34 @@
package com.jeethink.activiti.form;
import org.activiti.engine.form.AbstractFormType;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* 用户表单字段类型
*
* @author henryyan
*/
@Component
public class UsersFormType extends AbstractFormType {
@Override
public String getName() {
return "users";
}
@Override
public Object convertFormValueToModelValue(String propertyValue) {
String[] split = StringUtils.split(propertyValue, ",");
return Arrays.asList(split);
}
@Override
public String convertModelValueToFormValue(Object modelValue) {
return ObjectUtils.toString(modelValue);
}
}

View File

@ -0,0 +1,76 @@
package com.jeethink.activiti.mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import com.jeethink.activiti.domain.BizTodoItem;
import java.util.List;
/**
* 待办事项Mapper接口
*
* @author Xianlu Tech
* @date 2019-11-08
*/
public interface BizTodoItemMapper {
/**
* 查询待办事项
*
* @param id 待办事项ID
* @return 待办事项
*/
public BizTodoItem selectBizTodoItemById(Long id);
/**
* 查询待办事项列表
*
* @param bizTodoItem 待办事项
* @return 待办事项集合
*/
public List<BizTodoItem> selectBizTodoItemList(BizTodoItem bizTodoItem);
/**
* 新增待办事项
*
* @param bizTodoItem 待办事项
* @return 结果
*/
public int insertBizTodoItem(BizTodoItem bizTodoItem);
/**
* 修改待办事项
*
* @param bizTodoItem 待办事项
* @return 结果
*/
public int updateBizTodoItem(BizTodoItem bizTodoItem);
/**
* 删除待办事项
*
* @param id 待办事项ID
* @return 结果
*/
public int deleteBizTodoItemById(Long id);
/**
* 批量删除待办事项
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public int deleteBizTodoItemByIds(String[] ids);
@Select("SELECT * FROM BIZ_TODO_ITEM WHERE TASK_ID = #{taskId}")
BizTodoItem selectTodoItemByTaskId(@Param(value = "taskId") String taskId);
@Select("SELECT USER_ID_ FROM ACT_ID_MEMBERSHIP WHERE GROUP_ID_ = (SELECT GROUP_ID_ FROM ACT_RU_IDENTITYLINK WHERE TASK_ID_ = #{taskId})")
List<String> selectTodoUserListByTaskId(@Param(value = "taskId") String taskId);
@Select("SELECT * FROM BIZ_TODO_ITEM WHERE TASK_ID = #{taskId} AND TODO_USER_ID = #{todoUserId}")
BizTodoItem selectTodoItemByCondition(@Param(value = "taskId") String taskId, @Param(value = "todoUserId") String todoUserId);
@Select("SELECT USER_ID_ FROM ACT_ID_MEMBERSHIP WHERE USER_ID_ = (SELECT USER_ID_ FROM ACT_RU_IDENTITYLINK WHERE TASK_ID_ = #{taskId})")
String selectTodoUserByTaskId(String id);
}

View File

@ -0,0 +1,70 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeethink.activiti.modeler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Tijs Rademakers
*/
@RestController
public class ModelEditorJsonRestResource implements ModelDataJsonConstants {
protected static final Logger LOGGER = LoggerFactory.getLogger(ModelEditorJsonRestResource.class);
@Autowired
private RepositoryService repositoryService;
@Autowired
private ObjectMapper objectMapper;
@RequestMapping(value="/modeler/model/{modelId}/json", method = RequestMethod.GET, produces = "application/json")
public ObjectNode getEditorJson(@PathVariable String modelId) {
ObjectNode modelNode = null;
Model model = repositoryService.getModel(modelId);
if (model != null) {
try {
if (StringUtils.isNotEmpty(model.getMetaInfo())) {
modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
} else {
modelNode = objectMapper.createObjectNode();
modelNode.put(MODEL_NAME, model.getName());
}
modelNode.put(MODEL_ID, model.getId());
ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(
new String(repositoryService.getModelEditorSource(model.getId()), "utf-8"));
modelNode.put("model", editorJsonNode);
} catch (Exception e) {
LOGGER.error("Error creating model JSON", e);
throw new ActivitiException("Error creating model JSON", e);
}
}
return modelNode;
}
}

View File

@ -0,0 +1,86 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeethink.activiti.modeler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.ActivitiException;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
/**
* @author Tijs Rademakers
*/
@RestController
public class ModelSaveRestResource implements ModelDataJsonConstants {
protected static final Logger LOGGER = LoggerFactory.getLogger(ModelSaveRestResource.class);
@Autowired
private RepositoryService repositoryService;
@Autowired
private ObjectMapper objectMapper;
@RequestMapping(value="/modeler/model/{modelId}/save", method = RequestMethod.POST)
@ResponseStatus(value = HttpStatus.OK)
public void saveModel(@PathVariable String modelId, @RequestBody MultiValueMap<String, String> values) {
try {
Model model = repositoryService.getModel(modelId);
ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
modelJson.put(MODEL_NAME, values.getFirst("name"));
modelJson.put(MODEL_DESCRIPTION, values.getFirst("description"));
model.setMetaInfo(modelJson.toString());
model.setName(values.getFirst("name"));
repositoryService.saveModel(model);
repositoryService.addModelEditorSource(model.getId(), values.getFirst("json_xml").getBytes("utf-8"));
InputStream svgStream = new ByteArrayInputStream(values.getFirst("svg_xml").getBytes("utf-8"));
TranscoderInput input = new TranscoderInput(svgStream);
PNGTranscoder transcoder = new PNGTranscoder();
// Setup output
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
TranscoderOutput output = new TranscoderOutput(outStream);
// Do the transformation
transcoder.transcode(input, output);
final byte[] result = outStream.toByteArray();
repositoryService.addModelEditorSourceExtra(model.getId(), result);
outStream.close();
} catch (Exception e) {
LOGGER.error("Error saving model", e);
throw new ActivitiException("Error saving model", e);
}
}
}

View File

@ -0,0 +1,217 @@
package com.jeethink.activiti.modeler;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.github.pagehelper.Page;
import com.jeethink.activiti.domain.ModelerVo;
import com.jeethink.common.annotation.Log;
import com.jeethink.common.config.JeeThinkConfig;
import com.jeethink.common.constant.HttpStatus;
import com.jeethink.common.core.controller.BaseController;
import com.jeethink.common.core.domain.AjaxResult;
import com.jeethink.common.core.page.PageDomain;
import com.jeethink.common.core.page.TableDataInfo;
import com.jeethink.common.core.page.TableSupport;
import com.jeethink.common.enums.BusinessType;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.persistence.entity.ModelEntityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ModelQuery;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.List;
import static org.activiti.editor.constants.ModelDataJsonConstants.MODEL_DESCRIPTION;
import static org.activiti.editor.constants.ModelDataJsonConstants.MODEL_NAME;
@Controller
public class ModelerController extends BaseController {
protected static final Logger LOGGER = LoggerFactory.getLogger(ModelEditorJsonRestResource.class);
@Autowired
private RepositoryService repositoryService;
@Autowired
private ObjectMapper objectMapper;
@GetMapping("/modeler/list")
@ResponseBody
public TableDataInfo list(ModelEntityImpl modelEntity) {
ModelQuery modelQuery = repositoryService.createModelQuery();
modelQuery.orderByLastUpdateTime().desc();
// 条件过滤
if (com.jeethink.common.utils.StringUtils.isNotBlank(modelEntity.getKey())) {
modelQuery.modelKey(modelEntity.getKey());
}
if (com.jeethink.common.utils.StringUtils.isNotBlank(modelEntity.getName())) {
modelQuery.modelNameLike("%" + modelEntity.getName() + "%");
}
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
List<Model> resultList = modelQuery.listPage((pageNum - 1) * pageSize, pageSize);
Page<Model> list = new Page<>();
list.addAll(resultList);
list.setTotal(modelQuery.count());
list.setPageNum(pageNum);
list.setPageSize(pageSize);
return getDataTable(list);
}
/**
* 创建模型
*/
@RequestMapping(value = "/modeler/create")
@ResponseBody
public AjaxResult create( @RequestBody ModelerVo modelerVo) {
try {
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode editorNode = objectMapper.createObjectNode();
editorNode.put("id", "canvas");
editorNode.put("resourceId", "canvas");
ObjectNode stencilSetNode = objectMapper.createObjectNode();
stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
editorNode.put("stencilset", stencilSetNode);
ObjectNode modelObjectNode = objectMapper.createObjectNode();
modelObjectNode.put(MODEL_NAME, modelerVo.getName());
modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
String description = StringUtils.defaultString(modelerVo.getDescription());
modelObjectNode.put(MODEL_DESCRIPTION, description);
Model newModel = repositoryService.newModel();
newModel.setMetaInfo(modelObjectNode.toString());
newModel.setName(modelerVo.getName());
newModel.setKey(StringUtils.defaultString(modelerVo.getKey()));
repositoryService.saveModel(newModel);
repositoryService.addModelEditorSource(newModel.getId(), editorNode.toString().getBytes("utf-8"));
return new AjaxResult(HttpStatus.SUCCESS, "创建模型成功", newModel.getId());
} catch (Exception e) {
logger.error("创建模型失败:", e);
}
return AjaxResult.error();
}
/**
* 根据Model部署流程
*/
@RequestMapping(value = "/modeler/deploy/{modelId}")
@ResponseBody
public AjaxResult deploy(@PathVariable("modelId") String modelId, RedirectAttributes redirectAttributes) {
try {
Model modelData = repositoryService.getModel(modelId);
ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
byte[] bpmnBytes = null;
BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
bpmnBytes = new BpmnXMLConverter().convertToXML(model);
String processName = modelData.getName() + ".bpmn20.xml";
Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes, "UTF-8")).deploy();
LOGGER.info("部署成功部署ID=" + deployment.getId());
return AjaxResult.success("部署成功");
} catch (Exception e) {
LOGGER.error("根据模型部署流程失败modelId={}", modelId, e);
}
return AjaxResult.error("部署失败");
}
/**
* 导出model的xml文件
*/
@RequestMapping(value = "/modeler/export/{modelId}")
@ResponseBody
public AjaxResult export(@PathVariable("modelId") String modelId) {
OutputStream out = null;
try {
Model modelData = repositoryService.getModel(modelId);
BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
// 流程非空判断
if (!CollectionUtils.isEmpty(bpmnModel.getProcesses())) {
BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);
ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
String filename = bpmnModel.getMainProcess().getId() + ".bpmn";
File file = new File(getAbsoluteFile(filename));
if(file.exists()){
file.delete();
}
FileOutputStream fos = new FileOutputStream(file);
fos.write(bpmnBytes,0,bpmnBytes.length);
fos.flush();
fos.close();
return AjaxResult.success(filename);
} else {
return AjaxResult.error();
}
} catch (Exception e) {
LOGGER.error("导出model的xml文件失败modelId={}", modelId, e);
return AjaxResult.error("导出model的xml文件失败modelId={}", modelId);
}
}
/**
* 获取下载路径
*
* @param filename 文件名称
*/
public String getAbsoluteFile(String filename)
{
String downloadPath = JeeThinkConfig.getDownloadPath() + filename;
File desc = new File(downloadPath);
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
}
return downloadPath;
}
@Log(title = "流程模型", businessType = BusinessType.DELETE)
@DeleteMapping("/modeler/remove/{ids}")
@ResponseBody
public AjaxResult remove(@PathVariable String ids) {
try {
repositoryService.deleteModel(ids);
return AjaxResult.success();
}
catch (Exception e) {
return AjaxResult.error(e.getMessage());
}
}
}

View File

@ -0,0 +1,40 @@
/* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jeethink.activiti.modeler;
import java.io.InputStream;
import org.activiti.engine.ActivitiException;
import org.apache.commons.io.IOUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Tijs Rademakers
*/
@RestController
public class StencilsetRestResource {
@RequestMapping(value="/modeler/editor/stencilset", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
public @ResponseBody String getStencilset() {
InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("stencilset.json");
try {
return IOUtils.toString(stencilsetStream, "utf-8");
} catch (Exception e) {
throw new ActivitiException("Error while loading stencil set", e);
}
}
}

View File

@ -0,0 +1,65 @@
package com.jeethink.activiti.service;
import java.util.List;
import com.jeethink.activiti.domain.BizTodoItem;
/**
* 待办事项Service接口
*
* @author Xianlu Tech
* @date 2019-11-08
*/
public interface IBizTodoItemService {
/**
* 查询待办事项
*
* @param id 待办事项ID
* @return 待办事项
*/
public BizTodoItem selectBizTodoItemById(Long id);
/**
* 查询待办事项列表
*
* @param bizTodoItem 待办事项
* @return 待办事项集合
*/
public List<BizTodoItem> selectBizTodoItemList(BizTodoItem bizTodoItem);
/**
* 新增待办事项
*
* @param bizTodoItem 待办事项
* @return 结果
*/
public int insertBizTodoItem(BizTodoItem bizTodoItem);
/**
* 修改待办事项
*
* @param bizTodoItem 待办事项
* @return 结果
*/
public int updateBizTodoItem(BizTodoItem bizTodoItem);
/**
* 批量删除待办事项
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public int deleteBizTodoItemByIds(String ids);
/**
* 删除待办事项信息
*
* @param id 待办事项ID
* @return 结果
*/
public int deleteBizTodoItemById(Long id);
int insertTodoItem(String instanceId, String itemName, String itemContent, String module);
BizTodoItem selectBizTodoItemByCondition(String taskId, String todoUserId);
}

View File

@ -0,0 +1,52 @@
package com.jeethink.activiti.service;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import com.jeethink.activiti.domain.ActivitiBaseEntity;
import com.jeethink.activiti.domain.HistoricActivity;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
public interface IProcessService {
/**
* 查询审批历史列表
* @param processInstanceId
* @param historicActivity
* @return
*/
List<HistoricActivity> selectHistoryList(String processInstanceId, HistoricActivity historicActivity);
/**
* 提交申请
* @param applyUserId 申请人
* @param businessKey 业务表 id
* @param key 流程定义 key
* @param variables 流程变量
* @return
*/
ProcessInstance submitApply(String applyUserId, String businessKey, String itemName, String itemConent, String key, Map<String, Object> variables);
List<Task> findTodoTasks(String userId, String key);
List<HistoricTaskInstance> findDoneTasks(String userId, String key);
void complete(ActivitiBaseEntity activitiBaseEntity, String module);
/**
* 委托任务
* @param taskId
* @param delegateToUser
*/
void delegate(String taskId, String fromUser, String delegateToUser);
void cancelApply(String instanceId, String deleteReason);
void suspendOrActiveApply(String instanceId, String suspendState);
String findBusinessKeyByInstanceId(String instanceId);
}

View File

@ -0,0 +1,137 @@
package com.jeethink.activiti.service;
import com.github.pagehelper.Page;
import com.jeethink.common.core.page.PageDomain;
import com.jeethink.common.core.page.TableSupport;
import com.jeethink.common.core.text.Convert;
import com.jeethink.common.utils.StringUtils;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;
import java.util.zip.ZipInputStream;
@Transactional
@Service
public class ProcessDefinitionService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private RepositoryService repositoryService;
/**
* 分页查询流程定义文件
* @return
*/
public Page<com.jeethink.activiti.domain.ProcessDefinition> listProcessDefinition(com.jeethink.activiti.domain.ProcessDefinition processDefinition) {
PageDomain pageDomain = TableSupport.buildPageRequest();
Integer pageNum = pageDomain.getPageNum();
Integer pageSize = pageDomain.getPageSize();
Page<com.jeethink.activiti.domain.ProcessDefinition> list = new Page<>();
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
processDefinitionQuery.orderByProcessDefinitionId().orderByProcessDefinitionVersion().desc();
if (StringUtils.isNotBlank(processDefinition.getName())) {
processDefinitionQuery.processDefinitionNameLike("%" + processDefinition.getName() + "%");
}
if (StringUtils.isNotBlank(processDefinition.getKey())) {
processDefinitionQuery.processDefinitionKeyLike("%" + processDefinition.getKey() + "%");
}
if (StringUtils.isNotBlank(processDefinition.getCategory())) {
processDefinitionQuery.processDefinitionCategoryLike("%" + processDefinition.getCategory() + "%");
}
List<ProcessDefinition> processDefinitionList;
if (pageNum != null && pageSize != null) {
processDefinitionList = processDefinitionQuery.listPage((pageNum - 1) * pageSize, pageSize);
list.setTotal(processDefinitionQuery.count());
list.setPageNum(pageNum);
list.setPageSize(pageSize);
} else {
processDefinitionList = processDefinitionQuery.list();
}
for (ProcessDefinition definition: processDefinitionList) {
ProcessDefinitionEntityImpl entityImpl = (ProcessDefinitionEntityImpl) definition;
com.jeethink.activiti.domain.ProcessDefinition entity = new com.jeethink.activiti.domain.ProcessDefinition();
entity.setId(definition.getId());
entity.setKey(definition.getKey());
entity.setName(definition.getName());
entity.setCategory(definition.getCategory());
entity.setVersion(definition.getVersion());
entity.setDescription(definition.getDescription());
entity.setDeploymentId(definition.getDeploymentId());
Deployment deployment = repositoryService.createDeploymentQuery()
.deploymentId(definition.getDeploymentId())
.singleResult();
entity.setDeploymentTime(deployment.getDeploymentTime());
entity.setDiagramResourceName(definition.getDiagramResourceName());
entity.setResourceName(definition.getResourceName());
entity.setSuspendState(entityImpl.getSuspensionState() + "");
if (entityImpl.getSuspensionState() == 1) {
entity.setSuspendStateName("已激活");
} else {
entity.setSuspendStateName("已挂起");
}
list.add(entity);
}
return list;
}
public void deployProcessDefinition(String filePath) throws FileNotFoundException {
if (StringUtils.isNotBlank(filePath)) {
if (filePath.endsWith(".zip")) {
ZipInputStream inputStream = new ZipInputStream(new FileInputStream(filePath));
repositoryService.createDeployment()
.addZipInputStream(inputStream)
.deploy();
} else if (filePath.endsWith(".bpmn")) {
repositoryService.createDeployment()
.addInputStream(filePath, new FileInputStream(filePath))
.deploy();
}
}
}
public int deleteProcessDeploymentByIds(String deploymentIds) throws Exception {
String[] deploymentIdsArr = Convert.toStrArray(deploymentIds);
int counter = 0;
for (String deploymentId: deploymentIdsArr) {
List<ProcessInstance> instanceList = runtimeService.createProcessInstanceQuery()
.deploymentId(deploymentId)
.list();
if (!CollectionUtils.isEmpty(instanceList)) {
// 存在流程实例的流程定义
throw new Exception("删除失败,存在运行中的流程实例");
}
repositoryService.deleteDeployment(deploymentId, true); // true 表示级联删除引用,比如 act_ru_execution 数据
counter++;
}
return counter;
}
public void suspendOrActiveApply(String id, String suspendState) {
if ("1".equals(suspendState)) {
// 当流程定义被挂起时,已经发起的该流程定义的流程实例不受影响(如果选择级联挂起则流程实例也会被挂起)。
// 当流程定义被挂起时,无法发起新的该流程定义的流程实例。
// 直观变化act_re_procdef 的 SUSPENSION_STATE_ 为 2
repositoryService.suspendProcessDefinitionById(id);
} else if ("2".equals(suspendState)) {
repositoryService.activateProcessDefinitionById(id);
}
}
}

View File

@ -0,0 +1,163 @@
package com.jeethink.activiti.service.impl;
import com.jeethink.activiti.domain.BizTodoItem;
import com.jeethink.activiti.mapper.BizTodoItemMapper;
import com.jeethink.activiti.service.IBizTodoItemService;
import com.jeethink.common.core.domain.entity.SysUser;
import com.jeethink.common.core.text.Convert;
import com.jeethink.common.utils.DateUtils;
import com.jeethink.common.utils.StringUtils;
import com.jeethink.system.mapper.SysUserMapper;
import org.activiti.engine.TaskService;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.List;
/**
* 待办事项Service业务层处理
*
* @author Xianlu Tech
* @date 2019-11-08
*/
@Service
@Transactional
public class BizTodoItemServiceImpl implements IBizTodoItemService {
@Autowired
private BizTodoItemMapper bizTodoItemMapper;
@Autowired
private SysUserMapper userMapper;
@Autowired
private TaskService taskService;
/**
* 查询待办事项
*
* @param id 待办事项ID
* @return 待办事项
*/
@Override
public BizTodoItem selectBizTodoItemById(Long id) {
return bizTodoItemMapper.selectBizTodoItemById(id);
}
/**
* 查询待办事项列表
*
* @param bizTodoItem 待办事项
* @return 待办事项
*/
@Override
public List<BizTodoItem> selectBizTodoItemList(BizTodoItem bizTodoItem) {
return bizTodoItemMapper.selectBizTodoItemList(bizTodoItem);
}
/**
* 新增待办事项
*
* @param bizTodoItem 待办事项
* @return 结果
*/
@Override
public int insertBizTodoItem(BizTodoItem bizTodoItem) {
return bizTodoItemMapper.insertBizTodoItem(bizTodoItem);
}
/**
* 修改待办事项
*
* @param bizTodoItem 待办事项
* @return 结果
*/
@Override
public int updateBizTodoItem(BizTodoItem bizTodoItem) {
return bizTodoItemMapper.updateBizTodoItem(bizTodoItem);
}
/**
* 删除待办事项对象
*
* @param ids 需要删除的数据ID
* @return 结果
*/
@Override
public int deleteBizTodoItemByIds(String ids) {
return bizTodoItemMapper.deleteBizTodoItemByIds(Convert.toStrArray(ids));
}
/**
* 删除待办事项信息
*
* @param id 待办事项ID
* @return 结果
*/
@Override
public int deleteBizTodoItemById(Long id) {
return bizTodoItemMapper.deleteBizTodoItemById(id);
}
@Override
public int insertTodoItem(String instanceId, String itemName, String itemContent, String module) {
BizTodoItem todoItem = new BizTodoItem();
todoItem.setItemName(itemName);
todoItem.setItemContent(itemContent);
todoItem.setIsView("0");
todoItem.setIsHandle("0");
todoItem.setModule(module);
todoItem.setTodoTime(DateUtils.getNowDate());
List<Task> taskList = taskService.createTaskQuery().processInstanceId(instanceId).active().list();
int counter = 0;
for (Task task: taskList) {
// todoitem 去重
BizTodoItem bizTodoItem = bizTodoItemMapper.selectTodoItemByTaskId(task.getId());
if (bizTodoItem != null) continue;
BizTodoItem newItem = new BizTodoItem();
BeanUtils.copyProperties(todoItem, newItem);
newItem.setInstanceId(instanceId);
newItem.setTaskId(task.getId());
newItem.setTaskName("task" + task.getTaskDefinitionKey().substring(0, 1).toUpperCase() + task.getTaskDefinitionKey().substring(1));
newItem.setNodeName(task.getName());
String assignee = task.getAssignee();
if (StringUtils.isNotBlank(assignee)) {
newItem.setTodoUserId(assignee);
SysUser user = userMapper.selectUserByUserName(assignee);
newItem.setTodoUserName(user.getNickName());
bizTodoItemMapper.insertBizTodoItem(newItem);
counter++;
} else {
// 查询候选用户组
List<String> todoUserIdList = bizTodoItemMapper.selectTodoUserListByTaskId(task.getId());
if (!CollectionUtils.isEmpty(todoUserIdList)) {
for (String todoUserId: todoUserIdList) {
SysUser todoUser = userMapper.selectUserByUserName(todoUserId);
newItem.setTodoUserId(todoUser.getUserName());
newItem.setTodoUserName(todoUser.getNickName());
bizTodoItemMapper.insertBizTodoItem(newItem);
counter++;
}
} else {
// 查询候选用户
String todoUserId = bizTodoItemMapper.selectTodoUserByTaskId(task.getId());
SysUser todoUser = userMapper.selectUserByUserName(todoUserId);
newItem.setTodoUserId(todoUser.getUserName());
newItem.setTodoUserName(todoUser.getNickName());
bizTodoItemMapper.insertBizTodoItem(newItem);
counter++;
}
}
}
return counter;
}
@Override
public BizTodoItem selectBizTodoItemByCondition(String taskId, String todoUserId) {
return bizTodoItemMapper.selectTodoItemByCondition(taskId, todoUserId);
}
}

View File

@ -0,0 +1,252 @@
package com.jeethink.activiti.service.impl;
import com.jeethink.activiti.domain.ActivitiBaseEntity;
import com.jeethink.activiti.domain.BizTodoItem;
import com.jeethink.activiti.domain.HistoricActivity;
import com.jeethink.activiti.service.IBizTodoItemService;
import com.jeethink.activiti.service.IProcessService;
import com.jeethink.common.core.domain.entity.SysUser;
import com.jeethink.common.utils.DateUtils;
import com.jeethink.common.utils.SecurityUtils;
import com.jeethink.common.utils.StringUtils;
import com.jeethink.system.mapper.SysUserMapper;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;
@Service
@Transactional
public class ProcessServiceImpl implements IProcessService {
protected final Logger logger = LoggerFactory.getLogger(ProcessServiceImpl.class);
@Autowired
private RuntimeService runtimeService;
@Autowired
private IdentityService identityService;
@Autowired
private TaskService taskService;
@Autowired
private HistoryService historyService;
@Autowired
private SysUserMapper userMapper;
@Autowired
private IBizTodoItemService bizTodoItemService;
@Override
public ProcessInstance submitApply(String applyUserId, String businessKey, String itemName, String itemConent, String module, Map<String, Object> variables) {
// 用来设置启动流程的人员ID引擎会自动把用户ID保存到activiti:initiator中
identityService.setAuthenticatedUserId(applyUserId);
// 启动流程时设置业务 key
ProcessInstance instance = runtimeService.startProcessInstanceByKey(module, businessKey, variables);
// 下一节点处理人待办事项
bizTodoItemService.insertTodoItem(instance.getProcessInstanceId(), itemName, itemConent, module);
return instance;
}
@Override
public List<Task> findTodoTasks(String userId, String key) {
List<Task> tasks = new ArrayList<Task>();
// 根据当前人的ID查询
List<Task> todoList = taskService
.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(userId)
.list();
// 根据当前人未签收的任务
List<Task> unsignedTasks = taskService
.createTaskQuery()
.processDefinitionKey(key)
.taskCandidateUser(userId)
.list();
// 合并
tasks.addAll(todoList);
tasks.addAll(unsignedTasks);
return tasks;
}
@Override
public List<HistoricTaskInstance> findDoneTasks(String userId, String key) {
List<HistoricTaskInstance> list = historyService
.createHistoricTaskInstanceQuery()
.processDefinitionKey(key)
.taskAssignee(userId)
.finished()
.orderByHistoricTaskInstanceEndTime()
.desc()
.list();
return list;
}
@Override
public void complete(ActivitiBaseEntity activitiBaseEntity,String module) {
Map<String, Object> variables =new HashMap<String, Object>();
String comment = null; // 批注
boolean agree = true;
try {
for(Map.Entry<String, Object> entry : activitiBaseEntity.getProcessParams().entrySet()){
String parameterName = entry.getKey();
// 参数结构B_nameB为类型name为属性名称
String[] parameter = parameterName.split("_");
if (parameter.length == 2) {
String paramValue = (String) entry.getValue();
Object value = paramValue;
if (parameter[0].equals("B")) {
value = BooleanUtils.toBoolean(paramValue);
agree = (boolean) value;
} else if (parameter[0].equals("DT")) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
value = sdf.parse(paramValue);
} else if (parameter[0].equals("COM")) {
comment = paramValue;
}
variables.put(parameter[1], value);
}
}
if (StringUtils.isNotEmpty(comment)) {
identityService.setAuthenticatedUserId(SecurityUtils.getUsername());
comment = agree ? "【同意】" + comment : "【拒绝】" + comment;
taskService.addComment(activitiBaseEntity.getTaskId(), activitiBaseEntity.getInstanceId(), comment);
}
// 被委派人处理完成任务
// p.s. 被委托的流程需要先 resolved 这个任务再提交。
// 所以在 complete 之前需要先 resolved
// resolveTask() 要在 claim() 之前,不然 act_hi_taskinst 表的 assignee 字段会为 null
taskService.resolveTask(activitiBaseEntity.getTaskId(), variables);
// 只有签收任务act_hi_taskinst 表的 assignee 字段才不为 null
taskService.claim(activitiBaseEntity.getTaskId(), SecurityUtils.getUsername());
taskService.complete(activitiBaseEntity.getTaskId(), variables);
// 更新待办事项状态
BizTodoItem query = new BizTodoItem();
query.setTaskId(activitiBaseEntity.getTaskId());
// 考虑到候选用户组,会有多个 todoitem 办理同个 task
List<BizTodoItem> updateList = CollectionUtils.isEmpty(bizTodoItemService.selectBizTodoItemList(query)) ? null : bizTodoItemService.selectBizTodoItemList(query);
for (BizTodoItem update: updateList) {
// 找到当前登录用户的 todoitem置为已办
if (update.getTodoUserId().equals(SecurityUtils.getUsername())) {
update.setIsView("1");
update.setIsHandle("1");
update.setHandleUserId(SecurityUtils.getUsername());
update.setHandleUserName(SecurityUtils.getNickName());
update.setHandleTime(DateUtils.getNowDate());
bizTodoItemService.updateBizTodoItem(update);
} else {
bizTodoItemService.deleteBizTodoItemById(update.getId()); // 删除候选用户组其他 todoitem
}
}
// 下一节点处理人待办事项
bizTodoItemService.insertTodoItem(activitiBaseEntity.getInstanceId(),activitiBaseEntity.getTitle(),activitiBaseEntity.getReason(), module);
} catch (Exception e) {
logger.error("error on complete task {}, variables={}", new Object[]{activitiBaseEntity.getTaskId(), variables, e});
}
}
@Override
public List<HistoricActivity> selectHistoryList(String processInstanceId, HistoricActivity historicActivity) {
// PageDomain pageDomain = TableSupport.buildPageRequest();
// Integer pageNum = pageDomain.getPageNum();
// Integer pageSize = pageDomain.getPageSize();
List<HistoricActivity> activityList = new ArrayList<>();
HistoricActivityInstanceQuery query = historyService.createHistoricActivityInstanceQuery();
if (StringUtils.isNotBlank(historicActivity.getAssignee())) {
query.taskAssignee(historicActivity.getAssignee());
}
if (StringUtils.isNotBlank(historicActivity.getActivityName())) {
query.activityName(historicActivity.getActivityName());
}
List<HistoricActivityInstance> list = query.processInstanceId(processInstanceId)
.activityType("userTask")
.finished()
.orderByHistoricActivityInstanceStartTime()
.desc()
.list();
// .listPage((pageNum - 1) * pageSize, pageNum * pageSize);
list.forEach(instance -> {
HistoricActivity activity = new HistoricActivity();
BeanUtils.copyProperties(instance, activity);
String taskId = instance.getTaskId();
List<Comment> comment = taskService.getTaskComments(taskId, "comment");
if (!CollectionUtils.isEmpty(comment)) {
activity.setComment(comment.get(0).getFullMessage());
}
SysUser sysUser = userMapper.selectUserByUserName(instance.getAssignee());
if (sysUser != null) {
activity.setAssigneeName(sysUser.getUserName());
}
activityList.add(activity);
});
return activityList;
}
@Override
public void delegate(String taskId, String fromUser, String delegateToUser) {
taskService.delegateTask(taskId, delegateToUser);
// 更新待办事项
// BizTodoItem updateItem = bizTodoItemService.selectBizTodoItemByCondition(taskId, fromUser);
// if (updateItem != null) {
// SysUser todoUser = userMapper.selectUserByLoginName(delegateToUser);
// updateItem.setTodoUserId(delegateToUser);
// updateItem.setTodoUserName(todoUser.getUserName());
// bizTodoItemService.updateBizTodoItem(updateItem);
// }
}
@Override
public void cancelApply(String instanceId, String deleteReason) {
// 执行此方法后未审批的任务 act_ru_task 会被删除,流程历史 act_hi_taskinst 不会被删除并且流程历史的状态为finished完成
runtimeService.deleteProcessInstance(instanceId, deleteReason);
}
@Override
public void suspendOrActiveApply(String instanceId, String suspendState) {
if ("1".equals(suspendState)) {
// 当流程实例被挂起时无法通过下一个节点对应的任务id来继续这个流程实例。
// 通过挂起某一特定的流程实例,可以终止当前的流程实例,而不影响到该流程定义的其他流程实例。
// 激活之后可以继续该流程实例,不会对后续任务造成影响。
// 直观变化act_ru_task 的 SUSPENSION_STATE_ 为 2
runtimeService.suspendProcessInstanceById(instanceId);
} else if ("2".equals(suspendState)) {
runtimeService.activateProcessInstanceById(instanceId);
}
}
@Override
public String findBusinessKeyByInstanceId(String instanceId) {
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
if (processInstance == null) {
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(instanceId)
.singleResult();
return historicProcessInstance.getBusinessKey();
} else {
return processInstance.getBusinessKey();
}
}
}

View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jeethink.activiti.mapper.BizTodoItemMapper">
<resultMap type="BizTodoItem" id="BizTodoItemResult">
<result property="id" column="id" />
<result property="itemName" column="item_name" />
<result property="itemContent" column="item_content" />
<result property="module" column="module" />
<result property="instanceId" column="instance_id" />
<result property="taskId" column="task_id" />
<result property="taskName" column="task_name" />
<result property="nodeName" column="node_name" />
<result property="isView" column="is_view" />
<result property="isHandle" column="is_handle" />
<result property="todoUserId" column="todo_user_id" />
<result property="todoUserName" column="todo_user_name" />
<result property="handleUserId" column="handle_user_id" />
<result property="handleUserName" column="handle_user_name" />
<result property="todoTime" column="todo_time" />
<result property="handleTime" column="handle_time" />
</resultMap>
<sql id="selectBizTodoItemVo">
select id, item_name, item_content, module, instance_id, task_id, task_name, node_name, is_view, is_handle, todo_user_id, todo_user_name, handle_user_id, handle_user_name, todo_time, handle_time from biz_todo_item
</sql>
<select id="selectBizTodoItemList" parameterType="BizTodoItem" resultMap="BizTodoItemResult">
<include refid="selectBizTodoItemVo"/>
<where>
<if test="itemName != null and itemName != ''"> and item_name like concat('%', #{itemName}, '%')</if>
<if test="itemContent != null and itemContent != ''"> and item_content = #{itemContent}</if>
<if test="module != null and module != ''"> and module = #{module}</if>
<if test="instanceId != null and instanceId != ''"> and instance_id = #{instanceId}</if>
<if test="taskId != null and taskId != ''"> and task_id = #{taskId}</if>
<if test="taskName != null and taskName != ''"> and task_name like concat('%', #{taskName}, '%')</if>
<if test="nodeName != null and nodeName != ''"> and node_name like concat('%', #{nodeName}, '%')</if>
<if test="isView != null and isView != ''"> and is_view = #{isView}</if>
<if test="isHandle != null and isHandle != ''"> and is_handle = #{isHandle}</if>
<if test="todoUserId != null and todoUserId != ''"> and todo_user_id like concat('%', #{todoUserId}, '%')</if>
<if test="todoUserName != null and todoUserName != ''"> and todo_user_name like concat('%', #{todoUserName}, '%')</if>
<if test="handleUserId != null and handleUserId != ''"> and handle_user_id like concat('%', #{handleUserId}, '%')</if>
<if test="handleUserName != null and handleUserName != ''"> and handle_user_name like concat('%', #{handleUserName}, '%')</if>
<if test="todoTime != null "> and todo_time = #{todoTime}</if>
<if test="handleTime != null "> and handle_time = #{handleTime}</if>
<if test="params.todoItemStartTime != null and params.todoItemStartTime != ''"><!-- 开始时间检索 -->
and date_format(todo_time,'%y%m%d') &gt;= date_format(#{params.todoItemStartTime},'%y%m%d')
</if>
<if test="params.todoItemEndTime != null and params.todoItemEndTime != ''"><!-- 结束时间检索 -->
and date_format(todo_time,'%y%m%d') &lt;= date_format(#{params.todoItemEndTime},'%y%m%d')
</if>
<if test="params.handleStartTime != null and params.handleStartTime != ''"><!-- 开始时间检索 -->
and date_format(handle_time,'%y%m%d') &gt;= date_format(#{params.handleStartTime},'%y%m%d')
</if>
<if test="params.handleEndTime != null and params.handleEndTime != ''"><!-- 结束时间检索 -->
and date_format(handle_time,'%y%m%d') &lt;= date_format(#{params.handleEndTime},'%y%m%d')
</if>
order by todo_time desc
</where>
</select>
<select id="selectBizTodoItemById" parameterType="Long" resultMap="BizTodoItemResult">
<include refid="selectBizTodoItemVo"/>
where id = #{id}
</select>
<insert id="insertBizTodoItem" parameterType="BizTodoItem" useGeneratedKeys="true" keyProperty="id">
insert into biz_todo_item
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="itemName != null and itemName != ''">item_name,</if>
<if test="itemContent != null and itemContent != ''">item_content,</if>
<if test="module != null and module != ''">module,</if>
<if test="instanceId != null and instanceId != ''">instance_id,</if>
<if test="taskId != null and taskId != ''">task_id,</if>
<if test="taskName != null and taskName != ''">task_name,</if>
<if test="nodeName != null and nodeName != ''">node_name,</if>
<if test="isView != null and isView != ''">is_view,</if>
<if test="isHandle != null and isHandle != ''">is_handle,</if>
<if test="todoUserId != null ">todo_user_id,</if>
<if test="todoUserName != null and todoUserName != ''">todo_user_name,</if>
<if test="handleUserId != null ">handle_user_id,</if>
<if test="handleUserName != null and handleUserName != ''">handle_user_name,</if>
<if test="todoTime != null ">todo_time,</if>
<if test="handleTime != null ">handle_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="itemName != null and itemName != ''">#{itemName},</if>
<if test="itemContent != null and itemContent != ''">#{itemContent},</if>
<if test="module != null and module != ''">#{module},</if>
<if test="instanceId != null and instanceId != ''">#{instanceId},</if>
<if test="taskId != null and taskId != ''">#{taskId},</if>
<if test="taskName != null and taskName != ''">#{taskName},</if>
<if test="nodeName != null and nodeName != ''">#{nodeName},</if>
<if test="isView != null and isView != ''">#{isView},</if>
<if test="isHandle != null and isHandle != ''">#{isHandle},</if>
<if test="todoUserId != null ">#{todoUserId},</if>
<if test="todoUserName != null and todoUserName != ''">#{todoUserName},</if>
<if test="handleUserId != null ">#{handleUserId},</if>
<if test="handleUserName != null and handleUserName != ''">#{handleUserName},</if>
<if test="todoTime != null ">#{todoTime},</if>
<if test="handleTime != null ">#{handleTime},</if>
</trim>
</insert>
<update id="updateBizTodoItem" parameterType="BizTodoItem">
update biz_todo_item
<trim prefix="SET" suffixOverrides=",">
<if test="itemName != null and itemName != ''">item_name = #{itemName},</if>
<if test="itemContent != null and itemContent != ''">item_content = #{itemContent},</if>
<if test="module != null and module != ''">module = #{module},</if>
<if test="instanceId != null and instanceId != ''">instance_id = #{instanceId},</if>
<if test="taskId != null and taskId != ''">task_id = #{taskId},</if>
<if test="taskName != null and taskName != ''">task_name = #{taskName},</if>
<if test="nodeName != null and nodeName != ''">node_name = #{nodeName},</if>
<if test="isView != null and isView != ''">is_view = #{isView},</if>
<if test="isHandle != null and isHandle != ''">is_handle = #{isHandle},</if>
<if test="todoUserId != null ">todo_user_id = #{todoUserId},</if>
<if test="todoUserName != null and todoUserName != ''">todo_user_name = #{todoUserName},</if>
<if test="handleUserId != null ">handle_user_id = #{handleUserId},</if>
<if test="handleUserName != null and handleUserName != ''">handle_user_name = #{handleUserName},</if>
<if test="todoTime != null ">todo_time = #{todoTime},</if>
<if test="handleTime != null ">handle_time = #{handleTime},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteBizTodoItemById" parameterType="Long">
delete from biz_todo_item where id = #{id}
</delete>
<delete id="deleteBizTodoItemByIds" parameterType="String">
delete from biz_todo_item where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>

File diff suppressed because one or more lines are too long