Commit 4e9583fae4ea6d7de60704dd861694b844624f43

Authored by YunaiV
2 parents b8e56a6b 129e9868

Merge branch 'feature/bpm' of https://gitee.com/zhijiantianya/ruoyi-vue-pro into master-jdk17

Showing 21 changed files with 460 additions and 224 deletions
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/json/JsonUtils.java
@@ -199,4 +199,12 @@ public class JsonUtils { @@ -199,4 +199,12 @@ public class JsonUtils {
199 return JSONUtil.isTypeJSON(text); 199 return JSONUtil.isTypeJSON(text);
200 } 200 }
201 201
  202 + /**
  203 + * 判断字符串是否为 JSON 类型的字符串
  204 + * @param str 字符串
  205 + */
  206 + public static boolean isJsonObject(String str) {
  207 + return JSONUtil.isTypeJSONObject(str);
  208 + }
  209 +
202 } 210 }
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmTriggerTypeEnum.java
@@ -16,7 +16,8 @@ import java.util.Arrays; @@ -16,7 +16,8 @@ import java.util.Arrays;
16 @AllArgsConstructor 16 @AllArgsConstructor
17 public enum BpmTriggerTypeEnum implements ArrayValuable<Integer> { 17 public enum BpmTriggerTypeEnum implements ArrayValuable<Integer> {
18 18
19 - HTTP_REQUEST(1, "发起 HTTP 请求"); 19 + HTTP_REQUEST(1, "发起 HTTP 请求"),
  20 + UPDATE_NORMAL_FORM(2, "更新流程表单"); // TODO @jason:FORM_UPDATE
20 21
21 /** 22 /**
22 * 触发器执行动作类型 23 * 触发器执行动作类型
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmReasonEnum.java
@@ -32,6 +32,7 @@ public enum BpmReasonEnum { @@ -32,6 +32,7 @@ public enum BpmReasonEnum {
32 ASSIGN_EMPTY_REJECT("审批人为空,自动不通过"), 32 ASSIGN_EMPTY_REJECT("审批人为空,自动不通过"),
33 APPROVE_TYPE_AUTO_APPROVE("非人工审核,自动通过"), 33 APPROVE_TYPE_AUTO_APPROVE("非人工审核,自动通过"),
34 APPROVE_TYPE_AUTO_REJECT("非人工审核,自动不通过"), 34 APPROVE_TYPE_AUTO_REJECT("非人工审核,自动不通过"),
  35 + CANCEL_BY_PROCESS_CLEAN("进程清理自动取消"),
35 ; 36 ;
36 37
37 private final String reason; 38 private final String reason;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/simple/BpmSimpleModelNodeVO.java
1 package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple; 1 package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple;
2 2
  3 +import cn.iocoder.yudao.framework.common.core.KeyValue;
3 import cn.iocoder.yudao.framework.common.validation.InEnum; 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
4 import cn.iocoder.yudao.module.bpm.enums.definition.*; 5 import cn.iocoder.yudao.module.bpm.enums.definition.*;
5 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; 6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum;
@@ -157,6 +158,7 @@ public class BpmSimpleModelNodeVO { @@ -157,6 +158,7 @@ public class BpmSimpleModelNodeVO {
157 @Schema(description = "值", example = "xxx") 158 @Schema(description = "值", example = "xxx")
158 @NotEmpty(message = "值不能为空") 159 @NotEmpty(message = "值不能为空")
159 private String value; 160 private String value;
  161 +
160 } 162 }
161 163
162 @Schema(description = "审批节点拒绝处理策略") 164 @Schema(description = "审批节点拒绝处理策略")
@@ -343,6 +345,13 @@ public class BpmSimpleModelNodeVO { @@ -343,6 +345,13 @@ public class BpmSimpleModelNodeVO {
343 @Valid 345 @Valid
344 private HttpRequestTriggerSetting httpRequestSetting; 346 private HttpRequestTriggerSetting httpRequestSetting;
345 347
  348 + // TODO @jason:这个要不直接叫 formSetting,更好理解一点哈
  349 + // TODO @jason:如果搞成 List<NormalFormTriggerSetting>,是不是可以做条件组了?微信讨论哈
  350 + /**
  351 + * 流程表单触发器设置
  352 + */
  353 + private NormalFormTriggerSetting normalFormSetting;
  354 +
346 @Schema(description = "http 请求触发器设置", example = "{}") 355 @Schema(description = "http 请求触发器设置", example = "{}")
347 @Data 356 @Data
348 public static class HttpRequestTriggerSetting { 357 public static class HttpRequestTriggerSetting {
@@ -359,6 +368,26 @@ public class BpmSimpleModelNodeVO { @@ -359,6 +368,26 @@ public class BpmSimpleModelNodeVO {
359 @Schema(description = "请求头参数设置", example = "[]") 368 @Schema(description = "请求头参数设置", example = "[]")
360 @Valid 369 @Valid
361 private List<HttpRequestParam> body; 370 private List<HttpRequestParam> body;
  371 +
  372 + // TODO @json:可能未来看情况,搞个 HttpResponseParam;得看看有没别的业务需要,抽象统一
  373 + /**
  374 + * 请求返回处理设置,用于修改流程表单值
  375 + * <p>
  376 + * key:表示要修改的流程表单字段名(name)
  377 + * value:接口返回的字段名
  378 + */
  379 + @Schema(description = "请求返回处理设置", example = "[]")
  380 + private List<KeyValue<String, String>> response;
  381 +
  382 + }
  383 +
  384 + @Schema(description = "流程表单触发器设置", example = "{}")
  385 + @Data
  386 + public static class NormalFormTriggerSetting {
  387 +
  388 + @Schema(description = "修改的表单字段", example = "userName")
  389 + private Map<String, Object> updateFormFields;
  390 +
362 } 391 }
363 392
364 } 393 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java
@@ -9,7 +9,10 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -9,7 +9,10 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
9 import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; 9 import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
10 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc.BpmProcessInstanceCopyRespVO; 10 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc.BpmProcessInstanceCopyRespVO;
11 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO; 11 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO;
  12 +import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
12 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO; 13 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceCopyDO;
  14 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils;
  15 +import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
13 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceCopyService; 16 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceCopyService;
14 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; 17 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
15 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 18 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@@ -42,6 +45,8 @@ public class BpmProcessInstanceCopyController { @@ -42,6 +45,8 @@ public class BpmProcessInstanceCopyController {
42 private BpmProcessInstanceCopyService processInstanceCopyService; 45 private BpmProcessInstanceCopyService processInstanceCopyService;
43 @Resource 46 @Resource
44 private BpmProcessInstanceService processInstanceService; 47 private BpmProcessInstanceService processInstanceService;
  48 + @Resource
  49 + private BpmProcessDefinitionService processDefinitionService;
45 50
46 @Resource 51 @Resource
47 private AdminUserApi adminUserApi; 52 private AdminUserApi adminUserApi;
@@ -62,6 +67,8 @@ public class BpmProcessInstanceCopyController { @@ -62,6 +67,8 @@ public class BpmProcessInstanceCopyController {
62 convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessInstanceId)); 67 convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessInstanceId));
63 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(), 68 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(),
64 copy -> Stream.of(copy.getStartUserId(), Long.parseLong(copy.getCreator())))); 69 copy -> Stream.of(copy.getStartUserId(), Long.parseLong(copy.getCreator()))));
  70 + Map<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap(
  71 + convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessDefinitionId));
