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