Commit ba4b3701bf0a8d0fd2bc51f0aba9ee1b20166607

Authored by YunaiV
1 parent e5444c5d

BPM:新增【流程实例】菜单,用于全部流程实例的查询

Showing 13 changed files with 97 additions and 38 deletions
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmDeleteReasonEnum.java
@@ -16,11 +16,12 @@ public enum BpmDeleteReasonEnum { @@ -16,11 +16,12 @@ public enum BpmDeleteReasonEnum {
16 // ========== 流程实例的独有原因 ========== 16 // ========== 流程实例的独有原因 ==========
17 17
18 REJECT_TASK("审批不通过任务,原因:{}"), // 场景:用户审批不通过任务。修改文案时,需要注意 isRejectReason 方法 18 REJECT_TASK("审批不通过任务,原因:{}"), // 场景:用户审批不通过任务。修改文案时,需要注意 isRejectReason 方法
19 - CANCEL_PROCESS_INSTANCE("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程 19 + CANCEL_PROCESS_INSTANCE_BY_START_USER("用户主动取消流程,原因:{}"), // 场景:用户主动取消流程
  20 + CANCEL_PROCESS_INSTANCE_BY_ADMIN("管理员【{}】取消流程,原因:{}"), // 场景:管理员取消流程
20 21
21 // ========== 流程任务的独有原因 ========== 22 // ========== 流程任务的独有原因 ==========
22 23
23 - CANCEL_SYSTEM("系统自动取消"), // 场景:非常多,比如说:1)多任务审批已经满足条件,无需审批该任务;2)流程实例被取消,无需审批该任务;等等 24 + CANCEL_BY_SYSTEM("系统自动取消"), // 场景:非常多,比如说:1)多任务审批已经满足条件,无需审批该任务;2)流程实例被取消,无需审批该任务;等等
24 ; 25 ;
25 26
26 private final String reason; 27 private final String reason;
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/process/BpmProcessDefinitionRespVO.java
@@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process; @@ -3,8 +3,6 @@ package cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.process;
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 import lombok.Data; 4 import lombok.Data;
5 5
6 -import jakarta.validation.constraints.NotEmpty;  
7 -  
8 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
9 import java.util.List; 7 import java.util.List;
10 8
@@ -19,9 +17,11 @@ public class BpmProcessDefinitionRespVO { @@ -19,9 +17,11 @@ public class BpmProcessDefinitionRespVO {
19 private Integer version; 17 private Integer version;
20 18
21 @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道") 19 @Schema(description = "流程名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
22 - @NotEmpty(message = "流程名称不能为空")  
23 private String name; 20 private String name;
24 21
  22 + @Schema(description = "流程标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "yudao")
  23 + private String key;
  24 +
25 @Schema(description = "流程描述", example = "我是描述") 25 @Schema(description = "流程描述", example = "我是描述")
26 private String description; 26 private String description;
27 27
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java
@@ -4,7 +4,10 @@ import cn.hutool.core.collection.CollUtil; @@ -4,7 +4,10 @@ import cn.hutool.core.collection.CollUtil;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 6 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
7 -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; 7 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO;
  8 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO;
  9 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO;
  10 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO;
8 import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; 11 import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert;
9 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; 12 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO;
10 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; 13 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO;
@@ -59,9 +62,10 @@ public class BpmProcessInstanceController { @@ -59,9 +62,10 @@ public class BpmProcessInstanceController {
59 @GetMapping("/my-page") 62 @GetMapping("/my-page")
60 @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用") 63 @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用")
61 @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')") 64 @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
62 - public CommonResult<PageResult<BpmProcessInstanceRespVO>> getMyProcessInstancePage(  
63 - @Valid BpmProcessInstanceMyPageReqVO pageReqVO) {  
64 - PageResult<HistoricProcessInstance> pageResult = processInstanceService.getMyProcessInstancePage(getLoginUserId(), pageReqVO); 65 + public CommonResult<PageResult<BpmProcessInstanceRespVO>> getProcessInstanceMyPage(
  66 + @Valid BpmProcessInstancePageReqVO pageReqVO) {
  67 + PageResult<HistoricProcessInstance> pageResult = processInstanceService.getProcessInstancePage(
  68 + getLoginUserId(), pageReqVO);
65 if (CollUtil.isEmpty(pageResult.getList())) { 69 if (CollUtil.isEmpty(pageResult.getList())) {
66 return success(PageResult.empty(pageResult.getTotal())); 70 return success(PageResult.empty(pageResult.getTotal()));
67 } 71 }
@@ -73,8 +77,35 @@ public class BpmProcessInstanceController { @@ -73,8 +77,35 @@ public class BpmProcessInstanceController {
73 convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId)); 77 convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId));
74 Map<String, BpmCategoryDO> categoryMap = categoryService.getCategoryMap( 78 Map<String, BpmCategoryDO> categoryMap = categoryService.getCategoryMap(
75 convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory)); 79 convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory));
76 - return success(BpmProcessInstanceConvert.INSTANCE.buildMyProcessInstancePage(pageResult,  
77 - processDefinitionMap, categoryMap, taskMap)); 80 + return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult,
  81 + processDefinitionMap, categoryMap, taskMap, null, null));
  82 + }
  83 +
  84 + @GetMapping("/manager-page")
  85 + @Operation(summary = "获得管理流程实例的分页列表", description = "在【流程实例】菜单中,进行调用")
  86 + @PreAuthorize("@ss.hasPermission('bpm:process-instance:manager-query')")
  87 + public CommonResult<PageResult<BpmProcessInstanceRespVO>> getProcessInstanceManagerPage(
  88 + @Valid BpmProcessInstancePageReqVO pageReqVO) {
  89 + PageResult<HistoricProcessInstance> pageResult = processInstanceService.getProcessInstancePage(
  90 + null, pageReqVO);
  91 + if (CollUtil.isEmpty(pageResult.getList())) {
  92 + return success(PageResult.empty(pageResult.getTotal()));
  93 + }
  94 +
  95 + // 拼接返回
  96 + Map<String, List<Task>> taskMap = taskService.getTaskMapByProcessInstanceIds(
  97 + convertList(pageResult.getList(), HistoricProcessInstance::getId));
  98 + Map<String, ProcessDefinition> processDefinitionMap = processDefinitionService.getProcessDefinitionMap(
  99 + convertSet(pageResult.getList(), HistoricProcessInstance::getProcessDefinitionId));
  100 + Map<String, BpmCategoryDO> categoryMap = categoryService.getCategoryMap(
  101 + convertSet(processDefinitionMap.values(), ProcessDefinition::getCategory));
  102 + // 发起人信息
  103 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
  104 + convertSet(pageResult.getList(), processInstance -> NumberUtils.parseLong(processInstance.getStartUserId())));
  105 + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(
  106 + convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
  107 + return success(BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePage(pageResult,
  108 + processDefinitionMap, categoryMap, taskMap, userMap, deptMap));
78 } 109 }
79 110
80 @PostMapping("/create") 111 @PostMapping("/create")
@@ -109,11 +140,21 @@ public class BpmProcessInstanceController { @@ -109,11 +140,21 @@ public class BpmProcessInstanceController {
109 processDefinition, processDefinitionInfo, bpmnXml, startUser, dept)); 140 processDefinition, processDefinitionInfo, bpmnXml, startUser, dept));
110 } 141 }
111 142
112 - @DeleteMapping("/cancel")  
113 - @Operation(summary = "取消流程实例", description = "撤回发起的流程") 143 + @DeleteMapping("/cancel-by-start-user")
  144 + @Operation(summary = "用户取消流程实例", description = "取消发起的流程")