65 return success(convertPage(pageResult, copy -> { 72 return success(convertPage(pageResult, copy -> {
66 BpmProcessInstanceCopyRespVO copyVO = BeanUtils.toBean(copy, BpmProcessInstanceCopyRespVO.class); 73 BpmProcessInstanceCopyRespVO copyVO = BeanUtils.toBean(copy, BpmProcessInstanceCopyRespVO.class);
67 MapUtils.findAndThen(userMap, Long.valueOf(copy.getCreator()), 74 MapUtils.findAndThen(userMap, Long.valueOf(copy.getCreator()),
@@ -69,7 +76,12 @@ public class BpmProcessInstanceCopyController { @@ -69,7 +76,12 @@ public class BpmProcessInstanceCopyController {
69 MapUtils.findAndThen(userMap, copy.getStartUserId(), 76 MapUtils.findAndThen(userMap, copy.getStartUserId(),
70 user -> copyVO.setCreateUser(BeanUtils.toBean(user, UserSimpleBaseVO.class))); 77 user -> copyVO.setCreateUser(BeanUtils.toBean(user, UserSimpleBaseVO.class)));
71 MapUtils.findAndThen(processInstanceMap, copyVO.getProcessInstanceId(), 78 MapUtils.findAndThen(processInstanceMap, copyVO.getProcessInstanceId(),
72 - processInstance -> copyVO.setProcessInstanceStartTime(DateUtils.of(processInstance.getStartTime()))); 79 + processInstance -> {
  80 + copyVO.setSummary(FlowableUtils.getSummary(
  81 + processDefinitionInfoMap.get(processInstance.getProcessDefinitionId()),
  82 + processInstance.getProcessVariables()));
  83 + copyVO.setProcessInstanceStartTime(DateUtils.of(processInstance.getStartTime()));
  84 + });
73 return copyVO; 85 return copyVO;
74 })); 86 }));
75 } 87 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java
1 package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc; 1 package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc;
2 2
  3 +import cn.iocoder.yudao.framework.common.core.KeyValue;
3 import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; 4 import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO;
4 import io.swagger.v3.oas.annotations.media.Schema; 5 import io.swagger.v3.oas.annotations.media.Schema;
5 import lombok.Data; 6 import lombok.Data;
6 7
7 import java.time.LocalDateTime; 8 import java.time.LocalDateTime;
  9 +import java.util.List;
8 10
9 @Schema(description = "管理后台 - 流程实例抄送的分页 Item Response VO") 11 @Schema(description = "管理后台 - 流程实例抄送的分页 Item Response VO")
10 @Data 12 @Data
@@ -40,4 +42,7 @@ public class BpmProcessInstanceCopyRespVO { @@ -40,4 +42,7 @@ public class BpmProcessInstanceCopyRespVO {
40 @Schema(description = "抄送时间", requiredMode = Schema.RequiredMode.REQUIRED) 42 @Schema(description = "抄送时间", requiredMode = Schema.RequiredMode.REQUIRED)
41 private LocalDateTime createTime; 43 private LocalDateTime createTime;
42 44
  45 + @Schema(description = "流程摘要", example = "[]")
  46 + private List<KeyValue<String, String>> summary;
  47 +
43 } 48 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageReqVO.java
@@ -32,7 +32,14 @@ public class BpmProcessInstancePageReqVO extends PageParam { @@ -32,7 +32,14 @@ public class BpmProcessInstancePageReqVO extends PageParam {
32 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 32 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
33 private LocalDateTime[] createTime; 33 private LocalDateTime[] createTime;
34 34
  35 + @Schema(description = "结束时间")
  36 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  37 + private LocalDateTime[] endTime;
  38 +
35 @Schema(description = "发起用户编号", example = "1024") 39 @Schema(description = "发起用户编号", example = "1024")
36 private Long startUserId; // 注意,只有在【流程实例】菜单,才使用该参数 40 private Long startUserId; // 注意,只有在【流程实例】菜单,才使用该参数
37 41
  42 + @Schema(description = "动态表单字段查询 JSON Str", example = "{}")
  43 + private String formFieldsParams; // SpringMVC 在 get 请求下,无法方便的定义 Map 类型的参数,所以通过 String 接收后,逻辑里面转换
  44 +
38 } 45 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java
@@ -85,10 +85,6 @@ public class BpmTaskRespVO { @@ -85,10 +85,6 @@ public class BpmTaskRespVO {
85 @Schema(description = "是否填写审批意见", example = "false") 85 @Schema(description = "是否填写审批意见", example = "false")
86 private Boolean reasonRequire; 86 private Boolean reasonRequire;
87 87
88 - // TODO @lesan:要不放到 processInstance 里面?因为摘要是流程实例的,不是流程任务的  
89 - @Schema(description = "流程摘要", example = "[]")  
90 - private List<KeyValue<String, String>> summary; // 只有流程表单,才有摘要!  
91 -  
92 @Data 88 @Data
93 @Schema(description = "流程实例") 89 @Schema(description = "流程实例")
94 public static class ProcessInstance { 90 public static class ProcessInstance {
@@ -105,6 +101,9 @@ public class BpmTaskRespVO { @@ -105,6 +101,9 @@ public class BpmTaskRespVO {
105 @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") 101 @Schema(description = "流程定义的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
106 private String processDefinitionId; 102 private String processDefinitionId;
107 103
  104 + @Schema(description = "流程摘要", example = "[]")
  105 + private List<KeyValue<String, String>> summary; // 只有流程表单,才有摘要!
  106 +
108 /** 107 /**
109 * 发起人的用户信息 108 * 发起人的用户信息
110 */ 109 */
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
@@ -80,6 +80,8 @@ public interface BpmProcessInstanceConvert { @@ -80,6 +80,8 @@ public interface BpmProcessInstanceConvert {
80 // 摘要 80 // 摘要
81 respVO.setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(respVO.getProcessDefinitionId()), 81 respVO.setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(respVO.getProcessDefinitionId()),
82 pageResult.getList().get(i).getProcessVariables())); 82 pageResult.getList().get(i).getProcessVariables()));
  83 + // 表单
  84 + respVO.setFormVariables(pageResult.getList().get(i).getProcessVariables());
83 } 85 }
84 return vpPageResult; 86 return vpPageResult;
85 } 87 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
@@ -54,7 +54,7 @@ public interface BpmTaskConvert { @@ -54,7 +54,7 @@ public interface BpmTaskConvert {
54 AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); 54 AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
55 taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class)); 55 taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class));
56 // 摘要 56 // 摘要
57 - taskVO.setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(processInstance.getProcessDefinitionId()), 57 + taskVO.getProcessInstance().setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(processInstance.getProcessDefinitionId()),
58 processInstance.getProcessVariables())); 58 processInstance.getProcessVariables()));
59 }); 59 });
60 } 60 }
@@ -80,7 +80,7 @@ public interface BpmTaskConvert { @@ -80,7 +80,7 @@ public interface BpmTaskConvert {
80 taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class)); 80 taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class));
81 taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class)); 81 taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, UserSimpleBaseVO.class));
82 // 摘要 82 // 摘要
83 - taskVO.setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(processInstance.getProcessDefinitionId()), 83 + taskVO.getProcessInstance().setSummary(FlowableUtils.getSummary(processDefinitionInfoMap.get(processInstance.getProcessDefinitionId()),
84 processInstance.getProcessVariables())); 84 processInstance.getProcessVariables()));
85 } 85 }
86 return taskVO; 86 return taskVO;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/task/BpmProcessInstanceCopyDO.java
@@ -50,6 +50,12 @@ public class BpmProcessInstanceCopyDO extends BaseDO { @@ -50,6 +50,12 @@ public class BpmProcessInstanceCopyDO extends BaseDO {
50 */ 50 */
51 private String processInstanceId; 51 private String processInstanceId;
52 /** 52 /**
  53 + * 流程实例的流程定义编号
  54 + *
  55 + * 关联 ProcessInstance 的 processDefinitionId 属性
  56 + */
  57 + private String processDefinitionId;
  58 + /**
53 * 流程分类 59 * 流程分类
54 * 60 *
55 * 冗余 ProcessInstance 的 category 字段 61 * 冗余 ProcessInstance 的 category 字段
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/redis/BpmProcessIdRedisDAO.java
1 package cn.iocoder.yudao.module.bpm.dal.redis; 1 package cn.iocoder.yudao.module.bpm.dal.redis;
2 2
3 import cn.hutool.core.date.DateUtil; 3 import cn.hutool.core.date.DateUtil;
  4 +import cn.hutool.core.util.StrUtil;
4 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; 5 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO;
5 import jakarta.annotation.Resource; 6 import jakarta.annotation.Resource;
6 import org.springframework.data.redis.core.StringRedisTemplate; 7 import org.springframework.data.redis.core.StringRedisTemplate;
@@ -48,7 +49,10 @@ public class BpmProcessIdRedisDAO { @@ -48,7 +49,10 @@ public class BpmProcessIdRedisDAO {
48 String noPrefix = processIdRule.getPrefix() + infix + processIdRule.getPostfix(); 49 String noPrefix = processIdRule.getPrefix() + infix + processIdRule.getPostfix();
49 String key = RedisKeyConstants.BPM_PROCESS_ID + noPrefix; 50 String key = RedisKeyConstants.BPM_PROCESS_ID + noPrefix;
50 Long no = stringRedisTemplate.opsForValue().increment(key); 51 Long no = stringRedisTemplate.opsForValue().increment(key);
51 - stringRedisTemplate.expire(key, Duration.ofDays(1L)); 52 + if (StrUtil.isEmpty(infix)) {
  53 + // 特殊:没有前缀,则不能过期,不能每次都是从 0 开始
  54 + stringRedisTemplate.expire(key, Duration.ofDays(1L));
  55 + }
52 return noPrefix + String.format("%0" + processIdRule.getLength() + "d", no); 56 return noPrefix + String.format("%0" + processIdRule.getLength() + "d", no);
53 } 57 }
54 58
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnModelUtils.java
@@ -64,6 +64,13 @@ public class BpmnModelUtils { @@ -64,6 +64,13 @@ public class BpmnModelUtils {
64 addExtensionElement(element, name, String.valueOf(value)); 64 addExtensionElement(element, name, String.valueOf(value));
65 } 65 }
66 66
  67 + public static void addExtensionElementJson(FlowElement element, String name, Object value) {
  68 + if (value == null) {
  69 + return;
  70 + }
  71 + addExtensionElement(element, name, JsonUtils.toJsonString(value));
  72 + }
  73 +
67 public static void addExtensionElement(FlowElement element, String name, Map<String, String> attributes) { 74 public static void addExtensionElement(FlowElement element, String name, Map<String, String> attributes) {
68 if (attributes == null) { 75 if (attributes == null) {
69 return; 76 return;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/FlowableUtils.java
@@ -26,6 +26,9 @@ import org.flowable.task.api.TaskInfo; @@ -26,6 +26,9 @@ import org.flowable.task.api.TaskInfo;
26 26
27 import java.util.*; 27 import java.util.*;
28 import java.util.concurrent.Callable; 28 import java.util.concurrent.Callable;
  29 +import java.util.stream.Collectors;
  30 +
  31 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
29 32
30 /** 33 /**
31 * Flowable 相关的工具方法 34 * Flowable 相关的工具方法
@@ -193,7 +196,6 @@ public class FlowableUtils { @@ -193,7 +196,6 @@ public class FlowableUtils {
193 BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES); 196 BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES);
194 } 197 }
195 198
196 - // TODO @lesan:如果值是 null 的情况,可能要调研下飞书、钉钉,是不是不返回哈!  
197 /** 199 /**
198 * 获得流程实例的摘要 200 * 获得流程实例的摘要
199 * 201 *
@@ -206,53 +208,40 @@ public class FlowableUtils { @@ -206,53 +208,40 @@ public class FlowableUtils {
206 */ 208 */
207 public static List<KeyValue<String, String>> getSummary(BpmProcessDefinitionInfoDO processDefinitionInfo, 209 public static List<KeyValue<String, String>> getSummary(BpmProcessDefinitionInfoDO processDefinitionInfo,
208 Map<String, Object> processVariables) { 210 Map<String, Object> processVariables) {
209 - // TODO @lesan:建议 if return,减少 { 层级  
210 - if (ObjectUtil.isNotNull(processDefinitionInfo)  
211 - && BpmModelFormTypeEnum.NORMAL.getType().equals(processDefinitionInfo.getFormType())) {  
212 - List<KeyValue<String, String>> summaryList = new ArrayList<>();  
213 - // TODO @lesan:可以使用 CollUtils.convertMap 简化工作量哈。  
214 - Map<String, BpmFormFieldVO> formFieldsMap = new HashMap<>();  
215 - processDefinitionInfo.getFormFields().forEach(formFieldStr -> {  
216 - BpmFormFieldVO formField = JsonUtils.parseObject(formFieldStr, BpmFormFieldVO.class); 211 + // 只有流程表单才会显示摘要!
  212 + if (ObjectUtil.isNull(processDefinitionInfo)
  213 + || !BpmModelFormTypeEnum.NORMAL.getType().equals(processDefinitionInfo.getFormType())) {
  214 + return null;
  215 + }
  216 +
  217 + // 解析表单配置
  218 + Map<String, BpmFormFieldVO> formFieldsMap = new HashMap<>();
  219 + processDefinitionInfo.getFormFields().forEach(formFieldStr -> {
  220 + BpmFormFieldVO formField = JsonUtils.parseObject(formFieldStr, BpmFormFieldVO.class);
  221 + if (formField != null) {
  222 + formFieldsMap.put(formField.getField(), formField);
  223 + }
  224 + });
  225 +
  226 + // 情况一:当自定义了摘要
  227 + if (ObjectUtil.isNotNull(processDefinitionInfo.getSummarySetting())
  228 + && Boolean.TRUE.equals(processDefinitionInfo.getSummarySetting().getEnable())) {
  229 + return convertList(processDefinitionInfo.getSummarySetting().getSummary(), item -> {
  230 + BpmFormFieldVO formField = formFieldsMap.get(item);
217 if (formField != null) { 231 if (formField != null) {
218 - formFieldsMap.put(formField.getField(), formField); 232 + return new KeyValue<String, String>(formField.getTitle(),
  233 + processVariables.getOrDefault(item, "").toString());
219 } 234 }
  235 + return null;
220 }); 236 });
221 -  
222 - // TODO @lesan:这里也可以 if return,还是为了减少括号哈。这样,就可以写注释,情况一:;情况二:  
223 - if (ObjectUtil.isNotNull(processDefinitionInfo.getSummarySetting())  
224 - && Boolean.TRUE.equals(processDefinitionInfo.getSummarySetting().getEnable())) {  
225 - // TODO @lesan:这里,也可以通过 CollUtils.convertList 简化哈。  
226 - for (String item : processDefinitionInfo.getSummarySetting().getSummary()) {  
227 - BpmFormFieldVO formField = formFieldsMap.get(item);  
228 - if (formField != null) {  
229 - summaryList.add(new KeyValue<>(formField.getTitle(),  
230 - processVariables.getOrDefault(item, "").toString()));  
231 - }  
232 - }  
233 - } else {  
234 - // 默认展示前三个  
235 - /* TODO @lesan:stream 简化  
236 - * summaryList.addAll(formFieldsMap.entrySet().stream()  
237 - * .limit(3)  
238 - * .map(entry -> new KeyValue<>(entry.getValue().getTitle(),  
239 - * processVariables.getOrDefault(entry.getValue().getField(), "").toString()))  
240 - * .collect(Collectors.toList()));  
241 - */  
242 - int j = 0;  
243 - for (Map.Entry<String, BpmFormFieldVO> entry : formFieldsMap.entrySet()) {  
244 - BpmFormFieldVO formField = entry.getValue();  
245 - if (j > 2) {  
246 - break;  
247 - }  
248 - summaryList.add(new KeyValue<>(formField.getTitle(),  
249 - processVariables.getOrDefault(formField.getField(), "").toString()));  
250 - j++;  
251 - }  
252 - }  
253 - return summaryList;  
254 } 237 }
255 - return null; 238 +
  239 + // 情况二:默认摘要展示前三个表单字段
  240 + return formFieldsMap.entrySet().stream()
  241 + .limit(3)
  242 + .map(entry -> new KeyValue<>(entry.getValue().getTitle(),
  243 + processVariables.getOrDefault(entry.getValue().getField(), "").toString()))
  244 + .collect(Collectors.toList());
256 } 245 }
257 246
258 // ========== Task 相关的工具方法 ========== 247 // ========== Task 相关的工具方法 ==========
@@ -317,9 +306,9 @@ public class FlowableUtils { @@ -317,9 +306,9 @@ public class FlowableUtils {
317 306
318 private static Object getExpressionValue(VariableContainer variableContainer, String expressionString, 307 private static Object getExpressionValue(VariableContainer variableContainer, String expressionString,
319 ProcessEngineConfigurationImpl processEngineConfiguration) { 308 ProcessEngineConfigurationImpl processEngineConfiguration) {
320 - assert processEngineConfiguration!= null; 309 + assert processEngineConfiguration != null;
321 ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager(); 310 ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
322 - assert expressionManager!= null; 311 + assert expressionManager != null;
323 Expression expression = expressionManager.createExpression(expressionString); 312 Expression expression = expressionManager.createExpression(expressionString);
324 return expression.getValue(variableContainer); 313 return expression.getValue(variableContainer);
325 } 314 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -5,7 +5,6 @@ import cn.hutool.core.lang.Assert; @@ -5,7 +5,6 @@ import cn.hutool.core.lang.Assert;
5 import cn.hutool.core.map.MapUtil; 5 import cn.hutool.core.map.MapUtil;
6 import cn.hutool.core.util.*; 6 import cn.hutool.core.util.*;
7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;  
9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; 8 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO;
10 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups; 9 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.ConditionGroups;
11 import cn.iocoder.yudao.module.bpm.enums.definition.*; 10 import cn.iocoder.yudao.module.bpm.enums.definition.*;
@@ -626,54 +625,50 @@ public class SimpleModelUtils { @@ -626,54 +625,50 @@ public class SimpleModelUtils {
626 625
627 public static SequenceFlow buildSequenceFlow(String sourceId, String targetId, 626 public static SequenceFlow buildSequenceFlow(String sourceId, String targetId,
628 BpmSimpleModelNodeVO node) { 627 BpmSimpleModelNodeVO node) {
629 - String conditionExpression = buildConditionExpression(node); 628 + String conditionExpression = buildConditionExpression(node.getConditionSetting());
630 return buildBpmnSequenceFlow(sourceId, targetId, node.getId(), node.getName(), conditionExpression); 629 return buildBpmnSequenceFlow(sourceId, targetId, node.getId(), node.getName(), conditionExpression);
631 } 630 }
  631 + }
632 632
633 - /**  
634 - * 构造条件表达式  
635 - *  
636 - * @param node 条件节点  
637 - */  
638 - public static String buildConditionExpression(BpmSimpleModelNodeVO node) {  
639 - return buildConditionExpression(node.getConditionSetting().getConditionType(), node.getConditionSetting().getConditionExpression(),  
640 - node.getConditionSetting().getConditionGroups());  
641 - } 633 + /**
  634 + * 构造条件表达式
  635 + */
  636 + public static String buildConditionExpression(BpmSimpleModelNodeVO.ConditionSetting conditionSetting) {
  637 + return buildConditionExpression(conditionSetting.getConditionType(), conditionSetting.getConditionExpression(),
  638 + conditionSetting.getConditionGroups());
  639 + }
642 640
643 - public static String buildConditionExpression(BpmSimpleModelNodeVO.RouterSetting router) {  
644 - return buildConditionExpression(router.getConditionType(), router.getConditionExpression(),  
645 - router.getConditionGroups());  
646 - } 641 + public static String buildConditionExpression(BpmSimpleModelNodeVO.RouterSetting routerSetting) {
  642 + return buildConditionExpression(routerSetting.getConditionType(), routerSetting.getConditionExpression(),
  643 + routerSetting.getConditionGroups());
  644 + }
647 645
648 - public static String buildConditionExpression(Integer conditionType, String conditionExpression,  
649 - ConditionGroups conditionGroups) {  
650 - BpmSimpleModeConditionTypeEnum conditionTypeEnum = BpmSimpleModeConditionTypeEnum.valueOf(conditionType);  
651 - if (conditionTypeEnum == BpmSimpleModeConditionTypeEnum.EXPRESSION) {  
652 - return conditionExpression; 646 + public static String buildConditionExpression(Integer conditionType, String conditionExpression, ConditionGroups conditionGroups) {
  647 + BpmSimpleModeConditionTypeEnum conditionTypeEnum = BpmSimpleModeConditionTypeEnum.valueOf(conditionType);
  648 + if (conditionTypeEnum == BpmSimpleModeConditionTypeEnum.EXPRESSION) {
  649 + return conditionExpression;
  650 + }
  651 + if (conditionTypeEnum == BpmSimpleModeConditionTypeEnum.RULE) {
  652 + if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) {
  653 + return null;
653 } 654 }
654 - if (conditionTypeEnum == BpmSimpleModeConditionTypeEnum.RULE) {  
655 - if (conditionGroups == null || CollUtil.isEmpty(conditionGroups.getConditions())) {  
656 - return null; 655 + List<String> strConditionGroups = CollectionUtils.convertList(conditionGroups.getConditions(), item -> {
  656 + if (CollUtil.isEmpty(item.getRules())) {
  657 + return "";
657 } 658 }
658 - List<String> strConditionGroups = CollectionUtils.convertList(conditionGroups.getConditions(), item -> {  
659 - if (CollUtil.isEmpty(item.getRules())) {  
660 - return "";  
661 - }  
662 - // 构造规则表达式  
663 - List<String> list = CollectionUtils.convertList(item.getRules(), (rule) -> {  
664 - String rightSide = NumberUtil.isNumber(rule.getRightSide()) ? rule.getRightSide()  
665 - : "\"" + rule.getRightSide() + "\""; // 如果非数值类型加引号  
666 - return String.format(" %s %s var:convertByType(%s,%s)", rule.getLeftSide(), rule.getOpCode(), rule.getLeftSide(), rightSide);  
667 - });  
668 - // 构造条件组的表达式  
669 - Boolean and = item.getAnd();  
670 - return "(" + CollUtil.join(list, and ? " && " : " || ") + ")"; 659 + // 构造规则表达式
  660 + List<String> list = CollectionUtils.convertList(item.getRules(), (rule) -> {
  661 + String rightSide = NumberUtil.isNumber(rule.getRightSide()) ? rule.getRightSide()
  662 + : "\"" + rule.getRightSide() + "\""; // 如果非数值类型加引号
  663 + return String.format(" %s %s var:convertByType(%s,%s)", rule.getLeftSide(), rule.getOpCode(), rule.getLeftSide(), rightSide);
671 }); 664 });
672 - return String.format("${%s}", CollUtil.join(strConditionGroups, conditionGroups.getAnd() ? " && " : " || "));  
673 - }  
674 - return null; 665 + // 构造条件组的表达式
  666 + Boolean and = item.getAnd();
  667 + return "(" + CollUtil.join(list, and ? " && " : " || ") + ")";
  668 + });
  669 + return String.format("${%s}", CollUtil.join(strConditionGroups, conditionGroups.getAnd() ? " && " : " || "));
675 } 670 }
676 - 671 + return null;
677 } 672 }
678 673
679 public static class DelayTimerNodeConvert implements NodeConvert { 674 public static class DelayTimerNodeConvert implements NodeConvert {
@@ -727,9 +722,10 @@ public class SimpleModelUtils { @@ -727,9 +722,10 @@ public class SimpleModelUtils {
727 if (node.getTriggerSetting() != null) { 722 if (node.getTriggerSetting() != null) {
728 addExtensionElement(serviceTask, TRIGGER_TYPE, node.getTriggerSetting().getType()); 723 addExtensionElement(serviceTask, TRIGGER_TYPE, node.getTriggerSetting().getType());
729 if (node.getTriggerSetting().getHttpRequestSetting() != null) { 724 if (node.getTriggerSetting().getHttpRequestSetting() != null) {
730 - // TODO @jason:加个 addExtensionElementJson 方法,方便设置 JSON 类型的属性  
731 - addExtensionElement(serviceTask, TRIGGER_PARAM,  
732 - JsonUtils.toJsonString(node.getTriggerSetting().getHttpRequestSetting())); 725 + addExtensionElementJson(serviceTask, TRIGGER_PARAM, node.getTriggerSetting().getHttpRequestSetting());
  726 + }
  727 + if (node.getTriggerSetting().getNormalFormSetting() != null) {
  728 + addExtensionElementJson(serviceTask, TRIGGER_PARAM, node.getTriggerSetting().getNormalFormSetting());
733 } 729 }
734 } 730 }
735 return serviceTask; 731 return serviceTask;
@@ -760,7 +756,7 @@ public class SimpleModelUtils { @@ -760,7 +756,7 @@ public class SimpleModelUtils {
760 } 756 }
761 757
762 public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouterSetting router) { 758 public static SequenceFlow buildSequenceFlow(String nodeId, BpmSimpleModelNodeVO.RouterSetting router) {
763 - String conditionExpression = ConditionNodeConvert.buildConditionExpression(router); 759 + String conditionExpression = SimpleModelUtils.buildConditionExpression(router);
764 return buildBpmnSequenceFlow(nodeId, router.getNodeId(), null, null, conditionExpression); 760 return buildBpmnSequenceFlow(nodeId, router.getNodeId(), null, null, conditionExpression);
765 } 761 }
766 762
@@ -804,7 +800,7 @@ public class SimpleModelUtils { @@ -804,7 +800,7 @@ public class SimpleModelUtils {
804 // 查找满足条件的 BpmSimpleModelNodeVO 节点 800 // 查找满足条件的 BpmSimpleModelNodeVO 节点
805 BpmSimpleModelNodeVO matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(), 801 BpmSimpleModelNodeVO matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
806 conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()) 802 conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())
807 - && evalConditionExpress(variables, conditionNode)); 803 + && evalConditionExpress(variables, conditionNode.getConditionSetting()));
808 if (matchConditionNode == null) { 804 if (matchConditionNode == null) {
809 matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(), 805 matchConditionNode = CollUtil.findOne(currentNode.getConditionNodes(),
810 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())); 806 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()));
@@ -819,7 +815,7 @@ public class SimpleModelUtils { @@ -819,7 +815,7 @@ public class SimpleModelUtils {
819 // 查找满足条件的 BpmSimpleModelNodeVO 节点 815 // 查找满足条件的 BpmSimpleModelNodeVO 节点
820 Collection<BpmSimpleModelNodeVO> matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(), 816 Collection<BpmSimpleModelNodeVO> matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(),
821 conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()) 817 conditionNode -> !BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())
822 - && evalConditionExpress(variables, conditionNode)); 818 + && evalConditionExpress(variables, conditionNode.getConditionSetting()));
823 if (CollUtil.isEmpty(matchConditionNodes)) { 819 if (CollUtil.isEmpty(matchConditionNodes)) {
824 matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(), 820 matchConditionNodes = CollUtil.filterNew(currentNode.getConditionNodes(),
825 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow())); 821 conditionNode -> BooleanUtil.isTrue(conditionNode.getConditionSetting().getDefaultFlow()));
@@ -841,16 +837,17 @@ public class SimpleModelUtils { @@ -841,16 +837,17 @@ public class SimpleModelUtils {
841 simulateNextNode(currentNode.getChildNode(), variables, resultNodes); 837 simulateNextNode(currentNode.getChildNode(), variables, resultNodes);
842 } 838 }
843 839
844 - public static boolean evalConditionExpress(Map<String, Object> variables, BpmSimpleModelNodeVO conditionNode) {  
845 - return BpmnModelUtils.evalConditionExpress(variables, ConditionNodeConvert.buildConditionExpression(conditionNode)); 840 + public static boolean evalConditionExpress(Map<String, Object> variables, BpmSimpleModelNodeVO.ConditionSetting conditionSetting) {
  841 + return BpmnModelUtils.evalConditionExpress(variables, buildConditionExpression(conditionSetting));
846 } 842 }
847 843
848 // TODO @芋艿:【高】要不要优化下,抽个 HttpUtils 844 // TODO @芋艿:【高】要不要优化下,抽个 HttpUtils
  845 +
849 /** 846 /**
850 * 添加 HTTP 请求参数。请求头或者请求体 847 * 添加 HTTP 请求参数。请求头或者请求体
851 * 848 *
852 - * @param params HTTP 请求参数  
853 - * @param paramSettings HTTP 请求参数设置 849 + * @param params HTTP 请求参数
  850 + * @param paramSettings HTTP 请求参数设置
854 * @param processVariables 流程变量 851 * @param processVariables 流程变量
855 */ 852 */
856 public static void addHttpRequestParam(MultiValueMap<String, String> params, 853 public static void addHttpRequestParam(MultiValueMap<String, String> params,
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java
@@ -86,6 +86,7 @@ public class BpmModelServiceImpl implements BpmModelService { @@ -86,6 +86,7 @@ public class BpmModelServiceImpl implements BpmModelService {
86 if (StrUtil.isNotEmpty(name)) { 86 if (StrUtil.isNotEmpty(name)) {
87 modelQuery.modelNameLike("%" + name + "%"); 87 modelQuery.modelNameLike("%" + name + "%");
88 } 88 }
  89 + modelQuery.modelTenantId(FlowableUtils.getTenantId());
89 return modelQuery.list(); 90 return modelQuery.list();
90 } 91 }
91 92
@@ -288,8 +289,7 @@ public class BpmModelServiceImpl implements BpmModelService { @@ -288,8 +289,7 @@ public class BpmModelServiceImpl implements BpmModelService {
288 // 2.3 清理所有 Task 289 // 2.3 清理所有 Task
289 List<Task> tasks = taskService.createTaskQuery() 290 List<Task> tasks = taskService.createTaskQuery()
290 .processDefinitionKey(model.getKey()).list(); 291 .processDefinitionKey(model.getKey()).list();
291 - // TODO @lesan:貌似传递一个 reason 会好点!  
292 - tasks.forEach(task -> taskService.deleteTask(task.getId())); 292 + tasks.forEach(task -> taskService.deleteTask(task.getId(),BpmReasonEnum.CANCEL_BY_PROCESS_CLEAN.getReason()));
293 } 293 }
294 294
295 @Override 295 @Override
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java
@@ -77,7 +77,8 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy @@ -77,7 +77,8 @@ public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopy
77 .setUserId(userId).setReason(reason).setStartUserId(Long.valueOf(processInstance.getStartUserId())) 77 .setUserId(userId).setReason(reason).setStartUserId(Long.valueOf(processInstance.getStartUserId()))
78 .setProcessInstanceId(processInstanceId).setProcessInstanceName(processInstance.getName()) 78 .setProcessInstanceId(processInstanceId).setProcessInstanceName(processInstance.getName())
79 .setCategory(processDefinition.getCategory()).setTaskId(taskId) 79 .setCategory(processDefinition.getCategory()).setTaskId(taskId)
80 - .setActivityId(activityId).setActivityName(activityName)); 80 + .setActivityId(activityId).setActivityName(activityName)
  81 + .setProcessDefinitionId(processInstance.getProcessDefinitionId()));
81 processInstanceCopyMapper.insertBatch(copyList); 82 processInstanceCopyMapper.insertBatch(copyList);
82 } 83 }
83 84
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java
@@ -157,4 +157,12 @@ public interface BpmProcessInstanceService { @@ -157,4 +157,12 @@ public interface BpmProcessInstanceService {
157 */ 157 */
158 void processProcessInstanceCompleted(ProcessInstance instance); 158 void processProcessInstanceCompleted(ProcessInstance instance);
159 159
  160 + /**
  161 + * 更新 ProcessInstance 的变量
  162 + *
  163 + * @param id 流程编号
  164 + * @param variables 流程变量
  165 + */
  166 + void updateProcessInstanceVariables(String id, Map<String, Object> variables);
  167 +
160 } 168 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
@@ -133,56 +133,18 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -133,56 +133,18 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
133 133
134 @Override 134 @Override
135 public HistoricProcessInstance getHistoricProcessInstance(String id) { 135 public HistoricProcessInstance getHistoricProcessInstance(String id) {
136 - return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); 136 + return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables()
  137 + .singleResult();
137 } 138 }
138 139
139 @Override 140 @Override
140 public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { 141 public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
141 - return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).includeProcessVariables().list(); 142 + return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).includeProcessVariables()
  143 + .list();
