Commit 5bafc0ce57cb3f01a803b779dfcc75534b076454

Authored by YunaiV
1 parent 923b9677

【代码评审】工作流:快搭部分的 code review

Showing 13 changed files with 41 additions and 30 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmApproveMethodEnum.java
@@ -16,10 +16,10 @@ import java.util.Arrays; @@ -16,10 +16,10 @@ import java.util.Arrays;
16 @AllArgsConstructor 16 @AllArgsConstructor
17 public enum BpmApproveMethodEnum implements IntArrayValuable { 17 public enum BpmApproveMethodEnum implements IntArrayValuable {
18 18
19 - RANDOM_SELECT_ONE_APPROVE(1, "随机挑选一人审批"),  
20 - APPROVE_BY_RATIO(2, "多人会签(按通过比例)"), // 会签(按通过比例)  
21 - ANY_APPROVE(3, "多人或签(一人通过或拒绝)"), // 或签(通过只需一人,拒绝只需一人)  
22 - SEQUENTIAL_APPROVE(4, "依次审批"); // 依次审批 19 + RANDOM(1, "随机挑选一人审批"),
  20 + RATIO(2, "多人会签(按通过比例)"), // 会签(按通过比例)
  21 + ANY(3, "多人或签(一人通过或拒绝)"), // 或签(通过只需一人,拒绝只需一人)
  22 + SEQUENTIAL(4, "依次审批"); // 依次审批
23 23
24 /** 24 /**
25 * 审批方式 25 * 审批方式
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskRejectHandlerType.java
@@ -16,7 +16,7 @@ import java.util.Arrays; @@ -16,7 +16,7 @@ import java.util.Arrays;
16 @AllArgsConstructor 16 @AllArgsConstructor
17 public enum BpmUserTaskRejectHandlerType implements IntArrayValuable { 17 public enum BpmUserTaskRejectHandlerType implements IntArrayValuable {
18 18
19 - FINISH_PROCESS(1, "终止流程"), 19 + FINISH_PROCESS_INSTANCE(1, "终止流程"),
20 RETURN_USER_TASK(2, "驳回到指定任务节点"); 20 RETURN_USER_TASK(2, "驳回到指定任务节点");
21 21
22 private final Integer type; 22 private final Integer type;
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/definition/BpmUserTaskTimeoutActionEnum.java
@@ -7,6 +7,7 @@ import lombok.Getter; @@ -7,6 +7,7 @@ import lombok.Getter;
7 7
8 import java.util.Arrays; 8 import java.util.Arrays;
9 9
  10 +// TODO @jason:BpmUserTaskTimeoutHandlerTypeEnum 会不会更匹配哈
10 /** 11 /**
11 * 用户任务超时处理执行动作枚举 12 * 用户任务超时处理执行动作枚举
12 * 13 *
@@ -16,9 +17,9 @@ import java.util.Arrays; @@ -16,9 +17,9 @@ import java.util.Arrays;
16 @AllArgsConstructor 17 @AllArgsConstructor
17 public enum BpmUserTaskTimeoutActionEnum implements IntArrayValuable { 18 public enum BpmUserTaskTimeoutActionEnum implements IntArrayValuable {
18 19
19 - AUTO_REMINDER(1,"自动提醒"),  
20 - AUTO_APPROVE(2, "自动同意"),  
21 - AUTO_REJECT(3, "自动拒绝"); 20 + REMINDER(1,"自动提醒"),
  21 + APPROVE(2, "自动同意"),
  22 + REJECT(3, "自动拒绝");
22 23
23 private final Integer action; 24 private final Integer action;
24 private final String name; 25 private final String name;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java
@@ -61,16 +61,18 @@ public class BpmTaskRespVO { @@ -61,16 +61,18 @@ public class BpmTaskRespVO {
61 private Long formId; 61 private Long formId;
62 @Schema(description = "表单名字", example = "请假表单") 62 @Schema(description = "表单名字", example = "请假表单")
63 private String formName; 63 private String formName;
64 - @Schema(description = "表单的配置-JSON 字符串") 64 + @Schema(description = "表单的配置,JSON 字符串")
65 private String formConf; 65 private String formConf;
66 @Schema(description = "表单项的数组") 66 @Schema(description = "表单项的数组")
67 private List<String> formFields; 67 private List<String> formFields;
68 @Schema(description = "提交的表单值", requiredMode = Schema.RequiredMode.REQUIRED) 68 @Schema(description = "提交的表单值", requiredMode = Schema.RequiredMode.REQUIRED)
69 private Map<String, Object> formVariables; 69 private Map<String, Object> formVariables;
  70 + // TODO @jason:fieldsPermissions
70 @Schema(description = "表单字段权限值") 71 @Schema(description = "表单字段权限值")
71 - private Map<String,String> fieldsPermission; 72 + private Map<String, String> fieldsPermission;
  73 + // TODO @jason:buttonsSettings
72 @Schema(description = "操作按钮设置值") 74 @Schema(description = "操作按钮设置值")
73 - private Map<Integer,OperationButtonSetting> buttonsSetting; 75 + private Map<Integer, OperationButtonSetting> buttonsSetting;
74 76
75 @Data 77 @Data
76 @Schema(description = "流程实例") 78 @Schema(description = "流程实例")
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
@@ -111,8 +111,8 @@ public interface BpmTaskConvert { @@ -111,8 +111,8 @@ public interface BpmTaskConvert {
111 taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class)); 111 taskVO.setOwnerUser(BeanUtils.toBean(ownerUser, BpmProcessInstanceRespVO.User.class));
112 findAndThen(deptMap, ownerUser.getDeptId(), dept -> taskVO.getOwnerUser().setDeptName(dept.getName())); 112 findAndThen(deptMap, ownerUser.getDeptId(), dept -> taskVO.getOwnerUser().setDeptName(dept.getName()));
113 } 113 }
114 - if(BpmTaskStatusEnum.RUNNING.getStatus().equals(taskStatus)){  
115 - // 设置表单权限 TODO @芋艿 是不是还要加一个全局的权限 基于 processInstance 的权限 114 + if (BpmTaskStatusEnum.RUNNING.getStatus().equals(taskStatus)){
  115 + // 设置表单权限 TODO @芋艿 是不是还要加一个全局的权限 基于 processInstance 的权限;回复:可能不需要,但是发起人,需要有个权限配置
116 taskVO.setFieldsPermission(BpmnModelUtils.parseFormFieldsPermission(bpmnModel, task.getTaskDefinitionKey())); 116 taskVO.setFieldsPermission(BpmnModelUtils.parseFormFieldsPermission(bpmnModel, task.getTaskDefinitionKey()));
117 // 操作按钮设置 117 // 操作按钮设置
118 taskVO.setButtonsSetting(BpmnModelUtils.parseButtonsSetting(bpmnModel, task.getTaskDefinitionKey())); 118 taskVO.setButtonsSetting(BpmnModelUtils.parseButtonsSetting(bpmnModel, task.getTaskDefinitionKey()));
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateStartUserStrategy.java
@@ -12,7 +12,9 @@ import org.springframework.stereotype.Component; @@ -12,7 +12,9 @@ import org.springframework.stereotype.Component;
12 import java.util.Set; 12 import java.util.Set;
13 13
14 /** 14 /**
15 - * 发起人自己 {@link BpmTaskCandidateUserStrategy} 实现类。 用于需要发起人信息复核等场景 15 + * 发起人自己 {@link BpmTaskCandidateUserStrategy} 实现类
  16 + *
  17 + * 适合场景:用于需要发起人信息复核等场景
16 * 18 *
17 * @author jason 19 * @author jason
18 */ 20 */
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/enums/BpmnModelConstants.java
@@ -35,6 +35,7 @@ public interface BpmnModelConstants { @@ -35,6 +35,7 @@ public interface BpmnModelConstants {
35 */ 35 */
36 String BOUNDARY_EVENT_TYPE = "boundaryEventType"; 36 String BOUNDARY_EVENT_TYPE = "boundaryEventType";
37 37
  38 + // TODO @jason:这个命名,应该也要改哈
38 /** 39 /**
39 * BPMN ExtensionElement 的扩展属性,用于标记用户任务超时执行动作 40 * BPMN ExtensionElement 的扩展属性,用于标记用户任务超时执行动作
40 */ 41 */
@@ -45,7 +46,6 @@ public interface BpmnModelConstants { @@ -45,7 +46,6 @@ public interface BpmnModelConstants {
45 * BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝处理类型 46 * BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝处理类型
46 */ 47 */
47 String USER_TASK_REJECT_HANDLER_TYPE = "rejectHandlerType"; 48 String USER_TASK_REJECT_HANDLER_TYPE = "rejectHandlerType";
48 -  
49 /** 49 /**
50 * BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝后的回退的任务 Id 50 * BPMN ExtensionElement 的扩展属性,用于标记用户任务拒绝后的回退的任务 Id
51 */ 51 */
@@ -56,6 +56,7 @@ public interface BpmnModelConstants { @@ -56,6 +56,7 @@ public interface BpmnModelConstants {
56 */ 56 */
57 String USER_TASK_APPROVE_METHOD = "approveMethod"; 57 String USER_TASK_APPROVE_METHOD = "approveMethod";
58 58
  59 + // TODO @jason:这个命名,可能有个 fieldsPermissions 更合适点。可能 formPermissions 会更更合适。
59 /** 60 /**
60 * BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限 61 * BPMN ExtensionElement 流程表单字段权限元素, 用于标记字段权限
61 */ 62 */
@@ -65,7 +66,6 @@ public interface BpmnModelConstants { @@ -65,7 +66,6 @@ public interface BpmnModelConstants {
65 * BPMN ExtensionElement Attribute, 用于标记表单字段 66 * BPMN ExtensionElement Attribute, 用于标记表单字段
66 */ 67 */
67 String FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE = "field"; 68 String FORM_FIELD_PERMISSION_ELEMENT_FIELD_ATTRIBUTE = "field";
68 -  
69 /** 69 /**
70 * BPMN ExtensionElement Attribute, 用于标记表单权限 70 * BPMN ExtensionElement Attribute, 用于标记表单权限
71 */ 71 */
@@ -75,12 +75,10 @@ public interface BpmnModelConstants { @@ -75,12 +75,10 @@ public interface BpmnModelConstants {
75 * BPMN ExtensionElement 操作按钮设置元素, 用于审批节点操作按钮设置 75 * BPMN ExtensionElement 操作按钮设置元素, 用于审批节点操作按钮设置
76 */ 76 */
77 String BUTTON_SETTING_ELEMENT = "buttonsSettings"; 77 String BUTTON_SETTING_ELEMENT = "buttonsSettings";
78 -  
79 /** 78 /**
80 * BPMN ExtensionElement Attribute, 用于标记按钮编号 79 * BPMN ExtensionElement Attribute, 用于标记按钮编号
81 */ 80 */
82 String BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE = "id"; 81 String BUTTON_SETTING_ELEMENT_ID_ATTRIBUTE = "id";
83 -  
84 /** 82 /**
85 * BPMN ExtensionElement Attribute, 用于标记按钮显示名称 83 * BPMN ExtensionElement Attribute, 用于标记按钮显示名称
86 */ 84 */
@@ -91,14 +89,16 @@ public interface BpmnModelConstants { @@ -91,14 +89,16 @@ public interface BpmnModelConstants {
91 */ 89 */
92 String BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE = "enable"; 90 String BUTTON_SETTING_ELEMENT_ENABLE_ATTRIBUTE = "enable";
93 91
94 - // TODO @芋艿:这里后面得关注下; 92 + // TODO @jason:这个是不是可以删除啦
95 /** 93 /**
96 * BPMN End Event 节点 Id, 用于后端生成 End Event 节点 94 * BPMN End Event 节点 Id, 用于后端生成 End Event 节点
97 */ 95 */
98 String END_EVENT_ID = "EndEvent_1"; 96 String END_EVENT_ID = "EndEvent_1";
99 97
  98 + // TODO @jason:这个是不是可以删除啦
100 /** 99 /**
101 * 支持转仿钉钉设计模型的 Bpmn 节点 100 * 支持转仿钉钉设计模型的 Bpmn 节点
102 */ 101 */
103 Set<Class<? extends FlowNode>> SUPPORT_CONVERT_SIMPLE_FlOW_NODES = ImmutableSet.of(UserTask.class, EndEvent.class); 102 Set<Class<? extends FlowNode>> SUPPORT_CONVERT_SIMPLE_FlOW_NODES = ImmutableSet.of(UserTask.class, EndEvent.class);
  103 +
104 } 104 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTimerFiredEventListener.java
@@ -85,13 +85,13 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe @@ -85,13 +85,13 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe
85 null, taskDefKey); 85 null, taskDefKey);
86 taskList.forEach(task -> { 86 taskList.forEach(task -> {
87 // 自动提醒 87 // 自动提醒
88 - if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_REMINDER) { 88 + if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.REMINDER) {
89 TodoTaskReminderMessage message = new TodoTaskReminderMessage().setTenantId(Long.parseLong(task.getTenantId())) 89 TodoTaskReminderMessage message = new TodoTaskReminderMessage().setTenantId(Long.parseLong(task.getTenantId()))
90 .setUserId(Long.parseLong(task.getAssignee())).setTaskName(task.getName()); 90 .setUserId(Long.parseLong(task.getAssignee())).setTaskName(task.getName());
91 todoTaskReminderProducer.sendReminderMessage(message); 91 todoTaskReminderProducer.sendReminderMessage(message);
92 } 92 }
93 // 自动同意 93 // 自动同意
94 - if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_APPROVE) { 94 + if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.APPROVE) {
95 // TODO @芋艿 这个上下文如何清除呢? 任务通过后, BpmProcessInstanceEventListener 会有回调 95 // TODO @芋艿 这个上下文如何清除呢? 任务通过后, BpmProcessInstanceEventListener 会有回调
96 TenantContextHolder.setTenantId(Long.parseLong(task.getTenantId())); 96 TenantContextHolder.setTenantId(Long.parseLong(task.getTenantId()));
97 TenantContextHolder.setIgnore(false); 97 TenantContextHolder.setIgnore(false);
@@ -100,7 +100,7 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe @@ -100,7 +100,7 @@ public class BpmTimerFiredEventListener extends AbstractFlowableEngineEventListe
100 bpmTaskService.approveTask(Long.parseLong(task.getAssignee()), req); 100 bpmTaskService.approveTask(Long.parseLong(task.getAssignee()), req);
101 } 101 }
102 // 自动拒绝 102 // 自动拒绝
103 - if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.AUTO_REJECT) { 103 + if (userTaskTimeoutAction == BpmUserTaskTimeoutActionEnum.REJECT) {
104 // TODO @芋艿 这个上下文如何清除呢? 任务拒绝后, BpmProcessInstanceEventListener 会有回调 104 // TODO @芋艿 这个上下文如何清除呢? 任务拒绝后, BpmProcessInstanceEventListener 会有回调
105 TenantContextHolder.setTenantId(Long.parseLong(task.getTenantId())); 105 TenantContextHolder.setTenantId(Long.parseLong(task.getTenantId()));
106 TenantContextHolder.setIgnore(false); 106 TenantContextHolder.setIgnore(false);
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/simplemodel/SimpleModelUserTaskConfig.java
@@ -7,6 +7,7 @@ import lombok.Data; @@ -7,6 +7,7 @@ import lombok.Data;
7 import java.util.List; 7 import java.util.List;
8 import java.util.Map; 8 import java.util.Map;
9 9
  10 +// TODO @jason:这个貌似没用到,是不是可以删除啦
10 /** 11 /**
11 * 仿钉钉流程设计器审批节点配置 Model 12 * 仿钉钉流程设计器审批节点配置 Model
12 * 13 *
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/BpmnFormUtils.java
@@ -26,8 +26,10 @@ public class BpmnFormUtils { @@ -26,8 +26,10 @@ public class BpmnFormUtils {
26 private static final String CREATE_FORM_DISPLAY_ATTRIBUTE = "display"; 26 private static final String CREATE_FORM_DISPLAY_ATTRIBUTE = "display";
27 private static final String CREATE_FORM_DISABLED_ATTRIBUTE = "disabled"; 27 private static final String CREATE_FORM_DISABLED_ATTRIBUTE = "disabled";
28 28
  29 + // TODO @jason:这个方法,还要哇?
29 /** 30 /**
30 * 修改 form-create 表单组件字段权限规则: 包括可编辑、只读、隐藏规则 31 * 修改 form-create 表单组件字段权限规则: 包括可编辑、只读、隐藏规则
  32 + *
31 * @param fields 字段规则 33 * @param fields 字段规则
32 * @param fieldsPermission 字段权限 34 * @param fieldsPermission 字段权限
33 * @return 修改权限后的字段规则 35 * @return 修改权限后的字段规则
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/util/SimpleModelUtils.java
@@ -27,7 +27,7 @@ import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.s @@ -27,7 +27,7 @@ import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.s
27 import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TimeoutHandler; 27 import static cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO.TimeoutHandler;
28 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT; 28 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmBoundaryEventType.USER_TASK_TIMEOUT;
29 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.*; 29 import static cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeType.*;
30 -import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.AUTO_REMINDER; 30 +import static cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutActionEnum.REMINDER;
31 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*; 31 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.*;
32 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*; 32 import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.SimpleModelConstants.*;
33 import static org.flowable.bpmn.constants.BpmnXMLConstants.*; 33 import static org.flowable.bpmn.constants.BpmnXMLConstants.*;
@@ -356,7 +356,7 @@ public class SimpleModelUtils { @@ -356,7 +356,7 @@ public class SimpleModelUtils {
356 boundaryEvent.setAttachedToRef(userTask); 356 boundaryEvent.setAttachedToRef(userTask);
357 TimerEventDefinition eventDefinition = new TimerEventDefinition(); 357 TimerEventDefinition eventDefinition = new TimerEventDefinition();
358 eventDefinition.setTimeDuration(timeoutHandler.getTimeDuration()); 358 eventDefinition.setTimeDuration(timeoutHandler.getTimeDuration());
359 - if (Objects.equals(AUTO_REMINDER.getAction(), timeoutHandler.getAction()) && 359 + if (Objects.equals(REMINDER.getAction(), timeoutHandler.getAction()) &&
360 timeoutHandler.getMaxRemindCount() != null && timeoutHandler.getMaxRemindCount() > 1) { 360 timeoutHandler.getMaxRemindCount() != null && timeoutHandler.getMaxRemindCount() > 1) {
361 // 最大提醒次数 361 // 最大提醒次数
362 eventDefinition.setTimeCycle(String.format("R%d/%s", timeoutHandler.getMaxRemindCount(), timeoutHandler.getTimeDuration())); 362 eventDefinition.setTimeCycle(String.format("R%d/%s", timeoutHandler.getMaxRemindCount(), timeoutHandler.getTimeDuration()));
@@ -475,7 +475,7 @@ public class SimpleModelUtils { @@ -475,7 +475,7 @@ public class SimpleModelUtils {
475 475
476 private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) { 476 private static void processMultiInstanceLoopCharacteristics(Integer approveMethod, Integer approveRatio, UserTask userTask) {
477 BpmApproveMethodEnum bpmApproveMethodEnum = BpmApproveMethodEnum.valueOf(approveMethod); 477 BpmApproveMethodEnum bpmApproveMethodEnum = BpmApproveMethodEnum.valueOf(approveMethod);
478 - if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.RANDOM_SELECT_ONE_APPROVE) { 478 + if (bpmApproveMethodEnum == null || bpmApproveMethodEnum == BpmApproveMethodEnum.RANDOM) {
479 return; 479 return;
480 } 480 }
481 // 添加审批方式的扩展属性 481 // 添加审批方式的扩展属性
@@ -484,16 +484,16 @@ public class SimpleModelUtils { @@ -484,16 +484,16 @@ public class SimpleModelUtils {
484 MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics(); 484 MultiInstanceLoopCharacteristics multiInstanceCharacteristics = new MultiInstanceLoopCharacteristics();
485 // 设置 collectionVariable。本系统用不到。会在 仅仅为了校验。 485 // 设置 collectionVariable。本系统用不到。会在 仅仅为了校验。
486 multiInstanceCharacteristics.setInputDataItem("${coll_userList}"); 486 multiInstanceCharacteristics.setInputDataItem("${coll_userList}");
487 - if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY_APPROVE) { 487 + if (bpmApproveMethodEnum == BpmApproveMethodEnum.ANY) {
488 multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION); 488 multiInstanceCharacteristics.setCompletionCondition(ANY_OF_APPROVE_COMPLETE_EXPRESSION);
489 multiInstanceCharacteristics.setSequential(false); 489 multiInstanceCharacteristics.setSequential(false);
490 userTask.setLoopCharacteristics(multiInstanceCharacteristics); 490 userTask.setLoopCharacteristics(multiInstanceCharacteristics);
491 - } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.SEQUENTIAL_APPROVE) { 491 + } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.SEQUENTIAL) {
492 multiInstanceCharacteristics.setCompletionCondition(ALL_APPROVE_COMPLETE_EXPRESSION); 492 multiInstanceCharacteristics.setCompletionCondition(ALL_APPROVE_COMPLETE_EXPRESSION);
493 multiInstanceCharacteristics.setSequential(true); 493 multiInstanceCharacteristics.setSequential(true);
494 multiInstanceCharacteristics.setLoopCardinality("1"); 494 multiInstanceCharacteristics.setLoopCardinality("1");
495 userTask.setLoopCharacteristics(multiInstanceCharacteristics); 495 userTask.setLoopCharacteristics(multiInstanceCharacteristics);
496 - } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.APPROVE_BY_RATIO) { 496 + } else if (bpmApproveMethodEnum == BpmApproveMethodEnum.RATIO) {
497 Assert.notNull(approveRatio, "通过比例不能为空"); 497 Assert.notNull(approveRatio, "通过比例不能为空");
498 double approvePct = approveRatio / (double) 100; 498 double approvePct = approveRatio / (double) 100;
499 multiInstanceCharacteristics.setCompletionCondition(String.format(APPROVE_BY_RATIO_COMPLETE_EXPRESSION, String.format("%.2f", approvePct))); 499 multiInstanceCharacteristics.setCompletionCondition(String.format(APPROVE_BY_RATIO_COMPLETE_EXPRESSION, String.format("%.2f", approvePct)));
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
1 -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .processInstanceTenantId(FlowableUtils.getTenantId()) .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List<HistoricProcessInstance> processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getStartUserSelectAssignees()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getStartUserSelectAssignees()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey, Map<String, List<Long>> startUserSelectAssignees) { // 1.1 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 1.2 校验发起人自选审批人 validateStartUserSelectAssignees(definition, startUserSelectAssignees); // 2. 创建流程实例 if (variables == null) { variables = new HashMap<>(); } FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); if (CollUtil.isNotEmpty(startUserSelectAssignees)) { variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); } ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } private void validateStartUserSelectAssignees(ProcessDefinition definition, Map<String, List<Long>> startUserSelectAssignees) { // 1. 获得发起人自选审批人的 UserTask 列表 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); List<UserTask> userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel); if (CollUtil.isEmpty(userTaskList)) { return; } // 2. 校验发起人自选审批人的 UserTask 是否都配置了 userTaskList.forEach(userTask -> { List<Long> assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(userTask.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, userTask.getName()); } Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assignees); assignees.forEach(assignee -> { if (userMap.get(assignee) == null) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, userTask.getName(), assignee); } }); }); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 管理员取消,不用校验是否为自己的 AdminUserRespDTO user = adminUserApi.getUser(userId); // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // @芋艿 这种情况不会发生了。 拒绝时候不会删除流程 // // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 // if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { // return; // } // 1. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 2. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(ProcessInstance processInstance, List<String> activityIds, String endId, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 跳转到流程结束 EndEvent 节点,结束流程 runtimeService.createChangeActivityStateBuilder() .processInstanceId(processInstance.getProcessInstanceId()) .moveActivityIdsToSingleActivityId(CollUtil.newArrayList(activityIds), endId) .changeState(); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } @Override public void updateProcessInstanceWhenCompleted(ProcessInstance instance) { Integer status = (Integer) instance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS); // 当流程状态还是审批状态中, 更新为审批通过 if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { updateProcessInstanceWhenApprove(instance); } // 审批不通过状态。已经在 updateProcessInstanceReject 处理 } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } }  
2 \ No newline at end of file 1 \ No newline at end of file
  2 +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.object.PageUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.enums.task.BpmDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.strategy.BpmTaskCandidateStartUserSelectStrategy; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.flowable.bpmn.model.BpmnModel; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstanceQuery; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.util.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 * * ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. <a href="https://blog.csdn.net/bobozai86/article/details/105210414" /> * * HistoricProcessInstance & ProcessInstance 的关系: * 1. <a href=" https://my.oschina.net/843294669/blog/71902" /> * * 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 * * @author 芋道源码 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private RuntimeService runtimeService; @Resource private HistoryService historyService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private BpmMessageService messageService; @Resource private AdminUserApi adminUserApi; @Resource private BpmProcessInstanceEventPublisher processInstanceEventPublisher; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery() .includeProcessVariables() .processInstanceId(id) .singleResult(); } @Override public List<ProcessInstance> getProcessInstances(Set<String> ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).includeProcessVariables().singleResult(); } @Override public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId, BpmProcessInstancePageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery() .includeProcessVariables() .processInstanceTenantId(FlowableUtils.getTenantId()) .orderByProcessInstanceStartTime().desc(); if (userId != null) { // 【我的流程】菜单时,需要传递该字段 processInstanceQuery.startedBy(String.valueOf(userId)); } else if (pageReqVO.getStartUserId() != null) { // 【管理流程】菜单时,才会传递该字段 processInstanceQuery.startedBy(String.valueOf(pageReqVO.getStartUserId())); } if (StrUtil.isNotEmpty(pageReqVO.getName())) { processInstanceQuery.processInstanceNameLike("%" + pageReqVO.getName() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getProcessDefinitionId())) { processInstanceQuery.processDefinitionId("%" + pageReqVO.getProcessDefinitionId() + "%"); } if (StrUtil.isNotEmpty(pageReqVO.getCategory())) { processInstanceQuery.processDefinitionCategory(pageReqVO.getCategory()); } if (pageReqVO.getStatus() != null) { processInstanceQuery.variableValueEquals(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, pageReqVO.getStatus()); } if (ArrayUtil.isNotEmpty(pageReqVO.getCreateTime())) { processInstanceQuery.startedAfter(DateUtils.of(pageReqVO.getCreateTime()[0])); processInstanceQuery.startedBefore(DateUtils.of(pageReqVO.getCreateTime()[1])); } // 查询数量 long processInstanceCount = processInstanceQuery.count(); if (processInstanceCount == 0) { return PageResult.empty(processInstanceCount); } // 查询列表 List<HistoricProcessInstance> processInstanceList = processInstanceQuery.listPage(PageUtils.getStart(pageReqVO), pageReqVO.getPageSize()); return new PageResult<>(processInstanceList, processInstanceCount); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null, createReqVO.getStartUserSelectAssignees()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getStartUserSelectAssignees()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey, Map<String, List<Long>> startUserSelectAssignees) { // 1.1 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 1.2 校验发起人自选审批人 validateStartUserSelectAssignees(definition, startUserSelectAssignees); // 2. 创建流程实例 if (variables == null) { variables = new HashMap<>(); } FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); if (CollUtil.isNotEmpty(startUserSelectAssignees)) { variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_START_USER_SELECT_ASSIGNEES, startUserSelectAssignees); } ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } private void validateStartUserSelectAssignees(ProcessDefinition definition, Map<String, List<Long>> startUserSelectAssignees) { // 1. 获得发起人自选审批人的 UserTask 列表 BpmnModel bpmnModel = processDefinitionService.getProcessDefinitionBpmnModel(definition.getId()); List<UserTask> userTaskList = BpmTaskCandidateStartUserSelectStrategy.getStartUserSelectUserTaskList(bpmnModel); if (CollUtil.isEmpty(userTaskList)) { return; } // 2. 校验发起人自选审批人的 UserTask 是否都配置了 userTaskList.forEach(userTask -> { List<Long> assignees = startUserSelectAssignees != null ? startUserSelectAssignees.get(userTask.getId()) : null; if (CollUtil.isEmpty(assignees)) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_CONFIG, userTask.getName()); } Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(assignees); assignees.forEach(assignee -> { if (userMap.get(assignee) == null) { throw exception(PROCESS_INSTANCE_START_USER_SELECT_ASSIGNEES_NOT_EXISTS, userTask.getName(), assignee); } }); }); } @Override public void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_START_USER.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO) { // 1.1 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 1.2 管理员取消,不用校验是否为自己的 AdminUserRespDTO user = adminUserApi.getUser(userId); // 2. 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。 deleteProcessInstance(cancelReqVO.getId(), BpmDeleteReasonEnum.CANCEL_PROCESS_INSTANCE_BY_ADMIN.format(user.getNickname(), cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // TODO @芋艿 这种情况不会发生了。 拒绝时候不会删除流程 // // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 // if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { // return; // } // 1. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 2. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.CANCEL.getStatus())); } @Override public void updateProcessInstanceWhenApprove(ProcessInstance instance) { // 1. 更新流程实例 status runtimeService.setVariable(instance.getId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.APPROVE.getStatus()); // 2. 发送流程被【通过】的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceApproveMessage(instance)); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(ProcessInstance processInstance, List<String> activityIds, String endId, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(processInstance.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 跳转到流程结束 EndEvent 节点,结束流程 runtimeService.createChangeActivityStateBuilder() .processInstanceId(processInstance.getProcessInstanceId()) .moveActivityIdsToSingleActivityId(CollUtil.newArrayList(activityIds), endId) .changeState(); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } @Override public void updateProcessInstanceWhenCompleted(ProcessInstance instance) { Integer status = (Integer) instance.getProcessVariables().get(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS); // 当流程状态还是审批状态中, 更新为审批通过 if (Objects.equals(status, BpmProcessInstanceStatusEnum.RUNNING.getStatus())) { updateProcessInstanceWhenApprove(instance); } // 审批不通过状态。已经在 updateProcessInstanceReject 处理 } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } }
3 \ No newline at end of file 3 \ No newline at end of file
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
@@ -137,7 +137,10 @@ public interface BpmTaskService { @@ -137,7 +137,10 @@ public interface BpmTaskService {
137 * @param executionId execution Id 137 * @param executionId execution Id
138 * @param taskDefineKey 任务定义 Key 138 * @param taskDefineKey 任务定义 Key
139 */ 139 */
140 - List<Task> getRunningTaskListByProcessInstanceId(String processInstanceId, Boolean assigned, String executionId, String taskDefineKey); 140 + List<Task> getRunningTaskListByProcessInstanceId(String processInstanceId,
  141 + Boolean assigned,
  142 + String executionId,
  143 + String taskDefineKey);
141 144
142 /** 145 /**
143 * 获取当前任务的可回退的 UserTask 集合 146 * 获取当前任务的可回退的 UserTask 集合