57 changed files with 5985 additions and 47 deletions
@ -0,0 +1,43 @@ |
|||
package com.ruoyi.common.exception; |
|||
|
|||
/** |
|||
* 自定义异常 |
|||
* |
|||
* @author ruoyi |
|||
*/ |
|||
public class CustomException extends RuntimeException |
|||
{ |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
private Integer code; |
|||
|
|||
private String message; |
|||
|
|||
public CustomException(String message) |
|||
{ |
|||
this.message = message; |
|||
} |
|||
|
|||
public CustomException(String message, Integer code) |
|||
{ |
|||
this.message = message; |
|||
this.code = code; |
|||
} |
|||
|
|||
public CustomException(String message, Throwable e) |
|||
{ |
|||
super(message, e); |
|||
this.message = message; |
|||
} |
|||
|
|||
@Override |
|||
public String getMessage() |
|||
{ |
|||
return message; |
|||
} |
|||
|
|||
public Integer getCode() |
|||
{ |
|||
return code; |
|||
} |
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> |
|||
<parent> |
|||
<artifactId>ruoyi</artifactId> |
|||
<groupId>com.ruoyi</groupId> |
|||
<version>3.8.4</version> |
|||
</parent> |
|||
<modelVersion>4.0.0</modelVersion> |
|||
|
|||
<artifactId>ruoyi-flowable</artifactId> |
|||
|
|||
<dependencies> |
|||
|
|||
<dependency> |
|||
<groupId>com.ruoyi</groupId> |
|||
<artifactId>ruoyi-framework</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.ruoyi</groupId> |
|||
<artifactId>ruoyi-system</artifactId> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>com.ruoyi</groupId> |
|||
<artifactId>ruoyi-common</artifactId> |
|||
</dependency> |
|||
|
|||
<!--常用工具类 --> |
|||
<dependency> |
|||
<groupId>org.apache.commons</groupId> |
|||
<artifactId>commons-lang3</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- JSON工具类 --> |
|||
<dependency> |
|||
<groupId>com.fasterxml.jackson.core</groupId> |
|||
<artifactId>jackson-databind</artifactId> |
|||
</dependency> |
|||
|
|||
<!-- 阿里JSON解析器 --> |
|||
<dependency> |
|||
<groupId>com.alibaba.fastjson2</groupId> |
|||
<artifactId>fastjson2</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.projectlombok</groupId> |
|||
<artifactId>lombok</artifactId> |
|||
<optional>true</optional> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>io.swagger</groupId> |
|||
<artifactId>swagger-annotations</artifactId> |
|||
<scope>compile</scope> |
|||
</dependency> |
|||
<dependency> |
|||
<groupId>org.flowable</groupId> |
|||
<artifactId>flowable-engine</artifactId> |
|||
<scope>compile</scope> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>org.flowable</groupId> |
|||
<artifactId>flowable-spring-boot-starter-basic</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<groupId>com.baomidou</groupId> |
|||
<artifactId>mybatis-plus-boot-starter</artifactId> |
|||
</dependency> |
|||
|
|||
<dependency> |
|||
<!-- websocket --> |
|||
<groupId>org.springframework.boot</groupId> |
|||
<artifactId>spring-boot-starter-websocket</artifactId> |
|||
</dependency> |
|||
|
|||
<!--el表达式计算--> |
|||
<dependency> |
|||
<groupId>com.googlecode.aviator</groupId> |
|||
<artifactId>aviator</artifactId> |
|||
<version>5.3.3</version> |
|||
</dependency> |
|||
|
|||
</dependencies> |
|||
|
|||
<!-- <build>--> |
|||
<!-- <plugins>--> |
|||
<!-- <plugin>--> |
|||
<!-- <groupId>org.springframework.boot</groupId>--> |
|||
<!-- <artifactId>spring-boot-maven-plugin</artifactId>--> |
|||
<!-- </plugin>--> |
|||
<!-- </plugins>--> |
|||
<!-- </build>--> |
|||
|
|||
</project> |
|||
@ -0,0 +1,80 @@ |
|||
package com.ruoyi.flowable.common.constant; |
|||
|
|||
/** |
|||
* 流程常量信息 |
|||
* |
|||
* @author Xuan xuan |
|||
* @date 2021/4/17 22:46 |
|||
*/ |
|||
public class ProcessConstants { |
|||
|
|||
/** |
|||
* 动态数据 |
|||
*/ |
|||
public static final String DATA_TYPE = "dynamic"; |
|||
|
|||
/** |
|||
* 固定任务接收 |
|||
*/ |
|||
public static final String FIXED = "fixed"; |
|||
|
|||
/** |
|||
* 单个审批人 |
|||
*/ |
|||
public static final String USER_TYPE_ASSIGNEE = "assignee"; |
|||
|
|||
|
|||
/** |
|||
* 候选人 |
|||
*/ |
|||
public static final String USER_TYPE_USERS = "candidateUsers"; |
|||
|
|||
|
|||
/** |
|||
* 审批组 |
|||
*/ |
|||
public static final String USER_TYPE_ROUPS = "candidateGroups"; |
|||
|
|||
/** |
|||
* 单个审批人 |
|||
*/ |
|||
public static final String PROCESS_APPROVAL = "approval"; |
|||
|
|||
/** |
|||
* 会签人员 |
|||
*/ |
|||
public static final String PROCESS_MULTI_INSTANCE_USER = "userList"; |
|||
|
|||
/** |
|||
* nameapace |
|||
*/ |
|||
public static final String NAMASPASE = "http://flowable.org/bpmn"; |
|||
|
|||
/** |
|||
* 会签节点 |
|||
*/ |
|||
public static final String PROCESS_MULTI_INSTANCE = "multiInstance"; |
|||
|
|||
/** |
|||
* 自定义属性 dataType |
|||
*/ |
|||
public static final String PROCESS_CUSTOM_DATA_TYPE = "dataType"; |
|||
|
|||
/** |
|||
* 自定义属性 userType |
|||
*/ |
|||
public static final String PROCESS_CUSTOM_USER_TYPE = "userType"; |
|||
|
|||
/** |
|||
* 初始化人员 |
|||
*/ |
|||
public static final String PROCESS_INITIATOR = "INITIATOR"; |
|||
|
|||
|
|||
/** |
|||
* 流程跳过 |
|||
*/ |
|||
public static final String FLOWABLE_SKIP_EXPRESSION_ENABLED = "_FLOWABLE_SKIP_EXPRESSION_ENABLED"; |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
package com.ruoyi.flowable.common.enums; |
|||
|
|||
/** |
|||
* 流程意见类型 |
|||
* |
|||
* @author Xuan xuan |
|||
* @date 2021/4/19 |
|||
*/ |
|||
public enum FlowComment { |
|||
|
|||
/** |
|||
* 说明 |
|||
*/ |
|||
NORMAL("1", "正常意见"), |
|||
REBACK("2", "退回意见"), |
|||
REJECT("3", "驳回意见"), |
|||
DELEGATE("4", "委派意见"), |
|||
ASSIGN("5", "转办意见"), |
|||
STOP("6", "终止流程"); |
|||
|
|||
/** |
|||
* 类型 |
|||
*/ |
|||
private final String type; |
|||
|
|||
/** |
|||
* 说明 |
|||
*/ |
|||
private final String remark; |
|||
|
|||
FlowComment(String type, String remark) { |
|||
this.type = type; |
|||
this.remark = remark; |
|||
} |
|||
|
|||
public String getType() { |
|||
return type; |
|||
} |
|||
|
|||
public String getRemark() { |
|||
return remark; |
|||
} |
|||
} |
|||
@ -0,0 +1,95 @@ |
|||
//package com.ruoyi.flowable.config;
|
|||
//
|
|||
//import com.sun.prism.paint.Color;
|
|||
//import org.flowable.bpmn.model.AssociationDirection;
|
|||
//import org.flowable.image.impl.DefaultProcessDiagramCanvas;
|
|||
//
|
|||
//import java.awt.*;
|
|||
//import java.awt.geom.Line2D;
|
|||
//import java.awt.geom.RoundRectangle2D;
|
|||
//
|
|||
///**
|
|||
// * @author XuanXuan
|
|||
// * @date 2021-04-03
|
|||
// */
|
|||
//public class MyDefaultProcessDiagramCanvas extends DefaultProcessDiagramCanvas {
|
|||
// //设置高亮线的颜色 这里我设置成绿色
|
|||
// protected static Color HIGHLIGHT_SEQUENCEFLOW_COLOR = Color.GREEN;
|
|||
//
|
|||
// public MyDefaultProcessDiagramCanvas(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 MyDefaultProcessDiagramCanvas(int width, int height, int minX, int minY, String imageType) {
|
|||
// super(width, height, minX, minY, imageType);
|
|||
// }
|
|||
//
|
|||
//
|
|||
// /**
|
|||
// * 画线颜色设置
|
|||
// */
|
|||
// @Override
|
|||
// public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType,
|
|||
// AssociationDirection associationDirection, boolean highLighted, double scaleFactor) {
|
|||
//
|
|||
// Paint originalPaint = g.getPaint();
|
|||
// Stroke originalStroke = g.getStroke();
|
|||
//
|
|||
// g.setPaint(CONNECTION_COLOR);
|
|||
// if (connectionType.equals("association")) {
|
|||
// g.setStroke(ASSOCIATION_STROKE);
|
|||
// } else if (highLighted) {
|
|||
// //设置线的颜色
|
|||
// g.setPaint(originalPaint);
|
|||
// g.setStroke(HIGHLIGHT_FLOW_STROKE);
|
|||
// }
|
|||
//
|
|||
// for (int i = 1; i < xPoints.length; i++) {
|
|||
// Integer sourceX = xPoints[i - 1];
|
|||
// Integer sourceY = yPoints[i - 1];
|
|||
// Integer targetX = xPoints[i];
|
|||
// Integer targetY = yPoints[i];
|
|||
// Line2D.Double line = new Line2D.Double(sourceX, sourceY, targetX, targetY);
|
|||
// g.draw(line);
|
|||
// }
|
|||
//
|
|||
// if (isDefault) {
|
|||
// Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
|
|||
// drawDefaultSequenceFlowIndicator(line, scaleFactor);
|
|||
// }
|
|||
//
|
|||
// if (conditional) {
|
|||
// Line2D.Double line = new Line2D.Double(xPoints[0], yPoints[0], xPoints[1], yPoints[1]);
|
|||
// drawConditionalSequenceFlowIndicator(line, scaleFactor);
|
|||
// }
|
|||
//
|
|||
// if (associationDirection == AssociationDirection.ONE || associationDirection == AssociationDirection.BOTH) {
|
|||
// Line2D.Double line = new Line2D.Double(xPoints[xPoints.length - 2], yPoints[xPoints.length - 2], xPoints[xPoints.length - 1], yPoints[xPoints.length - 1]);
|
|||
// drawArrowHead(line, scaleFactor);
|
|||
// }
|
|||
// if (associationDirection == AssociationDirection.BOTH) {
|
|||
// Line2D.Double line = new Line2D.Double(xPoints[1], yPoints[1], xPoints[0], yPoints[0]);
|
|||
// drawArrowHead(line, scaleFactor);
|
|||
// }
|
|||
// g.setPaint(originalPaint);
|
|||
// g.setStroke(originalStroke);
|
|||
// }
|
|||
//
|
|||
// /**
|
|||
// * 高亮节点设置
|
|||
// */
|
|||
// @Override
|
|||
// public void drawHighLight(int x, int y, int width, int height) {
|
|||
// Paint originalPaint = g.getPaint();
|
|||
// Stroke originalStroke = g.getStroke();
|
|||
// //设置高亮节点的颜色
|
|||
// g.setPaint(HIGHLIGHT_COLOR);
|
|||
// g.setStroke(THICK_TASK_BORDER_STROKE);
|
|||
//
|
|||
// RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20);
|
|||
// g.draw(rect);
|
|||
//
|
|||
// g.setPaint(originalPaint);
|
|||
// g.setStroke(originalStroke);
|
|||
// }
|
|||
//}
|
|||
@ -0,0 +1,192 @@ |
|||
package com.ruoyi.flowable.controller; |
|||
|
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.common.core.domain.entity.SysRole; |
|||
import com.ruoyi.common.core.domain.entity.SysUser; |
|||
import com.ruoyi.system.domain.FlowProcDefDto; |
|||
import com.ruoyi.flowable.domain.dto.FlowSaveXmlVo; |
|||
import com.ruoyi.flowable.service.IFlowDefinitionService; |
|||
import com.ruoyi.system.service.ISysRoleService; |
|||
import com.ruoyi.system.service.ISysUserService; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import io.swagger.annotations.ApiParam; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.*; |
|||
import org.springframework.web.multipart.MultipartFile; |
|||
|
|||
import javax.annotation.Resource; |
|||
import javax.imageio.ImageIO; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.awt.image.BufferedImage; |
|||
import java.io.ByteArrayInputStream; |
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.io.OutputStream; |
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* <p> |
|||
* 工作流程定义 |
|||
* </p> |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Slf4j |
|||
@Api(tags = "流程定义") |
|||
@RestController |
|||
@RequestMapping("/flowable/definition") |
|||
public class FlowDefinitionController { |
|||
|
|||
@Autowired |
|||
private IFlowDefinitionService flowDefinitionService; |
|||
|
|||
@Autowired |
|||
private ISysUserService userService; |
|||
|
|||
@Resource |
|||
private ISysRoleService sysRoleService; |
|||
|
|||
|
|||
@GetMapping(value = "/list") |
|||
@ApiOperation(value = "流程定义列表", response = FlowProcDefDto.class) |
|||
public AjaxResult list(@ApiParam(value = "当前页码", required = true) @RequestParam Integer pageNum, |
|||
@ApiParam(value = "每页条数", required = true) @RequestParam Integer pageSize, |
|||
@ApiParam(value = "流程名称", required = false) @RequestParam(required = false) String name) { |
|||
return AjaxResult.success(flowDefinitionService.list(name,pageNum, pageSize)); |
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "导入流程文件", notes = "上传bpmn20的xml文件") |
|||
@PostMapping("/import") |
|||
public AjaxResult importFile(@RequestParam(required = false) String name, |
|||
@RequestParam(required = false) String category, |
|||
MultipartFile file) { |
|||
InputStream in = null; |
|||
try { |
|||
in = file.getInputStream(); |
|||
flowDefinitionService.importFile(name, category, in); |
|||
} catch (Exception e) { |
|||
log.error("导入失败:", e); |
|||
return AjaxResult.success(e.getMessage()); |
|||
} finally { |
|||
try { |
|||
if (in != null) { |
|||
in.close(); |
|||
} |
|||
} catch (IOException e) { |
|||
log.error("关闭输入流出错", e); |
|||
} |
|||
} |
|||
|
|||
return AjaxResult.success("导入成功"); |
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "读取xml文件") |
|||
@GetMapping("/readXml/{deployId}") |
|||
public AjaxResult readXml(@ApiParam(value = "流程定义id") @PathVariable(value = "deployId") String deployId) { |
|||
try { |
|||
return flowDefinitionService.readXml(deployId); |
|||
} catch (Exception e) { |
|||
return AjaxResult.error("加载xml文件异常"); |
|||
} |
|||
|
|||
} |
|||
|
|||
@ApiOperation(value = "读取图片文件") |
|||
@GetMapping("/readImage/{deployId}") |
|||
public void readImage(@ApiParam(value = "流程定义id") @PathVariable(value = "deployId") String deployId, HttpServletResponse response) { |
|||
OutputStream os = null; |
|||
BufferedImage image = null; |
|||
try { |
|||
image = ImageIO.read(flowDefinitionService.readImage(deployId)); |
|||
response.setContentType("image/png"); |
|||
os = response.getOutputStream(); |
|||
if (image != null) { |
|||
ImageIO.write(image, "png", os); |
|||
} |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} finally { |
|||
try { |
|||
if (os != null) { |
|||
os.flush(); |
|||
os.close(); |
|||
} |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "保存流程设计器内的xml文件") |
|||
@PostMapping("/save") |
|||
public AjaxResult save(@RequestBody FlowSaveXmlVo vo) { |
|||
InputStream in = null; |
|||
try { |
|||
in = new ByteArrayInputStream(vo.getXml().getBytes(StandardCharsets.UTF_8)); |
|||
flowDefinitionService.importFile(vo.getName(), vo.getCategory(), in); |
|||
} catch (Exception e) { |
|||
log.error("导入失败:", e); |
|||
return AjaxResult.success(e.getMessage()); |
|||
} finally { |
|||
try { |
|||
if (in != null) { |
|||
in.close(); |
|||
} |
|||
} catch (IOException e) { |
|||
log.error("关闭输入流出错", e); |
|||
} |
|||
} |
|||
|
|||
return AjaxResult.success("导入成功"); |
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "根据流程定义id启动流程实例") |
|||
@PostMapping("/start/{procDefId}") |
|||
public AjaxResult start(@ApiParam(value = "流程定义id") @PathVariable(value = "procDefId") String procDefId, |
|||
@ApiParam(value = "变量集合,json对象") @RequestBody Map<String, Object> variables) { |
|||
return flowDefinitionService.startProcessInstanceById(procDefId, variables); |
|||
|
|||
} |
|||
|
|||
@ApiOperation(value = "激活或挂起流程定义") |
|||
@PutMapping(value = "/updateState") |
|||
public AjaxResult updateState(@ApiParam(value = "1:激活,2:挂起", required = true) @RequestParam Integer state, |
|||
@ApiParam(value = "流程部署ID", required = true) @RequestParam String deployId) { |
|||
flowDefinitionService.updateState(state, deployId); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "删除流程") |
|||
@DeleteMapping(value = "/{deployIds}") |
|||
public AjaxResult delete(@PathVariable String[] deployIds) { |
|||
for (String deployId : deployIds) { |
|||
flowDefinitionService.delete(deployId); |
|||
} |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "指定流程办理人员列表") |
|||
@GetMapping("/userList") |
|||
public AjaxResult userList(SysUser user) { |
|||
List<SysUser> list = userService.selectUserList(user); |
|||
return AjaxResult.success(list); |
|||
} |
|||
|
|||
@ApiOperation(value = "指定流程办理组列表") |
|||
@GetMapping("/roleList") |
|||
public AjaxResult roleList(SysRole role) { |
|||
List<SysRole> list = sysRoleService.selectRoleList(role); |
|||
return AjaxResult.success(list); |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
package com.ruoyi.flowable.controller; |
|||
|
|||
|
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.flowable.domain.vo.FlowTaskVo; |
|||
import com.ruoyi.flowable.service.IFlowInstanceService; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import io.swagger.annotations.ApiParam; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* <p>工作流流程实例管理<p> |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Slf4j |
|||
@Api(tags = "工作流流程实例管理") |
|||
@RestController |
|||
@RequestMapping("/flowable/instance") |
|||
public class FlowInstanceController { |
|||
|
|||
@Autowired |
|||
private IFlowInstanceService flowInstanceService; |
|||
|
|||
@ApiOperation(value = "根据流程定义id启动流程实例") |
|||
@PostMapping("/startBy/{procDefId}") |
|||
public AjaxResult startById(@ApiParam(value = "流程定义id") @PathVariable(value = "procDefId") String procDefId, |
|||
@ApiParam(value = "变量集合,json对象") @RequestBody Map<String, Object> variables) { |
|||
return flowInstanceService.startProcessInstanceById(procDefId, variables); |
|||
|
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "激活或挂起流程实例") |
|||
@PostMapping(value = "/updateState") |
|||
public AjaxResult updateState(@ApiParam(value = "1:激活,2:挂起", required = true) @RequestParam Integer state, |
|||
@ApiParam(value = "流程实例ID", required = true) @RequestParam String instanceId) { |
|||
flowInstanceService.updateState(state,instanceId); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation("结束流程实例") |
|||
@PostMapping(value = "/stopProcessInstance") |
|||
public AjaxResult stopProcessInstance(@RequestBody FlowTaskVo flowTaskVo) { |
|||
flowInstanceService.stopProcessInstance(flowTaskVo); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "删除流程实例") |
|||
@DeleteMapping(value = "/delete") |
|||
public AjaxResult delete(@ApiParam(value = "流程实例ID", required = true) @RequestParam String instanceId, |
|||
@ApiParam(value = "删除原因") @RequestParam(required = false) String deleteReason) { |
|||
flowInstanceService.delete(instanceId,deleteReason); |
|||
return AjaxResult.success(); |
|||
} |
|||
} |
|||
@ -0,0 +1,192 @@ |
|||
package com.ruoyi.flowable.controller; |
|||
|
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.flowable.domain.dto.FlowTaskDto; |
|||
import com.ruoyi.flowable.domain.vo.FlowTaskVo; |
|||
import com.ruoyi.flowable.service.IFlowTaskService; |
|||
import io.swagger.annotations.Api; |
|||
import io.swagger.annotations.ApiOperation; |
|||
import io.swagger.annotations.ApiParam; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.*; |
|||
|
|||
import javax.imageio.ImageIO; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.awt.image.BufferedImage; |
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.io.OutputStream; |
|||
|
|||
/** |
|||
* <p>工作流任务管理<p> |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Slf4j |
|||
@Api(tags = "工作流流程任务管理") |
|||
@RestController |
|||
@RequestMapping("/flowable/task") |
|||
public class FlowTaskController { |
|||
|
|||
@Autowired |
|||
private IFlowTaskService flowTaskService; |
|||
|
|||
@ApiOperation(value = "我发起的流程", response = FlowTaskDto.class) |
|||
@GetMapping(value = "/myProcess") |
|||
public AjaxResult myProcess(@ApiParam(value = "当前页码", required = true) @RequestParam Integer pageNum, |
|||
@ApiParam(value = "每页条数", required = true) @RequestParam Integer pageSize) { |
|||
return flowTaskService.myProcess(pageNum, pageSize); |
|||
} |
|||
|
|||
@ApiOperation(value = "取消申请", response = FlowTaskDto.class) |
|||
@PostMapping(value = "/stopProcess") |
|||
public AjaxResult stopProcess(@RequestBody FlowTaskVo flowTaskVo) { |
|||
return flowTaskService.stopProcess(flowTaskVo); |
|||
} |
|||
|
|||
@ApiOperation(value = "撤回流程", response = FlowTaskDto.class) |
|||
@PostMapping(value = "/revokeProcess") |
|||
public AjaxResult revokeProcess(@RequestBody FlowTaskVo flowTaskVo) { |
|||
return flowTaskService.revokeProcess(flowTaskVo); |
|||
} |
|||
|
|||
@ApiOperation(value = "获取待办列表", response = FlowTaskDto.class) |
|||
@GetMapping(value = "/todoList") |
|||
public AjaxResult todoList(@ApiParam(value = "当前页码", required = true) @RequestParam Integer pageNum, |
|||
@ApiParam(value = "每页条数", required = true) @RequestParam Integer pageSize) { |
|||
return flowTaskService.todoList(pageNum, pageSize); |
|||
} |
|||
|
|||
@ApiOperation(value = "获取已办任务", response = FlowTaskDto.class) |
|||
@GetMapping(value = "/finishedList") |
|||
public AjaxResult finishedList(@ApiParam(value = "当前页码", required = true) @RequestParam Integer pageNum, |
|||
@ApiParam(value = "每页条数", required = true) @RequestParam Integer pageSize) { |
|||
return flowTaskService.finishedList(pageNum, pageSize); |
|||
} |
|||
|
|||
|
|||
@ApiOperation(value = "流程历史流转记录", response = FlowTaskDto.class) |
|||
@GetMapping(value = "/flowRecord") |
|||
public AjaxResult flowRecord(String procInsId, String deployId) { |
|||
return flowTaskService.flowRecord(procInsId, deployId); |
|||
} |
|||
|
|||
@ApiOperation(value = "获取流程变量", response = FlowTaskDto.class) |
|||
@GetMapping(value = "/processVariables/{taskId}") |
|||
public AjaxResult processVariables(@ApiParam(value = "流程任务Id") @PathVariable(value = "taskId") String taskId) { |
|||
return flowTaskService.processVariables(taskId); |
|||
} |
|||
|
|||
@ApiOperation(value = "审批任务") |
|||
@PostMapping(value = "/complete") |
|||
public AjaxResult complete(@RequestBody FlowTaskVo flowTaskVo) { |
|||
return flowTaskService.complete(flowTaskVo); |
|||
} |
|||
|
|||
@ApiOperation(value = "驳回任务") |
|||
@PostMapping(value = "/reject") |
|||
public AjaxResult taskReject(@RequestBody FlowTaskVo flowTaskVo) { |
|||
flowTaskService.taskReject(flowTaskVo); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "退回任务") |
|||
@PostMapping(value = "/return") |
|||
public AjaxResult taskReturn(@RequestBody FlowTaskVo flowTaskVo) { |
|||
flowTaskService.taskReturn(flowTaskVo); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "获取所有可回退的节点") |
|||
@PostMapping(value = "/returnList") |
|||
public AjaxResult findReturnTaskList(@RequestBody FlowTaskVo flowTaskVo) { |
|||
return flowTaskService.findReturnTaskList(flowTaskVo); |
|||
} |
|||
|
|||
@ApiOperation(value = "删除任务") |
|||
@DeleteMapping(value = "/delete") |
|||
public AjaxResult delete(@RequestBody FlowTaskVo flowTaskVo) { |
|||
flowTaskService.deleteTask(flowTaskVo); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "认领/签收任务") |
|||
@PostMapping(value = "/claim") |
|||
public AjaxResult claim(@RequestBody FlowTaskVo flowTaskVo) { |
|||
flowTaskService.claim(flowTaskVo); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "取消认领/签收任务") |
|||
@PostMapping(value = "/unClaim") |
|||
public AjaxResult unClaim(@RequestBody FlowTaskVo flowTaskVo) { |
|||
flowTaskService.unClaim(flowTaskVo); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "委派任务") |
|||
@PostMapping(value = "/delegate") |
|||
public AjaxResult delegate(@RequestBody FlowTaskVo flowTaskVo) { |
|||
flowTaskService.delegateTask(flowTaskVo); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "转办任务") |
|||
@PostMapping(value = "/assign") |
|||
public AjaxResult assign(@RequestBody FlowTaskVo flowTaskVo) { |
|||
flowTaskService.assignTask(flowTaskVo); |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
@ApiOperation(value = "获取下一节点") |
|||
@PostMapping(value = "/nextFlowNode") |
|||
public AjaxResult getNextFlowNode(@RequestBody FlowTaskVo flowTaskVo) { |
|||
return flowTaskService.getNextFlowNode(flowTaskVo); |
|||
} |
|||
|
|||
/** |
|||
* 生成流程图 |
|||
* |
|||
* @param processId 任务ID |
|||
*/ |
|||
@RequestMapping("/diagram/{processId}") |
|||
public void genProcessDiagram(HttpServletResponse response, |
|||
@PathVariable("processId") String processId) { |
|||
InputStream inputStream = flowTaskService.diagram(processId); |
|||
OutputStream os = null; |
|||
BufferedImage image = null; |
|||
try { |
|||
image = ImageIO.read(inputStream); |
|||
response.setContentType("image/png"); |
|||
os = response.getOutputStream(); |
|||
if (image != null) { |
|||
ImageIO.write(image, "png", os); |
|||
} |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
} finally { |
|||
try { |
|||
if (os != null) { |
|||
os.flush(); |
|||
os.close(); |
|||
} |
|||
} catch (IOException e) { |
|||
e.printStackTrace(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 生成流程图 |
|||
* |
|||
* @param procInsId 流程实例编号 |
|||
* @param procInsId 任务执行编号 |
|||
*/ |
|||
@RequestMapping("/flowViewer/{procInsId}/{executionId}") |
|||
public AjaxResult getFlowViewer(@PathVariable("procInsId") String procInsId, |
|||
@PathVariable("executionId") String executionId) { |
|||
return flowTaskService.getFlowViewer(procInsId, executionId); |
|||
} |
|||
} |
|||
@ -0,0 +1,112 @@ |
|||
package com.ruoyi.flowable.controller; |
|||
|
|||
import java.util.List; |
|||
|
|||
import com.ruoyi.flowable.service.ISysDeployFormService; |
|||
import com.ruoyi.system.domain.SysDeployForm; |
|||
import org.springframework.security.access.prepost.PreAuthorize; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.web.bind.annotation.GetMapping; |
|||
import org.springframework.web.bind.annotation.PostMapping; |
|||
import org.springframework.web.bind.annotation.PutMapping; |
|||
import org.springframework.web.bind.annotation.DeleteMapping; |
|||
import org.springframework.web.bind.annotation.PathVariable; |
|||
import org.springframework.web.bind.annotation.RequestBody; |
|||
import org.springframework.web.bind.annotation.RequestMapping; |
|||
import org.springframework.web.bind.annotation.RestController; |
|||
import com.ruoyi.common.annotation.Log; |
|||
import com.ruoyi.common.core.controller.BaseController; |
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.common.enums.BusinessType; |
|||
import com.ruoyi.system.domain.SysForm; |
|||
import com.ruoyi.flowable.service.ISysFormService; |
|||
import com.ruoyi.common.utils.poi.ExcelUtil; |
|||
import com.ruoyi.common.core.page.TableDataInfo; |
|||
|
|||
/** |
|||
* 流程表单Controller |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@RestController |
|||
@RequestMapping("/flowable/form") |
|||
public class SysFormController extends BaseController { |
|||
@Autowired |
|||
private ISysFormService SysFormService; |
|||
|
|||
@Autowired |
|||
private ISysDeployFormService sysDeployFormService; |
|||
|
|||
/** |
|||
* 查询流程表单列表 |
|||
*/ |
|||
@PreAuthorize("@ss.hasPermi('flowable:form:list')") |
|||
@GetMapping("/list") |
|||
public TableDataInfo list(SysForm sysForm) { |
|||
startPage(); |
|||
List<SysForm> list = SysFormService.selectSysFormList(sysForm); |
|||
return getDataTable(list); |
|||
} |
|||
|
|||
/** |
|||
* 导出流程表单列表 |
|||
*/ |
|||
@PreAuthorize("@ss.hasPermi('flowable:form:export')") |
|||
@Log(title = "流程表单", businessType = BusinessType.EXPORT) |
|||
@GetMapping("/export") |
|||
public AjaxResult export(SysForm sysForm) { |
|||
List<SysForm> list = SysFormService.selectSysFormList(sysForm); |
|||
ExcelUtil<SysForm> util = new ExcelUtil<SysForm>(SysForm.class); |
|||
return util.exportExcel(list, "form"); |
|||
} |
|||
|
|||
/** |
|||
* 获取流程表单详细信息 |
|||
*/ |
|||
@PreAuthorize("@ss.hasPermi('flowable:form:query')") |
|||
@GetMapping(value = "/{formId}") |
|||
public AjaxResult getInfo(@PathVariable("formId") Long formId) { |
|||
return AjaxResult.success(SysFormService.selectSysFormById(formId)); |
|||
} |
|||
|
|||
/** |
|||
* 新增流程表单 |
|||
*/ |
|||
@PreAuthorize("@ss.hasPermi('flowable:form:add')") |
|||
@Log(title = "流程表单", businessType = BusinessType.INSERT) |
|||
@PostMapping |
|||
public AjaxResult add(@RequestBody SysForm sysForm) { |
|||
return toAjax(SysFormService.insertSysForm(sysForm)); |
|||
} |
|||
|
|||
/** |
|||
* 修改流程表单 |
|||
*/ |
|||
@PreAuthorize("@ss.hasPermi('flowable:form:edit')") |
|||
@Log(title = "流程表单", businessType = BusinessType.UPDATE) |
|||
@PutMapping |
|||
public AjaxResult edit(@RequestBody SysForm sysForm) { |
|||
return toAjax(SysFormService.updateSysForm(sysForm)); |
|||
} |
|||
|
|||
/** |
|||
* 删除流程表单 |
|||
*/ |
|||
@PreAuthorize("@ss.hasPermi('flowable:form:remove')") |
|||
@Log(title = "流程表单", businessType = BusinessType.DELETE) |
|||
@DeleteMapping("/{formIds}") |
|||
public AjaxResult remove(@PathVariable Long[] formIds) { |
|||
return toAjax(SysFormService.deleteSysFormByIds(formIds)); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 挂载流程表单 |
|||
*/ |
|||
@Log(title = "流程表单", businessType = BusinessType.INSERT) |
|||
@PostMapping("/addDeployForm") |
|||
public AjaxResult addDeployForm(@RequestBody SysDeployForm sysDeployForm) { |
|||
return toAjax(sysDeployFormService.insertSysDeployForm(sysDeployForm)); |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
package com.ruoyi.flowable.domain.dto; |
|||
|
|||
import lombok.Builder; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021/3/28 15:50 |
|||
*/ |
|||
@Data |
|||
@Builder |
|||
public class FlowCommentDto implements Serializable { |
|||
|
|||
/** |
|||
* 意见类别 0 正常意见 1 退回意见 2 驳回意见 |
|||
*/ |
|||
private String type; |
|||
|
|||
/** |
|||
* 意见内容 |
|||
*/ |
|||
private String comment; |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
package com.ruoyi.flowable.domain.dto; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021/3/31 23:20 |
|||
*/ |
|||
@Data |
|||
public class FlowFromFieldDTO implements Serializable { |
|||
|
|||
private Object fields; |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
package com.ruoyi.flowable.domain.dto; |
|||
|
|||
import com.ruoyi.common.core.domain.entity.SysRole; |
|||
import com.ruoyi.common.core.domain.entity.SysUser; |
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 动态人员、组 |
|||
* @author Xuan xuan |
|||
* @date 2021/4/17 22:59 |
|||
*/ |
|||
@Data |
|||
public class FlowNextDto implements Serializable { |
|||
|
|||
private String type; |
|||
|
|||
private String vars; |
|||
|
|||
private List<SysUser> userList; |
|||
|
|||
private List<SysRole> roleList; |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
package com.ruoyi.flowable.domain.dto; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021/3/28 19:48 |
|||
*/ |
|||
@Data |
|||
public class FlowSaveXmlVo implements Serializable { |
|||
|
|||
/** |
|||
* 流程名称 |
|||
*/ |
|||
private String name; |
|||
|
|||
/** |
|||
* 流程分类 |
|||
*/ |
|||
private String category; |
|||
|
|||
/** |
|||
* xml 文件 |
|||
*/ |
|||
private String xml; |
|||
} |
|||
@ -0,0 +1,103 @@ |
|||
package com.ruoyi.flowable.domain.dto; |
|||
|
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import com.ruoyi.common.core.domain.entity.SysUser; |
|||
import io.swagger.annotations.ApiModel; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Getter; |
|||
import lombok.Setter; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* <p>工作流任务<p> |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Getter |
|||
@Setter |
|||
@ApiModel("工作流任务相关-返回参数") |
|||
public class FlowTaskDto implements Serializable { |
|||
|
|||
@ApiModelProperty("任务编号") |
|||
private String taskId; |
|||
|
|||
@ApiModelProperty("任务执行编号") |
|||
private String executionId; |
|||
|
|||
@ApiModelProperty("任务名称") |
|||
private String taskName; |
|||
|
|||
@ApiModelProperty("任务Key") |
|||
private String taskDefKey; |
|||
|
|||
@ApiModelProperty("任务执行人Id") |
|||
private Long assigneeId; |
|||
|
|||
@ApiModelProperty("部门名称") |
|||
private String deptName; |
|||
|
|||
@ApiModelProperty("流程发起人部门名称") |
|||
private String startDeptName; |
|||
|
|||
@ApiModelProperty("任务执行人名称") |
|||
private String assigneeName; |
|||
|
|||
@ApiModelProperty("流程发起人Id") |
|||
private String startUserId; |
|||
|
|||
@ApiModelProperty("流程发起人名称") |
|||
private String startUserName; |
|||
|
|||
@ApiModelProperty("流程类型") |
|||
private String category; |
|||
|
|||
@ApiModelProperty("流程变量信息") |
|||
private Object procVars; |
|||
|
|||
@ApiModelProperty("局部变量信息") |
|||
private Object taskLocalVars; |
|||
|
|||
@ApiModelProperty("流程部署编号") |
|||
private String deployId; |
|||
|
|||
@ApiModelProperty("流程ID") |
|||
private String procDefId; |
|||
|
|||
@ApiModelProperty("流程key") |
|||
private String procDefKey; |
|||
|
|||
@ApiModelProperty("流程定义名称") |
|||
private String procDefName; |
|||
|
|||
@ApiModelProperty("流程定义内置使用版本") |
|||
private int procDefVersion; |
|||
|
|||
@ApiModelProperty("流程实例ID") |
|||
private String procInsId; |
|||
|
|||
@ApiModelProperty("历史流程实例ID") |
|||
private String hisProcInsId; |
|||
|
|||
@ApiModelProperty("任务耗时") |
|||
private String duration; |
|||
|
|||
@ApiModelProperty("任务意见") |
|||
private FlowCommentDto comment; |
|||
|
|||
@ApiModelProperty("候选执行人") |
|||
private String candidate; |
|||
|
|||
@ApiModelProperty("任务创建时间") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private Date createTime; |
|||
|
|||
@ApiModelProperty("任务完成时间") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private Date finishTime; |
|||
|
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
package com.ruoyi.flowable.domain.dto; |
|||
|
|||
import lombok.Data; |
|||
|
|||
import java.io.Serializable; |
|||
|
|||
/** |
|||
* @author Xuan xuan |
|||
* @date 2021/4/21 20:55 |
|||
*/ |
|||
@Data |
|||
public class FlowViewerDto implements Serializable { |
|||
|
|||
/** |
|||
* 流程key |
|||
*/ |
|||
private String key; |
|||
|
|||
/** |
|||
* 是否完成(已经审批) |
|||
*/ |
|||
private boolean completed; |
|||
} |
|||
@ -0,0 +1,46 @@ |
|||
package com.ruoyi.flowable.domain.vo; |
|||
|
|||
import io.swagger.annotations.ApiModel; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* <p>流程任务<p> |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Data |
|||
@ApiModel("工作流任务相关--请求参数") |
|||
public class FlowTaskVo { |
|||
|
|||
@ApiModelProperty("任务Id") |
|||
private String taskId; |
|||
|
|||
@ApiModelProperty("用户Id") |
|||
private String userId; |
|||
|
|||
@ApiModelProperty("任务意见") |
|||
private String comment; |
|||
|
|||
@ApiModelProperty("流程实例Id") |
|||
private String instanceId; |
|||
|
|||
@ApiModelProperty("节点") |
|||
private String targetKey; |
|||
|
|||
@ApiModelProperty("流程变量信息") |
|||
private Map<String, Object> values; |
|||
|
|||
@ApiModelProperty("审批人") |
|||
private String assignee; |
|||
|
|||
@ApiModelProperty("候选人") |
|||
private List<String> candidateUsers; |
|||
|
|||
@ApiModelProperty("审批组") |
|||
private List<String> candidateGroups; |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
package com.ruoyi.flowable.domain.vo; |
|||
|
|||
import io.swagger.annotations.ApiModel; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* <p>可退回节点<p> |
|||
* |
|||
* @author tony |
|||
* @date 2022-04-23 11:01:52 |
|||
*/ |
|||
@Data |
|||
@ApiModel("可退回节点") |
|||
public class ReturnTaskNodeVo { |
|||
|
|||
@ApiModelProperty("任务Id") |
|||
private String id; |
|||
|
|||
@ApiModelProperty("用户Id") |
|||
private String name; |
|||
|
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
package com.ruoyi.flowable.factory; |
|||
|
|||
import lombok.Getter; |
|||
import org.flowable.engine.*; |
|||
import org.springframework.beans.factory.annotation.Qualifier; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
import javax.annotation.Resource; |
|||
|
|||
/** |
|||
* flowable 引擎注入封装 |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Component |
|||
@Getter |
|||
public class FlowServiceFactory { |
|||
|
|||
@Resource |
|||
protected RepositoryService repositoryService; |
|||
|
|||
@Resource |
|||
protected RuntimeService runtimeService; |
|||
|
|||
@Resource |
|||
protected IdentityService identityService; |
|||
|
|||
@Resource |
|||
protected TaskService taskService; |
|||
|
|||
@Resource |
|||
protected FormService formService; |
|||
|
|||
@Resource |
|||
protected HistoryService historyService; |
|||
|
|||
@Resource |
|||
protected ManagementService managementService; |
|||
|
|||
@Qualifier("processEngine") |
|||
@Resource |
|||
protected ProcessEngine processEngine; |
|||
|
|||
} |
|||
@ -0,0 +1,370 @@ |
|||
package com.ruoyi.flowable.flow; |
|||
|
|||
import org.flowable.bpmn.model.AssociationDirection; |
|||
import org.flowable.bpmn.model.GraphicInfo; |
|||
import org.flowable.image.impl.DefaultProcessDiagramCanvas; |
|||
import org.flowable.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.Ellipse2D; |
|||
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; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021/4/4 23:58 |
|||
*/ |
|||
public class CustomProcessDiagramCanvas extends DefaultProcessDiagramCanvas { |
|||
//定义走过流程连线颜色为绿色
|
|||
protected static Color HIGHLIGHT_SequenceFlow_COLOR = Color.GREEN; |
|||
//设置未走过流程的连接线颜色
|
|||
protected static Color CONNECTION_COLOR = Color.BLACK; |
|||
//设置flows连接线字体颜色red
|
|||
protected static Color LABEL_COLOR = new Color(0, 0, 0); |
|||
//高亮显示task框颜色
|
|||
protected static Color HIGHLIGHT_COLOR = Color.GREEN; |
|||
protected static Color HIGHLIGHT_COLOR1 = Color.RED; |
|||
|
|||
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); |
|||
this.initialize(imageType); |
|||
} |
|||
|
|||
/** |
|||
* 重写绘制连线的方式,设置绘制颜色 |
|||
* @param xPoints |
|||
* @param yPoints |
|||
* @param conditional |
|||
* @param isDefault |
|||
* @param connectionType |
|||
* @param associationDirection |
|||
* @param highLighted |
|||
* @param scaleFactor |
|||
*/ |
|||
@Override |
|||
public void drawConnection(int[] xPoints, int[] yPoints, boolean conditional, boolean isDefault, String connectionType, AssociationDirection associationDirection, boolean highLighted, double scaleFactor) { |
|||
Paint originalPaint = this.g.getPaint(); |
|||
Stroke originalStroke = this.g.getStroke(); |
|||
this.g.setPaint(CONNECTION_COLOR); |
|||
if (connectionType.equals("association")) { |
|||
this.g.setStroke(ASSOCIATION_STROKE); |
|||
} else if (highLighted) { |
|||
this.g.setPaint(HIGHLIGHT_SequenceFlow_COLOR); |
|||
this.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]; |
|||
java.awt.geom.Line2D.Double line = new java.awt.geom.Line2D.Double((double) sourceX, (double) sourceY, (double) targetX, (double) targetY); |
|||
this.g.draw(line); |
|||
} |
|||
|
|||
java.awt.geom.Line2D.Double line; |
|||
if (isDefault) { |
|||
line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]); |
|||
this.drawDefaultSequenceFlowIndicator(line, scaleFactor); |
|||
} |
|||
|
|||
if (conditional) { |
|||
line = new java.awt.geom.Line2D.Double((double) xPoints[0], (double) yPoints[0], (double) xPoints[1], (double) yPoints[1]); |
|||
this.drawConditionalSequenceFlowIndicator(line, scaleFactor); |
|||
} |
|||
|
|||
if (associationDirection.equals(AssociationDirection.ONE) || associationDirection.equals(AssociationDirection.BOTH)) { |
|||
line = new java.awt.geom.Line2D.Double((double) xPoints[xPoints.length - 2], (double) yPoints[xPoints.length - 2], (double) xPoints[xPoints.length - 1], (double) yPoints[xPoints.length - 1]); |
|||
this.drawArrowHead(line, scaleFactor); |
|||
} |
|||
|
|||
if (associationDirection.equals(AssociationDirection.BOTH)) { |
|||
line = new java.awt.geom.Line2D.Double((double) xPoints[1], (double) yPoints[1], (double) xPoints[0], (double) yPoints[0]); |
|||
this.drawArrowHead(line, scaleFactor); |
|||
} |
|||
|
|||
this.g.setPaint(originalPaint); |
|||
this.g.setStroke(originalStroke); |
|||
} |
|||
|
|||
/** |
|||
* 设置字体大小图标颜色 |
|||
* @param imageType |
|||
*/ |
|||
@Override |
|||
public void initialize(String imageType) { |
|||
if ("png".equalsIgnoreCase(imageType)) { |
|||
this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 2); |
|||
} else { |
|||
this.processDiagram = new BufferedImage(this.canvasWidth, this.canvasHeight, 1); |
|||
} |
|||
|
|||
this.g = this.processDiagram.createGraphics(); |
|||
if (!"png".equalsIgnoreCase(imageType)) { |
|||
this.g.setBackground(new Color(255, 255, 255, 0)); |
|||
this.g.clearRect(0, 0, this.canvasWidth, this.canvasHeight); |
|||
} |
|||
|
|||
this.g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); |
|||
//修改图标颜色,修改图标字体大小
|
|||
this.g.setPaint(Color.black); |
|||
Font font = new Font(this.activityFontName, 10, 14); |
|||
this.g.setFont(font); |
|||
this.fontMetrics = this.g.getFontMetrics(); |
|||
//修改连接线字体大小
|
|||
LABEL_FONT = new Font(this.labelFontName, 10, 15); |
|||
ANNOTATION_FONT = new Font(this.annotationFontName, 0, 11); |
|||
|
|||
try { |
|||
USERTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/userTask.png", this.customClassLoader)); |
|||
SCRIPTTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/scriptTask.png", this.customClassLoader)); |
|||
SERVICETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/serviceTask.png", this.customClassLoader)); |
|||
RECEIVETASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/receiveTask.png", this.customClassLoader)); |
|||
SENDTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/sendTask.png", this.customClassLoader)); |
|||
MANUALTASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/manualTask.png", this.customClassLoader)); |
|||
BUSINESS_RULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/businessRuleTask.png", this.customClassLoader)); |
|||
SHELL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/shellTask.png", this.customClassLoader)); |
|||
DMN_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/dmnTask.png", this.customClassLoader)); |
|||
CAMEL_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/camelTask.png", this.customClassLoader)); |
|||
MULE_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/muleTask.png", this.customClassLoader)); |
|||
HTTP_TASK_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/httpTask.png", this.customClassLoader)); |
|||
TIMER_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/timer.png", this.customClassLoader)); |
|||
COMPENSATE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate-throw.png", this.customClassLoader)); |
|||
COMPENSATE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/compensate.png", this.customClassLoader)); |
|||
ERROR_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error-throw.png", this.customClassLoader)); |
|||
ERROR_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/error.png", this.customClassLoader)); |
|||
MESSAGE_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message-throw.png", this.customClassLoader)); |
|||
MESSAGE_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/message.png", this.customClassLoader)); |
|||
SIGNAL_THROW_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal-throw.png", this.customClassLoader)); |
|||
SIGNAL_CATCH_IMAGE = ImageIO.read(ReflectUtil.getResource("org/flowable/icons/signal.png", this.customClassLoader)); |
|||
} catch (IOException var4) { |
|||
LOGGER.warn("Could not load image for process diagram creation: {}", var4.getMessage()); |
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 设置连接线字体 |
|||
* @param text |
|||
* @param graphicInfo |
|||
* @param centered |
|||
*/ |
|||
@Override |
|||
public void drawLabel(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(); |
|||
|
|||
g.setPaint(LABEL_COLOR); |
|||
g.setFont(LABEL_FONT); |
|||
|
|||
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); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 高亮显示task框完成的 |
|||
* @param x |
|||
* @param y |
|||
* @param width |
|||
* @param height |
|||
*/ |
|||
@Override |
|||
public void drawHighLight(int x, int y, int width, int height) { |
|||
Paint originalPaint = g.getPaint(); |
|||
Stroke originalStroke = g.getStroke(); |
|||
|
|||
g.setPaint(HIGHLIGHT_COLOR); |
|||
g.setStroke(THICK_TASK_BORDER_STROKE); |
|||
|
|||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); |
|||
g.draw(rect); |
|||
|
|||
g.setPaint(originalPaint); |
|||
g.setStroke(originalStroke); |
|||
} |
|||
|
|||
/** |
|||
* 自定义task框当前的位置 |
|||
* @param x |
|||
* @param y |
|||
* @param width |
|||
* @param height |
|||
*/ |
|||
public void drawHighLightNow(int x, int y, int width, int height) { |
|||
Paint originalPaint = g.getPaint(); |
|||
Stroke originalStroke = g.getStroke(); |
|||
|
|||
g.setPaint(HIGHLIGHT_COLOR1); |
|||
g.setStroke(THICK_TASK_BORDER_STROKE); |
|||
|
|||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); |
|||
g.draw(rect); |
|||
|
|||
g.setPaint(originalPaint); |
|||
g.setStroke(originalStroke); |
|||
} |
|||
|
|||
/** |
|||
* 自定义结束节点 |
|||
* @param x |
|||
* @param y |
|||
* @param width |
|||
* @param height |
|||
*/ |
|||
public void drawHighLightEnd(int x, int y, int width, int height) { |
|||
Paint originalPaint = g.getPaint(); |
|||
Stroke originalStroke = g.getStroke(); |
|||
|
|||
g.setPaint(HIGHLIGHT_COLOR); |
|||
g.setStroke(THICK_TASK_BORDER_STROKE); |
|||
|
|||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, 20, 20); |
|||
g.draw(rect); |
|||
|
|||
g.setPaint(originalPaint); |
|||
g.setStroke(originalStroke); |
|||
} |
|||
|
|||
/** |
|||
* task框自定义文字 |
|||
* @param name |
|||
* @param graphicInfo |
|||
* @param thickBorder |
|||
* @param scaleFactor |
|||
*/ |
|||
@Override |
|||
protected void drawTask(String name, GraphicInfo graphicInfo, boolean thickBorder, double scaleFactor) { |
|||
|
|||
Paint originalPaint = g.getPaint(); |
|||
int x = (int) graphicInfo.getX(); |
|||
int y = (int) graphicInfo.getY(); |
|||
int width = (int) graphicInfo.getWidth(); |
|||
int height = (int) graphicInfo.getHeight(); |
|||
|
|||
// Create a new gradient paint for every task box, gradient depends on x and y and is not relative
|
|||
g.setPaint(TASK_BOX_COLOR); |
|||
|
|||
int arcR = 6; |
|||
if (thickBorder) { |
|||
arcR = 3; |
|||
} |
|||
|
|||
// shape
|
|||
RoundRectangle2D rect = new RoundRectangle2D.Double(x, y, width, height, arcR, arcR); |
|||
g.fill(rect); |
|||
g.setPaint(TASK_BORDER_COLOR); |
|||
|
|||
if (thickBorder) { |
|||
Stroke originalStroke = g.getStroke(); |
|||
g.setStroke(THICK_TASK_BORDER_STROKE); |
|||
g.draw(rect); |
|||
g.setStroke(originalStroke); |
|||
} else { |
|||
g.draw(rect); |
|||
} |
|||
|
|||
g.setPaint(originalPaint); |
|||
// text
|
|||
if (scaleFactor == 1.0 && name != null && name.length() > 0) { |
|||
int boxWidth = width - (2 * TEXT_PADDING); |
|||
int boxHeight = height - 16 - ICON_PADDING - ICON_PADDING - MARKER_WIDTH - 2 - 2; |
|||
int boxX = x + width / 2 - boxWidth / 2; |
|||
int boxY = y + height / 2 - boxHeight / 2 + ICON_PADDING + ICON_PADDING - 2 - 2; |
|||
|
|||
drawMultilineCentredText(name, boxX, boxY, boxWidth, boxHeight); |
|||
} |
|||
} |
|||
|
|||
protected static Color EVENT_COLOR = new Color(255, 255, 255); |
|||
|
|||
/** |
|||
* 重写开始事件 |
|||
* @param graphicInfo |
|||
* @param image |
|||
* @param scaleFactor |
|||
*/ |
|||
@Override |
|||
public void drawStartEvent(GraphicInfo graphicInfo, BufferedImage image, double scaleFactor) { |
|||
Paint originalPaint = g.getPaint(); |
|||
g.setPaint(EVENT_COLOR); |
|||
Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), |
|||
graphicInfo.getWidth(), graphicInfo.getHeight()); |
|||
g.fill(circle); |
|||
g.setPaint(EVENT_BORDER_COLOR); |
|||
g.draw(circle); |
|||
g.setPaint(originalPaint); |
|||
if (image != null) { |
|||
// calculate coordinates to center image
|
|||
int imageX = (int) Math.round(graphicInfo.getX() + (graphicInfo.getWidth() / 2) - (image.getWidth() / (2 * scaleFactor))); |
|||
int imageY = (int) Math.round(graphicInfo.getY() + (graphicInfo.getHeight() / 2) - (image.getHeight() / (2 * scaleFactor))); |
|||
g.drawImage(image, imageX, imageY, |
|||
(int) (image.getWidth() / scaleFactor), (int) (image.getHeight() / scaleFactor), null); |
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 重写结束事件 |
|||
* @param graphicInfo |
|||
* @param scaleFactor |
|||
*/ |
|||
@Override |
|||
public void drawNoneEndEvent(GraphicInfo graphicInfo, double scaleFactor) { |
|||
Paint originalPaint = g.getPaint(); |
|||
Stroke originalStroke = g.getStroke(); |
|||
g.setPaint(EVENT_COLOR); |
|||
Ellipse2D circle = new Ellipse2D.Double(graphicInfo.getX(), graphicInfo.getY(), |
|||
graphicInfo.getWidth(), graphicInfo.getHeight()); |
|||
g.fill(circle); |
|||
g.setPaint(EVENT_BORDER_COLOR); |
|||
// g.setPaint(HIGHLIGHT_COLOR);
|
|||
if (scaleFactor == 1.0) { |
|||
g.setStroke(END_EVENT_STROKE); |
|||
} else { |
|||
g.setStroke(new BasicStroke(2.0f)); |
|||
} |
|||
g.draw(circle); |
|||
g.setStroke(originalStroke); |
|||
g.setPaint(originalPaint); |
|||
} |
|||
} |
|||
@ -0,0 +1,404 @@ |
|||
package com.ruoyi.flowable.flow; |
|||
|
|||
|
|||
import org.flowable.bpmn.model.Process; |
|||
import org.flowable.bpmn.model.*; |
|||
import org.flowable.image.impl.DefaultProcessDiagramCanvas; |
|||
import org.flowable.image.impl.DefaultProcessDiagramGenerator; |
|||
|
|||
import java.util.Iterator; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021/4/5 0:31 |
|||
*/ |
|||
public class CustomProcessDiagramGenerator extends DefaultProcessDiagramGenerator { |
|||
@Override |
|||
protected DefaultProcessDiagramCanvas generateProcessDiagram(BpmnModel bpmnModel, String imageType, List<String> highLightedActivities, List<String> highLightedFlows, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader, double scaleFactor, boolean drawSequenceFlowNameWithNoLabelDI) { |
|||
this.prepareBpmnModel(bpmnModel); |
|||
DefaultProcessDiagramCanvas processDiagramCanvas = initProcessDiagramCanvas(bpmnModel, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); |
|||
Iterator var13 = bpmnModel.getPools().iterator(); |
|||
|
|||
while (var13.hasNext()) { |
|||
Pool process = (Pool) var13.next(); |
|||
GraphicInfo subProcesses = bpmnModel.getGraphicInfo(process.getId()); |
|||
processDiagramCanvas.drawPoolOrLane(process.getName(), subProcesses, scaleFactor); |
|||
} |
|||
|
|||
var13 = bpmnModel.getProcesses().iterator(); |
|||
|
|||
Process process1; |
|||
Iterator subProcesses1; |
|||
while (var13.hasNext()) { |
|||
process1 = (Process) var13.next(); |
|||
subProcesses1 = process1.getLanes().iterator(); |
|||
|
|||
while (subProcesses1.hasNext()) { |
|||
Lane artifact = (Lane) subProcesses1.next(); |
|||
GraphicInfo subProcess = bpmnModel.getGraphicInfo(artifact.getId()); |
|||
processDiagramCanvas.drawPoolOrLane(artifact.getName(), subProcess, scaleFactor); |
|||
} |
|||
} |
|||
|
|||
var13 = bpmnModel.getProcesses().iterator(); |
|||
|
|||
while (var13.hasNext()) { |
|||
process1 = (Process) var13.next(); |
|||
subProcesses1 = process1.findFlowElementsOfType(FlowNode.class).iterator(); |
|||
|
|||
while (subProcesses1.hasNext()) { |
|||
FlowNode artifact1 = (FlowNode) subProcesses1.next(); |
|||
if (!this.isPartOfCollapsedSubProcess(artifact1, bpmnModel)) { |
|||
this.drawActivity(processDiagramCanvas, bpmnModel, artifact1, highLightedActivities, highLightedFlows, scaleFactor, Boolean.valueOf(drawSequenceFlowNameWithNoLabelDI)); |
|||
} |
|||
} |
|||
} |
|||
|
|||
var13 = bpmnModel.getProcesses().iterator(); |
|||
|
|||
label75: |
|||
while (true) { |
|||
List subProcesses2; |
|||
do { |
|||
if (!var13.hasNext()) { |
|||
return processDiagramCanvas; |
|||
} |
|||
|
|||
process1 = (Process) var13.next(); |
|||
subProcesses1 = process1.getArtifacts().iterator(); |
|||
|
|||
while (subProcesses1.hasNext()) { |
|||
Artifact artifact2 = (Artifact) subProcesses1.next(); |
|||
this.drawArtifact(processDiagramCanvas, bpmnModel, artifact2); |
|||
} |
|||
|
|||
subProcesses2 = process1.findFlowElementsOfType(SubProcess.class, true); |
|||
} while (subProcesses2 == null); |
|||
|
|||
Iterator artifact3 = subProcesses2.iterator(); |
|||
|
|||
while (true) { |
|||
GraphicInfo graphicInfo; |
|||
SubProcess subProcess1; |
|||
do { |
|||
do { |
|||
if (!artifact3.hasNext()) { |
|||
continue label75; |
|||
} |
|||
|
|||
subProcess1 = (SubProcess) artifact3.next(); |
|||
graphicInfo = bpmnModel.getGraphicInfo(subProcess1.getId()); |
|||
} while (graphicInfo != null && graphicInfo.getExpanded() != null && !graphicInfo.getExpanded().booleanValue()); |
|||
} while (this.isPartOfCollapsedSubProcess(subProcess1, bpmnModel)); |
|||
|
|||
Iterator var19 = subProcess1.getArtifacts().iterator(); |
|||
|
|||
while (var19.hasNext()) { |
|||
Artifact subProcessArtifact = (Artifact) var19.next(); |
|||
this.drawArtifact(processDiagramCanvas, bpmnModel, subProcessArtifact); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected static DefaultProcessDiagramCanvas initProcessDiagramCanvas(BpmnModel bpmnModel, String imageType, String activityFontName, String labelFontName, String annotationFontName, ClassLoader customClassLoader) { |
|||
double minX = 1.7976931348623157E308D; |
|||
double maxX = 0.0D; |
|||
double minY = 1.7976931348623157E308D; |
|||
double maxY = 0.0D; |
|||
|
|||
GraphicInfo nrOfLanes; |
|||
for (Iterator flowNodes = bpmnModel.getPools().iterator(); flowNodes.hasNext(); maxY = nrOfLanes.getY() + nrOfLanes.getHeight()) { |
|||
Pool artifacts = (Pool) flowNodes.next(); |
|||
nrOfLanes = bpmnModel.getGraphicInfo(artifacts.getId()); |
|||
minX = nrOfLanes.getX(); |
|||
maxX = nrOfLanes.getX() + nrOfLanes.getWidth(); |
|||
minY = nrOfLanes.getY(); |
|||
} |
|||
|
|||
List var23 = gatherAllFlowNodes(bpmnModel); |
|||
Iterator var24 = var23.iterator(); |
|||
|
|||
label155: |
|||
while (var24.hasNext()) { |
|||
FlowNode var26 = (FlowNode) var24.next(); |
|||
GraphicInfo artifact = bpmnModel.getGraphicInfo(var26.getId()); |
|||
if (artifact.getX() + artifact.getWidth() > maxX) { |
|||
maxX = artifact.getX() + artifact.getWidth(); |
|||
} |
|||
|
|||
if (artifact.getX() < minX) { |
|||
minX = artifact.getX(); |
|||
} |
|||
|
|||
if (artifact.getY() + artifact.getHeight() > maxY) { |
|||
maxY = artifact.getY() + artifact.getHeight(); |
|||
} |
|||
|
|||
if (artifact.getY() < minY) { |
|||
minY = artifact.getY(); |
|||
} |
|||
|
|||
Iterator process = var26.getOutgoingFlows().iterator(); |
|||
|
|||
while (true) { |
|||
List l; |
|||
do { |
|||
if (!process.hasNext()) { |
|||
continue label155; |
|||
} |
|||
|
|||
SequenceFlow graphicInfoList = (SequenceFlow) process.next(); |
|||
l = bpmnModel.getFlowLocationGraphicInfo(graphicInfoList.getId()); |
|||
} while (l == null); |
|||
|
|||
Iterator graphicInfo = l.iterator(); |
|||
|
|||
while (graphicInfo.hasNext()) { |
|||
GraphicInfo graphicInfo1 = (GraphicInfo) graphicInfo.next(); |
|||
if (graphicInfo1.getX() > maxX) { |
|||
maxX = graphicInfo1.getX(); |
|||
} |
|||
|
|||
if (graphicInfo1.getX() < minX) { |
|||
minX = graphicInfo1.getX(); |
|||
} |
|||
|
|||
if (graphicInfo1.getY() > maxY) { |
|||
maxY = graphicInfo1.getY(); |
|||
} |
|||
|
|||
if (graphicInfo1.getY() < minY) { |
|||
minY = graphicInfo1.getY(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
List var25 = gatherAllArtifacts(bpmnModel); |
|||
Iterator var27 = var25.iterator(); |
|||
|
|||
GraphicInfo var37; |
|||
while (var27.hasNext()) { |
|||
Artifact var29 = (Artifact) var27.next(); |
|||
GraphicInfo var31 = bpmnModel.getGraphicInfo(var29.getId()); |
|||
if (var31 != null) { |
|||
if (var31.getX() + var31.getWidth() > maxX) { |
|||
maxX = var31.getX() + var31.getWidth(); |
|||
} |
|||
|
|||
if (var31.getX() < minX) { |
|||
minX = var31.getX(); |
|||
} |
|||
|
|||
if (var31.getY() + var31.getHeight() > maxY) { |
|||
maxY = var31.getY() + var31.getHeight(); |
|||
} |
|||
|
|||
if (var31.getY() < minY) { |
|||
minY = var31.getY(); |
|||
} |
|||
} |
|||
|
|||
List var33 = bpmnModel.getFlowLocationGraphicInfo(var29.getId()); |
|||
if (var33 != null) { |
|||
Iterator var35 = var33.iterator(); |
|||
|
|||
while (var35.hasNext()) { |
|||
var37 = (GraphicInfo) var35.next(); |
|||
if (var37.getX() > maxX) { |
|||
maxX = var37.getX(); |
|||
} |
|||
|
|||
if (var37.getX() < minX) { |
|||
minX = var37.getX(); |
|||
} |
|||
|
|||
if (var37.getY() > maxY) { |
|||
maxY = var37.getY(); |
|||
} |
|||
|
|||
if (var37.getY() < minY) { |
|||
minY = var37.getY(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
int var28 = 0; |
|||
Iterator var30 = bpmnModel.getProcesses().iterator(); |
|||
|
|||
while (var30.hasNext()) { |
|||
Process var32 = (Process) var30.next(); |
|||
Iterator var34 = var32.getLanes().iterator(); |
|||
|
|||
while (var34.hasNext()) { |
|||
Lane var36 = (Lane) var34.next(); |
|||
++var28; |
|||
var37 = bpmnModel.getGraphicInfo(var36.getId()); |
|||
if (var37.getX() + var37.getWidth() > maxX) { |
|||
maxX = var37.getX() + var37.getWidth(); |
|||
} |
|||
|
|||
if (var37.getX() < minX) { |
|||
minX = var37.getX(); |
|||
} |
|||
|
|||
if (var37.getY() + var37.getHeight() > maxY) { |
|||
maxY = var37.getY() + var37.getHeight(); |
|||
} |
|||
|
|||
if (var37.getY() < minY) { |
|||
minY = var37.getY(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
if (var23.isEmpty() && bpmnModel.getPools().isEmpty() && var28 == 0) { |
|||
minX = 0.0D; |
|||
minY = 0.0D; |
|||
} |
|||
|
|||
return new CustomProcessDiagramCanvas((int) maxX + 10, (int) maxY + 10, (int) minX, (int) minY, imageType, activityFontName, labelFontName, annotationFontName, customClassLoader); |
|||
} |
|||
|
|||
|
|||
private static void drawHighLight(DefaultProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { |
|||
processDiagramCanvas.drawHighLight((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); |
|||
|
|||
} |
|||
|
|||
private static void drawHighLightNow(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { |
|||
processDiagramCanvas.drawHighLightNow((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); |
|||
|
|||
} |
|||
|
|||
private static void drawHighLightEnd(CustomProcessDiagramCanvas processDiagramCanvas, GraphicInfo graphicInfo) { |
|||
processDiagramCanvas.drawHighLightEnd((int) graphicInfo.getX(), (int) graphicInfo.getY(), (int) graphicInfo.getWidth(), (int) graphicInfo.getHeight()); |
|||
|
|||
} |
|||
|
|||
@Override |
|||
protected void drawActivity(DefaultProcessDiagramCanvas processDiagramCanvas, BpmnModel bpmnModel, |
|||
FlowNode flowNode, java.util.List<String> highLightedActivities, java.util.List<String> highLightedFlows, double scaleFactor, Boolean drawSequenceFlowNameWithNoLabelDI) { |
|||
|
|||
DefaultProcessDiagramGenerator.ActivityDrawInstruction drawInstruction = activityDrawInstructions.get(flowNode.getClass()); |
|||
if (drawInstruction != null) { |
|||
|
|||
drawInstruction.draw(processDiagramCanvas, bpmnModel, flowNode); |
|||
|
|||
// Gather info on the multi instance marker
|
|||
boolean multiInstanceSequential = false; |
|||
boolean multiInstanceParallel = false; |
|||
boolean 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 (highLightedActivities.get(highLightedActivities.size() - 1).equals(flowNode.getId()) |
|||
&& !"endenv".equals(flowNode.getId())) { |
|||
if ((flowNode.getId().contains("Event_"))) { |
|||
drawHighLightEnd((CustomProcessDiagramCanvas) processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); |
|||
} else { |
|||
drawHighLightNow((CustomProcessDiagramCanvas) processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); |
|||
} |
|||
} else { |
|||
drawHighLight(processDiagramCanvas, bpmnModel.getGraphicInfo(flowNode.getId())); |
|||
} |
|||
|
|||
|
|||
} |
|||
|
|||
} |
|||
|
|||
// Outgoing transitions of activity
|
|||
for (SequenceFlow sequenceFlow : flowNode.getOutgoingFlows()) { |
|||
boolean highLighted = (highLightedFlows.contains(sequenceFlow.getId())); |
|||
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(sequenceFlow.getId())) { |
|||
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); |
|||
java.util.List<GraphicInfo> graphicInfoList = bpmnModel.getFlowLocationGraphicInfo(sequenceFlow.getId()); |
|||
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, drawConditionalIndicator, isDefault, highLighted, scaleFactor); |
|||
|
|||
|
|||
// Draw sequenceflow label
|
|||
GraphicInfo labelGraphicInfo = bpmnModel.getLabelGraphicInfo(sequenceFlow.getId()); |
|||
if (labelGraphicInfo != null) { |
|||
processDiagramCanvas.drawLabel(sequenceFlow.getName(), labelGraphicInfo, false); |
|||
} else { |
|||
if (drawSequenceFlowNameWithNoLabelDI) { |
|||
GraphicInfo lineCenter = getLineCenter(graphicInfoList); |
|||
processDiagramCanvas.drawLabel(sequenceFlow.getName(), lineCenter, false); |
|||
} |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
// Nested elements
|
|||
if (flowNode instanceof FlowElementsContainer) { |
|||
for (FlowElement nestedFlowElement : ((FlowElementsContainer) flowNode).getFlowElements()) { |
|||
if (nestedFlowElement instanceof FlowNode && !isPartOfCollapsedSubProcess(nestedFlowElement, bpmnModel)) { |
|||
drawActivity(processDiagramCanvas, bpmnModel, (FlowNode) nestedFlowElement, |
|||
highLightedActivities, highLightedFlows, scaleFactor, drawSequenceFlowNameWithNoLabelDI); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,226 @@ |
|||
package com.ruoyi.flowable.flow; |
|||
|
|||
import com.googlecode.aviator.AviatorEvaluator; |
|||
import com.googlecode.aviator.Expression; |
|||
//import com.greenpineyu.fel.FelEngine;
|
|||
//import com.greenpineyu.fel.FelEngineImpl;
|
|||
//import com.greenpineyu.fel.context.FelContext;
|
|||
import org.flowable.bpmn.model.Process; |
|||
import org.flowable.bpmn.model.*; |
|||
import org.flowable.engine.RepositoryService; |
|||
import org.flowable.engine.TaskService; |
|||
import org.flowable.engine.repository.ProcessDefinition; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Collection; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* @author Xuan xuan |
|||
* @date 2021/4/19 20:51 |
|||
*/ |
|||
public class FindNextNodeUtil { |
|||
|
|||
/** |
|||
* 获取下一步骤的用户任务 |
|||
* |
|||
* @param repositoryService |
|||
* @param map |
|||
* @return |
|||
*/ |
|||
public static List<UserTask> getNextUserTasks(RepositoryService repositoryService, org.flowable.task.api.Task task, Map<String, Object> map) { |
|||
List<UserTask> data = new ArrayList<>(); |
|||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); |
|||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); |
|||
Process mainProcess = bpmnModel.getMainProcess(); |
|||
Collection<FlowElement> flowElements = mainProcess.getFlowElements(); |
|||
String key = task.getTaskDefinitionKey(); |
|||
FlowElement flowElement = bpmnModel.getFlowElement(key); |
|||
next(flowElements, flowElement, map, data); |
|||
return data; |
|||
} |
|||
|
|||
public static void next(Collection<FlowElement> flowElements, FlowElement flowElement, Map<String, Object> map, List<UserTask> nextUser) { |
|||
//如果是结束节点
|
|||
if (flowElement instanceof EndEvent) { |
|||
//如果是子任务的结束节点
|
|||
if (getSubProcess(flowElements, flowElement) != null) { |
|||
flowElement = getSubProcess(flowElements, flowElement); |
|||
} |
|||
} |
|||
//获取Task的出线信息--可以拥有多个
|
|||
List<SequenceFlow> outGoingFlows = null; |
|||
if (flowElement instanceof Task) { |
|||
outGoingFlows = ((Task) flowElement).getOutgoingFlows(); |
|||
} else if (flowElement instanceof Gateway) { |
|||
outGoingFlows = ((Gateway) flowElement).getOutgoingFlows(); |
|||
} else if (flowElement instanceof StartEvent) { |
|||
outGoingFlows = ((StartEvent) flowElement).getOutgoingFlows(); |
|||
} else if (flowElement instanceof SubProcess) { |
|||
outGoingFlows = ((SubProcess) flowElement).getOutgoingFlows(); |
|||
} else if (flowElement instanceof CallActivity) { |
|||
outGoingFlows = ((CallActivity) flowElement).getOutgoingFlows(); |
|||
} |
|||
if (outGoingFlows != null && outGoingFlows.size() > 0) { |
|||
//遍历所有的出线--找到可以正确执行的那一条
|
|||
for (SequenceFlow sequenceFlow : outGoingFlows) { |
|||
//1.有表达式,且为true
|
|||
//2.无表达式
|
|||
String expression = sequenceFlow.getConditionExpression(); |
|||
if (expression == null || |
|||
expressionResult(map, expression.substring(expression.lastIndexOf("{") + 1, expression.lastIndexOf("}")))) { |
|||
//出线的下一节点
|
|||
String nextFlowElementID = sequenceFlow.getTargetRef(); |
|||
if (checkSubProcess(nextFlowElementID, flowElements, nextUser)) { |
|||
continue; |
|||
} |
|||
|
|||
//查询下一节点的信息
|
|||
FlowElement nextFlowElement = getFlowElementById(nextFlowElementID, flowElements); |
|||
//调用流程
|
|||
if (nextFlowElement instanceof CallActivity) { |
|||
CallActivity ca = (CallActivity) nextFlowElement; |
|||
if (ca.getLoopCharacteristics() != null) { |
|||
UserTask userTask = new UserTask(); |
|||
userTask.setId(ca.getId()); |
|||
|
|||
userTask.setId(ca.getId()); |
|||
userTask.setLoopCharacteristics(ca.getLoopCharacteristics()); |
|||
userTask.setName(ca.getName()); |
|||
nextUser.add(userTask); |
|||
} |
|||
next(flowElements, nextFlowElement, map, nextUser); |
|||
} |
|||
//用户任务
|
|||
if (nextFlowElement instanceof UserTask) { |
|||
nextUser.add((UserTask) nextFlowElement); |
|||
} |
|||
//排他网关
|
|||
else if (nextFlowElement instanceof ExclusiveGateway) { |
|||
next(flowElements, nextFlowElement, map, nextUser); |
|||
} |
|||
//并行网关
|
|||
else if (nextFlowElement instanceof ParallelGateway) { |
|||
next(flowElements, nextFlowElement, map, nextUser); |
|||
} |
|||
//接收任务
|
|||
else if (nextFlowElement instanceof ReceiveTask) { |
|||
next(flowElements, nextFlowElement, map, nextUser); |
|||
} |
|||
//服务任务
|
|||
else if (nextFlowElement instanceof ServiceTask) { |
|||
next(flowElements, nextFlowElement, map, nextUser); |
|||
} |
|||
//子任务的起点
|
|||
else if (nextFlowElement instanceof StartEvent) { |
|||
next(flowElements, nextFlowElement, map, nextUser); |
|||
} |
|||
//结束节点
|
|||
else if (nextFlowElement instanceof EndEvent) { |
|||
next(flowElements, nextFlowElement, map, nextUser); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 判断是否是多实例子流程并且需要设置集合类型变量 |
|||
*/ |
|||
public static boolean checkSubProcess(String Id, Collection<FlowElement> flowElements, List<UserTask> nextUser) { |
|||
for (FlowElement flowElement1 : flowElements) { |
|||
if (flowElement1 instanceof SubProcess && flowElement1.getId().equals(Id)) { |
|||
|
|||
SubProcess sp = (SubProcess) flowElement1; |
|||
if (sp.getLoopCharacteristics() != null) { |
|||
String inputDataItem = sp.getLoopCharacteristics().getInputDataItem(); |
|||
UserTask userTask = new UserTask(); |
|||
userTask.setId(sp.getId()); |
|||
userTask.setLoopCharacteristics(sp.getLoopCharacteristics()); |
|||
userTask.setName(sp.getName()); |
|||
nextUser.add(userTask); |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 查询一个节点的是否子任务中的节点,如果是,返回子任务 |
|||
* |
|||
* @param flowElements 全流程的节点集合 |
|||
* @param flowElement 当前节点 |
|||
* @return |
|||
*/ |
|||
public static FlowElement getSubProcess(Collection<FlowElement> flowElements, FlowElement flowElement) { |
|||
for (FlowElement flowElement1 : flowElements) { |
|||
if (flowElement1 instanceof SubProcess) { |
|||
for (FlowElement flowElement2 : ((SubProcess) flowElement1).getFlowElements()) { |
|||
if (flowElement.equals(flowElement2)) { |
|||
return flowElement1; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 根据ID查询流程节点对象, 如果是子任务,则返回子任务的开始节点 |
|||
* |
|||
* @param Id 节点ID |
|||
* @param flowElements 流程节点集合 |
|||
* @return |
|||
*/ |
|||
public static FlowElement getFlowElementById(String Id, Collection<FlowElement> flowElements) { |
|||
for (FlowElement flowElement : flowElements) { |
|||
if (flowElement.getId().equals(Id)) { |
|||
//如果是子任务,则查询出子任务的开始节点
|
|||
if (flowElement instanceof SubProcess) { |
|||
return getStartFlowElement(((SubProcess) flowElement).getFlowElements()); |
|||
} |
|||
return flowElement; |
|||
} |
|||
if (flowElement instanceof SubProcess) { |
|||
FlowElement flowElement1 = getFlowElementById(Id, ((SubProcess) flowElement).getFlowElements()); |
|||
if (flowElement1 != null) { |
|||
return flowElement1; |
|||
} |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 返回流程的开始节点 |
|||
* |
|||
* @param flowElements 节点集合 |
|||
* @description: |
|||
*/ |
|||
public static FlowElement getStartFlowElement(Collection<FlowElement> flowElements) { |
|||
for (FlowElement flowElement : flowElements) { |
|||
if (flowElement instanceof StartEvent) { |
|||
return flowElement; |
|||
} |
|||
} |
|||
return null; |
|||
} |
|||
|
|||
/** |
|||
* 校验el表达式 |
|||
* |
|||
* @param map |
|||
* @param expression |
|||
* @return |
|||
*/ |
|||
public static boolean expressionResult(Map<String, Object> map, String expression) { |
|||
Expression exp = AviatorEvaluator.compile(expression); |
|||
final Object execute = exp.execute(map); |
|||
return Boolean.parseBoolean(String.valueOf(execute)); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
package com.ruoyi.flowable.flow; |
|||
|
|||
import org.flowable.spring.SpringProcessEngineConfiguration; |
|||
import org.flowable.spring.boot.EngineConfigurationConfigurer; |
|||
import org.springframework.context.annotation.Configuration; |
|||
|
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021/4/5 01:32 |
|||
*/ |
|||
@Configuration |
|||
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> { |
|||
|
|||
@Override |
|||
public void configure(SpringProcessEngineConfiguration engineConfiguration) { |
|||
engineConfiguration.setActivityFontName("宋体"); |
|||
engineConfiguration.setLabelFontName("宋体"); |
|||
engineConfiguration.setAnnotationFontName("宋体"); |
|||
|
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,590 @@ |
|||
package com.ruoyi.flowable.flow; |
|||
|
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.flowable.bpmn.model.*; |
|||
import org.flowable.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior; |
|||
import org.flowable.engine.impl.bpmn.behavior.SequentialMultiInstanceBehavior; |
|||
import org.flowable.task.api.Task; |
|||
import org.flowable.task.api.history.HistoricTaskInstance; |
|||
|
|||
import java.util.*; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 23:57 |
|||
*/ |
|||
@Slf4j |
|||
public class FlowableUtils { |
|||
|
|||
/** |
|||
* 根据节点,获取入口连线 |
|||
* @param source |
|||
* @return |
|||
*/ |
|||
public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) { |
|||
List<SequenceFlow> sequenceFlows = null; |
|||
if (source instanceof FlowNode) { |
|||
sequenceFlows = ((FlowNode) source).getIncomingFlows(); |
|||
} else if (source instanceof Gateway) { |
|||
sequenceFlows = ((Gateway) source).getIncomingFlows(); |
|||
} else if (source instanceof SubProcess) { |
|||
sequenceFlows = ((SubProcess) source).getIncomingFlows(); |
|||
} else if (source instanceof StartEvent) { |
|||
sequenceFlows = ((StartEvent) source).getIncomingFlows(); |
|||
} else if (source instanceof EndEvent) { |
|||
sequenceFlows = ((EndEvent) source).getIncomingFlows(); |
|||
} |
|||
return sequenceFlows; |
|||
} |
|||
|
|||
/** |
|||
* 根据节点,获取出口连线 |
|||
* @param source |
|||
* @return |
|||
*/ |
|||
public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) { |
|||
List<SequenceFlow> sequenceFlows = null; |
|||
if (source instanceof FlowNode) { |
|||
sequenceFlows = ((FlowNode) source).getOutgoingFlows(); |
|||
} else if (source instanceof Gateway) { |
|||
sequenceFlows = ((Gateway) source).getOutgoingFlows(); |
|||
} else if (source instanceof SubProcess) { |
|||
sequenceFlows = ((SubProcess) source).getOutgoingFlows(); |
|||
} else if (source instanceof StartEvent) { |
|||
sequenceFlows = ((StartEvent) source).getOutgoingFlows(); |
|||
} else if (source instanceof EndEvent) { |
|||
sequenceFlows = ((EndEvent) source).getOutgoingFlows(); |
|||
} |
|||
return sequenceFlows; |
|||
} |
|||
|
|||
/** |
|||
* 获取全部节点列表,包含子流程节点 |
|||
* @param flowElements |
|||
* @param allElements |
|||
* @return |
|||
*/ |
|||
public static Collection<FlowElement> getAllElements(Collection<FlowElement> flowElements, Collection<FlowElement> allElements) { |
|||
allElements = allElements == null ? new ArrayList<>() : allElements; |
|||
|
|||
for (FlowElement flowElement : flowElements) { |
|||
allElements.add(flowElement); |
|||
if (flowElement instanceof SubProcess) { |
|||
// 继续深入子流程,进一步获取子流程
|
|||
allElements = FlowableUtils.getAllElements(((SubProcess) flowElement).getFlowElements(), allElements); |
|||
} |
|||
} |
|||
return allElements; |
|||
} |
|||
|
|||
/** |
|||
* 迭代获取父级任务节点列表,向前找 |
|||
* @param source 起始节点 |
|||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 |
|||
* @param userTaskList 已找到的用户任务节点 |
|||
* @return |
|||
*/ |
|||
public static List<UserTask> iteratorFindParentUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) { |
|||
userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; |
|||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; |
|||
|
|||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
|||
if (source instanceof StartEvent && source.getSubProcess() != null) { |
|||
userTaskList = iteratorFindParentUserTasks(source.getSubProcess(), hasSequenceFlow, userTaskList); |
|||
} |
|||
|
|||
// 根据类型,获取入口连线
|
|||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source); |
|||
|
|||
if (sequenceFlows != null) { |
|||
// 循环找到目标元素
|
|||
for (SequenceFlow sequenceFlow: sequenceFlows) { |
|||
// 如果发现连线重复,说明循环了,跳过这个循环
|
|||
if (hasSequenceFlow.contains(sequenceFlow.getId())) { |
|||
continue; |
|||
} |
|||
// 添加已经走过的连线
|
|||
hasSequenceFlow.add(sequenceFlow.getId()); |
|||
// 类型为用户节点,则新增父级节点
|
|||
if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { |
|||
userTaskList.add((UserTask) sequenceFlow.getSourceFlowElement()); |
|||
continue; |
|||
} |
|||
// 类型为子流程,则添加子流程开始节点出口处相连的节点
|
|||
if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) { |
|||
// 获取子流程用户任务节点
|
|||
List<UserTask> childUserTaskList = findChildProcessUserTasks((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, null); |
|||
// 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
|
|||
if (childUserTaskList != null && childUserTaskList.size() > 0) { |
|||
userTaskList.addAll(childUserTaskList); |
|||
continue; |
|||
} |
|||
} |
|||
// 继续迭代
|
|||
userTaskList = iteratorFindParentUserTasks(sequenceFlow.getSourceFlowElement(), hasSequenceFlow, userTaskList); |
|||
} |
|||
} |
|||
return userTaskList; |
|||
} |
|||
|
|||
/** |
|||
* 根据正在运行的任务节点,迭代获取子级任务节点列表,向后找 |
|||
* @param source 起始节点(退回节点) |
|||
* @param runTaskKeyList 正在运行的任务 Key,用于校验任务节点是否是正在运行的节点 |
|||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 |
|||
* @param userTaskList 需要撤回的用户任务列表 |
|||
* @return |
|||
*/ |
|||
public static List<UserTask> iteratorFindChildUserTasks(FlowElement source, List<String> runTaskKeyList, Set<String> hasSequenceFlow, List<UserTask> userTaskList) { |
|||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; |
|||
userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; |
|||
|
|||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
|||
if (source instanceof EndEvent && source.getSubProcess() != null) { |
|||
userTaskList = iteratorFindChildUserTasks(source.getSubProcess(), runTaskKeyList, hasSequenceFlow, userTaskList); |
|||
} |
|||
|
|||
// 根据类型,获取出口连线
|
|||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source); |
|||
|
|||
if (sequenceFlows != null) { |
|||
// 循环找到目标元素
|
|||
for (SequenceFlow sequenceFlow: sequenceFlows) { |
|||
// 如果发现连线重复,说明循环了,跳过这个循环
|
|||
if (hasSequenceFlow.contains(sequenceFlow.getId())) { |
|||
continue; |
|||
} |
|||
// 添加已经走过的连线
|
|||
hasSequenceFlow.add(sequenceFlow.getId()); |
|||
// 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
|
|||
if (sequenceFlow.getTargetFlowElement() instanceof UserTask && runTaskKeyList.contains((sequenceFlow.getTargetFlowElement()).getId())) { |
|||
userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); |
|||
continue; |
|||
} |
|||
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
|
|||
if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { |
|||
List<UserTask> childUserTaskList = iteratorFindChildUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), runTaskKeyList, hasSequenceFlow, null); |
|||
// 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
|
|||
if (childUserTaskList != null && childUserTaskList.size() > 0) { |
|||
userTaskList.addAll(childUserTaskList); |
|||
continue; |
|||
} |
|||
} |
|||
// 继续迭代
|
|||
userTaskList = iteratorFindChildUserTasks(sequenceFlow.getTargetFlowElement(), runTaskKeyList, hasSequenceFlow, userTaskList); |
|||
} |
|||
} |
|||
return userTaskList; |
|||
} |
|||
|
|||
/** |
|||
* 迭代获取子流程用户任务节点 |
|||
* @param source 起始节点 |
|||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 |
|||
* @param userTaskList 需要撤回的用户任务列表 |
|||
* @return |
|||
*/ |
|||
public static List<UserTask> findChildProcessUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) { |
|||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; |
|||
userTaskList = userTaskList == null ? new ArrayList<>() : userTaskList; |
|||
|
|||
// 根据类型,获取出口连线
|
|||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source); |
|||
|
|||
if (sequenceFlows != null) { |
|||
// 循环找到目标元素
|
|||
for (SequenceFlow sequenceFlow: sequenceFlows) { |
|||
// 如果发现连线重复,说明循环了,跳过这个循环
|
|||
if (hasSequenceFlow.contains(sequenceFlow.getId())) { |
|||
continue; |
|||
} |
|||
// 添加已经走过的连线
|
|||
hasSequenceFlow.add(sequenceFlow.getId()); |
|||
// 如果为用户任务类型,且任务节点的 Key 正在运行的任务中存在,添加
|
|||
if (sequenceFlow.getTargetFlowElement() instanceof UserTask) { |
|||
userTaskList.add((UserTask) sequenceFlow.getTargetFlowElement()); |
|||
continue; |
|||
} |
|||
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
|
|||
if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { |
|||
List<UserTask> childUserTaskList = findChildProcessUserTasks((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, null); |
|||
// 如果找到节点,则说明该线路找到节点,不继续向下找,反之继续
|
|||
if (childUserTaskList != null && childUserTaskList.size() > 0) { |
|||
userTaskList.addAll(childUserTaskList); |
|||
continue; |
|||
} |
|||
} |
|||
// 继续迭代
|
|||
userTaskList = findChildProcessUserTasks(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, userTaskList); |
|||
} |
|||
} |
|||
return userTaskList; |
|||
} |
|||
|
|||
/** |
|||
* 从后向前寻路,获取所有脏线路上的点 |
|||
* @param source 起始节点 |
|||
* @param passRoads 已经经过的点集合 |
|||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 |
|||
* @param targets 目标脏线路终点 |
|||
* @param dirtyRoads 确定为脏数据的点,因为不需要重复,因此使用 set 存储 |
|||
* @return |
|||
*/ |
|||
public static Set<String> iteratorFindDirtyRoads(FlowElement source, List<String> passRoads, Set<String> hasSequenceFlow, List<String> targets, Set<String> dirtyRoads) { |
|||
passRoads = passRoads == null ? new ArrayList<>() : passRoads; |
|||
dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads; |
|||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; |
|||
|
|||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
|||
if (source instanceof StartEvent && source.getSubProcess() != null) { |
|||
dirtyRoads = iteratorFindDirtyRoads(source.getSubProcess(), passRoads, hasSequenceFlow, targets, dirtyRoads); |
|||
} |
|||
|
|||
// 根据类型,获取入口连线
|
|||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source); |
|||
|
|||
if (sequenceFlows != null) { |
|||
// 循环找到目标元素
|
|||
for (SequenceFlow sequenceFlow: sequenceFlows) { |
|||
// 如果发现连线重复,说明循环了,跳过这个循环
|
|||
if (hasSequenceFlow.contains(sequenceFlow.getId())) { |
|||
continue; |
|||
} |
|||
// 添加已经走过的连线
|
|||
hasSequenceFlow.add(sequenceFlow.getId()); |
|||
// 新增经过的路线
|
|||
passRoads.add(sequenceFlow.getSourceFlowElement().getId()); |
|||
// 如果此点为目标点,确定经过的路线为脏线路,添加点到脏线路中,然后找下个连线
|
|||
if (targets.contains(sequenceFlow.getSourceFlowElement().getId())) { |
|||
dirtyRoads.addAll(passRoads); |
|||
continue; |
|||
} |
|||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
|||
if (sequenceFlow.getSourceFlowElement() instanceof SubProcess) { |
|||
dirtyRoads = findChildProcessAllDirtyRoad((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, dirtyRoads); |
|||
// 是否存在子流程上,true 是,false 否
|
|||
Boolean isInChildProcess = dirtyTargetInChildProcess((StartEvent) ((SubProcess) sequenceFlow.getSourceFlowElement()).getFlowElements().toArray()[0], null, targets, null); |
|||
if (isInChildProcess) { |
|||
// 已在子流程上找到,该路线结束
|
|||
continue; |
|||
} |
|||
} |
|||
// 继续迭代
|
|||
dirtyRoads = iteratorFindDirtyRoads(sequenceFlow.getSourceFlowElement(), passRoads, hasSequenceFlow, targets, dirtyRoads); |
|||
} |
|||
} |
|||
return dirtyRoads; |
|||
} |
|||
|
|||
/** |
|||
* 迭代获取子流程脏路线 |
|||
* 说明,假如回退的点就是子流程,那么也肯定会回退到子流程最初的用户任务节点,因此子流程中的节点全是脏路线 |
|||
* @param source 起始节点 |
|||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 |
|||
* @param dirtyRoads 确定为脏数据的点,因为不需要重复,因此使用 set 存储 |
|||
* @return |
|||
*/ |
|||
public static Set<String> findChildProcessAllDirtyRoad(FlowElement source, Set<String> hasSequenceFlow, Set<String> dirtyRoads) { |
|||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; |
|||
dirtyRoads = dirtyRoads == null ? new HashSet<>() : dirtyRoads; |
|||
|
|||
// 根据类型,获取出口连线
|
|||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source); |
|||
|
|||
if (sequenceFlows != null) { |
|||
// 循环找到目标元素
|
|||
for (SequenceFlow sequenceFlow: sequenceFlows) { |
|||
// 如果发现连线重复,说明循环了,跳过这个循环
|
|||
if (hasSequenceFlow.contains(sequenceFlow.getId())) { |
|||
continue; |
|||
} |
|||
// 添加已经走过的连线
|
|||
hasSequenceFlow.add(sequenceFlow.getId()); |
|||
// 添加脏路线
|
|||
dirtyRoads.add(sequenceFlow.getTargetFlowElement().getId()); |
|||
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
|
|||
if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { |
|||
dirtyRoads = findChildProcessAllDirtyRoad((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, dirtyRoads); |
|||
} |
|||
// 继续迭代
|
|||
dirtyRoads = findChildProcessAllDirtyRoad(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, dirtyRoads); |
|||
} |
|||
} |
|||
return dirtyRoads; |
|||
} |
|||
|
|||
/** |
|||
* 判断脏路线结束节点是否在子流程上 |
|||
* @param source 起始节点 |
|||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 |
|||
* @param targets 判断脏路线节点是否存在子流程上,只要存在一个,说明脏路线只到子流程为止 |
|||
* @param inChildProcess 是否存在子流程上,true 是,false 否 |
|||
* @return |
|||
*/ |
|||
public static Boolean dirtyTargetInChildProcess(FlowElement source, Set<String> hasSequenceFlow, List<String> targets, Boolean inChildProcess) { |
|||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; |
|||
inChildProcess = inChildProcess != null && inChildProcess; |
|||
|
|||
// 根据类型,获取出口连线
|
|||
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source); |
|||
|
|||
if (sequenceFlows != null && !inChildProcess) { |
|||
// 循环找到目标元素
|
|||
for (SequenceFlow sequenceFlow: sequenceFlows) { |
|||
// 如果发现连线重复,说明循环了,跳过这个循环
|
|||
if (hasSequenceFlow.contains(sequenceFlow.getId())) { |
|||
continue; |
|||
} |
|||
// 添加已经走过的连线
|
|||
hasSequenceFlow.add(sequenceFlow.getId()); |
|||
// 如果发现目标点在子流程上存在,说明只到子流程为止
|
|||
if (targets.contains(sequenceFlow.getTargetFlowElement().getId())) { |
|||
inChildProcess = true; |
|||
break; |
|||
} |
|||
// 如果节点为子流程节点情况,则从节点中的第一个节点开始获取
|
|||
if (sequenceFlow.getTargetFlowElement() instanceof SubProcess) { |
|||
inChildProcess = dirtyTargetInChildProcess((FlowElement) (((SubProcess) sequenceFlow.getTargetFlowElement()).getFlowElements().toArray()[0]), hasSequenceFlow, targets, inChildProcess); |
|||
} |
|||
// 继续迭代
|
|||
inChildProcess = dirtyTargetInChildProcess(sequenceFlow.getTargetFlowElement(), hasSequenceFlow, targets, inChildProcess); |
|||
} |
|||
} |
|||
return inChildProcess; |
|||
} |
|||
|
|||
/** |
|||
* 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行 |
|||
* 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况 |
|||
* @param source 起始节点 |
|||
* @param isSequential 是否串行 |
|||
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复 |
|||
* @param targetKsy 目标节点 |
|||
* @return |
|||
*/ |
|||
public static Boolean iteratorCheckSequentialReferTarget(FlowElement source, String targetKsy, Set<String> hasSequenceFlow, Boolean isSequential) { |
|||
isSequential = isSequential == null || isSequential; |
|||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; |
|||
|
|||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
|||
if (source instanceof StartEvent && source.getSubProcess() != null) { |
|||
isSequential = iteratorCheckSequentialReferTarget(source.getSubProcess(), targetKsy, hasSequenceFlow, isSequential); |
|||
} |
|||
|
|||
// 根据类型,获取入口连线
|
|||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source); |
|||
|
|||
if (sequenceFlows != null) { |
|||
// 循环找到目标元素
|
|||
for (SequenceFlow sequenceFlow: sequenceFlows) { |
|||
// 如果发现连线重复,说明循环了,跳过这个循环
|
|||
if (hasSequenceFlow.contains(sequenceFlow.getId())) { |
|||
continue; |
|||
} |
|||
// 添加已经走过的连线
|
|||
hasSequenceFlow.add(sequenceFlow.getId()); |
|||
// 如果目标节点已被判断为并行,后面都不需要执行,直接返回
|
|||
if (!isSequential) { |
|||
break; |
|||
} |
|||
// 这条线路存在目标节点,这条线路完成,进入下个线路
|
|||
if (targetKsy.equals(sequenceFlow.getSourceFlowElement().getId())) { |
|||
continue; |
|||
} |
|||
if (sequenceFlow.getSourceFlowElement() instanceof StartEvent) { |
|||
isSequential = false; |
|||
break; |
|||
} |
|||
// 否则就继续迭代
|
|||
isSequential = iteratorCheckSequentialReferTarget(sequenceFlow.getSourceFlowElement(), targetKsy, hasSequenceFlow, isSequential); |
|||
} |
|||
} |
|||
return isSequential; |
|||
} |
|||
|
|||
/** |
|||
* 从后向前寻路,获取到达节点的所有路线 |
|||
* 不存在直接回退到子流程,但是存在回退到父级流程的情况 |
|||
* @param source 起始节点 |
|||
* @param passRoads 已经经过的点集合 |
|||
* @param roads 路线 |
|||
* @return |
|||
*/ |
|||
public static List<List<UserTask>> findRoad(FlowElement source, List<UserTask> passRoads, Set<String> hasSequenceFlow, List<List<UserTask>> roads) { |
|||
passRoads = passRoads == null ? new ArrayList<>() : passRoads; |
|||
roads = roads == null ? new ArrayList<>() : roads; |
|||
hasSequenceFlow = hasSequenceFlow == null ? new HashSet<>() : hasSequenceFlow; |
|||
|
|||
// 如果该节点为开始节点,且存在上级子节点,则顺着上级子节点继续迭代
|
|||
if (source instanceof StartEvent && source.getSubProcess() != null) { |
|||
roads = findRoad(source.getSubProcess(), passRoads, hasSequenceFlow, roads); |
|||
} |
|||
|
|||
// 根据类型,获取入口连线
|
|||
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source); |
|||
|
|||
if (sequenceFlows != null && sequenceFlows.size() != 0) { |
|||
for (SequenceFlow sequenceFlow: sequenceFlows) { |
|||
// 如果发现连线重复,说明循环了,跳过这个循环
|
|||
if (hasSequenceFlow.contains(sequenceFlow.getId())) { |
|||
continue; |
|||
} |
|||
// 添加已经走过的连线
|
|||
hasSequenceFlow.add(sequenceFlow.getId()); |
|||
// 添加经过路线
|
|||
if (sequenceFlow.getSourceFlowElement() instanceof UserTask) { |
|||
passRoads.add((UserTask) sequenceFlow.getSourceFlowElement()); |
|||
} |
|||
// 继续迭代
|
|||
roads = findRoad(sequenceFlow.getSourceFlowElement(), passRoads, hasSequenceFlow, roads); |
|||
} |
|||
} else { |
|||
// 添加路线
|
|||
roads.add(passRoads); |
|||
} |
|||
return roads; |
|||
} |
|||
|
|||
/** |
|||
* 历史节点数据清洗,清洗掉又回滚导致的脏数据 |
|||
* @param allElements 全部节点信息 |
|||
* @param historicTaskInstanceList 历史任务实例信息,数据采用开始时间升序 |
|||
* @return |
|||
*/ |
|||
public static List<String> historicTaskInstanceClean(Collection<FlowElement> allElements, List<HistoricTaskInstance> historicTaskInstanceList) { |
|||
// 会签节点收集
|
|||
List<String> multiTask = new ArrayList<>(); |
|||
allElements.forEach(flowElement -> { |
|||
if (flowElement instanceof UserTask) { |
|||
// 如果该节点的行为为会签行为,说明该节点为会签节点
|
|||
if (((UserTask) flowElement).getBehavior() instanceof ParallelMultiInstanceBehavior || ((UserTask) flowElement).getBehavior() instanceof SequentialMultiInstanceBehavior) { |
|||
multiTask.add(flowElement.getId()); |
|||
} |
|||
} |
|||
}); |
|||
// 循环放入栈,栈 LIFO:后进先出
|
|||
Stack<HistoricTaskInstance> stack = new Stack<>(); |
|||
historicTaskInstanceList.forEach(stack::push); |
|||
// 清洗后的历史任务实例
|
|||
List<String> lastHistoricTaskInstanceList = new ArrayList<>(); |
|||
// 网关存在可能只走了部分分支情况,且还存在跳转废弃数据以及其他分支数据的干扰,因此需要对历史节点数据进行清洗
|
|||
// 临时用户任务 key
|
|||
StringBuilder userTaskKey = null; |
|||
// 临时被删掉的任务 key,存在并行情况
|
|||
List<String> deleteKeyList = new ArrayList<>(); |
|||
// 临时脏数据线路
|
|||
List<Set<String>> dirtyDataLineList = new ArrayList<>(); |
|||
// 由某个点跳到会签点,此时出现多个会签实例对应 1 个跳转情况,需要把这些连续脏数据都找到
|
|||
// 会签特殊处理下标
|
|||
int multiIndex = -1; |
|||
// 会签特殊处理 key
|
|||
StringBuilder multiKey = null; |
|||
// 会签特殊处理操作标识
|
|||
boolean multiOpera = false; |
|||
while (!stack.empty()) { |
|||
// 从这里开始 userTaskKey 都还是上个栈的 key
|
|||
// 是否是脏数据线路上的点
|
|||
final boolean[] isDirtyData = {false}; |
|||
for (Set<String> oldDirtyDataLine : dirtyDataLineList) { |
|||
if (oldDirtyDataLine.contains(stack.peek().getTaskDefinitionKey())) { |
|||
isDirtyData[0] = true; |
|||
} |
|||
} |
|||
// 删除原因不为空,说明从这条数据开始回跳或者回退的
|
|||
// MI_END:会签完成后,其他未签到节点的删除原因,不在处理范围内
|
|||
if (stack.peek().getDeleteReason() != null && !"MI_END".equals(stack.peek().getDeleteReason())) { |
|||
// 可以理解为脏线路起点
|
|||
String dirtyPoint = ""; |
|||
if (stack.peek().getDeleteReason().contains("Change activity to ")) { |
|||
dirtyPoint = stack.peek().getDeleteReason().replace("Change activity to ", ""); |
|||
} |
|||
// 会签回退删除原因有点不同
|
|||
if (stack.peek().getDeleteReason().contains("Change parent activity to ")) { |
|||
dirtyPoint = stack.peek().getDeleteReason().replace("Change parent activity to ", ""); |
|||
} |
|||
FlowElement dirtyTask = null; |
|||
// 获取变更节点的对应的入口处连线
|
|||
// 如果是网关并行回退情况,会变成两条脏数据路线,效果一样
|
|||
for (FlowElement flowElement : allElements) { |
|||
if (flowElement.getId().equals(stack.peek().getTaskDefinitionKey())) { |
|||
dirtyTask = flowElement; |
|||
} |
|||
} |
|||
// 获取脏数据线路
|
|||
Set<String> dirtyDataLine = FlowableUtils.iteratorFindDirtyRoads(dirtyTask, null, null, Arrays.asList(dirtyPoint.split(",")), null); |
|||
// 自己本身也是脏线路上的点,加进去
|
|||
dirtyDataLine.add(stack.peek().getTaskDefinitionKey()); |
|||
log.info(stack.peek().getTaskDefinitionKey() + "点脏路线集合:" + dirtyDataLine); |
|||
// 是全新的需要添加的脏线路
|
|||
boolean isNewDirtyData = true; |
|||
for (int i = 0; i < dirtyDataLineList.size(); i++) { |
|||
// 如果发现他的上个节点在脏线路内,说明这个点可能是并行的节点,或者连续驳回
|
|||
// 这时,都以之前的脏线路节点为标准,只需合并脏线路即可,也就是路线补全
|
|||
if (dirtyDataLineList.get(i).contains(userTaskKey.toString())) { |
|||
isNewDirtyData = false; |
|||
dirtyDataLineList.get(i).addAll(dirtyDataLine); |
|||
} |
|||
} |
|||
// 已确定时全新的脏线路
|
|||
if (isNewDirtyData) { |
|||
// deleteKey 单一路线驳回到并行,这种同时生成多个新实例记录情况,这时 deleteKey 其实是由多个值组成
|
|||
// 按照逻辑,回退后立刻生成的实例记录就是回退的记录
|
|||
// 至于驳回所生成的 Key,直接从删除原因中获取,因为存在驳回到并行的情况
|
|||
deleteKeyList.add(dirtyPoint + ","); |
|||
dirtyDataLineList.add(dirtyDataLine); |
|||
} |
|||
// 添加后,现在这个点变成脏线路上的点了
|
|||
isDirtyData[0] = true; |
|||
} |
|||
// 如果不是脏线路上的点,说明是有效数据,添加历史实例 Key
|
|||
if (!isDirtyData[0]) { |
|||
lastHistoricTaskInstanceList.add(stack.peek().getTaskDefinitionKey()); |
|||
} |
|||
// 校验脏线路是否结束
|
|||
for (int i = 0; i < deleteKeyList.size(); i ++) { |
|||
// 如果发现脏数据属于会签,记录下下标与对应 Key,以备后续比对,会签脏数据范畴开始
|
|||
if (multiKey == null && multiTask.contains(stack.peek().getTaskDefinitionKey()) |
|||
&& deleteKeyList.get(i).contains(stack.peek().getTaskDefinitionKey())) { |
|||
multiIndex = i; |
|||
multiKey = new StringBuilder(stack.peek().getTaskDefinitionKey()); |
|||
} |
|||
// 会签脏数据处理,节点退回会签清空
|
|||
// 如果在会签脏数据范畴中发现 Key改变,说明会签脏数据在上个节点就结束了,可以把会签脏数据删掉
|
|||
if (multiKey != null && !multiKey.toString().equals(stack.peek().getTaskDefinitionKey())) { |
|||
deleteKeyList.set(multiIndex , deleteKeyList.get(multiIndex).replace(stack.peek().getTaskDefinitionKey() + ",", "")); |
|||
multiKey = null; |
|||
// 结束进行下校验删除
|
|||
multiOpera = true; |
|||
} |
|||
// 其他脏数据处理
|
|||
// 发现该路线最后一条脏数据,说明这条脏数据线路处理完了,删除脏数据信息
|
|||
// 脏数据产生的新实例中是否包含这条数据
|
|||
if (multiKey == null && deleteKeyList.get(i).contains(stack.peek().getTaskDefinitionKey())) { |
|||
// 删除匹配到的部分
|
|||
deleteKeyList.set(i , deleteKeyList.get(i).replace(stack.peek().getTaskDefinitionKey() + ",", "")); |
|||
} |
|||
// 如果每组中的元素都以匹配过,说明脏数据结束
|
|||
if ("".equals(deleteKeyList.get(i))) { |
|||
// 同时删除脏数据
|
|||
deleteKeyList.remove(i); |
|||
dirtyDataLineList.remove(i); |
|||
break; |
|||
} |
|||
} |
|||
// 会签数据处理需要在循环外处理,否则可能导致溢出
|
|||
// 会签的数据肯定是之前放进去的所以理论上不会溢出,但还是校验下
|
|||
if (multiOpera && deleteKeyList.size() > multiIndex && "".equals(deleteKeyList.get(multiIndex))) { |
|||
// 同时删除脏数据
|
|||
deleteKeyList.remove(multiIndex); |
|||
dirtyDataLineList.remove(multiIndex); |
|||
multiIndex = -1; |
|||
multiOpera = false; |
|||
} |
|||
// pop() 方法与 peek() 方法不同,在返回值的同时,会把值从栈中移除
|
|||
// 保存新的 userTaskKey 在下个循环中使用
|
|||
userTaskKey = new StringBuilder(stack.pop().getTaskDefinitionKey()); |
|||
} |
|||
log.info("清洗后的历史节点数据:" + lastHistoricTaskInstanceList); |
|||
return lastHistoricTaskInstanceList; |
|||
} |
|||
} |
|||
@ -0,0 +1,18 @@ |
|||
package com.ruoyi.flowable.listener; |
|||
|
|||
import org.flowable.engine.delegate.TaskListener; |
|||
import org.flowable.task.service.delegate.DelegateTask; |
|||
import org.springframework.stereotype.Component; |
|||
|
|||
/** |
|||
* @author Xuan xuan |
|||
* @date 2021/4/20 |
|||
*/ |
|||
public class UserTaskListener implements TaskListener{ |
|||
|
|||
@Override |
|||
public void notify(DelegateTask delegateTask) { |
|||
|
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
package com.ruoyi.flowable.service; |
|||
|
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.system.domain.FlowProcDefDto; |
|||
|
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 14:41 |
|||
*/ |
|||
public interface IFlowDefinitionService { |
|||
|
|||
boolean exist(String processDefinitionKey); |
|||
|
|||
|
|||
/** |
|||
* 流程定义列表 |
|||
* |
|||
* @param pageNum 当前页码 |
|||
* @param pageSize 每页条数 |
|||
* @return 流程定义分页列表数据 |
|||
*/ |
|||
Page<FlowProcDefDto> list(String name,Integer pageNum, Integer pageSize); |
|||
|
|||
/** |
|||
* 导入流程文件 |
|||
* |
|||
* @param name |
|||
* @param category |
|||
* @param in |
|||
*/ |
|||
void importFile(String name, String category, InputStream in); |
|||
|
|||
/** |
|||
* 读取xml |
|||
* @param deployId |
|||
* @return |
|||
*/ |
|||
AjaxResult readXml(String deployId) throws IOException; |
|||
|
|||
/** |
|||
* 根据流程定义ID启动流程实例 |
|||
* |
|||
* @param procDefId |
|||
* @param variables |
|||
* @return |
|||
*/ |
|||
|
|||
AjaxResult startProcessInstanceById(String procDefId, Map<String, Object> variables); |
|||
|
|||
|
|||
/** |
|||
* 激活或挂起流程定义 |
|||
* |
|||
* @param state 状态 |
|||
* @param deployId 流程部署ID |
|||
*/ |
|||
void updateState(Integer state, String deployId); |
|||
|
|||
|
|||
/** |
|||
* 删除流程定义 |
|||
* |
|||
* @param deployId 流程部署ID act_ge_bytearray 表中 deployment_id值 |
|||
*/ |
|||
void delete(String deployId); |
|||
|
|||
|
|||
/** |
|||
* 读取图片文件 |
|||
* @param deployId |
|||
* @return |
|||
*/ |
|||
InputStream readImage(String deployId); |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
package com.ruoyi.flowable.service; |
|||
|
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.flowable.domain.vo.FlowTaskVo; |
|||
import org.flowable.engine.history.HistoricProcessInstance; |
|||
import org.flowable.task.api.Task; |
|||
|
|||
import java.util.List; |
|||
import java.util.Map; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 14:40 |
|||
*/ |
|||
public interface IFlowInstanceService { |
|||
|
|||
List<Task> queryListByInstanceId(String instanceId); |
|||
|
|||
/** |
|||
* 结束流程实例 |
|||
* |
|||
* @param vo |
|||
*/ |
|||
void stopProcessInstance(FlowTaskVo vo); |
|||
|
|||
/** |
|||
* 激活或挂起流程实例 |
|||
* |
|||
* @param state 状态 |
|||
* @param instanceId 流程实例ID |
|||
*/ |
|||
void updateState(Integer state, String instanceId); |
|||
|
|||
/** |
|||
* 删除流程实例ID |
|||
* |
|||
* @param instanceId 流程实例ID |
|||
* @param deleteReason 删除原因 |
|||
*/ |
|||
void delete(String instanceId, String deleteReason); |
|||
|
|||
/** |
|||
* 根据实例ID查询历史实例数据 |
|||
* |
|||
* @param processInstanceId |
|||
* @return |
|||
*/ |
|||
HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId); |
|||
|
|||
/** |
|||
* 根据流程定义ID启动流程实例 |
|||
* |
|||
* @param procDefId 流程定义Id |
|||
* @param variables 流程变量 |
|||
* @return |
|||
*/ |
|||
AjaxResult startProcessInstanceById(String procDefId, Map<String, Object> variables); |
|||
} |
|||
@ -0,0 +1,167 @@ |
|||
package com.ruoyi.flowable.service; |
|||
|
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.flowable.domain.vo.FlowTaskVo; |
|||
import org.flowable.task.api.Task; |
|||
|
|||
import java.io.InputStream; |
|||
import java.util.List; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 14:42 |
|||
*/ |
|||
public interface IFlowTaskService { |
|||
|
|||
/** |
|||
* 审批任务 |
|||
* |
|||
* @param task 请求实体参数 |
|||
*/ |
|||
AjaxResult complete(FlowTaskVo task); |
|||
|
|||
/** |
|||
* 驳回任务 |
|||
* |
|||
* @param flowTaskVo |
|||
*/ |
|||
void taskReject(FlowTaskVo flowTaskVo); |
|||
|
|||
|
|||
/** |
|||
* 退回任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
void taskReturn(FlowTaskVo flowTaskVo); |
|||
|
|||
/** |
|||
* 获取所有可回退的节点 |
|||
* |
|||
* @param flowTaskVo |
|||
* @return |
|||
*/ |
|||
AjaxResult findReturnTaskList(FlowTaskVo flowTaskVo); |
|||
|
|||
/** |
|||
* 删除任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
void deleteTask(FlowTaskVo flowTaskVo); |
|||
|
|||
/** |
|||
* 认领/签收任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
void claim(FlowTaskVo flowTaskVo); |
|||
|
|||
/** |
|||
* 取消认领/签收任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
void unClaim(FlowTaskVo flowTaskVo); |
|||
|
|||
/** |
|||
* 委派任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
void delegateTask(FlowTaskVo flowTaskVo); |
|||
|
|||
|
|||
/** |
|||
* 转办任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
void assignTask(FlowTaskVo flowTaskVo); |
|||
|
|||
/** |
|||
* 我发起的流程 |
|||
* @param pageNum |
|||
* @param pageSize |
|||
* @return |
|||
*/ |
|||
AjaxResult myProcess(Integer pageNum, Integer pageSize); |
|||
|
|||
/** |
|||
* 取消申请 |
|||
* @param flowTaskVo |
|||
* @return |
|||
*/ |
|||
AjaxResult stopProcess(FlowTaskVo flowTaskVo); |
|||
|
|||
/** |
|||
* 撤回流程 |
|||
* @param flowTaskVo |
|||
* @return |
|||
*/ |
|||
AjaxResult revokeProcess(FlowTaskVo flowTaskVo); |
|||
|
|||
|
|||
/** |
|||
* 代办任务列表 |
|||
* |
|||
* @param pageNum 当前页码 |
|||
* @param pageSize 每页条数 |
|||
* @return |
|||
*/ |
|||
AjaxResult todoList(Integer pageNum, Integer pageSize); |
|||
|
|||
|
|||
/** |
|||
* 已办任务列表 |
|||
* |
|||
* @param pageNum 当前页码 |
|||
* @param pageSize 每页条数 |
|||
* @return |
|||
*/ |
|||
AjaxResult finishedList(Integer pageNum, Integer pageSize); |
|||
|
|||
/** |
|||
* 流程历史流转记录 |
|||
* |
|||
* @param procInsId 流程实例Id |
|||
* @return |
|||
*/ |
|||
AjaxResult flowRecord(String procInsId,String deployId); |
|||
|
|||
/** |
|||
* 根据任务ID查询挂载的表单信息 |
|||
* |
|||
* @param taskId 任务Id |
|||
* @return |
|||
*/ |
|||
Task getTaskForm(String taskId); |
|||
|
|||
/** |
|||
* 获取流程过程图 |
|||
* @param processId |
|||
* @return |
|||
*/ |
|||
InputStream diagram(String processId); |
|||
|
|||
/** |
|||
* 获取流程执行过程 |
|||
* @param procInsId |
|||
* @return |
|||
*/ |
|||
AjaxResult getFlowViewer(String procInsId,String executionId); |
|||
|
|||
/** |
|||
* 获取流程变量 |
|||
* @param taskId |
|||
* @return |
|||
*/ |
|||
AjaxResult processVariables(String taskId); |
|||
|
|||
/** |
|||
* 获取下一节点 |
|||
* @param flowTaskVo 任务 |
|||
* @return |
|||
*/ |
|||
AjaxResult getNextFlowNode(FlowTaskVo flowTaskVo); |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
package com.ruoyi.flowable.service; |
|||
|
|||
import java.util.List; |
|||
import com.ruoyi.system.domain.SysDeployForm; |
|||
import com.ruoyi.system.domain.SysForm; |
|||
|
|||
/** |
|||
* 流程实例关联表单Service接口 |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
public interface ISysDeployFormService |
|||
{ |
|||
/** |
|||
* 查询流程实例关联表单 |
|||
* |
|||
* @param id 流程实例关联表单ID |
|||
* @return 流程实例关联表单 |
|||
*/ |
|||
public SysDeployForm selectSysDeployFormById(Long id); |
|||
|
|||
/** |
|||
* 查询流程实例关联表单列表 |
|||
* |
|||
* @param sysDeployForm 流程实例关联表单 |
|||
* @return 流程实例关联表单集合 |
|||
*/ |
|||
public List<SysDeployForm> selectSysDeployFormList(SysDeployForm sysDeployForm); |
|||
|
|||
/** |
|||
* 新增流程实例关联表单 |
|||
* |
|||
* @param sysDeployForm 流程实例关联表单 |
|||
* @return 结果 |
|||
*/ |
|||
public int insertSysDeployForm(SysDeployForm sysDeployForm); |
|||
|
|||
/** |
|||
* 修改流程实例关联表单 |
|||
* |
|||
* @param sysDeployForm 流程实例关联表单 |
|||
* @return 结果 |
|||
*/ |
|||
public int updateSysDeployForm(SysDeployForm sysDeployForm); |
|||
|
|||
/** |
|||
* 批量删除流程实例关联表单 |
|||
* |
|||
* @param ids 需要删除的流程实例关联表单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysDeployFormByIds(Long[] ids); |
|||
|
|||
/** |
|||
* 删除流程实例关联表单信息 |
|||
* |
|||
* @param id 流程实例关联表单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysDeployFormById(Long id); |
|||
|
|||
/** |
|||
* 查询流程挂着的表单 |
|||
* @param deployId |
|||
* @return |
|||
*/ |
|||
SysForm selectSysDeployFormByDeployId(String deployId); |
|||
} |
|||
@ -0,0 +1,60 @@ |
|||
package com.ruoyi.flowable.service; |
|||
|
|||
import java.util.List; |
|||
import com.ruoyi.system.domain.SysForm; |
|||
|
|||
/** |
|||
* 表单 |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
public interface ISysFormService |
|||
{ |
|||
/** |
|||
* 查询流程表单 |
|||
* |
|||
* @param formId 流程表单ID |
|||
* @return 流程表单 |
|||
*/ |
|||
public SysForm selectSysFormById(Long formId); |
|||
|
|||
/** |
|||
* 查询流程表单列表 |
|||
* |
|||
* @param sysForm 流程表单 |
|||
* @return 流程表单集合 |
|||
*/ |
|||
public List<SysForm> selectSysFormList(SysForm sysForm); |
|||
|
|||
/** |
|||
* 新增流程表单 |
|||
* |
|||
* @param sysForm 流程表单 |
|||
* @return 结果 |
|||
*/ |
|||
public int insertSysForm(SysForm sysForm); |
|||
|
|||
/** |
|||
* 修改流程表单 |
|||
* |
|||
* @param sysForm 流程表单 |
|||
* @return 结果 |
|||
*/ |
|||
public int updateSysForm(SysForm sysForm); |
|||
|
|||
/** |
|||
* 批量删除流程表单 |
|||
* |
|||
* @param formIds 需要删除的流程表单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysFormByIds(Long[] formIds); |
|||
|
|||
/** |
|||
* 删除流程表单信息 |
|||
* |
|||
* @param formId 流程表单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysFormById(Long formId); |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
package com.ruoyi.flowable.service; |
|||
|
|||
import com.ruoyi.system.domain.SysTaskForm; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 流程任务关联单Service接口 |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Deprecated |
|||
public interface ISysTaskFormService { |
|||
/** |
|||
* 查询流程任务关联单 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 流程任务关联单 |
|||
*/ |
|||
public SysTaskForm selectSysTaskFormById(Long id); |
|||
|
|||
/** |
|||
* 查询流程任务关联单列表 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 流程任务关联单集合 |
|||
*/ |
|||
public List<SysTaskForm> selectSysTaskFormList(SysTaskForm sysTaskForm); |
|||
|
|||
/** |
|||
* 新增流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
public int insertSysTaskForm(SysTaskForm sysTaskForm); |
|||
|
|||
/** |
|||
* 修改流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
public int updateSysTaskForm(SysTaskForm sysTaskForm); |
|||
|
|||
/** |
|||
* 批量删除流程任务关联单 |
|||
* |
|||
* @param ids 需要删除的流程任务关联单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysTaskFormByIds(Long[] ids); |
|||
|
|||
/** |
|||
* 删除流程任务关联单信息 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysTaskFormById(Long id); |
|||
} |
|||
@ -0,0 +1,250 @@ |
|||
package com.ruoyi.flowable.service.impl; |
|||
|
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.github.pagehelper.PageHelper; |
|||
import com.github.pagehelper.PageInfo; |
|||
import com.ruoyi.flowable.common.constant.ProcessConstants; |
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.common.core.domain.entity.SysUser; |
|||
import com.ruoyi.flowable.common.enums.FlowComment; |
|||
import com.ruoyi.common.utils.SecurityUtils; |
|||
import com.ruoyi.system.domain.FlowProcDefDto; |
|||
import com.ruoyi.flowable.factory.FlowServiceFactory; |
|||
import com.ruoyi.flowable.service.IFlowDefinitionService; |
|||
import com.ruoyi.flowable.service.ISysDeployFormService; |
|||
import com.ruoyi.system.domain.SysForm; |
|||
import com.ruoyi.system.mapper.FlowDeployMapper; |
|||
import com.ruoyi.system.service.ISysDeptService; |
|||
import com.ruoyi.system.service.ISysPostService; |
|||
import com.ruoyi.system.service.ISysUserService; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.io.IOUtils; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.flowable.bpmn.model.BpmnModel; |
|||
import org.flowable.engine.repository.Deployment; |
|||
import org.flowable.engine.repository.ProcessDefinition; |
|||
import org.flowable.engine.repository.ProcessDefinitionQuery; |
|||
import org.flowable.engine.runtime.ProcessInstance; |
|||
import org.flowable.image.impl.DefaultProcessDiagramGenerator; |
|||
import org.flowable.task.api.Task; |
|||
import org.springframework.beans.BeanUtils; |
|||
import org.springframework.stereotype.Service; |
|||
|
|||
import javax.annotation.Resource; |
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.nio.charset.StandardCharsets; |
|||
import java.util.*; |
|||
|
|||
/** |
|||
* 流程定义 |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
public class FlowDefinitionServiceImpl extends FlowServiceFactory implements IFlowDefinitionService { |
|||
|
|||
@Resource |
|||
private ISysDeployFormService sysDeployFormService; |
|||
|
|||
@Resource |
|||
private ISysUserService sysUserService; |
|||
|
|||
@Resource |
|||
private ISysDeptService sysDeptService; |
|||
|
|||
@Resource |
|||
private ISysPostService postService; |
|||
|
|||
@Resource |
|||
private FlowDeployMapper flowDeployMapper; |
|||
|
|||
private static final String BPMN_FILE_SUFFIX = ".bpmn"; |
|||
|
|||
@Override |
|||
public boolean exist(String processDefinitionKey) { |
|||
ProcessDefinitionQuery processDefinitionQuery |
|||
= repositoryService.createProcessDefinitionQuery().processDefinitionKey(processDefinitionKey); |
|||
long count = processDefinitionQuery.count(); |
|||
return count > 0 ? true : false; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 流程定义列表 |
|||
* |
|||
* @param pageNum 当前页码 |
|||
* @param pageSize 每页条数 |
|||
* @return 流程定义分页列表数据 |
|||
*/ |
|||
@Override |
|||
public Page<FlowProcDefDto> list(String name, Integer pageNum, Integer pageSize) { |
|||
Page<FlowProcDefDto> page = new Page<>(); |
|||
// // 流程定义列表数据查询
|
|||
// final ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
|
|||
// if (StringUtils.isNotEmpty(name)) {
|
|||
// processDefinitionQuery.processDefinitionNameLike(name);
|
|||
// }
|
|||
//// processDefinitionQuery.orderByProcessDefinitionKey().asc();
|
|||
// page.setTotal(processDefinitionQuery.count());
|
|||
// List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(pageSize * (pageNum - 1), pageSize);
|
|||
//
|
|||
// List<FlowProcDefDto> dataList = new ArrayList<>();
|
|||
// for (ProcessDefinition processDefinition : processDefinitionList) {
|
|||
// String deploymentId = processDefinition.getDeploymentId();
|
|||
// Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
|
|||
// FlowProcDefDto reProcDef = new FlowProcDefDto();
|
|||
// BeanUtils.copyProperties(processDefinition, reProcDef);
|
|||
// SysForm sysForm = sysDeployFormService.selectSysDeployFormByDeployId(deploymentId);
|
|||
// if (Objects.nonNull(sysForm)) {
|
|||
// reProcDef.setFormName(sysForm.getFormName());
|
|||
// reProcDef.setFormId(sysForm.getFormId());
|
|||
// }
|
|||
// // 流程定义时间
|
|||
// reProcDef.setDeploymentTime(deployment.getDeploymentTime());
|
|||
// dataList.add(reProcDef);
|
|||
// }
|
|||
PageHelper.startPage(pageNum, pageSize); |
|||
final List<FlowProcDefDto> dataList = flowDeployMapper.selectDeployList(name); |
|||
// 加载挂表单
|
|||
for (FlowProcDefDto procDef : dataList) { |
|||
SysForm sysForm = sysDeployFormService.selectSysDeployFormByDeployId(procDef.getDeploymentId()); |
|||
if (Objects.nonNull(sysForm)) { |
|||
procDef.setFormName(sysForm.getFormName()); |
|||
procDef.setFormId(sysForm.getFormId()); |
|||
} |
|||
} |
|||
page.setTotal(new PageInfo(dataList).getTotal()); |
|||
page.setRecords(dataList); |
|||
return page; |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 导入流程文件 |
|||
* |
|||
* @param name |
|||
* @param category |
|||
* @param in |
|||
*/ |
|||
@Override |
|||
public void importFile(String name, String category, InputStream in) { |
|||
Deployment deploy = repositoryService.createDeployment().addInputStream(name + BPMN_FILE_SUFFIX, in).name(name).category(category).deploy(); |
|||
ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult(); |
|||
repositoryService.setProcessDefinitionCategory(definition.getId(), category); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 读取xml |
|||
* |
|||
* @param deployId |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult readXml(String deployId) throws IOException { |
|||
ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); |
|||
InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName()); |
|||
String result = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name()); |
|||
return AjaxResult.success("", result); |
|||
} |
|||
|
|||
/** |
|||
* 读取xml |
|||
* |
|||
* @param deployId |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public InputStream readImage(String deployId) { |
|||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); |
|||
//获得图片流
|
|||
DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator(); |
|||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId()); |
|||
//输出为图片
|
|||
return diagramGenerator.generateDiagram( |
|||
bpmnModel, |
|||
"png", |
|||
Collections.emptyList(), |
|||
Collections.emptyList(), |
|||
"宋体", |
|||
"宋体", |
|||
"宋体", |
|||
null, |
|||
1.0, |
|||
false); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 根据流程定义ID启动流程实例 |
|||
* |
|||
* @param procDefId 流程定义Id |
|||
* @param variables 流程变量 |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult startProcessInstanceById(String procDefId, Map<String, Object> variables) { |
|||
try { |
|||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId) |
|||
.latestVersion().singleResult(); |
|||
if (Objects.nonNull(processDefinition) && processDefinition.isSuspended()) { |
|||
return AjaxResult.error("流程已被挂起,请先激活流程"); |
|||
} |
|||
// variables.put("skip", true);
|
|||
// variables.put(ProcessConstants.FLOWABLE_SKIP_EXPRESSION_ENABLED, true);
|
|||
// 设置流程发起人Id到流程中
|
|||
SysUser sysUser = SecurityUtils.getLoginUser().getUser(); |
|||
identityService.setAuthenticatedUserId(sysUser.getUserId().toString()); |
|||
variables.put(ProcessConstants.PROCESS_INITIATOR, ""); |
|||
ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefId, variables); |
|||
// 给第一步申请人节点设置任务执行人和意见 todo:第一个节点不设置为申请人节点有点问题?
|
|||
Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult(); |
|||
if (Objects.nonNull(task)) { |
|||
taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.NORMAL.getType(), sysUser.getNickName() + "发起流程申请"); |
|||
// taskService.setAssignee(task.getId(), sysUser.getUserId().toString());
|
|||
taskService.complete(task.getId(), variables); |
|||
} |
|||
return AjaxResult.success("流程启动成功"); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return AjaxResult.error("流程启动错误"); |
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 激活或挂起流程定义 |
|||
* |
|||
* @param state 状态 |
|||
* @param deployId 流程部署ID |
|||
*/ |
|||
@Override |
|||
public void updateState(Integer state, String deployId) { |
|||
ProcessDefinition procDef = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); |
|||
// 激活
|
|||
if (state == 1) { |
|||
repositoryService.activateProcessDefinitionById(procDef.getId(), true, null); |
|||
} |
|||
// 挂起
|
|||
if (state == 2) { |
|||
repositoryService.suspendProcessDefinitionById(procDef.getId(), true, null); |
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 删除流程定义 |
|||
* |
|||
* @param deployId 流程部署ID act_ge_bytearray 表中 deployment_id值 |
|||
*/ |
|||
@Override |
|||
public void delete(String deployId) { |
|||
// true 允许级联删除 ,不设置会导致数据库外键关联异常
|
|||
repositoryService.deleteDeployment(deployId, true); |
|||
} |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,129 @@ |
|||
package com.ruoyi.flowable.service.impl; |
|||
|
|||
|
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.common.utils.SecurityUtils; |
|||
import com.ruoyi.flowable.domain.vo.FlowTaskVo; |
|||
import com.ruoyi.flowable.factory.FlowServiceFactory; |
|||
import com.ruoyi.flowable.service.IFlowInstanceService; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.flowable.common.engine.api.FlowableObjectNotFoundException; |
|||
import org.flowable.engine.history.HistoricProcessInstance; |
|||
import org.flowable.task.api.Task; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.Objects; |
|||
|
|||
/** |
|||
* <p>工作流流程实例管理<p> |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Service |
|||
@Slf4j |
|||
public class FlowInstanceServiceImpl extends FlowServiceFactory implements IFlowInstanceService { |
|||
|
|||
|
|||
@Override |
|||
public List<Task> queryListByInstanceId(String instanceId) { |
|||
List<Task> list = taskService.createTaskQuery().processInstanceId(instanceId).active().list(); |
|||
return list; |
|||
} |
|||
|
|||
/** |
|||
* 结束流程实例 |
|||
* |
|||
* @param vo |
|||
*/ |
|||
@Override |
|||
public void stopProcessInstance(FlowTaskVo vo) { |
|||
String taskId = vo.getTaskId(); |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 激活或挂起流程实例 |
|||
* |
|||
* @param state 状态 |
|||
* @param instanceId 流程实例ID |
|||
*/ |
|||
@Override |
|||
public void updateState(Integer state, String instanceId) { |
|||
|
|||
// 激活
|
|||
if (state == 1) { |
|||
runtimeService.activateProcessInstanceById(instanceId); |
|||
} |
|||
// 挂起
|
|||
if (state == 2) { |
|||
runtimeService.suspendProcessInstanceById(instanceId); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 删除流程实例ID |
|||
* |
|||
* @param instanceId 流程实例ID |
|||
* @param deleteReason 删除原因 |
|||
*/ |
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void delete(String instanceId, String deleteReason) { |
|||
|
|||
// 查询历史数据
|
|||
HistoricProcessInstance historicProcessInstance = getHistoricProcessInstanceById(instanceId); |
|||
if (historicProcessInstance.getEndTime() != null) { |
|||
historyService.deleteHistoricProcessInstance(historicProcessInstance.getId()); |
|||
return; |
|||
} |
|||
// 删除流程实例
|
|||
runtimeService.deleteProcessInstance(instanceId, deleteReason); |
|||
// 删除历史流程实例
|
|||
historyService.deleteHistoricProcessInstance(instanceId); |
|||
} |
|||
|
|||
/** |
|||
* 根据实例ID查询历史实例数据 |
|||
* |
|||
* @param processInstanceId |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public HistoricProcessInstance getHistoricProcessInstanceById(String processInstanceId) { |
|||
HistoricProcessInstance historicProcessInstance = |
|||
historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); |
|||
if (Objects.isNull(historicProcessInstance)) { |
|||
throw new FlowableObjectNotFoundException("流程实例不存在: " + processInstanceId); |
|||
} |
|||
return historicProcessInstance; |
|||
} |
|||
|
|||
/** |
|||
* 根据流程定义ID启动流程实例 |
|||
* |
|||
* @param procDefId 流程定义Id |
|||
* @param variables 流程变量 |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult startProcessInstanceById(String procDefId, Map<String, Object> variables) { |
|||
|
|||
try { |
|||
// 设置流程发起人Id到流程中
|
|||
Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); |
|||
// identityService.setAuthenticatedUserId(userId.toString());
|
|||
variables.put("initiator",userId); |
|||
variables.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED", true); |
|||
runtimeService.startProcessInstanceById(procDefId, variables); |
|||
return AjaxResult.success("流程启动成功"); |
|||
} catch (Exception e) { |
|||
e.printStackTrace(); |
|||
return AjaxResult.error("流程启动错误"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,998 @@ |
|||
package com.ruoyi.flowable.service.impl; |
|||
|
|||
|
|||
import com.alibaba.fastjson2.JSONObject; |
|||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
|||
import com.ruoyi.flowable.common.constant.ProcessConstants; |
|||
import com.ruoyi.common.core.domain.AjaxResult; |
|||
import com.ruoyi.common.core.domain.entity.SysRole; |
|||
import com.ruoyi.common.core.domain.entity.SysUser; |
|||
import com.ruoyi.flowable.common.enums.FlowComment; |
|||
import com.ruoyi.common.exception.CustomException; |
|||
import com.ruoyi.common.utils.SecurityUtils; |
|||
import com.ruoyi.flowable.domain.dto.FlowCommentDto; |
|||
import com.ruoyi.flowable.domain.dto.FlowNextDto; |
|||
import com.ruoyi.flowable.domain.dto.FlowTaskDto; |
|||
import com.ruoyi.flowable.domain.dto.FlowViewerDto; |
|||
import com.ruoyi.flowable.domain.vo.FlowTaskVo; |
|||
import com.ruoyi.flowable.domain.vo.ReturnTaskNodeVo; |
|||
import com.ruoyi.flowable.factory.FlowServiceFactory; |
|||
import com.ruoyi.flowable.flow.CustomProcessDiagramGenerator; |
|||
import com.ruoyi.flowable.flow.FindNextNodeUtil; |
|||
import com.ruoyi.flowable.flow.FlowableUtils; |
|||
import com.ruoyi.flowable.service.IFlowTaskService; |
|||
import com.ruoyi.flowable.service.ISysDeployFormService; |
|||
import com.ruoyi.system.domain.SysForm; |
|||
import com.ruoyi.system.service.ISysRoleService; |
|||
import com.ruoyi.system.service.ISysUserService; |
|||
import lombok.extern.slf4j.Slf4j; |
|||
import org.apache.commons.collections4.CollectionUtils; |
|||
import org.apache.commons.lang3.StringUtils; |
|||
import org.flowable.bpmn.model.Process; |
|||
import org.flowable.bpmn.model.*; |
|||
import org.flowable.common.engine.api.FlowableException; |
|||
import org.flowable.common.engine.api.FlowableObjectNotFoundException; |
|||
import org.flowable.common.engine.api.query.QueryProperty; |
|||
import org.flowable.common.engine.impl.identity.Authentication; |
|||
import org.flowable.engine.ProcessEngineConfiguration; |
|||
import org.flowable.engine.history.HistoricActivityInstance; |
|||
import org.flowable.engine.history.HistoricProcessInstance; |
|||
import org.flowable.engine.history.HistoricProcessInstanceQuery; |
|||
import org.flowable.engine.impl.ActivityInstanceQueryProperty; |
|||
import org.flowable.engine.repository.ProcessDefinition; |
|||
import org.flowable.engine.runtime.ActivityInstance; |
|||
import org.flowable.engine.runtime.Execution; |
|||
import org.flowable.engine.runtime.ProcessInstance; |
|||
import org.flowable.engine.task.Comment; |
|||
import org.flowable.identitylink.api.history.HistoricIdentityLink; |
|||
import org.flowable.image.ProcessDiagramGenerator; |
|||
import org.flowable.task.api.DelegationState; |
|||
import org.flowable.task.api.Task; |
|||
import org.flowable.task.api.TaskQuery; |
|||
import org.flowable.task.api.history.HistoricTaskInstance; |
|||
import org.flowable.task.api.history.HistoricTaskInstanceQuery; |
|||
import org.springframework.stereotype.Service; |
|||
import org.springframework.transaction.annotation.Transactional; |
|||
|
|||
import javax.annotation.Resource; |
|||
import java.io.InputStream; |
|||
import java.util.*; |
|||
import java.util.concurrent.ConcurrentHashMap; |
|||
import java.util.function.Function; |
|||
import java.util.function.Predicate; |
|||
import java.util.stream.Collectors; |
|||
|
|||
/** |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
**/ |
|||
@Service |
|||
@Slf4j |
|||
public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTaskService { |
|||
|
|||
@Resource |
|||
private ISysUserService sysUserService; |
|||
|
|||
|
|||
@Resource |
|||
private ISysRoleService sysRoleService; |
|||
|
|||
|
|||
@Resource |
|||
private ISysDeployFormService sysInstanceFormService; |
|||
|
|||
/** |
|||
* 完成任务 |
|||
* |
|||
* @param taskVo 请求实体参数 |
|||
*/ |
|||
@Transactional(rollbackFor = Exception.class) |
|||
@Override |
|||
public AjaxResult complete(FlowTaskVo taskVo) { |
|||
Task task = taskService.createTaskQuery().taskId(taskVo.getTaskId()).singleResult(); |
|||
if (Objects.isNull(task)) { |
|||
return AjaxResult.error("任务不存在"); |
|||
} |
|||
if (DelegationState.PENDING.equals(task.getDelegationState())) { |
|||
taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.DELEGATE.getType(), taskVo.getComment()); |
|||
taskService.resolveTask(taskVo.getTaskId(), taskVo.getValues()); |
|||
} else { |
|||
taskService.addComment(taskVo.getTaskId(), taskVo.getInstanceId(), FlowComment.NORMAL.getType(), taskVo.getComment()); |
|||
Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); |
|||
taskService.setAssignee(taskVo.getTaskId(), userId.toString()); |
|||
taskService.complete(taskVo.getTaskId(), taskVo.getValues()); |
|||
} |
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
/** |
|||
* 驳回任务 |
|||
* |
|||
* @param flowTaskVo |
|||
*/ |
|||
@Override |
|||
public void taskReject(FlowTaskVo flowTaskVo) { |
|||
if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) { |
|||
throw new CustomException("任务处于挂起状态!"); |
|||
} |
|||
// 当前任务 task
|
|||
Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); |
|||
// 获取流程定义信息
|
|||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); |
|||
// 获取所有节点信息
|
|||
Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); |
|||
// 获取全部节点列表,包含子节点
|
|||
Collection<FlowElement> allElements = FlowableUtils.getAllElements(process.getFlowElements(), null); |
|||
// 获取当前任务节点元素
|
|||
FlowElement source = null; |
|||
if (allElements != null) { |
|||
for (FlowElement flowElement : allElements) { |
|||
// 类型为用户节点
|
|||
if (flowElement.getId().equals(task.getTaskDefinitionKey())) { |
|||
// 获取节点信息
|
|||
source = flowElement; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 目的获取所有跳转到的节点 targetIds
|
|||
// 获取当前节点的所有父级用户任务节点
|
|||
// 深度优先算法思想:延边迭代深入
|
|||
List<UserTask> parentUserTaskList = FlowableUtils.iteratorFindParentUserTasks(source, null, null); |
|||
if (parentUserTaskList == null || parentUserTaskList.size() == 0) { |
|||
throw new CustomException("当前节点为初始任务节点,不能驳回"); |
|||
} |
|||
// 获取活动 ID 即节点 Key
|
|||
List<String> parentUserTaskKeyList = new ArrayList<>(); |
|||
parentUserTaskList.forEach(item -> parentUserTaskKeyList.add(item.getId())); |
|||
// 获取全部历史节点活动实例,即已经走过的节点历史,数据采用开始时间升序
|
|||
List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceStartTime().asc().list(); |
|||
// 数据清洗,将回滚导致的脏数据清洗掉
|
|||
List<String> lastHistoricTaskInstanceList = FlowableUtils.historicTaskInstanceClean(allElements, historicTaskInstanceList); |
|||
// 此时历史任务实例为倒序,获取最后走的节点
|
|||
List<String> targetIds = new ArrayList<>(); |
|||
// 循环结束标识,遇到当前目标节点的次数
|
|||
int number = 0; |
|||
StringBuilder parentHistoricTaskKey = new StringBuilder(); |
|||
for (String historicTaskInstanceKey : lastHistoricTaskInstanceList) { |
|||
// 当会签时候会出现特殊的,连续都是同一个节点历史数据的情况,这种时候跳过
|
|||
if (parentHistoricTaskKey.toString().equals(historicTaskInstanceKey)) { |
|||
continue; |
|||
} |
|||
parentHistoricTaskKey = new StringBuilder(historicTaskInstanceKey); |
|||
if (historicTaskInstanceKey.equals(task.getTaskDefinitionKey())) { |
|||
number++; |
|||
} |
|||
// 在数据清洗后,历史节点就是唯一一条从起始到当前节点的历史记录,理论上每个点只会出现一次
|
|||
// 在流程中如果出现循环,那么每次循环中间的点也只会出现一次,再出现就是下次循环
|
|||
// number == 1,第一次遇到当前节点
|
|||
// number == 2,第二次遇到,代表最后一次的循环范围
|
|||
if (number == 2) { |
|||
break; |
|||
} |
|||
// 如果当前历史节点,属于父级的节点,说明最后一次经过了这个点,需要退回这个点
|
|||
if (parentUserTaskKeyList.contains(historicTaskInstanceKey)) { |
|||
targetIds.add(historicTaskInstanceKey); |
|||
} |
|||
} |
|||
|
|||
|
|||
// 目的获取所有需要被跳转的节点 currentIds
|
|||
// 取其中一个父级任务,因为后续要么存在公共网关,要么就是串行公共线路
|
|||
UserTask oneUserTask = parentUserTaskList.get(0); |
|||
// 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务
|
|||
List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list(); |
|||
List<String> runTaskKeyList = new ArrayList<>(); |
|||
runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey())); |
|||
// 需驳回任务列表
|
|||
List<String> currentIds = new ArrayList<>(); |
|||
// 通过父级网关的出口连线,结合 runTaskList 比对,获取需要撤回的任务
|
|||
List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(oneUserTask, runTaskKeyList, null, null); |
|||
currentUserTaskList.forEach(item -> currentIds.add(item.getId())); |
|||
|
|||
|
|||
// 规定:并行网关之前节点必须需存在唯一用户任务节点,如果出现多个任务节点,则并行网关节点默认为结束节点,原因为不考虑多对多情况
|
|||
if (targetIds.size() > 1 && currentIds.size() > 1) { |
|||
throw new CustomException("任务出现多对多情况,无法撤回"); |
|||
} |
|||
|
|||
// 循环获取那些需要被撤回的节点的ID,用来设置驳回原因
|
|||
List<String> currentTaskIds = new ArrayList<>(); |
|||
currentIds.forEach(currentId -> runTaskList.forEach(runTask -> { |
|||
if (currentId.equals(runTask.getTaskDefinitionKey())) { |
|||
currentTaskIds.add(runTask.getId()); |
|||
} |
|||
})); |
|||
// 设置驳回意见
|
|||
currentTaskIds.forEach(item -> taskService.addComment(item, task.getProcessInstanceId(), FlowComment.REJECT.getType(), flowTaskVo.getComment())); |
|||
|
|||
try { |
|||
// 如果父级任务多于 1 个,说明当前节点不是并行节点,原因为不考虑多对多情况
|
|||
if (targetIds.size() > 1) { |
|||
// 1 对 多任务跳转,currentIds 当前节点(1),targetIds 跳转到的节点(多)
|
|||
runtimeService.createChangeActivityStateBuilder() |
|||
.processInstanceId(task.getProcessInstanceId()). |
|||
moveSingleActivityIdToActivityIds(currentIds.get(0), targetIds).changeState(); |
|||
} |
|||
// 如果父级任务只有一个,因此当前任务可能为网关中的任务
|
|||
if (targetIds.size() == 1) { |
|||
// 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetIds.get(0) 跳转到的节点(1)
|
|||
runtimeService.createChangeActivityStateBuilder() |
|||
.processInstanceId(task.getProcessInstanceId()) |
|||
.moveActivityIdsToSingleActivityId(currentIds, targetIds.get(0)).changeState(); |
|||
} |
|||
} catch (FlowableObjectNotFoundException e) { |
|||
throw new CustomException("未找到流程实例,流程可能已发生变化"); |
|||
} catch (FlowableException e) { |
|||
throw new CustomException("无法取消或开始活动"); |
|||
} |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 退回任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
@Transactional(rollbackFor = Exception.class) |
|||
@Override |
|||
public void taskReturn(FlowTaskVo flowTaskVo) { |
|||
if (taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult().isSuspended()) { |
|||
throw new CustomException("任务处于挂起状态"); |
|||
} |
|||
// 当前任务 task
|
|||
Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); |
|||
// 获取流程定义信息
|
|||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); |
|||
// 获取所有节点信息
|
|||
Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); |
|||
// 获取全部节点列表,包含子节点
|
|||
Collection<FlowElement> allElements = FlowableUtils.getAllElements(process.getFlowElements(), null); |
|||
// 获取当前任务节点元素
|
|||
FlowElement source = null; |
|||
// 获取跳转的节点元素
|
|||
FlowElement target = null; |
|||
if (allElements != null) { |
|||
for (FlowElement flowElement : allElements) { |
|||
// 当前任务节点元素
|
|||
if (flowElement.getId().equals(task.getTaskDefinitionKey())) { |
|||
source = flowElement; |
|||
} |
|||
// 跳转的节点元素
|
|||
if (flowElement.getId().equals(flowTaskVo.getTargetKey())) { |
|||
target = flowElement; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 从当前节点向前扫描
|
|||
// 如果存在路线上不存在目标节点,说明目标节点是在网关上或非同一路线上,不可跳转
|
|||
// 否则目标节点相对于当前节点,属于串行
|
|||
Boolean isSequential = FlowableUtils.iteratorCheckSequentialReferTarget(source, flowTaskVo.getTargetKey(), null, null); |
|||
if (!isSequential) { |
|||
throw new CustomException("当前节点相对于目标节点,不属于串行关系,无法回退"); |
|||
} |
|||
|
|||
|
|||
// 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务
|
|||
List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list(); |
|||
List<String> runTaskKeyList = new ArrayList<>(); |
|||
runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey())); |
|||
// 需退回任务列表
|
|||
List<String> currentIds = new ArrayList<>(); |
|||
// 通过父级网关的出口连线,结合 runTaskList 比对,获取需要撤回的任务
|
|||
List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target, runTaskKeyList, null, null); |
|||
currentUserTaskList.forEach(item -> currentIds.add(item.getId())); |
|||
|
|||
// 循环获取那些需要被撤回的节点的ID,用来设置驳回原因
|
|||
List<String> currentTaskIds = new ArrayList<>(); |
|||
currentIds.forEach(currentId -> runTaskList.forEach(runTask -> { |
|||
if (currentId.equals(runTask.getTaskDefinitionKey())) { |
|||
currentTaskIds.add(runTask.getId()); |
|||
} |
|||
})); |
|||
// 设置回退意见
|
|||
currentTaskIds.forEach(currentTaskId -> taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowComment.REBACK.getType(), flowTaskVo.getComment())); |
|||
|
|||
try { |
|||
// 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetKey 跳转到的节点(1)
|
|||
runtimeService.createChangeActivityStateBuilder() |
|||
.processInstanceId(task.getProcessInstanceId()) |
|||
.moveActivityIdsToSingleActivityId(currentIds, flowTaskVo.getTargetKey()).changeState(); |
|||
} catch (FlowableObjectNotFoundException e) { |
|||
throw new CustomException("未找到流程实例,流程可能已发生变化"); |
|||
} catch (FlowableException e) { |
|||
throw new CustomException("无法取消或开始活动"); |
|||
} |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 获取所有可回退的节点 |
|||
* |
|||
* @param flowTaskVo |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult findReturnTaskList(FlowTaskVo flowTaskVo) { |
|||
// 当前任务 task
|
|||
Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); |
|||
// 从流程历史任务中获取可退回节点
|
|||
// List<HistoricActivityInstance> hisActIns = historyService.createHistoricActivityInstanceQuery()
|
|||
// .executionId(task.getExecutionId())
|
|||
// .activityType("userTask")
|
|||
// .orderByHistoricActivityInstanceStartTime()
|
|||
// .finished()
|
|||
// .desc()
|
|||
// .list();
|
|||
//
|
|||
// // 可回退的节点列表
|
|||
// List<ReturnTaskNodeVo> returnTaskNodeList = new ArrayList<>();
|
|||
// ReturnTaskNodeVo returnTaskNodeVo;
|
|||
// for (HistoricActivityInstance activityInstance : hisActIns) {
|
|||
// returnTaskNodeVo = new ReturnTaskNodeVo();
|
|||
// returnTaskNodeVo.setId(activityInstance.getActivityId());
|
|||
// // 根据流程节点处理时间校验改节点是否已完成
|
|||
// returnTaskNodeVo.setName(activityInstance.getActivityName());
|
|||
// returnTaskNodeList.add(returnTaskNodeVo);
|
|||
// }
|
|||
List<UserTask> userTaskList = new ArrayList<>(); |
|||
// 获取流程定义信息
|
|||
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult(); |
|||
// 获取所有节点信息,暂不考虑子流程情况
|
|||
Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0); |
|||
Collection<FlowElement> flowElements = process.getFlowElements(); |
|||
// 获取当前任务节点元素
|
|||
UserTask source = null; |
|||
if (flowElements != null) { |
|||
for (FlowElement flowElement : flowElements) { |
|||
// 类型为用户节点
|
|||
if (flowElement.getId().equals(task.getTaskDefinitionKey())) { |
|||
source = (UserTask) flowElement; |
|||
} |
|||
} |
|||
} |
|||
// 获取节点的所有路线
|
|||
List<List<UserTask>> roads = FlowableUtils.findRoad(source, null, null, null); |
|||
|
|||
for (List<UserTask> road : roads) { |
|||
if (userTaskList.size() == 0) { |
|||
// 还没有可回退节点直接添加
|
|||
userTaskList = road; |
|||
} else { |
|||
// 如果已有回退节点,则比对取交集部分
|
|||
userTaskList.retainAll(road); |
|||
} |
|||
} |
|||
return AjaxResult.success(userTaskList); |
|||
} |
|||
|
|||
/** |
|||
* 删除任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
@Override |
|||
public void deleteTask(FlowTaskVo flowTaskVo) { |
|||
// todo 待确认删除任务是物理删除任务 还是逻辑删除,让这个任务直接通过?
|
|||
taskService.deleteTask(flowTaskVo.getTaskId(), flowTaskVo.getComment()); |
|||
} |
|||
|
|||
/** |
|||
* 认领/签收任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void claim(FlowTaskVo flowTaskVo) { |
|||
taskService.claim(flowTaskVo.getTaskId(), flowTaskVo.getUserId()); |
|||
} |
|||
|
|||
/** |
|||
* 取消认领/签收任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void unClaim(FlowTaskVo flowTaskVo) { |
|||
taskService.unclaim(flowTaskVo.getTaskId()); |
|||
} |
|||
|
|||
/** |
|||
* 委派任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void delegateTask(FlowTaskVo flowTaskVo) { |
|||
taskService.delegateTask(flowTaskVo.getTaskId(), flowTaskVo.getAssignee()); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 转办任务 |
|||
* |
|||
* @param flowTaskVo 请求实体参数 |
|||
*/ |
|||
@Override |
|||
@Transactional(rollbackFor = Exception.class) |
|||
public void assignTask(FlowTaskVo flowTaskVo) { |
|||
taskService.setAssignee(flowTaskVo.getTaskId(), flowTaskVo.getComment()); |
|||
} |
|||
|
|||
/** |
|||
* 我发起的流程 |
|||
* |
|||
* @param pageNum |
|||
* @param pageSize |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult myProcess(Integer pageNum, Integer pageSize) { |
|||
Page<FlowTaskDto> page = new Page<>(); |
|||
Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); |
|||
HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery() |
|||
.startedBy(userId.toString()) |
|||
.orderByProcessInstanceStartTime() |
|||
.desc(); |
|||
List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage(pageSize * (pageNum - 1), pageSize); |
|||
page.setTotal(historicProcessInstanceQuery.count()); |
|||
List<FlowTaskDto> flowList = new ArrayList<>(); |
|||
for (HistoricProcessInstance hisIns : historicProcessInstances) { |
|||
FlowTaskDto flowTask = new FlowTaskDto(); |
|||
flowTask.setCreateTime(hisIns.getStartTime()); |
|||
flowTask.setFinishTime(hisIns.getEndTime()); |
|||
flowTask.setProcInsId(hisIns.getId()); |
|||
|
|||
// 计算耗时
|
|||
if (Objects.nonNull(hisIns.getEndTime())) { |
|||
long time = hisIns.getEndTime().getTime() - hisIns.getStartTime().getTime(); |
|||
flowTask.setDuration(getDate(time)); |
|||
} else { |
|||
long time = System.currentTimeMillis() - hisIns.getStartTime().getTime(); |
|||
flowTask.setDuration(getDate(time)); |
|||
} |
|||
// 流程定义信息
|
|||
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() |
|||
.processDefinitionId(hisIns.getProcessDefinitionId()) |
|||
.singleResult(); |
|||
flowTask.setDeployId(pd.getDeploymentId()); |
|||
flowTask.setProcDefName(pd.getName()); |
|||
flowTask.setProcDefVersion(pd.getVersion()); |
|||
flowTask.setCategory(pd.getCategory()); |
|||
flowTask.setProcDefVersion(pd.getVersion()); |
|||
// 当前所处流程 todo: 本地启动放开以下注释
|
|||
// List<Task> taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list();
|
|||
// if (CollectionUtils.isNotEmpty(taskList)) {
|
|||
// flowTask.setTaskId(taskList.get(0).getId());
|
|||
// } else {
|
|||
// List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list();
|
|||
// flowTask.setTaskId(historicTaskInstance.get(0).getId());
|
|||
// }
|
|||
flowList.add(flowTask); |
|||
} |
|||
page.setRecords(flowList); |
|||
return AjaxResult.success(page); |
|||
} |
|||
|
|||
/** |
|||
* 取消申请 |
|||
* |
|||
* @param flowTaskVo |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult stopProcess(FlowTaskVo flowTaskVo) { |
|||
List<Task> task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).list(); |
|||
if (CollectionUtils.isEmpty(task)) { |
|||
throw new CustomException("流程未启动或已执行完成,取消申请失败"); |
|||
} |
|||
// 获取当前需撤回的流程实例
|
|||
ProcessInstance processInstance = |
|||
runtimeService.createProcessInstanceQuery() |
|||
.processInstanceId(flowTaskVo.getInstanceId()) |
|||
.singleResult(); |
|||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()); |
|||
if (Objects.nonNull(bpmnModel)) { |
|||
Process process = bpmnModel.getMainProcess(); |
|||
List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class, false); |
|||
if (CollectionUtils.isNotEmpty(endNodes)) { |
|||
SysUser loginUser = SecurityUtils.getLoginUser().getUser(); |
|||
Authentication.setAuthenticatedUserId(loginUser.getUserId().toString()); |
|||
// taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.STOP.getType(),
|
|||
// StringUtils.isBlank(flowTaskVo.getComment()) ? "取消申请" : flowTaskVo.getComment());
|
|||
// 获取当前流程最后一个节点
|
|||
String endId = endNodes.get(0).getId(); |
|||
List<Execution> executions = |
|||
runtimeService.createExecutionQuery().parentId(processInstance.getProcessInstanceId()).list(); |
|||
List<String> executionIds = new ArrayList<>(); |
|||
executions.forEach(execution -> executionIds.add(execution.getId())); |
|||
// 变更流程为已结束状态
|
|||
runtimeService.createChangeActivityStateBuilder() |
|||
.moveExecutionsToSingleActivityId(executionIds, endId).changeState(); |
|||
} |
|||
} |
|||
|
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
/** |
|||
* 撤回流程 目前存在错误 |
|||
* |
|||
* @param flowTaskVo |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult revokeProcess(FlowTaskVo flowTaskVo) { |
|||
Task task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).singleResult(); |
|||
if (task == null) { |
|||
throw new CustomException("流程未启动或已执行完成,无法撤回"); |
|||
} |
|||
|
|||
SysUser loginUser = SecurityUtils.getLoginUser().getUser(); |
|||
List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery() |
|||
.processInstanceId(task.getProcessInstanceId()) |
|||
.orderByTaskCreateTime() |
|||
.asc() |
|||
.list(); |
|||
String myTaskId = null; |
|||
HistoricTaskInstance myTask = null; |
|||
for (HistoricTaskInstance hti : htiList) { |
|||
if (loginUser.getUserId().toString().equals(hti.getAssignee())) { |
|||
myTaskId = hti.getId(); |
|||
myTask = hti; |
|||
break; |
|||
} |
|||
} |
|||
if (null == myTaskId) { |
|||
throw new CustomException("该任务非当前用户提交,无法撤回"); |
|||
} |
|||
|
|||
String processDefinitionId = myTask.getProcessDefinitionId(); |
|||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); |
|||
|
|||
//变量
|
|||
// Map<String, VariableInstance> variables = runtimeService.getVariableInstances(currentTask.getExecutionId());
|
|||
String myActivityId = null; |
|||
List<HistoricActivityInstance> haiList = historyService.createHistoricActivityInstanceQuery() |
|||
.executionId(myTask.getExecutionId()).finished().list(); |
|||
for (HistoricActivityInstance hai : haiList) { |
|||
if (myTaskId.equals(hai.getTaskId())) { |
|||
myActivityId = hai.getActivityId(); |
|||
break; |
|||
} |
|||
} |
|||
FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId); |
|||
|
|||
Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult(); |
|||
String activityId = execution.getActivityId(); |
|||
FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId); |
|||
|
|||
//记录原活动方向
|
|||
List<SequenceFlow> oriSequenceFlows = new ArrayList<>(flowNode.getOutgoingFlows()); |
|||
|
|||
|
|||
return AjaxResult.success(); |
|||
} |
|||
|
|||
/** |
|||
* 代办任务列表 |
|||
* |
|||
* @param pageNum 当前页码 |
|||
* @param pageSize 每页条数 |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult todoList(Integer pageNum, Integer pageSize) { |
|||
Page<FlowTaskDto> page = new Page<>(); |
|||
Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); |
|||
TaskQuery taskQuery = taskService.createTaskQuery() |
|||
.active() |
|||
.includeProcessVariables() |
|||
// .taskAssignee(userId.toString())
|
|||
.orderByTaskCreateTime().desc(); |
|||
page.setTotal(taskQuery.count()); |
|||
List<Task> taskList = taskQuery.listPage(pageSize * (pageNum - 1), pageSize); |
|||
List<FlowTaskDto> flowList = new ArrayList<>(); |
|||
for (Task task : taskList) { |
|||
FlowTaskDto flowTask = new FlowTaskDto(); |
|||
// 当前流程信息
|
|||
flowTask.setTaskId(task.getId()); |
|||
flowTask.setTaskDefKey(task.getTaskDefinitionKey()); |
|||
flowTask.setCreateTime(task.getCreateTime()); |
|||
flowTask.setProcDefId(task.getProcessDefinitionId()); |
|||
flowTask.setExecutionId(task.getExecutionId()); |
|||
flowTask.setTaskName(task.getName()); |
|||
// 流程定义信息
|
|||
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() |
|||
.processDefinitionId(task.getProcessDefinitionId()) |
|||
.singleResult(); |
|||
flowTask.setDeployId(pd.getDeploymentId()); |
|||
flowTask.setProcDefName(pd.getName()); |
|||
flowTask.setProcDefVersion(pd.getVersion()); |
|||
flowTask.setProcInsId(task.getProcessInstanceId()); |
|||
|
|||
// 流程发起人信息
|
|||
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() |
|||
.processInstanceId(task.getProcessInstanceId()) |
|||
.singleResult(); |
|||
SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId())); |
|||
// SysUser startUser = sysUserService.selectUserById(Long.parseLong(task.getAssignee()));
|
|||
flowTask.setStartUserId(startUser.getNickName()); |
|||
flowTask.setStartUserName(startUser.getNickName()); |
|||
flowTask.setStartDeptName(startUser.getDept().getDeptName()); |
|||
flowList.add(flowTask); |
|||
} |
|||
|
|||
page.setRecords(flowList); |
|||
return AjaxResult.success(page); |
|||
} |
|||
|
|||
|
|||
/** |
|||
* 已办任务列表 |
|||
* |
|||
* @param pageNum 当前页码 |
|||
* @param pageSize 每页条数 |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult finishedList(Integer pageNum, Integer pageSize) { |
|||
Page<FlowTaskDto> page = new Page<>(); |
|||
Long userId = SecurityUtils.getLoginUser().getUser().getUserId(); |
|||
HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery() |
|||
.includeProcessVariables() |
|||
.finished() |
|||
.taskAssignee(userId.toString()) |
|||
.orderByHistoricTaskInstanceEndTime() |
|||
.desc(); |
|||
List<HistoricTaskInstance> historicTaskInstanceList = taskInstanceQuery.listPage(pageSize * (pageNum - 1), pageSize); |
|||
List<FlowTaskDto> hisTaskList = new ArrayList<>(); |
|||
for (HistoricTaskInstance histTask : historicTaskInstanceList) { |
|||
FlowTaskDto flowTask = new FlowTaskDto(); |
|||
// 当前流程信息
|
|||
flowTask.setTaskId(histTask.getId()); |
|||
// 审批人员信息
|
|||
flowTask.setCreateTime(histTask.getCreateTime()); |
|||
flowTask.setFinishTime(histTask.getEndTime()); |
|||
flowTask.setDuration(getDate(histTask.getDurationInMillis())); |
|||
flowTask.setProcDefId(histTask.getProcessDefinitionId()); |
|||
flowTask.setTaskDefKey(histTask.getTaskDefinitionKey()); |
|||
flowTask.setTaskName(histTask.getName()); |
|||
|
|||
// 流程定义信息
|
|||
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery() |
|||
.processDefinitionId(histTask.getProcessDefinitionId()) |
|||
.singleResult(); |
|||
flowTask.setDeployId(pd.getDeploymentId()); |
|||
flowTask.setProcDefName(pd.getName()); |
|||
flowTask.setProcDefVersion(pd.getVersion()); |
|||
flowTask.setProcInsId(histTask.getProcessInstanceId()); |
|||
flowTask.setHisProcInsId(histTask.getProcessInstanceId()); |
|||
|
|||
// 流程发起人信息
|
|||
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery() |
|||
.processInstanceId(histTask.getProcessInstanceId()) |
|||
.singleResult(); |
|||
SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId())); |
|||
flowTask.setStartUserId(startUser.getNickName()); |
|||
flowTask.setStartUserName(startUser.getNickName()); |
|||
flowTask.setStartDeptName(startUser.getDept().getDeptName()); |
|||
hisTaskList.add(flowTask); |
|||
} |
|||
page.setTotal(taskInstanceQuery.count()); |
|||
page.setRecords(hisTaskList); |
|||
// Map<String, Object> result = new HashMap<>();
|
|||
// result.put("result",page);
|
|||
// result.put("finished",true);
|
|||
return AjaxResult.success(page); |
|||
} |
|||
|
|||
private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) { |
|||
Set<Object> seen = ConcurrentHashMap.newKeySet(); |
|||
return t -> seen.add(keyExtractor.apply(t)); |
|||
} |
|||
|
|||
/** |
|||
* 流程历史流转记录 |
|||
* |
|||
* @param procInsId 流程实例Id |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult flowRecord(String procInsId, String deployId) { |
|||
Map<String, Object> map = new HashMap<String, Object>(); |
|||
if (StringUtils.isNotBlank(procInsId)) { |
|||
List<HistoricActivityInstance> list = historyService |
|||
.createHistoricActivityInstanceQuery() |
|||
.processInstanceId(procInsId) |
|||
.orderByHistoricActivityInstanceStartTime() |
|||
.desc().list(); |
|||
List<FlowTaskDto> hisFlowList = new ArrayList<>(); |
|||
for (HistoricActivityInstance histIns : list) { |
|||
if (StringUtils.isNotBlank(histIns.getTaskId())) { |
|||
FlowTaskDto flowTask = new FlowTaskDto(); |
|||
flowTask.setTaskId(histIns.getTaskId()); |
|||
flowTask.setTaskName(histIns.getActivityName()); |
|||
flowTask.setCreateTime(histIns.getStartTime()); |
|||
flowTask.setFinishTime(histIns.getEndTime()); |
|||
if (StringUtils.isNotBlank(histIns.getAssignee())) { |
|||
SysUser sysUser = sysUserService.selectUserById(Long.parseLong(histIns.getAssignee())); |
|||
flowTask.setAssigneeId(sysUser.getUserId()); |
|||
flowTask.setAssigneeName(sysUser.getNickName()); |
|||
flowTask.setDeptName(sysUser.getDept().getDeptName()); |
|||
} |
|||
// 展示审批人员
|
|||
List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId()); |
|||
StringBuilder stringBuilder = new StringBuilder(); |
|||
for (HistoricIdentityLink identityLink : linksForTask) { |
|||
// 获选人,候选组/角色(多个)
|
|||
if ("candidate".equals(identityLink.getType())) { |
|||
if (StringUtils.isNotBlank(identityLink.getUserId())) { |
|||
SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId())); |
|||
stringBuilder.append(sysUser.getNickName()).append(","); |
|||
} |
|||
if (StringUtils.isNotBlank(identityLink.getGroupId())) { |
|||
SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId())); |
|||
stringBuilder.append(sysRole.getRoleName()).append(","); |
|||
} |
|||
} |
|||
} |
|||
if (StringUtils.isNotBlank(stringBuilder)) { |
|||
flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1)); |
|||
} |
|||
|
|||
flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis())); |
|||
// 获取意见评论内容
|
|||
List<Comment> commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId()); |
|||
commentList.forEach(comment -> { |
|||
if (histIns.getTaskId().equals(comment.getTaskId())) { |
|||
flowTask.setComment(FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build()); |
|||
} |
|||
}); |
|||
hisFlowList.add(flowTask); |
|||
} |
|||
} |
|||
map.put("flowList", hisFlowList); |
|||
// // 查询当前任务是否完成
|
|||
// List<Task> taskList = taskService.createTaskQuery().processInstanceId(procInsId).list();
|
|||
// if (CollectionUtils.isNotEmpty(taskList)) {
|
|||
// map.put("finished", true);
|
|||
// } else {
|
|||
// map.put("finished", false);
|
|||
// }
|
|||
} |
|||
// 第一次申请获取初始化表单
|
|||
if (StringUtils.isNotBlank(deployId)) { |
|||
SysForm sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId); |
|||
if (Objects.isNull(sysForm)) { |
|||
return AjaxResult.error("请先配置流程表单"); |
|||
} |
|||
map.put("formData", JSONObject.parseObject(sysForm.getFormContent())); |
|||
} |
|||
return AjaxResult.success(map); |
|||
} |
|||
|
|||
/** |
|||
* 根据任务ID查询挂载的表单信息 |
|||
* |
|||
* @param taskId 任务Id |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public Task getTaskForm(String taskId) { |
|||
Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); |
|||
return task; |
|||
} |
|||
|
|||
/** |
|||
* 获取流程过程图 |
|||
* |
|||
* @param processId |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public InputStream diagram(String processId) { |
|||
String processDefinitionId; |
|||
// 获取当前的流程实例
|
|||
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); |
|||
// 如果流程已经结束,则得到结束节点
|
|||
if (Objects.isNull(processInstance)) { |
|||
HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult(); |
|||
|
|||
processDefinitionId = pi.getProcessDefinitionId(); |
|||
} else {// 如果流程没有结束,则取当前活动节点
|
|||
// 根据流程实例ID获得当前处于活动状态的ActivityId合集
|
|||
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult(); |
|||
processDefinitionId = pi.getProcessDefinitionId(); |
|||
} |
|||
|
|||
// 获得活动的节点
|
|||
List<HistoricActivityInstance> highLightedFlowList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list(); |
|||
|
|||
List<String> highLightedFlows = new ArrayList<>(); |
|||
List<String> highLightedNodes = new ArrayList<>(); |
|||
//高亮线
|
|||
for (HistoricActivityInstance tempActivity : highLightedFlowList) { |
|||
if ("sequenceFlow".equals(tempActivity.getActivityType())) { |
|||
//高亮线
|
|||
highLightedFlows.add(tempActivity.getActivityId()); |
|||
} else { |
|||
//高亮节点
|
|||
highLightedNodes.add(tempActivity.getActivityId()); |
|||
} |
|||
} |
|||
|
|||
//获取流程图
|
|||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId); |
|||
ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration(); |
|||
//获取自定义图片生成器
|
|||
ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator(); |
|||
InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes, highLightedFlows, configuration.getActivityFontName(), |
|||
configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), 1.0, true); |
|||
return in; |
|||
|
|||
} |
|||
|
|||
/** |
|||
* 获取流程执行过程 |
|||
* |
|||
* @param procInsId 流程实例id |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult getFlowViewer(String procInsId, String executionId) { |
|||
List<FlowViewerDto> flowViewerList = new ArrayList<>(); |
|||
FlowViewerDto flowViewerDto; |
|||
// 获取任务开始节点(临时处理方式)
|
|||
List<HistoricActivityInstance> startNodeList = historyService.createHistoricActivityInstanceQuery() |
|||
.processInstanceId(procInsId) |
|||
.orderByHistoricActivityInstanceStartTime() |
|||
.asc().listPage(0, 3); |
|||
for (HistoricActivityInstance startInstance : startNodeList) { |
|||
if (!"sequenceFlow".equals(startInstance.getActivityType())) { |
|||
flowViewerDto = new FlowViewerDto(); |
|||
if (!"sequenceFlow".equals(startInstance.getActivityType())) { |
|||
flowViewerDto.setKey(startInstance.getActivityId()); |
|||
// 根据流程节点处理时间校验改节点是否已完成
|
|||
flowViewerDto.setCompleted(!Objects.isNull(startInstance.getEndTime())); |
|||
flowViewerList.add(flowViewerDto); |
|||
} |
|||
} |
|||
} |
|||
// 历史节点
|
|||
List<HistoricActivityInstance> hisActIns = historyService.createHistoricActivityInstanceQuery() |
|||
.executionId(executionId) |
|||
.orderByHistoricActivityInstanceStartTime() |
|||
.asc().list(); |
|||
for (HistoricActivityInstance activityInstance : hisActIns) { |
|||
if (!"sequenceFlow".equals(activityInstance.getActivityType())) { |
|||
flowViewerDto = new FlowViewerDto(); |
|||
flowViewerDto.setKey(activityInstance.getActivityId()); |
|||
// 根据流程节点处理时间校验改节点是否已完成
|
|||
flowViewerDto.setCompleted(!Objects.isNull(activityInstance.getEndTime())); |
|||
flowViewerList.add(flowViewerDto); |
|||
} |
|||
} |
|||
return AjaxResult.success(flowViewerList); |
|||
} |
|||
|
|||
/** |
|||
* 获取流程变量 |
|||
* |
|||
* @param taskId |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult processVariables(String taskId) { |
|||
// 流程变量
|
|||
HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().includeProcessVariables().finished().taskId(taskId).singleResult(); |
|||
if (Objects.nonNull(historicTaskInstance)) { |
|||
return AjaxResult.success(historicTaskInstance.getProcessVariables()); |
|||
} else { |
|||
Map<String, Object> variables = taskService.getVariables(taskId); |
|||
return AjaxResult.success(variables); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 获取下一节点 |
|||
* |
|||
* @param flowTaskVo 任务 |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public AjaxResult getNextFlowNode(FlowTaskVo flowTaskVo) { |
|||
// Step 1. 获取当前节点并找到下一步节点
|
|||
Task task = taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult(); |
|||
FlowNextDto flowNextDto = new FlowNextDto(); |
|||
if (Objects.nonNull(task)) { |
|||
// Step 2. 获取当前流程所有流程变量(网关节点时需要校验表达式)
|
|||
Map<String, Object> variables = taskService.getVariables(task.getId()); |
|||
List<UserTask> nextUserTask = FindNextNodeUtil.getNextUserTasks(repositoryService, task, variables); |
|||
if (CollectionUtils.isNotEmpty(nextUserTask)) { |
|||
for (UserTask userTask : nextUserTask) { |
|||
MultiInstanceLoopCharacteristics multiInstance = userTask.getLoopCharacteristics(); |
|||
// 会签节点
|
|||
if (Objects.nonNull(multiInstance)) { |
|||
List<SysUser> list = sysUserService.selectUserList(new SysUser()); |
|||
|
|||
flowNextDto.setVars(ProcessConstants.PROCESS_MULTI_INSTANCE_USER); |
|||
flowNextDto.setType(ProcessConstants.PROCESS_MULTI_INSTANCE); |
|||
flowNextDto.setUserList(list); |
|||
} else { |
|||
|
|||
// 读取自定义节点属性 判断是否是否需要动态指定任务接收人员、组
|
|||
String dataType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_DATA_TYPE); |
|||
String userType = userTask.getAttributeValue(ProcessConstants.NAMASPASE, ProcessConstants.PROCESS_CUSTOM_USER_TYPE); |
|||
|
|||
// 处理加载动态指定下一节点接收人员信息
|
|||
if (ProcessConstants.DATA_TYPE.equals(dataType)) { |
|||
// 指定单个人员
|
|||
if (ProcessConstants.USER_TYPE_ASSIGNEE.equals(userType)) { |
|||
List<SysUser> list = sysUserService.selectUserList(new SysUser()); |
|||
|
|||
flowNextDto.setVars(ProcessConstants.PROCESS_APPROVAL); |
|||
flowNextDto.setType(ProcessConstants.USER_TYPE_ASSIGNEE); |
|||
flowNextDto.setUserList(list); |
|||
} |
|||
// 候选人员(多个)
|
|||
if (ProcessConstants.USER_TYPE_USERS.equals(userType)) { |
|||
List<SysUser> list = sysUserService.selectUserList(new SysUser()); |
|||
|
|||
flowNextDto.setVars(ProcessConstants.PROCESS_APPROVAL); |
|||
flowNextDto.setType(ProcessConstants.USER_TYPE_USERS); |
|||
flowNextDto.setUserList(list); |
|||
} |
|||
// 候选组
|
|||
if (ProcessConstants.USER_TYPE_ROUPS.equals(userType)) { |
|||
List<SysRole> sysRoles = sysRoleService.selectRoleAll(); |
|||
|
|||
flowNextDto.setVars(ProcessConstants.PROCESS_APPROVAL); |
|||
flowNextDto.setType(ProcessConstants.USER_TYPE_ROUPS); |
|||
flowNextDto.setRoleList(sysRoles); |
|||
} |
|||
} else { |
|||
flowNextDto.setType(ProcessConstants.FIXED); |
|||
} |
|||
} |
|||
} |
|||
} else { |
|||
return AjaxResult.success("流程已完结", null); |
|||
} |
|||
} |
|||
return AjaxResult.success(flowNextDto); |
|||
} |
|||
|
|||
/** |
|||
* 流程完成时间处理 |
|||
* |
|||
* @param ms |
|||
* @return |
|||
*/ |
|||
private String getDate(long ms) { |
|||
|
|||
long day = ms / (24 * 60 * 60 * 1000); |
|||
long hour = (ms / (60 * 60 * 1000) - day * 24); |
|||
long minute = ((ms / (60 * 1000)) - day * 24 * 60 - hour * 60); |
|||
long second = (ms / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60); |
|||
|
|||
if (day > 0) { |
|||
return day + "天" + hour + "小时" + minute + "分钟"; |
|||
} |
|||
if (hour > 0) { |
|||
return hour + "小时" + minute + "分钟"; |
|||
} |
|||
if (minute > 0) { |
|||
return minute + "分钟"; |
|||
} |
|||
if (second > 0) { |
|||
return second + "秒"; |
|||
} else { |
|||
return 0 + "秒"; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,112 @@ |
|||
package com.ruoyi.flowable.service.impl; |
|||
|
|||
import java.util.List; |
|||
import java.util.Objects; |
|||
|
|||
import com.ruoyi.system.domain.SysForm; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import com.ruoyi.system.mapper.SysDeployFormMapper; |
|||
import com.ruoyi.system.domain.SysDeployForm; |
|||
import com.ruoyi.flowable.service.ISysDeployFormService; |
|||
|
|||
/** |
|||
* 流程实例关联表单Service业务层处理 |
|||
* |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Service |
|||
public class SysDeployFormServiceImpl implements ISysDeployFormService |
|||
{ |
|||
@Autowired |
|||
private SysDeployFormMapper sysDeployFormMapper; |
|||
|
|||
/** |
|||
* 查询流程实例关联表单 |
|||
* |
|||
* @param id 流程实例关联表单ID |
|||
* @return 流程实例关联表单 |
|||
*/ |
|||
@Override |
|||
public SysDeployForm selectSysDeployFormById(Long id) |
|||
{ |
|||
return sysDeployFormMapper.selectSysDeployFormById(id); |
|||
} |
|||
|
|||
/** |
|||
* 查询流程实例关联表单列表 |
|||
* |
|||
* @param sysDeployForm 流程实例关联表单 |
|||
* @return 流程实例关联表单 |
|||
*/ |
|||
@Override |
|||
public List<SysDeployForm> selectSysDeployFormList(SysDeployForm sysDeployForm) |
|||
{ |
|||
return sysDeployFormMapper.selectSysDeployFormList(sysDeployForm); |
|||
} |
|||
|
|||
/** |
|||
* 新增流程实例关联表单 |
|||
* |
|||
* @param sysDeployForm 流程实例关联表单 |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int insertSysDeployForm(SysDeployForm sysDeployForm) |
|||
{ |
|||
SysForm sysForm = sysDeployFormMapper.selectSysDeployFormByDeployId(sysDeployForm.getDeployId()); |
|||
if (Objects.isNull(sysForm)) { |
|||
return sysDeployFormMapper.insertSysDeployForm(sysDeployForm); |
|||
}else { |
|||
return 1; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 修改流程实例关联表单 |
|||
* |
|||
* @param sysDeployForm 流程实例关联表单 |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int updateSysDeployForm(SysDeployForm sysDeployForm) |
|||
{ |
|||
return sysDeployFormMapper.updateSysDeployForm(sysDeployForm); |
|||
} |
|||
|
|||
/** |
|||
* 批量删除流程实例关联表单 |
|||
* |
|||
* @param ids 需要删除的流程实例关联表单ID |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int deleteSysDeployFormByIds(Long[] ids) |
|||
{ |
|||
return sysDeployFormMapper.deleteSysDeployFormByIds(ids); |
|||
} |
|||
|
|||
/** |
|||
* 删除流程实例关联表单信息 |
|||
* |
|||
* @param id 流程实例关联表单ID |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int deleteSysDeployFormById(Long id) |
|||
{ |
|||
return sysDeployFormMapper.deleteSysDeployFormById(id); |
|||
} |
|||
|
|||
/** |
|||
* 查询流程挂着的表单 |
|||
* |
|||
* @param deployId |
|||
* @return |
|||
*/ |
|||
@Override |
|||
public SysForm selectSysDeployFormByDeployId(String deployId) { |
|||
return sysDeployFormMapper.selectSysDeployFormByDeployId(deployId); |
|||
} |
|||
} |
|||
@ -0,0 +1,96 @@ |
|||
package com.ruoyi.flowable.service.impl; |
|||
|
|||
import java.util.List; |
|||
import com.ruoyi.common.utils.DateUtils; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import com.ruoyi.system.mapper.SysFormMapper; |
|||
import com.ruoyi.system.domain.SysForm; |
|||
import com.ruoyi.flowable.service.ISysFormService; |
|||
|
|||
/** |
|||
* 流程表单Service业务层处理 |
|||
* |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Service |
|||
public class SysFormServiceImpl implements ISysFormService |
|||
{ |
|||
@Autowired |
|||
private SysFormMapper sysFormMapper; |
|||
|
|||
/** |
|||
* 查询流程表单 |
|||
* |
|||
* @param formId 流程表单ID |
|||
* @return 流程表单 |
|||
*/ |
|||
@Override |
|||
public SysForm selectSysFormById(Long formId) |
|||
{ |
|||
return sysFormMapper.selectSysFormById(formId); |
|||
} |
|||
|
|||
/** |
|||
* 查询流程表单列表 |
|||
* |
|||
* @param sysForm 流程表单 |
|||
* @return 流程表单 |
|||
*/ |
|||
@Override |
|||
public List<SysForm> selectSysFormList(SysForm sysForm) |
|||
{ |
|||
return sysFormMapper.selectSysFormList(sysForm); |
|||
} |
|||
|
|||
/** |
|||
* 新增流程表单 |
|||
* |
|||
* @param sysForm 流程表单 |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int insertSysForm(SysForm sysForm) |
|||
{ |
|||
sysForm.setCreateTime(DateUtils.getNowDate()); |
|||
return sysFormMapper.insertSysForm(sysForm); |
|||
} |
|||
|
|||
/** |
|||
* 修改流程表单 |
|||
* |
|||
* @param sysForm 流程表单 |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int updateSysForm(SysForm sysForm) |
|||
{ |
|||
sysForm.setUpdateTime(DateUtils.getNowDate()); |
|||
return sysFormMapper.updateSysForm(sysForm); |
|||
} |
|||
|
|||
/** |
|||
* 批量删除流程表单 |
|||
* |
|||
* @param formIds 需要删除的流程表单ID |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int deleteSysFormByIds(Long[] formIds) |
|||
{ |
|||
return sysFormMapper.deleteSysFormByIds(formIds); |
|||
} |
|||
|
|||
/** |
|||
* 删除流程表单信息 |
|||
* |
|||
* @param formId 流程表单ID |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int deleteSysFormById(Long formId) |
|||
{ |
|||
return sysFormMapper.deleteSysFormById(formId); |
|||
} |
|||
} |
|||
@ -0,0 +1,93 @@ |
|||
package com.ruoyi.flowable.service.impl; |
|||
|
|||
import java.util.List; |
|||
import org.springframework.beans.factory.annotation.Autowired; |
|||
import org.springframework.stereotype.Service; |
|||
import com.ruoyi.system.mapper.SysTaskFormMapper; |
|||
import com.ruoyi.system.domain.SysTaskForm; |
|||
import com.ruoyi.flowable.service.ISysTaskFormService; |
|||
|
|||
/** |
|||
* 流程任务关联单Service业务层处理 |
|||
* |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Service |
|||
public class SysTaskFormServiceImpl implements ISysTaskFormService |
|||
{ |
|||
@Autowired |
|||
private SysTaskFormMapper sysTaskFormMapper; |
|||
|
|||
/** |
|||
* 查询流程任务关联单 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 流程任务关联单 |
|||
*/ |
|||
@Override |
|||
public SysTaskForm selectSysTaskFormById(Long id) |
|||
{ |
|||
return sysTaskFormMapper.selectSysTaskFormById(id); |
|||
} |
|||
|
|||
/** |
|||
* 查询流程任务关联单列表 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 流程任务关联单 |
|||
*/ |
|||
@Override |
|||
public List<SysTaskForm> selectSysTaskFormList(SysTaskForm sysTaskForm) |
|||
{ |
|||
return sysTaskFormMapper.selectSysTaskFormList(sysTaskForm); |
|||
} |
|||
|
|||
/** |
|||
* 新增流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int insertSysTaskForm(SysTaskForm sysTaskForm) |
|||
{ |
|||
return sysTaskFormMapper.insertSysTaskForm(sysTaskForm); |
|||
} |
|||
|
|||
/** |
|||
* 修改流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int updateSysTaskForm(SysTaskForm sysTaskForm) |
|||
{ |
|||
return sysTaskFormMapper.updateSysTaskForm(sysTaskForm); |
|||
} |
|||
|
|||
/** |
|||
* 批量删除流程任务关联单 |
|||
* |
|||
* @param ids 需要删除的流程任务关联单ID |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int deleteSysTaskFormByIds(Long[] ids) |
|||
{ |
|||
return sysTaskFormMapper.deleteSysTaskFormByIds(ids); |
|||
} |
|||
|
|||
/** |
|||
* 删除流程任务关联单信息 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 结果 |
|||
*/ |
|||
@Override |
|||
public int deleteSysTaskFormById(Long id) |
|||
{ |
|||
return sysTaskFormMapper.deleteSysTaskFormById(id); |
|||
} |
|||
} |
|||
@ -0,0 +1,56 @@ |
|||
package com.ruoyi.system.domain; |
|||
import com.fasterxml.jackson.annotation.JsonFormat; |
|||
import io.swagger.annotations.ApiModel; |
|||
import io.swagger.annotations.ApiModelProperty; |
|||
import lombok.AllArgsConstructor; |
|||
import lombok.Data; |
|||
import lombok.NoArgsConstructor; |
|||
|
|||
import java.io.Serializable; |
|||
import java.util.Date; |
|||
|
|||
/** |
|||
* <p>流程定义<p> |
|||
* |
|||
* @author XuanXuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
@Data |
|||
@AllArgsConstructor |
|||
@NoArgsConstructor |
|||
@ApiModel("流程定义") |
|||
public class FlowProcDefDto implements Serializable { |
|||
|
|||
@ApiModelProperty("流程id") |
|||
private String id; |
|||
|
|||
@ApiModelProperty("流程名称") |
|||
private String name; |
|||
|
|||
@ApiModelProperty("流程key") |
|||
private String flowKey; |
|||
|
|||
@ApiModelProperty("流程分类") |
|||
private String category; |
|||
|
|||
@ApiModelProperty("配置表单名称") |
|||
private String formName; |
|||
|
|||
@ApiModelProperty("配置表单id") |
|||
private Long formId; |
|||
|
|||
@ApiModelProperty("版本") |
|||
private int version; |
|||
|
|||
@ApiModelProperty("部署ID") |
|||
private String deploymentId; |
|||
|
|||
@ApiModelProperty("流程定义状态: 1:激活 , 2:中止") |
|||
private int suspensionState; |
|||
|
|||
@ApiModelProperty("部署时间") |
|||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") |
|||
private Date deploymentTime; |
|||
|
|||
|
|||
} |
|||
@ -0,0 +1,64 @@ |
|||
package com.ruoyi.system.domain; |
|||
|
|||
import com.ruoyi.common.annotation.Excel; |
|||
import com.ruoyi.common.core.domain.BaseEntity; |
|||
import org.apache.commons.lang3.builder.ToStringBuilder; |
|||
import org.apache.commons.lang3.builder.ToStringStyle; |
|||
|
|||
/** |
|||
* 流程实例关联表单对象 sys_instance_form |
|||
* |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-03-30 |
|||
*/ |
|||
public class SysDeployForm extends BaseEntity |
|||
{ |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** 主键 */ |
|||
private Long id; |
|||
|
|||
/** 表单主键 */ |
|||
@Excel(name = "表单主键") |
|||
private Long formId; |
|||
|
|||
/** 流程定义主键 */ |
|||
@Excel(name = "流程定义主键") |
|||
private String deployId; |
|||
|
|||
public void setId(Long id) |
|||
{ |
|||
this.id = id; |
|||
} |
|||
|
|||
public Long getId() |
|||
{ |
|||
return id; |
|||
} |
|||
public void setFormId(Long formId) |
|||
{ |
|||
this.formId = formId; |
|||
} |
|||
|
|||
public Long getFormId() |
|||
{ |
|||
return formId; |
|||
} |
|||
|
|||
public String getDeployId() { |
|||
return deployId; |
|||
} |
|||
|
|||
public void setDeployId(String deployId) { |
|||
this.deployId = deployId; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) |
|||
.append("id", getId()) |
|||
.append("formId", getFormId()) |
|||
.append("deployId", getDeployId()) |
|||
.toString(); |
|||
} |
|||
} |
|||
@ -0,0 +1,70 @@ |
|||
package com.ruoyi.system.domain; |
|||
|
|||
import com.ruoyi.common.annotation.Excel; |
|||
import com.ruoyi.common.core.domain.BaseEntity; |
|||
import org.apache.commons.lang3.builder.ToStringBuilder; |
|||
import org.apache.commons.lang3.builder.ToStringStyle; |
|||
|
|||
/** |
|||
* 流程表单对象 sys_task_form |
|||
* |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-03-30 |
|||
*/ |
|||
public class SysForm extends BaseEntity |
|||
{ |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** 表单主键 */ |
|||
private Long formId; |
|||
|
|||
/** 表单名称 */ |
|||
@Excel(name = "表单名称") |
|||
private String formName; |
|||
|
|||
/** 表单内容 */ |
|||
@Excel(name = "表单内容") |
|||
private String formContent; |
|||
|
|||
public void setFormId(Long formId) |
|||
{ |
|||
this.formId = formId; |
|||
} |
|||
|
|||
public Long getFormId() |
|||
{ |
|||
return formId; |
|||
} |
|||
public void setFormName(String formName) |
|||
{ |
|||
this.formName = formName; |
|||
} |
|||
|
|||
public String getFormName() |
|||
{ |
|||
return formName; |
|||
} |
|||
public void setFormContent(String formContent) |
|||
{ |
|||
this.formContent = formContent; |
|||
} |
|||
|
|||
public String getFormContent() |
|||
{ |
|||
return formContent; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) |
|||
.append("formId", getFormId()) |
|||
.append("formName", getFormName()) |
|||
.append("formContent", getFormContent()) |
|||
.append("createTime", getCreateTime()) |
|||
.append("updateTime", getUpdateTime()) |
|||
.append("createBy", getCreateBy()) |
|||
.append("updateBy", getUpdateBy()) |
|||
.append("remark", getRemark()) |
|||
.toString(); |
|||
} |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
package com.ruoyi.system.domain; |
|||
|
|||
import com.ruoyi.common.annotation.Excel; |
|||
import com.ruoyi.common.core.domain.BaseEntity; |
|||
import org.apache.commons.lang3.builder.ToStringBuilder; |
|||
import org.apache.commons.lang3.builder.ToStringStyle; |
|||
|
|||
/** |
|||
* 流程任务关联单对象 sys_task_form |
|||
* |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
public class SysTaskForm extends BaseEntity |
|||
{ |
|||
private static final long serialVersionUID = 1L; |
|||
|
|||
/** 主键 */ |
|||
private Long id; |
|||
|
|||
/** 表单主键 */ |
|||
@Excel(name = "表单主键") |
|||
private Long formId; |
|||
|
|||
/** 所属任务 */ |
|||
@Excel(name = "所属任务") |
|||
private String taskId; |
|||
|
|||
public void setId(Long id) |
|||
{ |
|||
this.id = id; |
|||
} |
|||
|
|||
public Long getId() |
|||
{ |
|||
return id; |
|||
} |
|||
public void setFormId(Long formId) |
|||
{ |
|||
this.formId = formId; |
|||
} |
|||
|
|||
public Long getFormId() |
|||
{ |
|||
return formId; |
|||
} |
|||
public void setTaskId(String taskId) |
|||
{ |
|||
this.taskId = taskId; |
|||
} |
|||
|
|||
public String getTaskId() |
|||
{ |
|||
return taskId; |
|||
} |
|||
|
|||
@Override |
|||
public String toString() { |
|||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) |
|||
.append("id", getId()) |
|||
.append("formId", getFormId()) |
|||
.append("taskId", getTaskId()) |
|||
.toString(); |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
package com.ruoyi.system.mapper; |
|||
|
|||
import com.ruoyi.system.domain.FlowProcDefDto; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 流程定义查询 |
|||
* |
|||
* @author Xuan Xuan |
|||
* @email |
|||
* @date 2022/1/29 5:44 下午 |
|||
**/ |
|||
public interface FlowDeployMapper { |
|||
|
|||
/** |
|||
* 流程定义列表 |
|||
* @param name |
|||
* @return |
|||
*/ |
|||
List<FlowProcDefDto> selectDeployList(String name); |
|||
} |
|||
@ -0,0 +1,72 @@ |
|||
package com.ruoyi.system.mapper; |
|||
|
|||
import com.ruoyi.system.domain.SysDeployForm; |
|||
import com.ruoyi.system.domain.SysForm; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 流程实例关联表单Mapper接口 |
|||
* |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-03-30 |
|||
*/ |
|||
public interface SysDeployFormMapper |
|||
{ |
|||
/** |
|||
* 查询流程实例关联表单 |
|||
* |
|||
* @param id 流程实例关联表单ID |
|||
* @return 流程实例关联表单 |
|||
*/ |
|||
public SysDeployForm selectSysDeployFormById(Long id); |
|||
|
|||
/** |
|||
* 查询流程实例关联表单列表 |
|||
* |
|||
* @param SysDeployForm 流程实例关联表单 |
|||
* @return 流程实例关联表单集合 |
|||
*/ |
|||
public List<SysDeployForm> selectSysDeployFormList(SysDeployForm SysDeployForm); |
|||
|
|||
/** |
|||
* 新增流程实例关联表单 |
|||
* |
|||
* @param SysDeployForm 流程实例关联表单 |
|||
* @return 结果 |
|||
*/ |
|||
public int insertSysDeployForm(SysDeployForm SysDeployForm); |
|||
|
|||
/** |
|||
* 修改流程实例关联表单 |
|||
* |
|||
* @param SysDeployForm 流程实例关联表单 |
|||
* @return 结果 |
|||
*/ |
|||
public int updateSysDeployForm(SysDeployForm SysDeployForm); |
|||
|
|||
/** |
|||
* 删除流程实例关联表单 |
|||
* |
|||
* @param id 流程实例关联表单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysDeployFormById(Long id); |
|||
|
|||
/** |
|||
* 批量删除流程实例关联表单 |
|||
* |
|||
* @param ids 需要删除的数据ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysDeployFormByIds(Long[] ids); |
|||
|
|||
|
|||
|
|||
/** |
|||
* 查询流程挂着的表单 |
|||
* @param deployId |
|||
* @return |
|||
*/ |
|||
SysForm selectSysDeployFormByDeployId(String deployId); |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
package com.ruoyi.system.mapper; |
|||
|
|||
import com.ruoyi.system.domain.SysForm; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 流程表单Mapper接口 |
|||
* |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-03-30 |
|||
*/ |
|||
public interface SysFormMapper |
|||
{ |
|||
/** |
|||
* 查询流程表单 |
|||
* |
|||
* @param formId 流程表单ID |
|||
* @return 流程表单 |
|||
*/ |
|||
public SysForm selectSysFormById(Long formId); |
|||
|
|||
/** |
|||
* 查询流程表单列表 |
|||
* |
|||
* @param sysForm 流程表单 |
|||
* @return 流程表单集合 |
|||
*/ |
|||
public List<SysForm> selectSysFormList(SysForm sysForm); |
|||
|
|||
/** |
|||
* 新增流程表单 |
|||
* |
|||
* @param sysForm 流程表单 |
|||
* @return 结果 |
|||
*/ |
|||
public int insertSysForm(SysForm sysForm); |
|||
|
|||
/** |
|||
* 修改流程表单 |
|||
* |
|||
* @param sysForm 流程表单 |
|||
* @return 结果 |
|||
*/ |
|||
public int updateSysForm(SysForm sysForm); |
|||
|
|||
/** |
|||
* 删除流程表单 |
|||
* |
|||
* @param formId 流程表单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysFormById(Long formId); |
|||
|
|||
/** |
|||
* 批量删除流程表单 |
|||
* |
|||
* @param formIds 需要删除的数据ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysFormByIds(Long[] formIds); |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
package com.ruoyi.system.mapper; |
|||
|
|||
import com.ruoyi.system.domain.SysTaskForm; |
|||
|
|||
import java.util.List; |
|||
|
|||
/** |
|||
* 流程任务关联单Mapper接口 |
|||
* |
|||
* @author XuanXuan Xuan |
|||
* @date 2021-04-03 |
|||
*/ |
|||
public interface SysTaskFormMapper |
|||
{ |
|||
/** |
|||
* 查询流程任务关联单 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 流程任务关联单 |
|||
*/ |
|||
public SysTaskForm selectSysTaskFormById(Long id); |
|||
|
|||
/** |
|||
* 查询流程任务关联单列表 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 流程任务关联单集合 |
|||
*/ |
|||
public List<SysTaskForm> selectSysTaskFormList(SysTaskForm sysTaskForm); |
|||
|
|||
/** |
|||
* 新增流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
public int insertSysTaskForm(SysTaskForm sysTaskForm); |
|||
|
|||
/** |
|||
* 修改流程任务关联单 |
|||
* |
|||
* @param sysTaskForm 流程任务关联单 |
|||
* @return 结果 |
|||
*/ |
|||
public int updateSysTaskForm(SysTaskForm sysTaskForm); |
|||
|
|||
/** |
|||
* 删除流程任务关联单 |
|||
* |
|||
* @param id 流程任务关联单ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysTaskFormById(Long id); |
|||
|
|||
/** |
|||
* 批量删除流程任务关联单 |
|||
* |
|||
* @param ids 需要删除的数据ID |
|||
* @return 结果 |
|||
*/ |
|||
public int deleteSysTaskFormByIds(Long[] ids); |
|||
} |
|||
@ -0,0 +1,31 @@ |
|||
<?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.ruoyi.system.mapper.FlowDeployMapper"> |
|||
|
|||
|
|||
<select id="selectDeployList" resultType="com.ruoyi.system.domain.FlowProcDefDto"> |
|||
|
|||
SELECT |
|||
rp.id_ as id, |
|||
rd.id_ as deploymentId, |
|||
rd.name_ as name, |
|||
rd.category_ as category, |
|||
rp.key_ as flowKey, |
|||
rp.version_ as version, |
|||
rp.suspension_state_ as suspensionState, |
|||
rd.deploy_time_ as deploymentTime |
|||
FROM |
|||
ACT_RE_PROCDEF rp |
|||
LEFT JOIN ACT_RE_DEPLOYMENT rd ON rp.deployment_id_ = rd.id_ |
|||
<where> |
|||
<if test="name != null and name != ''"> |
|||
and rd.name_ like concat('%', #{name}, '%') |
|||
</if> |
|||
</where> |
|||
order by rd.deploy_time_ desc |
|||
</select> |
|||
|
|||
|
|||
</mapper> |
|||
@ -0,0 +1,61 @@ |
|||
<?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.ruoyi.system.mapper.SysTaskFormMapper"> |
|||
|
|||
<resultMap type="SysTaskForm" id="SysTaskFormResult"> |
|||
<result property="id" column="id" /> |
|||
<result property="formId" column="form_id" /> |
|||
<result property="taskId" column="task_id" /> |
|||
</resultMap> |
|||
|
|||
<sql id="selectSysTaskFormVo"> |
|||
select id, form_id, task_id from sys_task_form |
|||
</sql> |
|||
|
|||
<select id="selectSysTaskFormList" parameterType="SysTaskForm" resultMap="SysTaskFormResult"> |
|||
<include refid="selectSysTaskFormVo"/> |
|||
<where> |
|||
<if test="formId != null "> and form_id = #{formId}</if> |
|||
<if test="taskId != null and taskId != ''"> and task_id = #{taskId}</if> |
|||
</where> |
|||
</select> |
|||
|
|||
<select id="selectSysTaskFormById" parameterType="Long" resultMap="SysTaskFormResult"> |
|||
<include refid="selectSysTaskFormVo"/> |
|||
where id = #{id} |
|||
</select> |
|||
|
|||
<insert id="insertSysTaskForm" parameterType="SysTaskForm" useGeneratedKeys="true" keyProperty="id"> |
|||
insert into sys_task_form |
|||
<trim prefix="(" suffix=")" suffixOverrides=","> |
|||
<if test="formId != null">form_id,</if> |
|||
<if test="taskId != null">task_id,</if> |
|||
</trim> |
|||
<trim prefix="values (" suffix=")" suffixOverrides=","> |
|||
<if test="formId != null">#{formId},</if> |
|||
<if test="taskId != null">#{taskId},</if> |
|||
</trim> |
|||
</insert> |
|||
|
|||
<update id="updateSysTaskForm" parameterType="SysTaskForm"> |
|||
update sys_task_form |
|||
<trim prefix="SET" suffixOverrides=","> |
|||
<if test="formId != null">form_id = #{formId},</if> |
|||
<if test="taskId != null">task_id = #{taskId},</if> |
|||
</trim> |
|||
where id = #{id} |
|||
</update> |
|||
|
|||
<delete id="deleteSysTaskFormById" parameterType="Long"> |
|||
delete from sys_task_form where id = #{id} |
|||
</delete> |
|||
|
|||
<delete id="deleteSysTaskFormByIds" parameterType="String"> |
|||
delete from sys_task_form where id in |
|||
<foreach item="id" collection="array" open="(" separator="," close=")"> |
|||
#{id} |
|||
</foreach> |
|||
</delete> |
|||
</mapper> |
|||
@ -0,0 +1,66 @@ |
|||
<?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.ruoyi.system.mapper.SysDeployFormMapper"> |
|||
|
|||
<resultMap type="SysDeployForm" id="SysDeployFormResult"> |
|||
<result property="id" column="id" /> |
|||
<result property="formId" column="form_id" /> |
|||
<result property="deployId" column="deploy_id" /> |
|||
</resultMap> |
|||
|
|||
<sql id="selectSysDeployFormVo"> |
|||
select id, form_id, deploy_id from sys_deploy_form |
|||
</sql> |
|||
|
|||
<select id="selectSysDeployFormList" parameterType="SysDeployForm" resultMap="SysDeployFormResult"> |
|||
<include refid="selectSysDeployFormVo"/> |
|||
<where> |
|||
<if test="formId != null "> and form_id = #{formId}</if> |
|||
<if test="deployId != null and deployId != ''"> and deploy_id = #{deployId}</if> |
|||
</where> |
|||
</select> |
|||
|
|||
<select id="selectSysDeployFormById" parameterType="Long" resultMap="SysDeployFormResult"> |
|||
<include refid="selectSysDeployFormVo"/> |
|||
where id = #{id} |
|||
</select> |
|||
|
|||
<select id="selectSysDeployFormByDeployId" resultType="com.ruoyi.system.domain.SysForm"> |
|||
select t1.form_content as formContent,t1.form_name as formName,t1.form_id as formId from sys_form t1 left join sys_deploy_form t2 on t1.form_id = t2.form_id |
|||
where t2.deploy_id = #{deployId} limit 1 |
|||
</select> |
|||
|
|||
<insert id="insertSysDeployForm" parameterType="SysDeployForm" useGeneratedKeys="true" keyProperty="id"> |
|||
insert into sys_deploy_form |
|||
<trim prefix="(" suffix=")" suffixOverrides=","> |
|||
<if test="formId != null">form_id,</if> |
|||
<if test="deployId != null">deploy_id,</if> |
|||
</trim> |
|||
<trim prefix="values (" suffix=")" suffixOverrides=","> |
|||
<if test="formId != null">#{formId},</if> |
|||
<if test="deployId != null">#{deployId},</if> |
|||
</trim> |
|||
</insert> |
|||
|
|||
<update id="updateSysDeployForm" parameterType="SysDeployForm"> |
|||
update sys_deploy_form |
|||
<trim prefix="SET" suffixOverrides=","> |
|||
<if test="formId != null">form_id = #{formId},</if> |
|||
<if test="deployId != null">deploy_id = #{deployId},</if> |
|||
</trim> |
|||
where id = #{id} |
|||
</update> |
|||
|
|||
<delete id="deleteSysDeployFormById" parameterType="Long"> |
|||
delete from sys_deploy_form where id = #{id} |
|||
</delete> |
|||
|
|||
<delete id="deleteSysDeployFormByIds" parameterType="String"> |
|||
delete from sys_deploy_form where id in |
|||
<foreach item="id" collection="array" open="(" separator="," close=")"> |
|||
#{id} |
|||
</foreach> |
|||
</delete> |
|||
</mapper> |
|||
@ -0,0 +1,82 @@ |
|||
<?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.ruoyi.system.mapper.SysFormMapper"> |
|||
|
|||
<resultMap type="SysForm" id="SysFormResult"> |
|||
<result property="formId" column="form_id" /> |
|||
<result property="formName" column="form_name" /> |
|||
<result property="formContent" column="form_content" /> |
|||
<result property="createTime" column="create_time" /> |
|||
<result property="updateTime" column="update_time" /> |
|||
<result property="createBy" column="create_by" /> |
|||
<result property="updateBy" column="update_by" /> |
|||
<result property="remark" column="remark" /> |
|||
</resultMap> |
|||
|
|||
<sql id="selectSysFormVo"> |
|||
select form_id, form_name, form_content, create_time, update_time, create_by, update_by, remark from sys_form |
|||
</sql> |
|||
|
|||
<select id="selectSysFormList" parameterType="SysForm" resultMap="SysFormResult"> |
|||
<include refid="selectSysFormVo"/> |
|||
<where> |
|||
<if test="formName != null and formName != ''"> and form_name like concat('%', #{formName}, '%')</if> |
|||
<if test="formContent != null and formContent != ''"> and form_content = #{formContent}</if> |
|||
</where> |
|||
order by create_time desc |
|||
</select> |
|||
|
|||
<select id="selectSysFormById" parameterType="Long" resultMap="SysFormResult"> |
|||
<include refid="selectSysFormVo"/> |
|||
where form_id = #{formId} |
|||
</select> |
|||
|
|||
<insert id="insertSysForm" parameterType="SysForm" useGeneratedKeys="true" keyProperty="formId"> |
|||
insert into sys_form |
|||
<trim prefix="(" suffix=")" suffixOverrides=","> |
|||
<if test="formName != null">form_name,</if> |
|||
<if test="formContent != null">form_content,</if> |
|||
<if test="createTime != null">create_time,</if> |
|||
<if test="updateTime != null">update_time,</if> |
|||
<if test="createBy != null">create_by,</if> |
|||
<if test="updateBy != null">update_by,</if> |
|||
<if test="remark != null">remark,</if> |
|||
</trim> |
|||
<trim prefix="values (" suffix=")" suffixOverrides=","> |
|||
<if test="formName != null">#{formName},</if> |
|||
<if test="formContent != null">#{formContent},</if> |
|||
<if test="createTime != null">#{createTime},</if> |
|||
<if test="updateTime != null">#{updateTime},</if> |
|||
<if test="createBy != null">#{createBy},</if> |
|||
<if test="updateBy != null">#{updateBy},</if> |
|||
<if test="remark != null">#{remark},</if> |
|||
</trim> |
|||
</insert> |
|||
|
|||
<update id="updateSysForm" parameterType="SysForm"> |
|||
update sys_form |
|||
<trim prefix="SET" suffixOverrides=","> |
|||
<if test="formName != null">form_name = #{formName},</if> |
|||
<if test="formContent != null">form_content = #{formContent},</if> |
|||
<if test="createTime != null">create_time = #{createTime},</if> |
|||
<if test="updateTime != null">update_time = #{updateTime},</if> |
|||
<if test="createBy != null">create_by = #{createBy},</if> |
|||
<if test="updateBy != null">update_by = #{updateBy},</if> |
|||
<if test="remark != null">remark = #{remark},</if> |
|||
</trim> |
|||
where form_id = #{formId} |
|||
</update> |
|||
|
|||
<delete id="deleteSysFormById" parameterType="Long"> |
|||
delete from sys_form where form_id = #{formId} |
|||
</delete> |
|||
|
|||
<delete id="deleteSysFormByIds" parameterType="String"> |
|||
delete from sys_form where form_id in |
|||
<foreach item="formId" collection="array" open="(" separator="," close=")"> |
|||
#{formId} |
|||
</foreach> |
|||
</delete> |
|||
</mapper> |
|||
@ -0,0 +1,31 @@ |
|||
/* |
|||
Navicat Premium Data Transfer |
|||
|
|||
Source Server : tony |
|||
Source Server Type : MySQL |
|||
Source Server Version : 50737 (5.7.37-log) |
|||
Source Host : 43.142.119.38:3306 |
|||
Source Schema : flowable |
|||
|
|||
Target Server Type : MySQL |
|||
Target Server Version : 50737 (5.7.37-log) |
|||
File Encoding : 65001 |
|||
|
|||
Date: 11/12/2022 17:36:48 |
|||
*/ |
|||
|
|||
SET NAMES utf8mb4; |
|||
SET FOREIGN_KEY_CHECKS = 0; |
|||
|
|||
-- ---------------------------- |
|||
-- Table structure for sys_deploy_form |
|||
-- ---------------------------- |
|||
DROP TABLE IF EXISTS `sys_deploy_form`; |
|||
CREATE TABLE `sys_deploy_form` ( |
|||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', |
|||
`form_id` bigint(20) DEFAULT NULL COMMENT '表单主键', |
|||
`deploy_id` varchar(50) DEFAULT NULL COMMENT '流程实例主键', |
|||
PRIMARY KEY (`id`) USING BTREE |
|||
) ENGINE=InnoDB AUTO_INCREMENT=6180 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='流程实例关联表单'; |
|||
|
|||
SET FOREIGN_KEY_CHECKS = 1; |
|||
@ -0,0 +1,36 @@ |
|||
/* |
|||
Navicat Premium Data Transfer |
|||
|
|||
Source Server : tony |
|||
Source Server Type : MySQL |
|||
Source Server Version : 50737 (5.7.37-log) |
|||
Source Host : 43.142.119.38:3306 |
|||
Source Schema : flowable |
|||
|
|||
Target Server Type : MySQL |
|||
Target Server Version : 50737 (5.7.37-log) |
|||
File Encoding : 65001 |
|||
|
|||
Date: 11/12/2022 17:36:59 |
|||
*/ |
|||
|
|||
SET NAMES utf8mb4; |
|||
SET FOREIGN_KEY_CHECKS = 0; |
|||
|
|||
-- ---------------------------- |
|||
-- Table structure for sys_form |
|||
-- ---------------------------- |
|||
DROP TABLE IF EXISTS `sys_form`; |
|||
CREATE TABLE `sys_form` ( |
|||
`form_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '表单主键', |
|||
`form_name` varchar(50) DEFAULT NULL COMMENT '表单名称', |
|||
`form_content` longtext COMMENT '表单内容', |
|||
`create_time` datetime DEFAULT NULL COMMENT '创建时间', |
|||
`update_time` datetime DEFAULT NULL COMMENT '更新时间', |
|||
`create_by` bigint(20) DEFAULT NULL COMMENT '创建人员', |
|||
`update_by` bigint(20) DEFAULT NULL COMMENT '更新人员', |
|||
`remark` varchar(255) DEFAULT NULL COMMENT '备注', |
|||
PRIMARY KEY (`form_id`) USING BTREE |
|||
) ENGINE=InnoDB AUTO_INCREMENT=3170 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='流程表单'; |
|||
|
|||
SET FOREIGN_KEY_CHECKS = 1; |
|||
@ -0,0 +1,31 @@ |
|||
/* |
|||
Navicat Premium Data Transfer |
|||
|
|||
Source Server : tony |
|||
Source Server Type : MySQL |
|||
Source Server Version : 50737 (5.7.37-log) |
|||
Source Host : 43.142.119.38:3306 |
|||
Source Schema : flowable |
|||
|
|||
Target Server Type : MySQL |
|||
Target Server Version : 50737 (5.7.37-log) |
|||
File Encoding : 65001 |
|||
|
|||
Date: 11/12/2022 17:37:15 |
|||
*/ |
|||
|
|||
SET NAMES utf8mb4; |
|||
SET FOREIGN_KEY_CHECKS = 0; |
|||
|
|||
-- ---------------------------- |
|||
-- Table structure for sys_task_form |
|||
-- ---------------------------- |
|||
DROP TABLE IF EXISTS `sys_task_form`; |
|||
CREATE TABLE `sys_task_form` ( |
|||
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', |
|||
`form_id` bigint(20) DEFAULT NULL COMMENT '表单主键', |
|||
`task_id` varchar(50) DEFAULT NULL COMMENT '所属任务', |
|||
PRIMARY KEY (`id`) USING BTREE |
|||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='流程任务关联表单'; |
|||
|
|||
SET FOREIGN_KEY_CHECKS = 1; |
|||
Loading…
Reference in new issue