142 } 144 }
143 145
144 - @Override  
145 - public PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId,  
146 - BpmProcessInstancePageReqVO pageReqVO) {  
147 - // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页  
148 - HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery()  
149 - .includeProcessVariables()  
150 - .processInstanceTenantId(FlowableUtils.getTenantId())  
151 - .orderByProcessInstanceStartTime().desc();  
152 - if (userId != null) { // 【我的流程】菜单时,需要传递该字段  
153 - processInstanceQuery.startedBy(String.valueOf(userId));  
154 - } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段  
155 - processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId()));  
156 - }  
157 - if (StrUtil.isNotEmpty(pageReqVO.getName())) {  
158 - processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%");  
159 - }  
160 - if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionKey())) {  
161 - processInstanceQuery.processDefinitionKey(pageReqVO.getProcessDefinitionKey());  
162 - }  
163 - if (StrUtil.isNotEmpty(pageReqVO.getCategory())) {  
164 - processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory());  
165 - }  
166 - if (pageReqVO.getStatus() != null) {  
167 - processInstanceQuery.variableValueEquals(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus());  
168 - }  
169 - if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) {  
170 - processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0]));  
171 - processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1]));  
172 - }  
173 - // 查询数量  
174 - long processInstanceCount = processInstanceQuery.count();  
175 - if (processInstanceCount == 0) {  
176 - return PageResult.empty(processInstanceCount);  
177 - }  
178 - // 查询列表  
179 - List<HistoricProcessInstance> processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize());  
180 - return new PageResult<>(processInstanceList, processInstanceCount);  
181 - }  
182 -  
183 -  
184 private Map<String, String> getFormFieldsPermission(BpmnModel bpmnModel, 146 private Map<String, String> getFormFieldsPermission(BpmnModel bpmnModel,
185 - String activityId, String taskId) { 147 + String activityId, String taskId) {
186 // 1. 获取流程活动编号。流程活动 Id 为空事,从流程任务中获取流程活动 Id 148 // 1. 获取流程活动编号。流程活动 Id 为空事,从流程任务中获取流程活动 Id
187 if (StrUtil.isEmpty(activityId) && StrUtil.isNotEmpty(taskId)) { 149 if (StrUtil.isEmpty(activityId) && StrUtil.isNotEmpty(taskId)) {
188 activityId = Optional.ofNullable(taskService.getHistoricTask(taskId)) 150 activityId = Optional.ofNullable(taskService.getHistoricTask(taskId))
@@ -215,8 +177,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -215,8 +177,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
215 } 177 }
216 // 1.3 读取其它相关数据 178 // 1.3 读取其它相关数据
217 ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition( 179 ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(
218 - historicProcessInstance != null ? historicProcessInstance.getProcessDefinitionId() : reqVO.getProcessDefinitionId());  
219 - BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(processDefinition.getId()); 180 + historicProcessInstance != null ? historicProcessInstance.getProcessDefinitionId()
  181 + : reqVO.getProcessDefinitionId());
  182 + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService
  183 + .getProcessDefinitionInfo(processDefinition.getId());
220 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId()); 184 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processDefinition.getId());
221 185
222 // 2.1 已结束 + 进行中的活动节点 186 // 2.1 已结束 + 进行中的活动节点
@@ -225,24 +189,29 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -225,24 +189,29 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
225 List<HistoricActivityInstance> activities = null; // 流程实例列表 189 List<HistoricActivityInstance> activities = null; // 流程实例列表
226 if (reqVO.getProcessInstanceId() != null) { 190 if (reqVO.getProcessInstanceId() != null) {
227 activities = taskService.getActivityListByProcessInstanceId(reqVO.getProcessInstanceId()); 191 activities = taskService.getActivityListByProcessInstanceId(reqVO.getProcessInstanceId());
228 - List<HistoricTaskInstance> tasks = taskService.getTaskListByProcessInstanceId(reqVO.getProcessInstanceId(), true); 192 + List<HistoricTaskInstance> tasks = taskService.getTaskListByProcessInstanceId(reqVO.getProcessInstanceId(),
  193 + true);
229 endActivityNodes = getEndActivityNodeList(startUserId, bpmnModel, processDefinitionInfo, 194 endActivityNodes = getEndActivityNodeList(startUserId, bpmnModel, processDefinitionInfo,
230 historicProcessInstance, processInstanceStatus, activities, tasks); 195 historicProcessInstance, processInstanceStatus, activities, tasks);
231 - runActivityNodes = getRunApproveNodeList(startUserId, bpmnModel, processDefinition, processVariables, activities, tasks); 196 + runActivityNodes = getRunApproveNodeList(startUserId, bpmnModel, processDefinition, processVariables,
  197 + activities, tasks);
232 } 198 }
233 199
234 // 2.2 流程已经结束,直接 return,无需预测 200 // 2.2 流程已经结束,直接 return,无需预测
235 if (BpmProcessInstanceStatusEnum.isProcessEndStatus(processInstanceStatus)) { 201 if (BpmProcessInstanceStatusEnum.isProcessEndStatus(processInstanceStatus)) {
236 - return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, 202 + return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo,
  203 + historicProcessInstance,
237 processInstanceStatus, endActivityNodes, runActivityNodes, null, null); 204 processInstanceStatus, endActivityNodes, runActivityNodes, null, null);
238 } 205 }
239 206
240 // 3.1 计算当前登录用户的待办任务 207 // 3.1 计算当前登录用户的待办任务
241 - // TODO @jason:有一个极端情况,如果一个用户有 2 个 task A 和 B,A 已经通过,B 需要审核。这个时,通过 A 进来,todo 拿到 B,会不会表单权限不一致哈。 208 + // TODO @jason:有一个极端情况,如果一个用户有 2 个 task A 和 B,A 已经通过,B 需要审核。这个时,通过 A 进来,todo 拿到
  209 + // B,会不会表单权限不一致哈。