114 @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')") 145 @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')")
115 - public CommonResult<Boolean> cancelProcessInstance(@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {  
116 - processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO); 146 + public CommonResult<Boolean> cancelProcessInstanceByStartUser(
  147 + @Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
  148 + processInstanceService.cancelProcessInstanceByStartUser(getLoginUserId(), cancelReqVO);
  149 + return success(true);
  150 + }
  151 +
  152 + @DeleteMapping("/cancel-by-admin")
  153 + @Operation(summary = "管理员取消流程实例", description = "管理员撤回流程")
  154 + @PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel-by-admin')")
  155 + public CommonResult<Boolean> cancelProcessInstanceByManager(
  156 + @Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
  157 + processInstanceService.cancelProcessInstanceByAdmin(getLoginUserId(), cancelReqVO);
117 return success(true); 158 return success(true);
118 } 159 }
119 160
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceMyPageReqVO.java renamed to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstancePageReqVO.java
@@ -5,19 +5,15 @@ import cn.iocoder.yudao.framework.common.validation.InEnum; @@ -5,19 +5,15 @@ import cn.iocoder.yudao.framework.common.validation.InEnum;
5 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; 5 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
6 import io.swagger.v3.oas.annotations.media.Schema; 6 import io.swagger.v3.oas.annotations.media.Schema;
7 import lombok.Data; 7 import lombok.Data;
8 -import lombok.EqualsAndHashCode;  
9 -import lombok.ToString;  
10 import org.springframework.format.annotation.DateTimeFormat; 8 import org.springframework.format.annotation.DateTimeFormat;
11 9
12 import java.time.LocalDateTime; 10 import java.time.LocalDateTime;
13 11
14 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; 12 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
15 13
16 -@Schema(description = "管理后台 - 流程实例的分页 Item Response VO") 14 +@Schema(description = "管理后台 - 流程实例分页 Request VO")
17 @Data 15 @Data
18 -@EqualsAndHashCode(callSuper = true)  
19 -@ToString(callSuper = true)  
20 -public class BpmProcessInstanceMyPageReqVO extends PageParam { 16 +public class BpmProcessInstancePageReqVO extends PageParam {
21 17
22 @Schema(description = "流程名称", example = "芋道") 18 @Schema(description = "流程名称", example = "芋道")
23 private String name; 19 private String name;
@@ -36,4 +32,7 @@ public class BpmProcessInstanceMyPageReqVO extends PageParam { @@ -36,4 +32,7 @@ public class BpmProcessInstanceMyPageReqVO extends PageParam {
36 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) 32 @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
37 private LocalDateTime[] createTime; 33 private LocalDateTime[] createTime;
38 34
  35 + @Schema(description = "发起用户编号", example = "1024")
  36 + private Long startUserId; // 注意,只有在【流程实例】菜单,才使用该参数
  37 +
39 } 38 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceRespVO.java
@@ -26,12 +26,15 @@ public class BpmProcessInstanceRespVO { @@ -26,12 +26,15 @@ public class BpmProcessInstanceRespVO {
26 @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 26 @Schema(description = "流程实例的状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
27 private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举 27 private Integer status; // 参见 BpmProcessInstanceStatusEnum 枚举
28 28
29 - @Schema(description = "提交时间", requiredMode = Schema.RequiredMode.REQUIRED) 29 + @Schema(description = "发起时间", requiredMode = Schema.RequiredMode.REQUIRED)
30 private LocalDateTime startTime; 30 private LocalDateTime startTime;
31 31
32 @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) 32 @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
33 private LocalDateTime endTime; 33 private LocalDateTime endTime;
34 34
  35 + @Schema(description = "持续时间", example = "1000")
  36 + private Long durationInMillis;
  37 +
35 @Schema(description = "提交的表单值", requiredMode = Schema.RequiredMode.REQUIRED) 38 @Schema(description = "提交的表单值", requiredMode = Schema.RequiredMode.REQUIRED)
36 private Map<String, Object> formVariables; 39 private Map<String, Object> formVariables;
37 40
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java
@@ -24,7 +24,7 @@ public class BpmTaskRespVO { @@ -24,7 +24,7 @@ public class BpmTaskRespVO {
24 @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED) 24 @Schema(description = "结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
25 private LocalDateTime endTime; 25 private LocalDateTime endTime;
26 26
27 - @Schema(description = "持续时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000") 27 + @Schema(description = "持续时间", example = "1000")
28 private Long durationInMillis; 28 private Long durationInMillis;
29 29
30 @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") 30 @Schema(description = "任务状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
@@ -36,10 +36,12 @@ public interface BpmProcessInstanceConvert { @@ -36,10 +36,12 @@ public interface BpmProcessInstanceConvert {
36 36
37 BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class); 37 BpmProcessInstanceConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceConvert.class);
38 38
39 - default PageResult<BpmProcessInstanceRespVO> buildMyProcessInstancePage(PageResult<HistoricProcessInstance> pageResult,  
40 - Map<String, ProcessDefinition> processDefinitionMap,  
41 - Map<String, BpmCategoryDO> categoryMap,  
42 - Map<String, List<Task>> taskMap) { 39 + default PageResult<BpmProcessInstanceRespVO> buildProcessInstancePage(PageResult<HistoricProcessInstance> pageResult,
  40 + Map<String, ProcessDefinition> processDefinitionMap,
  41 + Map<String, BpmCategoryDO> categoryMap,
  42 + Map<String, List<Task>> taskMap,
  43 + Map<Long, AdminUserRespDTO> userMap,
  44 + Map<Long, DeptRespDTO> deptMap) {
43 PageResult<BpmProcessInstanceRespVO> vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstanceRespVO.class); 45 PageResult<BpmProcessInstanceRespVO> vpPageResult = BeanUtils.toBean(pageResult, BpmProcessInstanceRespVO.class);
44 for (int i = 0; i < pageResult.getList().size(); i++) { 46 for (int i = 0; i < pageResult.getList().size(); i++) {
45 BpmProcessInstanceRespVO respVO = vpPageResult.getList().get(i); 47 BpmProcessInstanceRespVO respVO = vpPageResult.getList().get(i);
@@ -48,6 +50,10 @@ public interface BpmProcessInstanceConvert { @@ -48,6 +50,10 @@ public interface BpmProcessInstanceConvert {
48 processDefinition -> respVO.setCategory(processDefinition.getCategory())); 50 processDefinition -> respVO.setCategory(processDefinition.getCategory()));
49 MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName())); 51 MapUtils.findAndThen(categoryMap, respVO.getCategory(), category -> respVO.setCategoryName(category.getName()));
50 respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstanceRespVO.Task.class)); 52 respVO.setTasks(BeanUtils.toBean(taskMap.get(respVO.getId()), BpmProcessInstanceRespVO.Task.class));
  53 + // user
  54 + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(pageResult.getList().get(i).getStartUserId()));
  55 + respVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class));
  56 + MapUtils.findAndThen(deptMap, startUser.getDeptId(), dept -> respVO.getStartUser().setDeptName(dept.getName()));
51 } 57 }
52 return vpPageResult; 58 return vpPageResult;
53 } 59 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
@@ -46,6 +46,7 @@ public interface BpmTaskConvert { @@ -46,6 +46,7 @@ public interface BpmTaskConvert {
46 if (processInstance == null) { 46 if (processInstance == null) {
47 return; 47 return;
48 } 48 }
  49 + taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class));
