This commit is contained in:
jiang 2024-04-29 16:45:54 +08:00
parent ff2adcb01e
commit ddff85aa7b
11 changed files with 1294 additions and 131 deletions

View File

@ -111,7 +111,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
// 过滤请求
.authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/register", "/captchaImage").permitAll()
.antMatchers("/login", "/register", "/captchaImage","/getLoginCode").permitAll()
// 静态资源可匿名访问
.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()

View File

@ -2,10 +2,13 @@ package com.ruoyi.project.common;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.FastByteArrayOutputStream;
@ -22,12 +25,11 @@ import com.ruoyi.project.system.service.ISysConfigService;
/**
* 验证码操作处理
*
*
* @author ruoyi
*/
@RestController
public class CaptchaController
{
public class CaptchaController {
@Resource(name = "captchaProducer")
private Producer captchaProducer;
@ -36,11 +38,11 @@ public class CaptchaController
@Autowired
private RedisCache redisCache;
// 验证码类型
@Value("${ruoyi.captchaType}")
private String captchaType;
@Autowired
private ISysConfigService configService;
@ -48,13 +50,11 @@ public class CaptchaController
* 生成验证码
*/
@GetMapping("/captchaImage")
public AjaxResult getCode(HttpServletResponse response) throws IOException
{
public AjaxResult getCode(HttpServletResponse response) throws IOException {
AjaxResult ajax = AjaxResult.success();
boolean captchaEnabled = configService.selectCaptchaEnabled();
ajax.put("captchaEnabled", captchaEnabled);
if (!captchaEnabled)
{
if (!captchaEnabled) {
return ajax;
}
@ -66,15 +66,12 @@ public class CaptchaController
BufferedImage image = null;
// 生成验证码
if ("math".equals(captchaType))
{
if ("math".equals(captchaType)) {
String capText = captchaProducerMath.createText();
capStr = capText.substring(0, capText.lastIndexOf("@"));
code = capText.substring(capText.lastIndexOf("@") + 1);
image = captchaProducerMath.createImage(capStr);
}
else if ("char".equals(captchaType))
{
} else if ("char".equals(captchaType)) {
capStr = code = captchaProducer.createText();
image = captchaProducer.createImage(capStr);
}
@ -82,12 +79,9 @@ public class CaptchaController
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
// 转换流信息写出
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
try
{
try {
ImageIO.write(image, "jpg", os);
}
catch (IOException e)
{
} catch (IOException e) {
return AjaxResult.error(e.getMessage());
}
@ -95,4 +89,19 @@ public class CaptchaController
ajax.put("img", Base64.encode(os.toByteArray()));
return ajax;
}
@GetMapping("/getLoginCode")
public AjaxResult getLoginCode(HttpServletResponse response) throws IOException {
// 保存验证码信息
String uuid = IdUtils.simpleUUID();
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
String verification = IdUtils.simpleUUID();
redisCache.setCacheObject(verifyKey, verification, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
Map<String,Object> map = new HashMap<>();
map.put("uuid", uuid);
map.put("verification", verification);
return AjaxResult.success(map);
}
}

View File

@ -66,7 +66,7 @@ public class FlowController extends BaseController {
* @return 数据
*/
@ApiOperation(value = "读取xml文件")
@GetMapping("/readXml/{deployId}")
@PostMapping("/readXml/{deployId}")
public AjaxResult readXml(@ApiParam(value = "流程定义id") @PathVariable(value = "deployId") String deployId) {
try {
return flowUtils.readXml(deployId);
@ -83,7 +83,7 @@ public class FlowController extends BaseController {
* @return 数据
*/
@ApiOperation(value = "激活或挂起流程定义")
@PutMapping(value = "/updateState")
@PostMapping(value = "/updateState")
public AjaxResult updateState(@ApiParam(value = "1:激活,2:挂起", required = true) @RequestParam Integer state,
@ApiParam(value = "流程部署ID", required = true) @RequestParam String deployId) {
flowUtils.updateState(state, deployId);
@ -97,7 +97,7 @@ public class FlowController extends BaseController {
* @return 数据
*/
@ApiOperation(value = "删除流程")
@DeleteMapping(value = "/{deployIds}")
@PostMapping(value = "/{deployIds}")
public AjaxResult delete(@ApiParam(value = "流程定义id数组", required = true) @PathVariable String[] deployIds) {
if (deployIds == null || deployIds.length == 0) {
return AjaxResult.error("删除的流程定义id不能为空");

View File

@ -1,8 +1,13 @@
package com.ruoyi.project.flowable.controller;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.project.flowable.domain.RequestEntity;
import com.ruoyi.project.flowable.utils.FlowTaskUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -15,11 +20,90 @@ import javax.annotation.Resource;
@RestController
@RequestMapping("/flowTask")
public class FlowTaskController extends BaseController {
@Resource
private FlowTaskUtils flowTaskUtils;
@ApiOperation(value = "获取单个流程详情")
@PostMapping(value = "/selectSingleFlow")
public AjaxResult selectSingleFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.selectSingleFlow(entity.getUserId(), entity.getProInsId());
}
@ApiOperation(value = "获取多个流程详情")
@PostMapping(value = "/selectAggregateFlow")
public AjaxResult selectAggregateFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.selectAggregateFlow(entity.getUserId(), entity.getProDefKey(), entity.getPageSize(), entity.getPageNum());
}
@ApiOperation(value = "发起流程")
@PostMapping(value = "/startFlow")
public AjaxResult startFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.startFlow(entity.getUserId(), entity.getProDefKey(), entity.getProcessVariables());
}
@ApiOperation(value = "获取待办流程")
@PostMapping(value = "/getStayAllFlow")
public AjaxResult getStayAllFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.getStayAllFlow(entity.getUserId(), entity.getPageSize(), entity.getPageNum());
}
@ApiOperation(value = "获取待办流程")
@PostMapping(value = "/getStayFlow")
public AjaxResult getStayFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.getStayFlow(entity.getUserId(), entity.getProDefKey(), entity.getPageSize(), entity.getPageNum());
}
@ApiOperation(value = "获取所有已办流程")
@PostMapping(value = "/getCompletedAllFlow")
public AjaxResult getCompletedAllFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.getCompletedAllFlow(entity.getUserId(), entity.getPageSize(), entity.getPageNum());
}
@ApiOperation(value = "获取已办流程")
@PostMapping(value = "/getCompletedFlow")
public AjaxResult getCompletedFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.getCompletedFlow(entity.getUserId(), entity.getProDefKey(), entity.getPageSize(), entity.getPageNum());
}
@ApiOperation(value = "流程历史流转记录")
@PostMapping(value = "/recordFlow")
public AjaxResult recordFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.recordFlow(entity.getProInsId());
}
@ApiOperation(value = "取消申请")
@PostMapping(value = "/stopFlow")
public AjaxResult stopFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.stopFlow(entity.getProInsId());
}
@ApiOperation(value = "撤回流程")
@PostMapping(value = "/revokeFlow")
public AjaxResult revokeFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.revokeFlow(entity.getProInsId());
}
@ApiOperation(value = "流程审批")
@PostMapping(value = "/approvalFlow")
public AjaxResult approvalFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.approvalFlow(entity.getUserId(), entity.getTaskId(), entity.getProInsId(), entity.getOptions(), entity.getProcessVariables());
}
@ApiOperation(value = "驳回任务")
@PostMapping(value = "/rejectFlow")
public AjaxResult rejectFlow(@RequestBody RequestEntity entity) {
return flowTaskUtils.rejectFlow(entity.getTaskId(), entity.getTargetKey(), entity.getOptions());
}
@ApiOperation(value = "获取流程变量")
@PostMapping(value = "/processVariables")
public AjaxResult processVariables(@RequestBody RequestEntity entity) {
return flowTaskUtils.processVariables(entity.getTaskId());
}
}

View File

@ -0,0 +1,25 @@
package com.ruoyi.project.flowable.domain;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
/**
* @author Tony
* @date 2021/3/28 15:50
*/
@Data
@Builder
public class FlowCommentDto implements Serializable {
/**
* 意见类别 0 正常意见 1 退回意见 2 驳回意见
*/
private String type;
/**
* 意见内容
*/
private String comment;
}

View File

@ -8,6 +8,7 @@ import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
/**
* 工作流实例
@ -97,4 +98,14 @@ public class FlowTaskEntity implements Serializable {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date finishTime;
@ApiModelProperty("流转参数")
private Map<String, Object> variables;
@ApiModelProperty("任务意见")
private FlowCommentDto comment;
@ApiModelProperty("审批意见")
private String opinions;
}

View File

@ -0,0 +1,61 @@
package com.ruoyi.project.flowable.domain;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.models.auth.In;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Map;
/**
* @author bonus
* 请求参数实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RequestEntity implements Serializable {
/**
* 用户id
*/
private String userId;
/**
* 流程定义id
*/
private String proDefId;
/**
* 流程定义标识
*/
private String proDefKey;
/**
* 流程实例id
*/
private String proInsId;
/**
* 流程部署编号
*/
private String deployId;
/**
* 流程携带参数
*/
private Map<String, Object> processVariables;
/**
* 当前页码
*/
private Integer pageSize;
/**
* 每页条数
*/
private Integer pageNum;
/**
* 审批意见
*/
private String options;
private String taskId;
private String targetKey;
}

View File

@ -0,0 +1,75 @@
package com.ruoyi.project.flowable.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author bonus
* 流程定义相关的数据传输对象DTO封装了流程实例的各种属性及内部变量信息便于序列化与反序列化处理
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TaskEntity implements Serializable {
/**
* 任务所在的执行流ID
*/
private String executionId;
/**
* 对应的流程实例ID
*/
private String proInstId;
/**
* 对应流程定义数据的ID
*/
private String proDefId;
/**
* 父任务
*/
private String parentTaskId;
/**
* 任务定义的ID值
*/
private String proDefKey;
/**
* 任务名称
*/
private String name;
/**
* 任务描述
*/
private String description;
/**
* 拥有人没有做外键关联
*/
private String owner;
/**
* 代理人没有做外键关联
*/
private String assignee;
/**
* 委托状态PENDING 委托中RESOLVED 已处理
*/
private DelegationStatus delegationStatus;
/**
* 优先级
*/
private Integer priority;
/**
* 过期时间
*/
private String dueDate;
/**
* 创建时间
*/
private String createTime;
public enum DelegationStatus {
PENDING, RESOLVED
}
}

View File

@ -0,0 +1,389 @@
package com.ruoyi.project.flowable.domain;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
public class test {
@JsonProperty("id")
private String id;
@JsonProperty("revision")
private Integer revision;
@JsonProperty("originalPersistentState")
private OriginalPersistentStateDTO originalPersistentState;
@JsonProperty("variableInstances")
private VariableInstancesDTO variableInstances;
@JsonProperty("usedVariablesCache")
private UsedVariablesCacheDTO usedVariablesCache;
@JsonProperty("transientVariables")
private TransientVariablesDTO transientVariables;
@JsonProperty("cachedElContext")
private Object cachedElContext;
@NoArgsConstructor
@Data
public static class OriginalPersistentStateDTO {
}
@NoArgsConstructor
@Data
public static class VariableInstancesDTO {
@JsonProperty("startUserId")
private StartUserIdDTO startUserId;
@JsonProperty("procDefKey")
private ProcDefKeyDTO procDefKey;
@JsonProperty("INITIATOR")
private INITIATORDTO initiator;
@NoArgsConstructor
@Data
public static class StartUserIdDTO {
@JsonProperty("id")
private String id;
@JsonProperty("revision")
private Integer revision;
@JsonProperty("originalPersistentState")
private OriginalPersistentStateDTO originalPersistentState;
@JsonProperty("name")
private String name;
@JsonProperty("type")
private TypeDTO type;
@JsonProperty("typeName")
private String typeName;
@JsonProperty("executionId")
private String executionId;
@JsonProperty("processInstanceId")
private String processInstanceId;
@JsonProperty("processDefinitionId")
private String processDefinitionId;
@JsonProperty("taskId")
private Object taskId;
@JsonProperty("scopeId")
private Object scopeId;
@JsonProperty("subScopeId")
private Object subScopeId;
@JsonProperty("scopeType")
private Object scopeType;
@JsonProperty("longValue")
private Object longValue;
@JsonProperty("doubleValue")
private Object doubleValue;
@JsonProperty("textValue")
private String textValue;
@JsonProperty("textValue2")
private Object textValue2;
@JsonProperty("byteArrayRef")
private ByteArrayRefDTO byteArrayRef;
@JsonProperty("cachedValue")
private String cachedValue;
@JsonProperty("deleted")
private Boolean deleted;
@JsonProperty("bytes")
private Object bytes;
@JsonProperty("persistentState")
private PersistentStateDTO persistentState;
@JsonProperty("value")
private String value;
@JsonProperty("readOnly")
private Boolean readOnly;
@JsonProperty("updated")
private Boolean updated;
@JsonProperty("inserted")
private Boolean inserted;
@JsonProperty("idPrefix")
private String idPrefix;
@JsonProperty("revisionNext")
private Integer revisionNext;
@NoArgsConstructor
@Data
public static class OriginalPersistentStateDTO {
}
@NoArgsConstructor
@Data
public static class TypeDTO {
@JsonProperty("cachable")
private Boolean cachable;
@JsonProperty("typeName")
private String typeName;
@JsonProperty("readOnly")
private Boolean readOnly;
}
@NoArgsConstructor
@Data
public static class ByteArrayRefDTO {
@JsonProperty("id")
private Object id;
@JsonProperty("name")
private Object name;
@JsonProperty("deleted")
private Boolean deleted;
}
@NoArgsConstructor
@Data
public static class PersistentStateDTO {
@JsonProperty("executionId")
private String executionId;
@JsonProperty("scopeId")
private Object scopeId;
@JsonProperty("subScopeId")
private Object subScopeId;
@JsonProperty("textValue")
private String textValue;
@JsonProperty("scopeType")
private Object scopeType;
@JsonProperty("name")
private String name;
@JsonProperty("typeName")
private String typeName;
@JsonProperty("doubleValue")
private Object doubleValue;
@JsonProperty("longValue")
private Object longValue;
@JsonProperty("textValue2")
private Object textValue2;
}
}
@NoArgsConstructor
@Data
public static class ProcDefKeyDTO {
@JsonProperty("id")
private String id;
@JsonProperty("revision")
private Integer revision;
@JsonProperty("originalPersistentState")
private OriginalPersistentStateDTO originalPersistentState;
@JsonProperty("name")
private String name;
@JsonProperty("type")
private TypeDTO type;
@JsonProperty("typeName")
private String typeName;
@JsonProperty("executionId")
private String executionId;
@JsonProperty("processInstanceId")
private String processInstanceId;
@JsonProperty("processDefinitionId")
private String processDefinitionId;
@JsonProperty("taskId")
private Object taskId;
@JsonProperty("scopeId")
private Object scopeId;
@JsonProperty("subScopeId")
private Object subScopeId;
@JsonProperty("scopeType")
private Object scopeType;
@JsonProperty("longValue")
private Object longValue;
@JsonProperty("doubleValue")
private Object doubleValue;
@JsonProperty("textValue")
private String textValue;
@JsonProperty("textValue2")
private Object textValue2;
@JsonProperty("byteArrayRef")
private ByteArrayRefDTO byteArrayRef;
@JsonProperty("cachedValue")
private String cachedValue;
@JsonProperty("deleted")
private Boolean deleted;
@JsonProperty("bytes")
private Object bytes;
@JsonProperty("persistentState")
private PersistentStateDTO persistentState;
@JsonProperty("value")
private String value;
@JsonProperty("readOnly")
private Boolean readOnly;
@JsonProperty("updated")
private Boolean updated;
@JsonProperty("inserted")
private Boolean inserted;
@JsonProperty("idPrefix")
private String idPrefix;
@JsonProperty("revisionNext")
private Integer revisionNext;
@NoArgsConstructor
@Data
public static class OriginalPersistentStateDTO {
}
@NoArgsConstructor
@Data
public static class TypeDTO {
@JsonProperty("cachable")
private Boolean cachable;
@JsonProperty("typeName")
private String typeName;
@JsonProperty("readOnly")
private Boolean readOnly;
}
@NoArgsConstructor
@Data
public static class ByteArrayRefDTO {
@JsonProperty("id")
private Object id;
@JsonProperty("name")
private Object name;
@JsonProperty("deleted")
private Boolean deleted;
}
@NoArgsConstructor
@Data
public static class PersistentStateDTO {
@JsonProperty("executionId")
private String executionId;
@JsonProperty("scopeId")
private Object scopeId;
@JsonProperty("subScopeId")
private Object subScopeId;
@JsonProperty("textValue")
private String textValue;
@JsonProperty("scopeType")
private Object scopeType;
@JsonProperty("name")
private String name;
@JsonProperty("typeName")
private String typeName;
@JsonProperty("doubleValue")
private Object doubleValue;
@JsonProperty("longValue")
private Object longValue;
@JsonProperty("textValue2")
private Object textValue2;
}
}
@NoArgsConstructor
@Data
public static class INITIATORDTO {
@JsonProperty("id")
private String id;
@JsonProperty("revision")
private Integer revision;
@JsonProperty("originalPersistentState")
private OriginalPersistentStateDTO originalPersistentState;
@JsonProperty("name")
private String name;
@JsonProperty("type")
private TypeDTO type;
@JsonProperty("typeName")
private String typeName;
@JsonProperty("executionId")
private String executionId;
@JsonProperty("processInstanceId")
private String processInstanceId;
@JsonProperty("processDefinitionId")
private String processDefinitionId;
@JsonProperty("taskId")
private Object taskId;
@JsonProperty("scopeId")
private Object scopeId;
@JsonProperty("subScopeId")
private Object subScopeId;
@JsonProperty("scopeType")
private Object scopeType;
@JsonProperty("longValue")
private Object longValue;
@JsonProperty("doubleValue")
private Object doubleValue;
@JsonProperty("textValue")
private String textValue;
@JsonProperty("textValue2")
private Object textValue2;
@JsonProperty("byteArrayRef")
private ByteArrayRefDTO byteArrayRef;
@JsonProperty("cachedValue")
private String cachedValue;
@JsonProperty("deleted")
private Boolean deleted;
@JsonProperty("bytes")
private Object bytes;
@JsonProperty("persistentState")
private PersistentStateDTO persistentState;
@JsonProperty("value")
private String value;
@JsonProperty("readOnly")
private Boolean readOnly;
@JsonProperty("updated")
private Boolean updated;
@JsonProperty("inserted")
private Boolean inserted;
@JsonProperty("idPrefix")
private String idPrefix;
@JsonProperty("revisionNext")
private Integer revisionNext;
@NoArgsConstructor
@Data
public static class OriginalPersistentStateDTO {
}
@NoArgsConstructor
@Data
public static class TypeDTO {
@JsonProperty("cachable")
private Boolean cachable;
@JsonProperty("typeName")
private String typeName;
@JsonProperty("readOnly")
private Boolean readOnly;
}
@NoArgsConstructor
@Data
public static class ByteArrayRefDTO {
@JsonProperty("id")
private Object id;
@JsonProperty("name")
private Object name;
@JsonProperty("deleted")
private Boolean deleted;
}
@NoArgsConstructor
@Data
public static class PersistentStateDTO {
@JsonProperty("executionId")
private String executionId;
@JsonProperty("scopeId")
private Object scopeId;
@JsonProperty("subScopeId")
private Object subScopeId;
@JsonProperty("textValue")
private String textValue;
@JsonProperty("scopeType")
private Object scopeType;
@JsonProperty("name")
private String name;
@JsonProperty("typeName")
private String typeName;
@JsonProperty("doubleValue")
private Object doubleValue;
@JsonProperty("longValue")
private Object longValue;
@JsonProperty("textValue2")
private Object textValue2;
}
}
}
@NoArgsConstructor
@Data
public static class UsedVariablesCacheDTO {
}
@NoArgsConstructor
@Data
public static class TransientVariablesDTO {
}
}

View File

@ -1,18 +1,27 @@
package com.ruoyi.project.flowable.utils;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.project.flowable.common.constant.ProcessConstants;
import com.ruoyi.project.flowable.common.enums.FlowComment;
import com.ruoyi.project.flowable.domain.FlowCommentDto;
import com.ruoyi.project.flowable.domain.FlowTaskEntity;
import com.ruoyi.project.flowable.domain.TaskEntity;
import com.ruoyi.project.flowable.factory.FlowServiceFactory;
import com.ruoyi.project.flowable.flow.CustomProcessDiagramGenerator;
import com.ruoyi.project.flowable.flow.FlowableUtils;
import com.ruoyi.project.system.domain.SysUser;
import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;
import io.netty.util.internal.ObjectUtil;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.bpmn.model.*;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.history.HistoricProcessInstanceQuery;
@ -20,16 +29,15 @@ import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.repository.ProcessDefinitionQuery;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.engine.task.Comment;
import org.flowable.identitylink.api.history.HistoricIdentityLink;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.stereotype.Service;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import static com.ruoyi.common.utils.DateUtils.getDate;
@ -45,12 +53,12 @@ public class FlowTaskUtils extends FlowServiceFactory {
/**
* 查询流程是否存在
*
* @param processDefinitionId 流程id
* @param procDefKey 流程id
* @return 是否存在
*/
public boolean exist(String processDefinitionId) {
public boolean exist(String procDefKey) {
ProcessDefinitionQuery processDefinitionQuery
= repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId);
= repositoryService.createProcessDefinitionQuery().processDefinitionKey(procDefKey);
long count = processDefinitionQuery.count();
return count > 0;
}
@ -70,30 +78,46 @@ public class FlowTaskUtils extends FlowServiceFactory {
/**
* 根据流程定义ID启动流程实例
*
* @param procDefId 流程模板ID
* @param variables 流程变量
* @param userId 用户id
* @param procDefKey 流程定义ID
* @param variables 流程变量
* @param userId 用户id
* @return 流程实例详细信息
*/
public AjaxResult startProcessInstanceById(String userId, String procDefId, Map<String, Object> variables) {
public AjaxResult startFlow(String userId, String procDefKey, Map<String, Object> variables) {
try {
if (Objects.isNull(variables)) {
variables = new HashMap<>();
}
if (Objects.isNull(userId)) {
return AjaxResult.error("userId为空");
}
if (Objects.isNull(procDefId)) {
return AjaxResult.error("procDefId不能为空");
if (Objects.isNull(procDefKey)) {
return AjaxResult.error("procDefKey不能为空");
}
if (!exist(procDefId)) {
if (!exist(procDefKey)) {
return AjaxResult.error("流程不存在");
}
if (singleResult(procDefId)) {
if (singleResult(procDefKey)) {
return AjaxResult.error("流程已被挂起,请先激活流程");
}
// 设置流程发起人Id到流程中
identityService.setAuthenticatedUserId(userId);
variables.put(ProcessConstants.PROCESS_INITIATOR, userId);
ProcessInstance processInstance = runtimeService.startProcessInstanceById(procDefId, variables);
return AjaxResult.success("流程启动成功");
variables.put(ProcessConstants.FLOWABLE_SKIP_EXPRESSION_ENABLED, true);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(procDefKey, variables);
Map<String, Object> map = new HashMap<>();
if (Objects.nonNull(processInstance)) {
map.put("proInsId", processInstance.getProcessInstanceId());
map.put("startUserId", processInstance.getStartUserId());
map.put("startTime", processInstance.getStartTime());
map.put("proDefKey", processInstance.getProcessDefinitionKey());
map.put("proDefId", processInstance.getDeploymentId());
map.put("proDefName", processInstance.getProcessDefinitionName());
map.put("proVariables", processInstance.getProcessVariables());
} else {
return AjaxResult.error("流程启动错误");
}
return AjaxResult.success("流程启动成功", map);
} catch (Exception e) {
logger.error("流程启动错误", e);
return AjaxResult.error("流程启动错误");
@ -103,81 +127,455 @@ public class FlowTaskUtils extends FlowServiceFactory {
/**
* 根据用户id和流程定义id查询用户发起的流程实例
* 分页处理
*
* @param userId 用户ID
* @param procDefId 流程定义id
* @param userId 用户ID
* @param proInsId 流程实例ID
* @return 集合
*/
public AjaxResult selectFlowTaskUserById(String userId, String procDefId) {
public AjaxResult selectSingleFlow(String userId, String proInsId) {
if (StringUtils.isBlank(userId)) {
return AjaxResult.error("userId不能为空");
}
if (StringUtils.isBlank(proInsId)) {
return AjaxResult.error("proInsId不能为空");
}
HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
.startedBy(userId)
.processDefinitionId("")
.processInstanceId(proInsId)
.orderByProcessInstanceStartTime()
.desc();
//queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize()
List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage(0, 50);
List<FlowTaskEntity> flowList = new ArrayList<>();
List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage(0, 10);
List<Map<String, Object>> mapList = new ArrayList<>();
for (HistoricProcessInstance hisIns : historicProcessInstances) {
FlowTaskEntity flowTask = new FlowTaskEntity();
flowTask.setCreateTime(hisIns.getStartTime());
flowTask.setFinishTime(hisIns.getEndTime());
flowTask.setProcInsId(hisIns.getId());
Map<String, Object> map = new HashMap<>();
map.put("createTime", hisIns.getStartTime());
map.put("finishTime", hisIns.getEndTime());
map.put("startUserId", hisIns.getStartUserId());
map.put("proInsId", hisIns.getId());
// 计算耗时
if (Objects.nonNull(hisIns.getEndTime())) {
long time = hisIns.getEndTime().getTime() - hisIns.getStartTime().getTime();
flowTask.setDuration(getDate(time));
map.put("duration", time);
} else {
long time = System.currentTimeMillis() - hisIns.getStartTime().getTime();
flowTask.setDuration(getDate(time));
map.put("duration", 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());
// 当前所处流程
List<Task> taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list();
if (CollectionUtils.isNotEmpty(taskList)) {
flowTask.setTaskId(taskList.get(0).getId());
flowTask.setTaskName(taskList.get(0).getName());
map.put("taskId", taskList.get(0).getId());
map.put("taskName", taskList.get(0).getName());
if (StringUtils.isNotBlank(taskList.get(0).getAssignee())) {
// 当前任务节点办理人信息
flowTask.setAssigneeId(Long.parseLong(taskList.get(0).getAssignee()));
}
} else {
List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list();
flowTask.setTaskId(historicTaskInstance.get(0).getId());
flowTask.setTaskName(historicTaskInstance.get(0).getName());
if (StringUtils.isNotBlank(historicTaskInstance.get(0).getAssignee())) {
flowTask.setAssigneeId(Long.parseLong(historicTaskInstance.get(0).getAssignee()));
map.put("assigneeId", taskList.get(0).getAssignee());
}
}
flowList.add(flowTask);
List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list();
List<Map<String, Object>> mapHistList = new ArrayList<>();
for (HistoricTaskInstance hti : historicTaskInstance) {
if (Objects.nonNull(hti.getDurationInMillis())) {
Map<String, Object> mapHist = new HashMap<>();
mapHist.put("taskId", hti.getId());
mapHist.put("taskName", hti.getName());
mapHist.put("assigneeId", hti.getAssignee());
mapHist.put("durationInMillis", hti.getDurationInMillis());
List<Comment> commentList = taskService.getProcessInstanceComments(hti.getProcessInstanceId());
commentList.forEach(comment -> {
if (hti.getId().equals(comment.getTaskId())) {
Map<String, Object> mapComment = new HashMap<>();
mapComment.put("comment", FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build());
mapHist.put("comment", mapComment);
}
});
mapHistList.add(mapHist);
}
}
// 获取意见评论内容
map.put("historicTask", mapHistList);
mapList.add(map);
}
return AjaxResult.success(flowList);
return AjaxResult.success(mapList);
}
/**
* 流程实例
*
* @param userId 用户id
* @param proDefKey 流程定义ID
* @param pageSize 当前页码
* @param pageNum 每页条数
* @return 分页数据
*/
public AjaxResult stopProcess(String instanceId) {
List<Task> task = taskService.createTaskQuery().processInstanceId(instanceId).list();
public AjaxResult selectAggregateFlow(String userId, String proDefKey, Integer pageSize, Integer pageNum) {
if (StringUtils.isBlank(userId)) {
return AjaxResult.error("userId不能为空");
}
if (StringUtils.isBlank(proDefKey)) {
return AjaxResult.error("proDefKey不能为空");
}
if (Objects.isNull(pageSize)) {
pageSize = 10;
}
if (Objects.isNull(pageNum)) {
pageNum = 1;
}
HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
.startedBy(userId)
.processDefinitionKey(proDefKey)
.orderByProcessInstanceStartTime()
.desc();
List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage(pageSize * (pageNum - 1), pageSize * pageNum);
List<Map<String, Object>> mapList = new ArrayList<>();
for (HistoricProcessInstance hisIns : historicProcessInstances) {
Map<String, Object> map = new HashMap<>();
map.put("createTime", hisIns.getStartTime());
map.put("finishTime", hisIns.getEndTime());
map.put("startUserId", hisIns.getStartUserId());
map.put("proInsId", hisIns.getId());
// 计算耗时
if (Objects.nonNull(hisIns.getEndTime())) {
long time = hisIns.getEndTime().getTime() - hisIns.getStartTime().getTime();
map.put("duration", time);
} else {
long time = System.currentTimeMillis() - hisIns.getStartTime().getTime();
map.put("duration", time);
}
// 当前所处流程
List<Task> taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list();
if (CollectionUtils.isNotEmpty(taskList)) {
map.put("taskId", taskList.get(0).getId());
map.put("taskName", taskList.get(0).getName());
if (StringUtils.isNotBlank(taskList.get(0).getAssignee())) {
// 当前任务节点办理人信息
map.put("assigneeId", taskList.get(0).getAssignee());
}
}
List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list();
List<Map<String, Object>> mapHistList = new ArrayList<>();
for (HistoricTaskInstance hti : historicTaskInstance) {
if (Objects.nonNull(hti.getDurationInMillis())) {
Map<String, Object> mapHist = new HashMap<>();
mapHist.put("taskId", hti.getId());
mapHist.put("taskName", hti.getName());
mapHist.put("assigneeId", hti.getAssignee());
mapHist.put("durationInMillis", hti.getDurationInMillis());
mapHistList.add(mapHist);
}
}
map.put("historicTask", mapHistList);
mapList.add(map);
}
return AjaxResult.success(mapList);
}
/**
* 待办流程实例
*
* @param userId 用户id
* @param pageSize 当前页码
* @param pageNum 每页条数
* @return 分页数据
*/
public AjaxResult getStayAllFlow(String userId, Integer pageSize, Integer pageNum) {
if (StringUtils.isBlank(userId)) {
return AjaxResult.error("userId不能为空");
}
if (Objects.isNull(pageSize)) {
pageSize = 10;
}
if (Objects.isNull(pageNum)) {
pageNum = 1;
}
List<Task> taskList = taskService.createTaskQuery()
.active()
.taskAssignee(userId)
.orderByTaskCreateTime().desc()
.listPage(pageSize * (pageNum - 1), pageSize);
List<Map<String, Object>> mapList = new ArrayList<>();
for (Task task : taskList) {
Map<String, Object> map = new HashMap<>();
map.put("createTime", task.getCreateTime());
map.put("proInsId", task.getProcessInstanceId());
map.put("taskId", task.getId());
map.put("taskName", task.getName());
map.put("assigneeId", task.getAssignee());
// 流程发起人信息
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(task.getProcessInstanceId())
.singleResult();
map.put("startUserId", historicProcessInstance.getStartUserId());
List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceEndTime().desc().list();
List<Map<String, Object>> mapHistList = new ArrayList<>();
for (HistoricTaskInstance hti : historicTaskInstance) {
if (Objects.nonNull(hti.getDurationInMillis())) {
Map<String, Object> mapHist = new HashMap<>();
mapHist.put("taskId", hti.getId());
mapHist.put("taskName", hti.getName());
mapHist.put("assigneeId", hti.getAssignee());
mapHist.put("durationInMillis", hti.getDurationInMillis());
mapHistList.add(mapHist);
}
}
map.put("historicTask", mapHistList);
mapList.add(map);
}
return AjaxResult.success(mapList);
}
public AjaxResult getStayFlow(String userId, String proDefKey, Integer pageSize, Integer pageNum) {
if (StringUtils.isBlank(userId)) {
return AjaxResult.error("userId不能为空");
}
if (StringUtils.isBlank(proDefKey)) {
return AjaxResult.error("proDefKey不能为空");
}
if (Objects.isNull(pageSize)) {
pageSize = 10;
}
if (Objects.isNull(pageNum)) {
pageNum = 1;
}
List<Task> taskList = taskService.createTaskQuery()
.active()
.taskAssignee(userId)
.processDefinitionKey(proDefKey)
.orderByTaskCreateTime().desc()
.listPage(pageSize * (pageNum - 1), pageSize);
List<Map<String, Object>> mapList = new ArrayList<>();
for (Task task : taskList) {
Map<String, Object> map = new HashMap<>();
map.put("createTime", task.getCreateTime());
map.put("proInsId", task.getProcessInstanceId());
map.put("taskId", task.getId());
map.put("taskName", task.getName());
map.put("assigneeId", task.getAssignee());
// 流程发起人信息
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(task.getProcessInstanceId())
.singleResult();
map.put("startUserId", historicProcessInstance.getStartUserId());
List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceEndTime().desc().list();
List<Map<String, Object>> mapHistList = new ArrayList<>();
for (HistoricTaskInstance hti : historicTaskInstance) {
if (Objects.nonNull(hti.getDurationInMillis())) {
Map<String, Object> mapHist = new HashMap<>();
mapHist.put("taskId", hti.getId());
mapHist.put("taskName", hti.getName());
mapHist.put("assigneeId", hti.getAssignee());
mapHist.put("durationInMillis", hti.getDurationInMillis());
mapHistList.add(mapHist);
}
}
map.put("historicTask", mapHistList);
mapList.add(map);
}
return AjaxResult.success(mapList);
}
/**
* @param userId
* @param pageSize
* @param pageNum
* @return
*/
public AjaxResult getCompletedAllFlow(String userId, Integer pageSize, Integer pageNum) {
if (StringUtils.isBlank(userId)) {
return AjaxResult.error("userId不能为空");
}
if (Objects.isNull(pageSize)) {
pageSize = 10;
}
if (Objects.isNull(pageNum)) {
pageNum = 1;
}
HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
.includeProcessVariables()
.finished()
.taskAssignee(userId)
.orderByHistoricTaskInstanceEndTime()
.desc();
List<HistoricTaskInstance> historicTaskInstanceList = taskInstanceQuery.listPage(pageSize * (pageNum - 1), pageSize * pageNum);
List<Map<String, Object>> mapList = new ArrayList<>();
for (HistoricTaskInstance histTask : historicTaskInstanceList) {
Map<String, Object> map = new HashMap<>();
// 当前流程信息
map.put("createTime", histTask.getCreateTime());
map.put("finishTime", histTask.getEndTime());
map.put("taskId", histTask.getId());
map.put("taskName", histTask.getName());
map.put("assigneeId", histTask.getAssignee());
map.put("duration", histTask.getDurationInMillis());
map.put("proDefId", histTask.getProcessDefinitionId());
// 流程定义信息
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(histTask.getProcessDefinitionId())
.singleResult();
map.put("deployId", pd.getDeploymentId());
map.put("procInsId", histTask.getProcessInstanceId());
// 流程发起人信息
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(histTask.getProcessInstanceId())
.singleResult();
map.put("startUserId", historicProcessInstance.getStartUserId());
mapList.add(map);
}
return AjaxResult.success(mapList);
}
/**
* @param userId
* @param pageSize
* @param pageNum
* @return
*/
public AjaxResult getCompletedFlow(String userId, String proDefKey, Integer pageSize, Integer pageNum) {
if (Objects.isNull(pageSize)) {
pageSize = 10;
}
if (Objects.isNull(pageNum)) {
pageNum = 1;
}
if (StringUtils.isBlank(userId)) {
return AjaxResult.error("userId不能为空");
}
if (StringUtils.isBlank(proDefKey)) {
return AjaxResult.error("proDefKey不能为空");
}
HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
.includeProcessVariables()
.finished()
.taskAssignee(userId)
.processDefinitionKey(proDefKey)
.orderByHistoricTaskInstanceEndTime()
.desc();
List<HistoricTaskInstance> historicTaskInstanceList = taskInstanceQuery.listPage(pageSize * (pageNum - 1), pageSize * pageNum);
List<Map<String, Object>> mapList = new ArrayList<>();
for (HistoricTaskInstance histTask : historicTaskInstanceList) {
Map<String, Object> map = new HashMap<>();
// 当前流程信息
map.put("createTime", histTask.getCreateTime());
map.put("finishTime", histTask.getEndTime());
map.put("taskId", histTask.getId());
map.put("taskName", histTask.getName());
map.put("assigneeId", histTask.getAssignee());
map.put("duration", histTask.getDurationInMillis());
map.put("proDefId", histTask.getProcessDefinitionId());
// 流程定义信息
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
.processDefinitionId(histTask.getProcessDefinitionId())
.singleResult();
map.put("deployId", pd.getDeploymentId());
map.put("procInsId", histTask.getProcessInstanceId());
// 流程发起人信息
HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(histTask.getProcessInstanceId())
.singleResult();
map.put("startUserId", historicProcessInstance.getStartUserId());
mapList.add(map);
}
return AjaxResult.success(mapList);
}
public AjaxResult recordFlow(String procInsId) {
if (StringUtils.isBlank(procInsId)) {
return AjaxResult.error("procInsId不能为空");
}
List<Map<String, Object>> mapList = new ArrayList<>();
if (StringUtils.isNotBlank(procInsId)) {
List<HistoricActivityInstance> list = historyService
.createHistoricActivityInstanceQuery()
.processInstanceId(procInsId)
.orderByHistoricActivityInstanceStartTime()
.desc().list();
for (HistoricActivityInstance histIns : list) {
if (StringUtils.isNotBlank(histIns.getTaskId())) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("taskId", histIns.getTaskId());
map.put("taskName", histIns.getActivityName());
map.put("startTime", histIns.getStartTime());
map.put("endTime", histIns.getEndTime());
if (StringUtils.isNotBlank(histIns.getAssignee())) {
map.put("assigneeId", histIns.getAssignee());
}
// 展示审批人员
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())) {
stringBuilder.append(identityLink.getUserId()).append(",");
}
if (StringUtils.isNotBlank(identityLink.getGroupId())) {
stringBuilder.append(identityLink.getGroupId()).append(",");
}
}
}
if (StringUtils.isNotBlank(stringBuilder)) {
map.put("candidate", stringBuilder.substring(0, stringBuilder.length() - 1));
}
map.put("duration", 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())) {
Map<String, Object> mapComment = new HashMap<>();
mapComment.put("comment", FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build());
map.put("comment", mapComment);
}
});
mapList.add(map);
}
}
}
return AjaxResult.success(mapList);
}
public AjaxResult approvalFlow(String userId, String taskId, String procInsId, String opinions, Map<String, Object> variables) {
if (StringUtils.isBlank(taskId)) {
return AjaxResult.error("taskId不能为空");
}
if (StringUtils.isBlank(procInsId)) {
return AjaxResult.error("procInsId不能为空");
}
if (StringUtils.isBlank(userId)) {
return AjaxResult.error("userId不能为空");
}
if (Objects.isNull(variables)) {
variables = new HashMap<>();
}
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (Objects.isNull(task)) {
return AjaxResult.error("任务不存在");
}
if (DelegationState.PENDING.equals(task.getDelegationState())) {
taskService.addComment(taskId, procInsId, FlowComment.DELEGATE.getType(), opinions);
taskService.resolveTask(taskId, variables);
} else {
taskService.addComment(taskId, procInsId, FlowComment.NORMAL.getType(), opinions);
taskService.setAssignee(taskId, userId);
taskService.complete(taskId, variables);
}
return AjaxResult.success();
}
public AjaxResult stopFlow(String procInstId) {
List<Task> task = taskService.createTaskQuery().processInstanceId(procInstId).list();
if (CollectionUtils.isEmpty(task)) {
AjaxResult.error("流程未启动或已执行完成,取消申请失败");
return AjaxResult.error("流程未启动或已执行完成,取消申请失败");
}
// 获取当前流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(instanceId)
.processInstanceId(procInstId)
.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)) {
// 获取当前流程最后一个节点
String endId = endNodes.get(0).getId();
List<Execution> executions = runtimeService.createExecutionQuery()
.parentId(processInstance.getProcessInstanceId()).list();
@ -188,54 +586,154 @@ public class FlowTaskUtils extends FlowServiceFactory {
.moveExecutionsToSingleActivityId(executionIds, endId).changeState();
}
}
return AjaxResult.success();
}
public AjaxResult revokeFlow(String proInstId) {
if (StringUtils.isBlank(proInstId)) {
return AjaxResult.error("proInsId不能为空");
}
Task task = taskService.createTaskQuery().processInstanceId(proInstId).singleResult();
if (task == null) {
return AjaxResult.error("流程未启动或已执行完成,取消申请失败");
}
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) {
return AjaxResult.error("该任务非当前用户提交,无法撤回");
}
String processDefinitionId = myTask.getProcessDefinitionId();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
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();
}
public AjaxResult processVariables(String taskId) {
if (StringUtils.isBlank(taskId)) {
return AjaxResult.error("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);
}
}
public AjaxResult rejectFlow(String taskId, String targetKey, String options) {
if (StringUtils.isBlank(taskId)) {
return AjaxResult.error("taskId不能为空");
}
if (StringUtils.isBlank(targetKey)) {
return AjaxResult.error("targetKey不能为空");
}
if (StringUtils.isBlank(options)) {
return AjaxResult.error("options不能为空");
}
if (taskService.createTaskQuery().taskId(taskId).singleResult().isSuspended()) {
return AjaxResult.error("任务处于挂起状态");
}
// 当前任务 task
Task task = taskService.createTaskQuery().taskId(taskId).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(targetKey)) {
target = flowElement;
}
}
}
// 从当前节点向前扫描
// 如果存在路线上不存在目标节点说明目标节点是在网关上或非同一路线上不可跳转
// 否则目标节点相对于当前节点属于串行
Boolean isSequential = FlowableUtils.iteratorCheckSequentialReferTarget(source, targetKey, null, null);
if (!isSequential) {
return AjaxResult.error("当前节点相对于目标节点,不属于串行关系,无法回退");
}
// 获取所有正常进行的任务节点 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(), options));
try {
// 1 1 1 情况currentIds 当前要跳转的节点列表(1或多)targetKey 跳转到的节点(1)
runtimeService.createChangeActivityStateBuilder()
.processInstanceId(task.getProcessInstanceId())
.moveActivityIdsToSingleActivityId(currentIds, targetKey).changeState();
} catch (FlowableObjectNotFoundException e) {
return AjaxResult.error("未找到流程实例,流程可能已发生变化");
} catch (FlowableException e) {
return AjaxResult.error("无法取消或开始活动");
}
return AjaxResult.success();
}
/**
* 获取流程过程图
*
* @param processId 流程实例id
* @return 图片流
*/
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();
return diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes, highLightedFlows, configuration.getActivityFontName(),
configuration.getLabelFontName(), configuration.getAnnotationFontName(), configuration.getClassLoader(), 1.0, true);
}
}

View File

@ -18,10 +18,21 @@
ACT_RE_PROCDEF rp
LEFT JOIN ACT_RE_DEPLOYMENT rd ON rp.deployment_id_ = rd.id_
<where>
rp.deployment_id_ IN (
SELECT d.deployment_id_
FROM ACT_RE_PROCDEF d
INNER JOIN (
SELECT key_, MAX(version_) AS max_version
FROM ACT_RE_PROCDEF
GROUP BY key_
) m ON d.key_ = m.key_ AND d.version_ = m.max_version
)
<!-- 动态添加名称过滤条件 -->
<if test="name != null and name != ''">
and rd.name_ like concat('%', #{name}, '%')
</if>
</where>
order by rd.deploy_time_ desc
</select>
</mapper>