242 BpmTaskRespVO todoTask = taskService.getFirstTodoTask(loginUserId, reqVO.getProcessInstanceId()); 210 BpmTaskRespVO todoTask = taskService.getFirstTodoTask(loginUserId, reqVO.getProcessInstanceId());
243 211
244 // 3.2 预测未运行节点的审批信息 212 // 3.2 预测未运行节点的审批信息
245 - List<ActivityNode> simulateActivityNodes = getSimulateApproveNodeList(startUserId, bpmnModel, processDefinitionInfo, 213 + List<ActivityNode> simulateActivityNodes = getSimulateApproveNodeList(startUserId, bpmnModel,
  214 + processDefinitionInfo,
246 processVariables, activities); 215 processVariables, activities);
247 216
248 // 4. 拼接最终数据 217 // 4. 拼接最终数据
@@ -250,34 +219,93 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -250,34 +219,93 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
250 processInstanceStatus, endActivityNodes, runActivityNodes, simulateActivityNodes, todoTask); 219 processInstanceStatus, endActivityNodes, runActivityNodes, simulateActivityNodes, todoTask);
251 } 220 }
252 221
  222 + @Override
  223 + @SuppressWarnings("unchecked")
  224 + public PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId,
  225 + BpmProcessInstancePageReqVO pageReqVO) {
  226 + // 1. 构建查询条件
  227 + HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery()
  228 + .includeProcessVariables()
  229 + .processInstanceTenantId(FlowableUtils.getTenantId())
  230 + .orderByProcessInstanceStartTime().desc();
  231 + if (userId != null) { // 【我的流程】菜单时,需要传递该字段
  232 + processInstanceQuery.startedBy(String.valueOf(userId));
  233 + } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段
  234 + processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId()));
  235 + }
  236 + if (StrUtil.isNotEmpty(pageReqVO.getName())) {
  237 + processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%");
  238 + }
  239 + if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionKey())) {
  240 + processInstanceQuery.processDefinitionKey(pageReqVO.getProcessDefinitionKey());
  241 + }
  242 + if (StrUtil.isNotEmpty(pageReqVO.getCategory())) {
  243 + processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory());
  244 + }
  245 + if (pageReqVO.getStatus() != null) {
  246 + processInstanceQuery.variableValueEquals(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS,
  247 + pageReqVO.getStatus());
  248 + }
  249 + if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) {
  250 + processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0]));
  251 + processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1]));
  252 + }
  253 + if (ArrayUtil.isNotEmpty(pageReqVO.getEndTime())) {
  254 + processInstanceQuery.finishedAfter(DateUtils.of(pageReqVO.getEndTime()[0]));
  255 + processInstanceQuery.finishedBefore(DateUtils.of(pageReqVO.getEndTime()[1]));
  256 + }
  257 + // 表单字段查询
  258 + Map<String, Object> formFieldsParams = JsonUtils.parseObject(pageReqVO.getFormFieldsParams(), Map.class);
  259 + if (CollUtil.isNotEmpty(formFieldsParams)) {
  260 + formFieldsParams.forEach((key, value) -> {
  261 + if (StrUtil.isEmpty(String.valueOf(value))) {
  262 + return;
  263 + }
  264 + // TODO @lesan:应支持多种类型的查询方式,目前只有字符串全等
  265 + processInstanceQuery.variableValueEquals(key, value);
  266 + });
  267 + }
  268 +
  269 + // 2.1 查询数量
  270 + long processInstanceCount = processInstanceQuery.count();
  271 + if (processInstanceCount == 0) {
  272 + return PageResult.empty(processInstanceCount);
  273 + }
  274 + // 2.2 查询列表
  275 + List<HistoricProcessInstance> processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO),
  276 + pageReqVO.getPageSize());
  277 + return new PageResult<>(processInstanceList, processInstanceCount);
  278 + }
  279 +