49 AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId())); 50 AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
50 taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class)); 51 taskVO.getProcessInstance().setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class));
51 }); 52 });
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/config/BpmFlowableConfiguration.java
@@ -4,7 +4,7 @@ import cn.hutool.core.collection.ListUtil; @@ -4,7 +4,7 @@ import cn.hutool.core.collection.ListUtil;
4 import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory; 4 import cn.iocoder.yudao.module.bpm.framework.flowable.core.behavior.BpmActivityBehaviorFactory;
5 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker; 5 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateInvoker;
6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy; 6 import cn.iocoder.yudao.module.bpm.framework.flowable.core.candidate.BpmTaskCandidateStrategy;
7 -import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceResultEventPublisher; 7 +import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceEventPublisher;
8 import cn.iocoder.yudao.module.system.api.user.AdminUserApi; 8 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
9 import org.flowable.common.engine.api.delegate.event.FlowableEventListener; 9 import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
10 import org.flowable.spring.SpringProcessEngineConfiguration; 10 import org.flowable.spring.SpringProcessEngineConfiguration;
@@ -84,8 +84,8 @@ public class BpmFlowableConfiguration { @@ -84,8 +84,8 @@ public class BpmFlowableConfiguration {
84 // =========== 自己拓展的 Bean ========== 84 // =========== 自己拓展的 Bean ==========
85 85
86 @Bean 86 @Bean
87 - public BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher(ApplicationEventPublisher publisher) {  
88 - return new BpmProcessInstanceResultEventPublisher(publisher); 87 + public BpmProcessInstanceEventPublisher processInstanceEventPublisher(ApplicationEventPublisher publisher) {
  88 + return new BpmProcessInstanceEventPublisher(publisher);
89 } 89 }
90 90
91 } 91 }
92 \ No newline at end of file 92 \ No newline at end of file
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceResultEventPublisher.java renamed to yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/event/BpmProcessInstanceEventPublisher.java
@@ -14,7 +14,7 @@ import jakarta.validation.Valid; @@ -14,7 +14,7 @@ import jakarta.validation.Valid;
14 */ 14 */
15 @AllArgsConstructor 15 @AllArgsConstructor
16 @Validated 16 @Validated
17 -public class BpmProcessInstanceResultEventPublisher { 17 +public class BpmProcessInstanceEventPublisher {
18 18
19 private final ApplicationEventPublisher publisher; 19 private final ApplicationEventPublisher publisher;
20 20
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java
@@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; 4 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
5 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO; 5 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCancelReqVO;
6 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO; 6 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCreateReqVO;
7 -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO; 7 +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageReqVO;
8 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
9 import org.flowable.engine.delegate.event.FlowableCancelledEvent; 9 import org.flowable.engine.delegate.event.FlowableCancelledEvent;
10 import org.flowable.engine.history.HistoricProcessInstance; 10 import org.flowable.engine.history.HistoricProcessInstance;
@@ -93,8 +93,8 @@ public interface BpmProcessInstanceService { @@ -93,8 +93,8 @@ public interface BpmProcessInstanceService {
93 * @param pageReqVO 分页请求 93 * @param pageReqVO 分页请求
94 * @return 流程实例的分页 94 * @return 流程实例的分页
95 */ 95 */
96 - PageResult<HistoricProcessInstance> getMyProcessInstancePage(Long userId,  
97 - @Valid BpmProcessInstanceMyPageReqVO pageReqVO); 96 + PageResult<HistoricProcessInstance> getProcessInstancePage(Long userId,
  97 + @Valid BpmProcessInstancePageReqVO pageReqVO);
98 98
99 /** 99 /**
100 * 创建流程实例(提供给前端) 100 * 创建流程实例(提供给前端)
@@ -115,12 +115,20 @@ public interface BpmProcessInstanceService { @@ -115,12 +115,20 @@ public interface BpmProcessInstanceService {
115 String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO); 115 String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO);
116 116
117 /** 117 /**
118 - * 取消流程实例 118 + * 发起人取消流程实例
119 * 119 *
120 * @param userId 用户编号 120 * @param userId 用户编号
121 * @param cancelReqVO 取消信息 121 * @param cancelReqVO 取消信息
122 */ 122 */
123 - void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO); 123 + void cancelProcessInstanceByStartUser(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO);
  124 +
  125 + /**
  126 + * 管理员取消流程实例
  127 + *
  128 + * @param userId 用户编号
  129 + * @param cancelReqVO 取消信息
  130 + */
  131 + void cancelProcessInstanceByAdmin(Long userId, BpmProcessInstanceCancelReqVO cancelReqVO);
124 132
125 /** 133 /**
126 * 更新 ProcessInstance 拓展记录为取消 134 * 更新 ProcessInstance 拓展记录为取消
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.BpmProcessInstanceMyPageReqVO; 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.FlowableContextHolder; import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants; import cn.iocoder.yudao.module.bpm.framework.flowable.core.event.BpmProcessInstanceResultEventPublisher; 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 jakarta.annotation.Resource; import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; 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 BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @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> getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 HistoricProcessInstanceQuery processInstanceQuery = historyService.createHistoricProcessInstanceQuery().includeProcessVariables() .startedBy(String.valueOf(userId)) .orderByProcessInstanceStartTime().desc(); 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.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey, Map<String, List<Long>> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @Override public void cancelProcessInstance(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.format(cancelReqVO.getReason())); // 3. 进一步的处理,交给 updateProcessInstanceCancel 方法 } @Override public void updateProcessInstanceWhenCancel(FlowableCancelledEvent event) { // 1. 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceReject 方法(审批不通过),已经进行更新了 if (BpmDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 发送流程实例的状态事件 processInstanceResultEventPublisher.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()); processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.APPROVE.getStatus())); } @Override @Transactional(rollbackFor = Exception.class) public void updateProcessInstanceReject(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List<Long> getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List<Long> result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } }  
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.FlowableContextHolder; 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.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() .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.getAssignee()); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey(), createReqDTO.getAssignee()); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map<String, Object> variables, String businessKey, Map<String, List<Long>> assignee) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置上下文信息 // TODO @hai:要不往 variables 存到一个全局固定 key 里,减少对上下文的依赖 FlowableContextHolder.setAssignee(assignee); // 创建流程实例 FlowableUtils.filterProcessInstanceFormVariable(variables); // 过滤一下,避免 ProcessInstance 系统级的变量被占用 variables.put(BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, // 流程实例状态:审批中 BpmProcessInstanceStatusEnum.RUNNING.getStatus()); ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); return instance.getId(); } @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; } // 2. 更新流程实例 status runtimeService.setVariable(event.getProcessInstanceId(), BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.CANCEL.getStatus()); // 3. 发送流程实例的状态事件 // 注意:此时如果去查询 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(String id, String reason) { // 1. 更新流程实例 status runtimeService.setVariable(id, BpmConstants.PROCESS_INSTANCE_VARIABLE_STATUS, BpmProcessInstanceStatusEnum.REJECT.getStatus()); // 2. 删除流程实例,以实现驳回任务时,取消整个审批流程 ProcessInstance processInstance = getProcessInstance(id); deleteProcessInstance(id, StrUtil.format(BpmDeleteReasonEnum.REJECT_TASK.format(reason))); // 3. 发送流程被【不通过】的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceRejectMessage(processInstance, reason)); // 4. 发送流程实例的状态事件 processInstanceEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, processInstance, BpmProcessInstanceStatusEnum.REJECT.getStatus())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } @Override public List<Long> getAssigneeByProcessInstanceIdAndTaskDefinitionKey(String processInstanceId, String taskDefinitionKey) { // 1. 先从上下文获取,首次提交数据库中查询不到 List<Long> result = FlowableContextHolder.getAssigneeByTaskDefinitionKey(taskDefinitionKey); if (CollUtil.isNotEmpty(result)) { return result; } // 2. 从数据库中获取 // TODO @芋艿:指定审批人,这里的存储方案有问题,后续优化下 // BpmProcessInstanceExtDO instance = processInstanceExtMapper.selectByProcessInstanceId(processInstanceId); // if (instance == null) { // throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); // } // if (CollUtil.isNotEmpty(instance.getAssignee())) { // return instance.getAssignee().get(taskDefinitionKey); // } return Collections.emptyList(); } }
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/BpmTaskServiceImpl.java
@@ -375,7 +375,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -375,7 +375,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
375 log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status); 375 log.error("[updateTaskStatusWhenCanceled][taskId({}) 处于结果({}),无需进行更新]", taskId, status);
376 return; 376 return;
377 } 377 }
378 - updateTaskStatusAndReason(taskId, BpmTaskStatustEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_SYSTEM.getReason()); 378 + updateTaskStatusAndReason(taskId, BpmTaskStatustEnum.CANCEL.getStatus(), BpmDeleteReasonEnum.CANCEL_BY_SYSTEM.getReason());
379 // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由 379 // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由
380 } 380 }
381 381