253 /** 280 /**
254 * 拼接审批详情的最终数据 281 * 拼接审批详情的最终数据
255 * <p> 282 * <p>
256 * 主要是,拼接审批人的用户信息、部门信息 283 * 主要是,拼接审批人的用户信息、部门信息
257 */ 284 */
258 private BpmApprovalDetailRespVO buildApprovalDetail(BpmApprovalDetailReqVO reqVO, 285 private BpmApprovalDetailRespVO buildApprovalDetail(BpmApprovalDetailReqVO reqVO,
259 - BpmnModel bpmnModel,  
260 - ProcessDefinition processDefinition,  
261 - BpmProcessDefinitionInfoDO processDefinitionInfo,  
262 - HistoricProcessInstance processInstance,  
263 - Integer processInstanceStatus,  
264 - List<ActivityNode> endApprovalNodeInfos,  
265 - List<ActivityNode> runningApprovalNodeInfos,  
266 - List<ActivityNode> simulateApprovalNodeInfos,  
267 - BpmTaskRespVO todoTask) { 286 + BpmnModel bpmnModel,
  287 + ProcessDefinition processDefinition,
  288 + BpmProcessDefinitionInfoDO processDefinitionInfo,
  289 + HistoricProcessInstance processInstance,
  290 + Integer processInstanceStatus,
  291 + List<ActivityNode> endApprovalNodeInfos,
  292 + List<ActivityNode> runningApprovalNodeInfos,
  293 + List<ActivityNode> simulateApprovalNodeInfos,
  294 + BpmTaskRespVO todoTask) {
268 // 1. 获取所有需要读取用户信息的 userIds 295 // 1. 获取所有需要读取用户信息的 userIds
269 - List<ActivityNode> approveNodes = newArrayList(asList(endApprovalNodeInfos, runningApprovalNodeInfos, simulateApprovalNodeInfos)); 296 + List<ActivityNode> approveNodes = newArrayList(
  297 + asList(endApprovalNodeInfos, runningApprovalNodeInfos, simulateApprovalNodeInfos));
270 Set<Long> userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds(processInstance, approveNodes, todoTask); 298 Set<Long> userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds(processInstance, approveNodes, todoTask);
271 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); 299 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
272 Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); 300 Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
273 301
274 -  
275 // 2. 表单权限 302 // 2. 表单权限
276 String taskId = reqVO.getTaskId() == null && todoTask != null ? todoTask.getId() : reqVO.getTaskId(); 303 String taskId = reqVO.getTaskId() == null && todoTask != null ? todoTask.getId() : reqVO.getTaskId();
277 Map<String, String> formFieldsPermission = getFormFieldsPermission(bpmnModel, reqVO.getActivityId(), taskId); 304 Map<String, String> formFieldsPermission = getFormFieldsPermission(bpmnModel, reqVO.getActivityId(), taskId);
278 305
279 // 3. 拼接数据 306 // 3. 拼接数据
280 - return BpmProcessInstanceConvert.INSTANCE.buildApprovalDetail(bpmnModel, processDefinition, processDefinitionInfo, processInstance, 307 + return BpmProcessInstanceConvert.INSTANCE.buildApprovalDetail(bpmnModel, processDefinition,
  308 + processDefinitionInfo, processInstance,
281 processInstanceStatus, approveNodes, todoTask, formFieldsPermission, userMap, deptMap); 309 processInstanceStatus, approveNodes, todoTask, formFieldsPermission, userMap, deptMap);
282 } 310 }
283 311
@@ -285,17 +313,19 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -285,17 +313,19 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
285 * 获得【已结束】的活动节点们 313 * 获得【已结束】的活动节点们
286 */ 314 */
287 private List<ActivityNode> getEndActivityNodeList(Long startUserId, BpmnModel bpmnModel, 315 private List<ActivityNode> getEndActivityNodeList(Long startUserId, BpmnModel bpmnModel,
288 - BpmProcessDefinitionInfoDO processDefinitionInfo,  
289 - HistoricProcessInstance historicProcessInstance, Integer processInstanceStatus,  
290 - List<HistoricActivityInstance> activities, List<HistoricTaskInstance> tasks) { 316 + BpmProcessDefinitionInfoDO processDefinitionInfo,
  317 + HistoricProcessInstance historicProcessInstance, Integer processInstanceStatus,
  318 + List<HistoricActivityInstance> activities, List<HistoricTaskInstance> tasks) {
291 // 遍历 tasks 列表,只处理已结束的 UserTask 319 // 遍历 tasks 列表,只处理已结束的 UserTask
292 - // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 的话,它无法成为一个节点 320 + // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities
  321 + // 的话,它无法成为一个节点
293 List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null); 322 List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null);
294 List<ActivityNode> approvalNodes = convertList(endTasks, task -> { 323 List<ActivityNode> approvalNodes = convertList(endTasks, task -> {
295 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); 324 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
296 ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName()) 325 ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName())
297 - .setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey()) ?  
298 - BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType() : BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()) 326 + .setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey())
  327 + ? BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType()
  328 + : BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
299 .setStatus(FlowableUtils.getTaskStatus(task)) 329 .setStatus(FlowableUtils.getTaskStatus(task))
300 .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) 330 .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
301 .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime())) 331 .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime()))
@@ -320,7 +350,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -320,7 +350,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
320 .setName(BpmSimpleModelNodeTypeEnum.START_USER_NODE.getName()) 350 .setName(BpmSimpleModelNodeTypeEnum.START_USER_NODE.getName())
321 .setNodeType(BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType()) 351 .setNodeType(BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType())
322 .setStatus(startTask.getStatus()).setTasks(ListUtil.of(startTask)) 352 .setStatus(startTask.getStatus()).setTasks(ListUtil.of(startTask))
323 - .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime())); 353 + .setStartTime(DateUtils.of(activity.getStartTime()))
  354 + .setEndTime(DateUtils.of(activity.getEndTime()));
324 approvalNodes.add(0, startNode); 355 approvalNodes.add(0, startNode);
325 return; 356 return;
326 } 357 }
@@ -333,7 +364,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -333,7 +364,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
333 ActivityNode endNode = new ActivityNode().setId(activity.getId()) 364 ActivityNode endNode = new ActivityNode().setId(activity.getId())
334 .setName(BpmSimpleModelNodeTypeEnum.END_NODE.getName()) 365 .setName(BpmSimpleModelNodeTypeEnum.END_NODE.getName())
335 .setNodeType(BpmSimpleModelNodeTypeEnum.END_NODE.getType()).setStatus(processInstanceStatus) 366 .setNodeType(BpmSimpleModelNodeTypeEnum.END_NODE.getType()).setStatus(processInstanceStatus)
336 - .setStartTime(DateUtils.of(activity.getStartTime())).setEndTime(DateUtils.of(activity.getEndTime())); 367 + .setStartTime(DateUtils.of(activity.getStartTime()))
  368 + .setEndTime(DateUtils.of(activity.getEndTime()));
337 String reason = FlowableUtils.getProcessInstanceReason(historicProcessInstance); 369 String reason = FlowableUtils.getProcessInstanceReason(historicProcessInstance);
338 if (StrUtil.isNotEmpty(reason)) { 370 if (StrUtil.isNotEmpty(reason)) {
339 endNode.setTasks(singletonList(new ActivityNodeTask().setId(endNode.getId()) 371 endNode.setTasks(singletonList(new ActivityNodeTask().setId(endNode.getId())
@@ -349,15 +381,16 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -349,15 +381,16 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
349 * 获得【进行中】的活动节点们 381 * 获得【进行中】的活动节点们
350 */ 382 */
351 private List<ActivityNode> getRunApproveNodeList(Long startUserId, 383 private List<ActivityNode> getRunApproveNodeList(Long startUserId,
352 - BpmnModel bpmnModel,  
353 - ProcessDefinition processDefinition,  
354 - Map<String, Object> processVariables,  
355 - List<HistoricActivityInstance> activities,  
356 - List<HistoricTaskInstance> tasks) { 384 + BpmnModel bpmnModel,
  385 + ProcessDefinition processDefinition,
  386 + Map<String, Object> processVariables,
  387 + List<HistoricActivityInstance> activities,
  388 + List<HistoricTaskInstance> tasks) {
357 // 构建运行中的任务,基于 activityId 分组 389 // 构建运行中的任务,基于 activityId 分组
358 List<HistoricActivityInstance> runActivities = filterList(activities, activity -> activity.getEndTime() == null 390 List<HistoricActivityInstance> runActivities = filterList(activities, activity -> activity.getEndTime() == null
359 && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER))); 391 && (StrUtil.equalsAny(activity.getActivityType(), ELEMENT_TASK_USER)));
360 - Map<String, List<HistoricActivityInstance>> runningTaskMap = convertMultiMap(runActivities, HistoricActivityInstance::getActivityId); 392 + Map<String, List<HistoricActivityInstance>> runningTaskMap = convertMultiMap(runActivities,
  393 + HistoricActivityInstance::getActivityId);
361 394
362 // 按照 activityId 分组,构建 ApprovalNodeInfo 节点 395 // 按照 activityId 分组,构建 ApprovalNodeInfo 节点
363 Map<String, HistoricTaskInstance> taskMap = convertMap(tasks, HistoricTaskInstance::getId); 396 Map<String, HistoricTaskInstance> taskMap = convertMap(tasks, HistoricTaskInstance::getId);
@@ -367,8 +400,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -367,8 +400,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
367 // 构建活动节点 400 // 构建活动节点
368 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, activityId); 401 FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, activityId);
369 HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务,会签/或签的任务,开始时间相同 402 HistoricActivityInstance firstActivity = CollUtil.getFirst(taskActivities); // 取第一个任务,会签/或签的任务,开始时间相同
370 - ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId()).setName(firstActivity.getActivityName())  
371 - .setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType()).setStatus(BpmTaskStatusEnum.RUNNING.getStatus()) 403 + ActivityNode activityNode = new ActivityNode().setId(firstActivity.getActivityId())
  404 + .setName(firstActivity.getActivityName())
  405 + .setNodeType(BpmSimpleModelNodeTypeEnum.APPROVE_NODE.getType())
  406 + .setStatus(BpmTaskStatusEnum.RUNNING.getStatus())
372 .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) 407 .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode))
373 .setStartTime(DateUtils.of(CollUtil.getFirst(taskActivities).getStartTime())) 408 .setStartTime(DateUtils.of(CollUtil.getFirst(taskActivities).getStartTime()))
374 .setTasks(new ArrayList<>()); 409 .setTasks(new ArrayList<>());
@@ -381,7 +416,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -381,7 +416,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
381 taskService.getAllChildrenTaskListByParentTaskId(activity.getTaskId(), tasks), 416 taskService.getAllChildrenTaskListByParentTaskId(activity.getTaskId(), tasks),
382 childTask -> childTask.getEndTime() == null); 417 childTask -> childTask.getEndTime() == null);
383 if (CollUtil.isNotEmpty(childrenTasks)) { 418 if (CollUtil.isNotEmpty(childrenTasks)) {
384 - activityNode.getTasks().addAll(convertList(childrenTasks, BpmProcessInstanceConvert.INSTANCE::buildApprovalTaskInfo)); 419 + activityNode.getTasks().addAll(
  420 + convertList(childrenTasks, BpmProcessInstanceConvert.INSTANCE::buildApprovalTaskInfo));
385 } 421 }
386 } 422 }
387 // 处理每个任务的 candidateUsers 属性:如果是依次审批,需要预测它的后续审批人。因为 Task 是审批完一个,创建一个新的 Task 423 // 处理每个任务的 candidateUsers 属性:如果是依次审批,需要预测它的后续审批人。因为 Task 是审批完一个,创建一个新的 Task
@@ -391,8 +427,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -391,8 +427,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
391 // 截取当前审批人位置后面的候选人,不包含当前审批人 427 // 截取当前审批人位置后面的候选人,不包含当前审批人
392 ActivityNodeTask approvalTaskInfo = CollUtil.getFirst(activityNode.getTasks()); 428 ActivityNodeTask approvalTaskInfo = CollUtil.getFirst(activityNode.getTasks());
393 Assert.notNull(approvalTaskInfo, "任务不能为空"); 429 Assert.notNull(approvalTaskInfo, "任务不能为空");
394 - int index = CollUtil.indexOf(candidateUserIds, userId -> ObjectUtils.equalsAny(userId, approvalTaskInfo.getOwner(),  
395 - approvalTaskInfo.getAssignee())); // 委派或者向前加签情况,需要先比较 owner 430 + int index = CollUtil.indexOf(candidateUserIds,
  431 + userId -> ObjectUtils.equalsAny(userId, approvalTaskInfo.getOwner(),
  432 + approvalTaskInfo.getAssignee())); // 委派或者向前加签情况,需要先比较 owner
396 activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size())); 433 activityNode.setCandidateUserIds(CollUtil.sub(candidateUserIds, index + 1, candidateUserIds.size()));
397 } 434 }
398 return activityNode; 435 return activityNode;
@@ -403,10 +440,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -403,10 +440,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
403 * 获得【预测(未来)】的活动节点们 440 * 获得【预测(未来)】的活动节点们
404 */ 441 */
405 private List<ActivityNode> getSimulateApproveNodeList(Long startUserId, BpmnModel bpmnModel, 442 private List<ActivityNode> getSimulateApproveNodeList(Long startUserId, BpmnModel bpmnModel,
406 - BpmProcessDefinitionInfoDO processDefinitionInfo,  
407 - Map<String, Object> processVariables,  
408 - List<HistoricActivityInstance> activities) {  
409 - // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录 443 + BpmProcessDefinitionInfoDO processDefinitionInfo,
  444 + Map<String, Object> processVariables,
  445 + List<HistoricActivityInstance> activities) {
  446 + // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance
  447 + // 包括了历史的操作,不是只有 startEvent 到当前节点的记录
410 Set<String> runActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId); 448 Set<String> runActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId);
411 // 情况一:BPMN 设计器 449 // 情况一:BPMN 设计器
412 if (Objects.equals(BpmModelTypeEnum.BPMN.getType(), processDefinitionInfo.getModelType())) { 450 if (Objects.equals(BpmModelTypeEnum.BPMN.getType(), processDefinitionInfo.getModelType())) {
@@ -416,7 +454,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -416,7 +454,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
416 } 454 }
417 // 情况二:SIMPLE 设计器 455 // 情况二:SIMPLE 设计器
418 if (Objects.equals(BpmModelTypeEnum.SIMPLE.getType(), processDefinitionInfo.getModelType())) { 456 if (Objects.equals(BpmModelTypeEnum.SIMPLE.getType(), processDefinitionInfo.getModelType())) {
419 - BpmSimpleModelNodeVO simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class); 457 + BpmSimpleModelNodeVO simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(),
  458 + BpmSimpleModelNodeVO.class);
420 List<BpmSimpleModelNodeVO> simpleNodes = SimpleModelUtils.simulateProcess(simpleModel, processVariables); 459 List<BpmSimpleModelNodeVO> simpleNodes = SimpleModelUtils.simulateProcess(simpleModel, processVariables);
421 return convertList(simpleNodes, simpleNode -> buildNotRunApproveNodeForSimple(startUserId, bpmnModel, 460 return convertList(simpleNodes, simpleNode -> buildNotRunApproveNodeForSimple(startUserId, bpmnModel,
422 processDefinitionInfo, processVariables, simpleNode, runActivityIds)); 461 processDefinitionInfo, processVariables, simpleNode, runActivityIds));
@@ -425,9 +464,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -425,9 +464,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
425 } 464 }
426 465
427 private ActivityNode buildNotRunApproveNodeForSimple(Long startUserId, BpmnModel bpmnModel, 466 private ActivityNode buildNotRunApproveNodeForSimple(Long startUserId, BpmnModel bpmnModel,
428 - BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables,  
429 - BpmSimpleModelNodeVO node, Set<String> runActivityIds) {  
430 - // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance 包括了历史的操作,不是只有 startEvent 到当前节点的记录 467 + BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables,
  468 + BpmSimpleModelNodeVO node, Set<String> runActivityIds) {
  469 + // TODO @芋艿:【可优化】在驳回场景下,未来的预测准确性不高。原因是,驳回后,HistoricActivityInstance
  470 + // 包括了历史的操作,不是只有 startEvent 到当前节点的记录
431 if (runActivityIds.contains(node.getId())) { 471 if (runActivityIds.contains(node.getId())) {
432 return null; 472 return null;
433 } 473 }
@@ -460,12 +500,13 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -460,12 +500,13 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
460 } 500 }
461 501
462 private ActivityNode buildNotRunApproveNodeForBpmn(Long startUserId, BpmnModel bpmnModel, 502 private ActivityNode buildNotRunApproveNodeForBpmn(Long startUserId, BpmnModel bpmnModel,
463 - BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables,  
464 - FlowElement node, Set<String> runActivityIds) { 503 + BpmProcessDefinitionInfoDO processDefinitionInfo, Map<String, Object> processVariables,
  504 + FlowElement node, Set<String> runActivityIds) {
465 if (runActivityIds.contains(node.getId())) { 505 if (runActivityIds.contains(node.getId())) {
466 return null; 506 return null;
467 } 507 }
468 - ActivityNode activityNode = new ActivityNode().setId(node.getId()).setStatus(BpmTaskStatusEnum.NOT_START.getStatus()); 508 + ActivityNode activityNode = new ActivityNode().setId(node.getId())
  509 + .setStatus(BpmTaskStatusEnum.NOT_START.getStatus());
469 510
470 // 1. 开始节点 511 // 1. 开始节点
471 if (node instanceof StartEvent) { 512 if (node instanceof StartEvent) {
@@ -491,7 +532,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -491,7 +532,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
491 } 532 }
492 533
493 private List<Long> getTaskCandidateUserList(BpmnModel bpmnModel, String activityId, 534 private List<Long> getTaskCandidateUserList(BpmnModel bpmnModel, String activityId,
494 - Long startUserId, String processDefinitionId, Map<String, Object> processVariables) { 535 + Long startUserId, String processDefinitionId, Map<String, Object> processVariables) {
495 Set<Long> userIds = taskCandidateInvoker.calculateUsersByActivity(bpmnModel, activityId, 536 Set<Long> userIds = taskCandidateInvoker.calculateUsersByActivity(bpmnModel, activityId,
496 startUserId, processDefinitionId, processVariables); 537 startUserId, processDefinitionId, processVariables);
497 return new ArrayList<>(userIds); 538 return new ArrayList<>(userIds);
@@ -505,14 +546,16 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -505,14 +546,16 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
505 return null; 546 return null;
506 } 547 }
507 // 1.2 获得流程定义 548 // 1.2 获得流程定义
508 - BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId()); 549 + BpmnModel bpmnModel = processDefinitionService
  550 + .getProcessDefinitionBpmnModel(processInstance.getProcessDefinitionId());
509 if (bpmnModel == null) { 551 if (bpmnModel == null) {
510 return null; 552 return null;
511 } 553 }
512 BpmSimpleModelNodeVO simpleModel = null; 554 BpmSimpleModelNodeVO simpleModel = null;
513 BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo( 555 BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(
514 processInstance.getProcessDefinitionId()); 556 processInstance.getProcessDefinitionId());
515 - if (processDefinitionInfo != null && BpmModelTypeEnum.SIMPLE.getType().equals(processDefinitionInfo.getModelType())) { 557 + if (processDefinitionInfo != null
  558 + && BpmModelTypeEnum.SIMPLE.getType().equals(processDefinitionInfo.getModelType())) {
516 simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class); 559 simpleModel = JsonUtils.parseObject(processDefinitionInfo.getSimpleModel(), BpmSimpleModelNodeVO.class);
517 } 560 }
518 // 1.3 获得流程实例对应的活动实例列表 + 任务列表 561 // 1.3 获得流程实例对应的活动实例列表 + 任务列表
@@ -524,10 +567,12 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -524,10 +567,12 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
524 activityInstance -> activityInstance.getEndTime() == null); 567 activityInstance -> activityInstance.getEndTime() == null);
525 Set<String> finishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, 568 Set<String> finishedTaskActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId,
526 activityInstance -> activityInstance.getEndTime() != null 569 activityInstance -> activityInstance.getEndTime() != null
527 - && ObjectUtil.notEqual(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); 570 + && ObjectUtil.notEqual(activityInstance.getActivityType(),
  571 + BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW));
528 Set<String> finishedSequenceFlowActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId, 572 Set<String> finishedSequenceFlowActivityIds = convertSet(activities, HistoricActivityInstance::getActivityId,
529 activityInstance -> activityInstance.getEndTime() != null 573 activityInstance -> activityInstance.getEndTime() != null
530 - && ObjectUtil.equals(activityInstance.getActivityType(), BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW)); 574 + && ObjectUtil.equals(activityInstance.getActivityType(),
  575 + BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW));
531 // 特殊:会签情况下,会有部分已完成(审批)、部分未完成(待审批),此时需要 finishedTaskActivityIds 移除掉 576 // 特殊:会签情况下,会有部分已完成(审批)、部分未完成(待审批),此时需要 finishedTaskActivityIds 移除掉
532 finishedTaskActivityIds.removeAll(unfinishedTaskActivityIds); 577 finishedTaskActivityIds.removeAll(unfinishedTaskActivityIds);
533 // 特殊:如果流程实例被拒绝,则需要计算是哪个活动节点。 578 // 特殊:如果流程实例被拒绝,则需要计算是哪个活动节点。
@@ -545,8 +590,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -545,8 +590,10 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
545 Set<Long> userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds02(processInstance, tasks); 590 Set<Long> userIds = BpmProcessInstanceConvert.INSTANCE.parseUserIds02(processInstance, tasks);
546 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); 591 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
547 Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); 592 Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
548 - return BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceBpmnModelView(processInstance, tasks, bpmnModel, simpleModel,  
549 - unfinishedTaskActivityIds, finishedTaskActivityIds, finishedSequenceFlowActivityIds, rejectTaskActivityIds, 593 + return BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceBpmnModelView(processInstance, tasks, bpmnModel,
  594 + simpleModel,
  595 + unfinishedTaskActivityIds, finishedTaskActivityIds, finishedSequenceFlowActivityIds,
  596 + rejectTaskActivityIds,
550 userMap, deptMap); 597 userMap, deptMap);
551 } 598 }
552 599
@@ -556,7 +603,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -556,7 +603,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
556 @Transactional(rollbackFor = Exception.class) 603 @Transactional(rollbackFor = Exception.class)
557 public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { 604 public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) {
558 // 获得流程定义 605 // 获得流程定义
559 - ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); 606 + ProcessDefinition definition = processDefinitionService
  607 + .getProcessDefinition(createReqVO.getProcessDefinitionId());
560 // 发起流程 608 // 发起流程
561 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, 609 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null,
562 createReqVO.getStartUserSelectAssignees()); 610 createReqVO.getStartUserSelectAssignees());
@@ -566,16 +614,18 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -566,16 +614,18 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
566 public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { 614 public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) {
567 return FlowableUtils.executeAuthenticatedUserId(userId, () -> { 615 return FlowableUtils.executeAuthenticatedUserId(userId, () -> {
568 // 获得流程定义 616 // 获得流程定义
569 - ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); 617 + ProcessDefinition definition = processDefinitionService
  618 + .getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey());
570 // 发起流程 619 // 发起流程
571 - return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), 620 + return createProcessInstance0(userId, definition, createReqDTO.getVariables(),
  621 + createReqDTO.getBusinessKey(),
572 createReqDTO.getStartUserSelectAssignees()); 622 createReqDTO.getStartUserSelectAssignees());
573 }); 623 });
574 } 624 }
575 625
576 private String createProcessInstance0(Long userId, ProcessDefinition definition, 626 private String createProcessInstance0(Long userId, ProcessDefinition definition,
577 - Map<String, Object> variables, String businessKey,  
578 - Map<String, List<Long>> startUserSelectAssignees) { 627 + Map<String, Object> variables, String businessKey,
  628 + Map<String, List<Long>> startUserSelectAssignees) {
579 // 1.1 校验流程定义 629 // 1.1 校验流程定义
580 if (definition == null) { 630 if (definition == null) {
581 throw exception(PROCESS_DEFINITION_NOT_EXISTS); 631 throw exception(PROCESS_DEFINITION_NOT_EXISTS);
@@ -583,7 +633,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -583,7 +633,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
583 if (definition.isSuspended()) { 633 if (definition.isSuspended()) {
584 throw exception(PROCESS_DEFINITION_IS_SUSPENDED); 634 throw exception(PROCESS_DEFINITION_IS_SUSPENDED);
585 } 635 }
586 - BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(definition.getId()); 636 + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService
  637 + .getProcessDefinitionInfo(definition.getId());
587 if (processDefinitionInfo == null) { 638 if (processDefinitionInfo == null) {
588 throw exception(PROCESS_DEFINITION_NOT_EXISTS); 639 throw exception(PROCESS_DEFINITION_NOT_EXISTS);
589 } 640 }
@@ -602,9 +653,12 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -602,9 +653,12 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
602 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, userId); // 设置流程变量,发起人 ID 653 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_ID, userId); // 设置流程变量,发起人 ID
603 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 654 variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中
604 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); 655 BpmProcessInstanceStatusEnum.RUNNING.getStatus());
605 - variables.put(BpmnVariableConstants.PROCESS_INSTANCE_SKIP_EXPRESSION_ENABLED, true); // 跳过表达式需要添加此变量为 true,不影响没配置 skipExpression 的节点 656 + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_SKIP_EXPRESSION_ENABLED, true); // 跳过表达式需要添加此变量为
  657 + // true,不影响没配置
  658 + // skipExpression 的节点
606 if (CollUtil.isNotEmpty(startUserSelectAssignees)) { 659 if (CollUtil.isNotEmpty(startUserSelectAssignees)) {
607 - variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); 660 + variables.put(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES,
  661 + startUserSelectAssignees);
608 } 662 }
609 663
610 // 3. 创建流程 664 // 3. 创建流程
@@ -634,7 +688,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -634,7 +688,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
634 return instance.getId(); 688 return instance.getId();
635 } 689 }
636 690
637 - private void validateStartUserSelectAssignees(ProcessDefinition definition, Map<String, List<Long>> startUserSelectAssignees) { 691 + private void validateStartUserSelectAssignees(ProcessDefinition definition,
  692 + Map<String, List<Long>> startUserSelectAssignees) {
638 // 1. 获得发起人自选审批人的 UserTask/ServiceTask 列表 693 // 1. 获得发起人自选审批人的 UserTask/ServiceTask 列表
639 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); 694 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId());
640 List<Task> tasks = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectTaskList(bpmnModel); 695 List<Task> tasks = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectTaskList(bpmnModel);
@@ -669,7 +724,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -669,7 +724,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
669 throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); 724 throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF);
670 } 725 }
671 // 1.3 校验允许撤销审批中的申请 726 // 1.3 校验允许撤销审批中的申请
672 - BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService.getProcessDefinitionInfo(instance.getProcessDefinitionId()); 727 + BpmProcessDefinitionInfoDO processDefinitionInfo = processDefinitionService
  728 + .getProcessDefinitionInfo(instance.getProcessDefinitionId());
673 Assert.notNull(processDefinitionInfo, "流程定义({})不存在", processDefinitionInfo); 729 Assert.notNull(processDefinitionInfo, "流程定义({})不存在", processDefinitionInfo);
674 if (processDefinitionInfo.getAllowCancelRunningProcess() != null // 防止未配置 AllowCancelRunningProcess , 默认为可取消 730 if (processDefinitionInfo.getAllowCancelRunningProcess() != null // 防止未配置 AllowCancelRunningProcess , 默认为可取消
675 && Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) { 731 && Boolean.FALSE.equals(processDefinitionInfo.getAllowCancelRunningProcess())) {
@@ -707,9 +763,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -707,9 +763,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
707 763
708 @Override 764 @Override
709 public void updateProcessInstanceReject(ProcessInstance processInstance, String reason) { 765 public void updateProcessInstanceReject(ProcessInstance processInstance, String reason) {
710 - runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, 766 + runtimeService.setVariable(processInstance.getProcessInstanceId(),
  767 + BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS,
711 BpmProcessInstanceStatusEnum.REJECT.getStatus()); 768 BpmProcessInstanceStatusEnum.REJECT.getStatus());
712 - runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON, 769 + runtimeService.setVariable(processInstance.getProcessInstanceId(),
  770 + BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON,
713 BpmReasonEnum.REJECT_TASK.format(reason)); 771 BpmReasonEnum.REJECT_TASK.format(reason));
714 } 772 }
715 773
@@ -720,18 +778,22 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -720,18 +778,22 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
720 // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号 778 // 注意:需要基于 instance 设置租户编号,避免 Flowable 内部异步时,丢失租户编号
721 FlowableUtils.execute(instance.getTenantId(), () -> { 779 FlowableUtils.execute(instance.getTenantId(), () -> {
722 // 1.1 获取当前状态 780 // 1.1 获取当前状态
723 - Integer status = (Integer) instance.getProcessVariables().get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);  
724 - String reason = (String) instance.getProcessVariables().get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON); 781 + Integer status = (Integer) instance.getProcessVariables()
  782 + .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS);
  783 + String reason = (String) instance.getProcessVariables()
  784 + .get(BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_REASON);
725 // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态 785 // 1.2 当流程状态还是审批状态中,说明审批通过了,则变更下它的状态
726 // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了 786 // 为什么这么处理?因为流程完成,并且完成了,说明审批通过了
727 if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { 787 if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) {
728 status = BpmProcessInstanceStatusEnum.APPROVE.getStatus(); 788 status = BpmProcessInstanceStatusEnum.APPROVE.getStatus();
729 - runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS, status); 789 + runtimeService.setVariable(instance.getId(), BpmnVariableConstants.PROCESS_INSTANCE_VARIABLE_STATUS,
  790 + status);
730 } 791 }
731 792
732 // 2. 发送对应的消息通知 793 // 2. 发送对应的消息通知
733 if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) { 794 if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
734 - messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); 795 + messageService.sendMessageWhenProcessInstanceApprove(
  796 + BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance));
735 } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) { 797 } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) {
736 messageService.sendMessageWhenProcessInstanceReject( 798 messageService.sendMessageWhenProcessInstanceReject(
737 BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason)); 799 BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(instance, reason));
@@ -743,4 +805,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService @@ -743,4 +805,9 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
743 }); 805 });
744 } 806 }
745 807
  808 + @Override
  809 + public void updateProcessInstanceVariables(String id, Map<String, Object> variables) {
  810 + runtimeService.setVariables(id, variables);
  811 + }
  812 +
746 } 813 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/BpmHttpRequestTrigger.java
1 package cn.iocoder.yudao.module.bpm.service.task.trigger; 1 package cn.iocoder.yudao.module.bpm.service.task.trigger;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.core.KeyValue;
  6 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils; 7 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TriggerSetting.HttpRequestTriggerSetting; 8 import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TriggerSetting.HttpRequestTriggerSetting;
5 import cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerTypeEnum; 9 import cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerTypeEnum;
6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils; 10 import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.SimpleModelUtils;
7 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; 11 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
  12 +import com.fasterxml.jackson.core.type.TypeReference;
8 import jakarta.annotation.Resource; 13 import jakarta.annotation.Resource;
9 import lombok.extern.slf4j.Slf4j; 14 import lombok.extern.slf4j.Slf4j;
10 import org.flowable.engine.runtime.ProcessInstance; 15 import org.flowable.engine.runtime.ProcessInstance;
@@ -17,6 +22,8 @@ import org.springframework.util.MultiValueMap; @@ -17,6 +22,8 @@ import org.springframework.util.MultiValueMap;
17 import org.springframework.web.client.RestClientException; 22 import org.springframework.web.client.RestClientException;
18 import org.springframework.web.client.RestTemplate; 23 import org.springframework.web.client.RestTemplate;
19 24
  25 +import java.util.HashMap;
  26 +import java.util.List;
20 import java.util.Map; 27 import java.util.Map;
21 28
22 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID; 29 import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.HEADER_TENANT_ID;
@@ -63,13 +70,55 @@ public class BpmHttpRequestTrigger implements BpmTrigger { @@ -63,13 +70,55 @@ public class BpmHttpRequestTrigger implements BpmTrigger {
63 // TODO @芋艿:要不要抽象一个 Http 请求的工具类,方便复用呢? 70 // TODO @芋艿:要不要抽象一个 Http 请求的工具类,方便复用呢?
64 // 3. 发起请求 71 // 3. 发起请求
65 HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers); 72 HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(body, headers);
  73 + ResponseEntity<String> responseEntity;
66 try { 74 try {
67 - ResponseEntity<String> responseEntity = restTemplate.exchange(setting.getUrl(), HttpMethod.POST, 75 + responseEntity = restTemplate.exchange(setting.getUrl(), HttpMethod.POST,
68 requestEntity, String.class); 76 requestEntity, String.class);
69 log.info("[execute][HTTP 触发器,请求头:{},请求体:{},响应结果:{}]", headers, body, responseEntity); 77 log.info("[execute][HTTP 触发器,请求头:{},请求体:{},响应结果:{}]", headers, body, responseEntity);
70 } catch (RestClientException e) { 78 } catch (RestClientException e) {
71 log.error("[execute][HTTP 触发器,请求头:{},请求体:{},请求出错:{}]", headers, body, e.getMessage()); 79 log.error("[execute][HTTP 触发器,请求头:{},请求体:{},请求出错:{}]", headers, body, e.getMessage());
  80 + return;
  81 + }
  82 +
  83 + // 4.1 判断是否需要解析返回值
  84 + if (StrUtil.isEmpty(responseEntity.getBody())
  85 + || !responseEntity.getStatusCode().is2xxSuccessful()
  86 + || CollUtil.isEmpty(setting.getResponse())) {
  87 + return;
  88 + }
  89 + // 4.2 解析返回值, 返回值必须符合 CommonResult 规范。
  90 + CommonResult<Map<String, Object>> respResult = JsonUtils.parseObjectQuietly(
  91 + responseEntity.getBody(), new TypeReference<>() {});
  92 + if (respResult == null || !respResult.isSuccess()){
  93 + return;
  94 + }
  95 + // 4.3 获取需要更新的流程变量
  96 + Map<String, Object> updateVariables = getNeedUpdatedVariablesFromResponse(respResult.getData(), setting.getResponse());
  97 + // 4.4 更新流程变量
  98 + if (CollUtil.isNotEmpty(updateVariables)) {
  99 + processInstanceService.updateProcessInstanceVariables(processInstanceId, updateVariables);
  100 + }
  101 + }
  102 +
  103 + /**
  104 + * 从请求返回值获取需要更新的流程变量
  105 + *
  106 + * @param result 请求返回结果
  107 + * @param responseSettings 返回设置
  108 + * @return 需要更新的流程变量
  109 + */
  110 + private Map<String, Object> getNeedUpdatedVariablesFromResponse(Map<String,Object> result,
  111 + List<KeyValue<String, String>> responseSettings) {
  112 + Map<String, Object> updateVariables = new HashMap<>();
  113 + if (CollUtil.isEmpty(result)) {
  114 + return updateVariables;
72 } 115 }
  116 + responseSettings.forEach(responseSetting -> {
  117 + if (StrUtil.isNotEmpty(responseSetting.getKey()) && result.containsKey(responseSetting.getValue())) {
  118 + updateVariables.put(responseSetting.getKey(), result.get(responseSetting.getValue()));
  119 + }
  120 + });
  121 + return updateVariables;
73 } 122 }
74 123
75 } 124 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/trigger/BpmUpdateNormalFormTrigger.java 0 → 100644
  1 +package cn.iocoder.yudao.module.bpm.service.task.trigger;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  5 +import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TriggerSetting.NormalFormTriggerSetting;
  6 +import cn.iocoder.yudao.module.bpm.enums.definition.BpmTriggerTypeEnum;
  7 +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
  8 +import jakarta.annotation.Resource;
  9 +import lombok.extern.slf4j.Slf4j;
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +// TODO @jason:改成 BpmFormUpdateTrigger
  13 +/**
  14 + * BPM 更新流程表单触发器
  15 + *
  16 + * @author jason
  17 + */
  18 +@Component
  19 +@Slf4j
  20 +public class BpmUpdateNormalFormTrigger implements BpmTrigger {
  21 +
  22 + @Resource
  23 + private BpmProcessInstanceService processInstanceService;
  24 +
  25 + @Override
  26 + public BpmTriggerTypeEnum getType() {
  27 + return BpmTriggerTypeEnum.UPDATE_NORMAL_FORM;
  28 + }
  29 +
  30 + @Override
  31 + public void execute(String processInstanceId, String param) {
  32 + // 1. 解析更新流程表单配置
  33 + NormalFormTriggerSetting setting = JsonUtils.parseObject(param, NormalFormTriggerSetting.class);
  34 + if (setting == null) {
  35 + log.error("[execute][流程({}) 更新流程表单触发器配置为空]", processInstanceId);
  36 + return;
  37 + }
  38 + // 2.更新流程变量
  39 + if (CollUtil.isNotEmpty(setting.getUpdateFormFields())) {
  40 + processInstanceService.updateProcessInstanceVariables(processInstanceId, setting.getUpdateFormFields());
  41 + }
  42 + }
  43 +
  44 +}