Commit cc67174f8793edcfb110c0de8df1bb259cdf9a84

Authored by 芋道源码
Committed by Gitee
2 parents 52ebcaaa 6dfef298

!689 【工作流】--加签减签review

Merge pull request !689 from Youkehai/feature/bpm-addSignAndSubSign
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
@@ -3,11 +3,13 @@ package cn.iocoder.yudao.framework.common.util.collection; @@ -3,11 +3,13 @@ package cn.iocoder.yudao.framework.common.util.collection;
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.collection.CollectionUtil; 4 import cn.hutool.core.collection.CollectionUtil;
5 import cn.hutool.core.util.ArrayUtil; 5 import cn.hutool.core.util.ArrayUtil;
  6 +import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
6 import com.google.common.collect.ImmutableMap; 7 import com.google.common.collect.ImmutableMap;
7 8
8 import java.util.*; 9 import java.util.*;
9 import java.util.function.*; 10 import java.util.function.*;
10 import java.util.stream.Collectors; 11 import java.util.stream.Collectors;
  12 +import java.util.stream.Stream;
11 13
12 import static java.util.Arrays.asList; 14 import static java.util.Arrays.asList;
13 15
@@ -267,4 +269,19 @@ public class CollectionUtils { @@ -267,4 +269,19 @@ public class CollectionUtils {
267 return deptId == null ? Collections.emptyList() : Collections.singleton(deptId); 269 return deptId == null ? Collections.emptyList() : Collections.singleton(deptId);
268 } 270 }
269 271
  272 + public static <T, U> List<U> convertListByMultiAttr(Collection<T> from,
  273 + Function<T, ? extends Stream<? extends U>> func) {
  274 + if (CollUtil.isEmpty(from)) {
  275 + return new ArrayList<>();
  276 + }
  277 + return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toList());
  278 + }
  279 +
  280 + public static <T, U> Set<U> convertSetByMultiAttr(Collection<T> from,
  281 + Function<T, ? extends Stream<? extends U>> func) {
  282 + if (CollUtil.isEmpty(from)) {
  283 + return new HashSet<>();
  284 + }
  285 + return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet());
  286 + }
270 } 287 }
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java
@@ -23,15 +23,13 @@ public enum BpmCommentTypeEnum { @@ -23,15 +23,13 @@ public enum BpmCommentTypeEnum {
23 * 操作类型 23 * 操作类型
24 */ 24 */
25 private final Integer type; 25 private final Integer type;
26 - // TODO @海:desc 可以改成 name;相当于操作名;  
27 /** 26 /**
28 * 操作名字 27 * 操作名字
29 */ 28 */
30 - private final String desc;  
31 - // TODO @海:直接改成 comment 哈;简单一点; 29 + private final String name;
32 /** 30 /**
33 * 操作描述 31 * 操作描述
34 */ 32 */
35 - private final String templateComment; 33 + private final String comment;
36 34
37 } 35 }
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmProcessInstanceResultEnum.java
@@ -30,13 +30,13 @@ public enum BpmProcessInstanceResultEnum { @@ -30,13 +30,13 @@ public enum BpmProcessInstanceResultEnum {
30 * 相当于是 通过 APPROVE 的特殊状态 30 * 相当于是 通过 APPROVE 的特殊状态
31 * 例如:A审批, A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成” 31 * 例如:A审批, A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成”
32 */ 32 */
33 - ADD_SIGN_AFTER(7, "待后加签任务完成"), 33 + SIGN_AFTER(7, "待后加签任务完成"),
34 /** 34 /**
35 * 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成” 35 * 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成”
36 * 相当于是 处理中 PROCESS 的特殊状态 36 * 相当于是 处理中 PROCESS 的特殊状态
37 * 例如:A 审批, A 前加签了 B,B 还未审核 37 * 例如:A 审批, A 前加签了 B,B 还未审核
38 */ 38 */
39 - ADD_SIGN_BEFORE(8, "待前加签任务完成"), 39 + SIGN_BEFORE(8, "待前加签任务完成"),
40 /** 40 /**
41 * 【加签】后加签任务被创建时的初始状态 41 * 【加签】后加签任务被创建时的初始状态
42 * 相当于是 处理中 PROCESS 的特殊状态 42 * 相当于是 处理中 PROCESS 的特殊状态
@@ -71,7 +71,7 @@ public enum BpmProcessInstanceResultEnum { @@ -71,7 +71,7 @@ public enum BpmProcessInstanceResultEnum {
71 public static boolean isEndResult(Integer result) { 71 public static boolean isEndResult(Integer result) {
72 return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(), 72 return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(),
73 CANCEL.getResult(), BACK.getResult(), 73 CANCEL.getResult(), BACK.getResult(),
74 - ADD_SIGN_AFTER.getResult()); 74 + SIGN_AFTER.getResult());
75 } 75 }
76 76
77 } 77 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
@@ -74,8 +74,7 @@ public class BpmTaskController { @@ -74,8 +74,7 @@ public class BpmTaskController {
74 return success(true); 74 return success(true);
75 } 75 }
76 76
77 - // TODO @海:/return-list,不用带 get;  
78 - @GetMapping("/get-return-list") 77 + @GetMapping("/return-list")
79 @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮") 78 @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮")
80 @Parameter(name = "taskId", description = "当前任务ID", required = true) 79 @Parameter(name = "taskId", description = "当前任务ID", required = true)
81 @PreAuthorize("@ss.hasPermission('bpm:task:update')") 80 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
@@ -99,8 +98,7 @@ public class BpmTaskController { @@ -99,8 +98,7 @@ public class BpmTaskController {
99 return success(true); 98 return success(true);
100 } 99 }
101 100
102 - // TODO @海:create-sign?创建加签任务;  
103 - @PutMapping("/add-sign") 101 + @PutMapping("/create-sign")
104 @Operation(summary = "加签", description = "before 前加签,after 后加签") 102 @Operation(summary = "加签", description = "before 前加签,after 后加签")
105 @PreAuthorize("@ss.hasPermission('bpm:task:update')") 103 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
106 public CommonResult<Boolean> addSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) { 104 public CommonResult<Boolean> addSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) {
@@ -108,8 +106,7 @@ public class BpmTaskController { @@ -108,8 +106,7 @@ public class BpmTaskController {
108 return success(true); 106 return success(true);
109 } 107 }
110 108
111 - // TODO @海:delete-sign?删除加签任务;然后 @DeleteMapping;这样感觉可以保持统一;  
112 - @PutMapping("/sub-sign") 109 + @DeleteMapping("/delete-sign")
113 @Operation(summary = "减签") 110 @Operation(summary = "减签")
114 @PreAuthorize("@ss.hasPermission('bpm:task:update')") 111 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
115 public CommonResult<Boolean> subSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) { 112 public CommonResult<Boolean> subSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) {
@@ -117,13 +114,12 @@ public class BpmTaskController { @@ -117,13 +114,12 @@ public class BpmTaskController {
117 return success(true); 114 return success(true);
118 } 115 }
119 116
120 - // TODO @海:/children-list,不用带 task 和 get;  
121 - // TODO @海:taskId 是不是改成 parentId?另外,它的 swagger 注解也加下哈;  
122 - @GetMapping("/get-children-task-list") 117 + @GetMapping("children-list")
123 @Operation(summary = "获取能被减签的任务") 118 @Operation(summary = "获取能被减签的任务")
  119 + @Parameter(name = "parentId", description = "父级任务ID", required = true)
124 @PreAuthorize("@ss.hasPermission('bpm:task:update')") 120 @PreAuthorize("@ss.hasPermission('bpm:task:update')")
125 - public CommonResult<List<BpmTaskSubSignRespVO>> getChildrenTaskList(@RequestParam("taskId") String taskId) {  
126 - return success(taskService.getChildrenTaskList(taskId)); 121 + public CommonResult<List<BpmTaskSubSignRespVO>> getChildrenTaskList(@RequestParam("parentId") String parentId) {
  122 + return success(taskService.getChildrenTaskList(parentId));
127 } 123 }
128 124
129 } 125 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
@@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.bpm.convert.task; @@ -2,8 +2,10 @@ package cn.iocoder.yudao.module.bpm.convert.task;
2 2
3 import cn.hutool.core.collection.CollUtil; 3 import cn.hutool.core.collection.CollUtil;
4 import cn.hutool.core.date.LocalDateTimeUtil; 4 import cn.hutool.core.date.LocalDateTimeUtil;
  5 +import cn.hutool.core.util.ObjectUtil;
5 import cn.hutool.core.util.StrUtil; 6 import cn.hutool.core.util.StrUtil;
6 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  8 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
7 import cn.iocoder.yudao.framework.common.util.date.DateUtils; 9 import cn.iocoder.yudao.framework.common.util.date.DateUtils;
8 import cn.iocoder.yudao.framework.common.util.number.NumberUtils; 10 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
9 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; 11 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
@@ -168,20 +170,15 @@ public interface BpmTaskConvert { @@ -168,20 +170,15 @@ public interface BpmTaskConvert {
168 Map<Long, AdminUserRespDTO> userMap, 170 Map<Long, AdminUserRespDTO> userMap,
169 Map<String, Task> idTaskMap){ 171 Map<String, Task> idTaskMap){
170 return CollectionUtils.convertList(bpmTaskExtDOList, task -> { 172 return CollectionUtils.convertList(bpmTaskExtDOList, task -> {
171 - // TODO @海:setId、name,可以链式调用  
172 - BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO();  
173 - bpmTaskSubSignRespVO.setName(task.getName());  
174 - bpmTaskSubSignRespVO.setId(task.getTaskId());  
175 - Task sourceTask = idTaskMap.get(task.getTaskId());  
176 - // TODO @海:下面这行注释,应该放到 idTaskMap.get(task.getTaskId()) 上面;原因是,应该注释之后,下面的逻辑是个整体; 173 + BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO()
  174 + .setName(task.getName())
  175 + .setId(task.getTaskId());
  176 +
177 // 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner 177 // 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner
178 - // TODO @海:可以使用 ObjUtil.default 方法  
179 - String assignee = StrUtil.isNotEmpty(sourceTask.getAssignee()) ? sourceTask.getAssignee() : sourceTask.getOwner();  
180 - // TODO @海:这里可以使用 MapUtils.findAndThen 写起来更简单一点;  
181 - AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(assignee));  
182 - if (assignUser != null) {  
183 - bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser));  
184 - } 178 + Task sourceTask = idTaskMap.get(task.getTaskId());
  179 + String assignee = ObjectUtil.defaultIfBlank(sourceTask.getOwner(),sourceTask.getAssignee());
  180 + MapUtils.findAndThen(userMap,NumberUtils.parseLong(assignee),
  181 + assignUser-> bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser)));
185 return bpmTaskSubSignRespVO; 182 return bpmTaskSubSignRespVO;
186 }); 183 });
187 } 184 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
@@ -176,9 +176,9 @@ public interface BpmTaskService { @@ -176,9 +176,9 @@ public interface BpmTaskService {
176 /** 176 /**
177 * 获取指定任务的子任务和审批人信息 177 * 获取指定任务的子任务和审批人信息
178 * 178 *
179 - * @param taskId 指定任务ID 179 + * @param parentId 指定任务ID
180 * @return 子任务列表 180 * @return 子任务列表
181 */ 181 */
182 - List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId); 182 + List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId);
183 183
184 } 184 }
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
@@ -53,7 +53,6 @@ import javax.annotation.Resource; @@ -53,7 +53,6 @@ import javax.annotation.Resource;
53 import javax.validation.Valid; 53 import javax.validation.Valid;
54 import java.time.LocalDateTime; 54 import java.time.LocalDateTime;
55 import java.util.*; 55 import java.util.*;
56 -import java.util.stream.Collectors;  
57 import java.util.stream.Stream; 56 import java.util.stream.Stream;
58 57
59 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 58 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -240,11 +239,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -240,11 +239,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
240 handleParentTask(task); 239 handleParentTask(task);
241 } 240 }
242 241
243 - // TODO @海:我们是不是加签统一认为是 SIGN,这样 SIGN_AFTER 就是后置;SIGN_BEFORE 就是前置; 242 +
244 /** 243 /**
245 * 审批通过存在“后加签”的任务。 244 * 审批通过存在“后加签”的任务。
246 * <p> 245 * <p>
247 - * 注意:该任务不能马上完成,需要一个中间状态(ADD_SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理 246 + * 注意:该任务不能马上完成,需要一个中间状态(SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理
248 * 247 *
249 * @param task 当前任务 248 * @param task 当前任务
250 * @param reqVO 前端请求参数 249 * @param reqVO 前端请求参数
@@ -252,7 +251,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -252,7 +251,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
252 private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) { 251 private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) {
253 // 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态 252 // 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态
254 taskExtMapper.updateByTaskId( 253 taskExtMapper.updateByTaskId(
255 - new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.ADD_SIGN_AFTER.getResult()) 254 + new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult())
256 .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now())); 255 .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now()));
257 256
258 // 2. 激活子任务 257 // 2. 激活子任务
@@ -275,50 +274,50 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -275,50 +274,50 @@ public class BpmTaskServiceImpl implements BpmTaskService {
275 if (StrUtil.isBlank(parentTaskId)) { 274 if (StrUtil.isBlank(parentTaskId)) {
276 return; 275 return;
277 } 276 }
278 - // TODO @海洋:279 这个判断就不需要啦;括号层级少一级噢;  
279 - if (StrUtil.isNotBlank(parentTaskId)) {  
280 - // 1. 判断当前任务的父任务是否还有子任务  
281 - Long childrenTaskCount = getChildrenTaskCount(parentTaskId);  
282 - if (childrenTaskCount > 0) {  
283 - return;  
284 - }  
285 - // TODO @海:如果非向前、向后加签,就直接 return 掉;就是把 3. 那判断做次提前;万一有别的父子任务经过这个逻辑,其实我们是不处理的,对哇?  
286 - // 2. 获取父任务  
287 - Task parentTask = validateTaskExist(parentTaskId);  
288 -  
289 - // 3.1 情况一:处理向前加签  
290 - String scopeType = parentTask.getScopeType();  
291 - if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {  
292 - // 3.1.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee,这样它就可以被审批  
293 - taskService.resolveTask(parentTaskId);  
294 - // 3.1.2 更新任务拓展表为处理中  
295 - taskExtMapper.updateByTaskId(  
296 - new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));  
297 - } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) {  
298 - // 3.2 情况二:处理向后加签  
299 - handleAfterSign(parentTask);  
300 - } 277 + // 1. 判断当前任务的父任务是否还有子任务
  278 + Long childrenTaskCount = getChildrenTaskCount(parentTaskId);
  279 + if (childrenTaskCount > 0) {
  280 + return;
  281 + }
  282 + // 2. 获取父任务
  283 + Task parentTask = validateTaskExist(parentTaskId);
301 284
302 - // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签  
303 - // 再查询一次的原因是避免报错:Task was updated by another transaction concurrently  
304 - // 因为前面处理后可能会导致 parentTask rev 字段被修改,需要重新获取最新的  
305 - parentTask = getTask(parentTaskId);  
306 - if (parentTask == null) {  
307 - // 为空的情况是:已经通过 handleAfterSign 方法将任务完成了,所以 ru_task 表会查不到数据  
308 - return;  
309 - }  
310 - clearTaskScopeTypeAndSave(parentTask); 285 + // 3. 处理加签情况
  286 + String scopeType = parentTask.getScopeType();
  287 + if(!validateSignType(scopeType)){
  288 + return;
311 } 289 }
  290 + // 3.1 情况一:处理向前加签
  291 + if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {
  292 + // 3.1.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee,这样它就可以被审批
  293 + taskService.resolveTask(parentTaskId);
  294 + // 3.1.2 更新任务拓展表为处理中
  295 + taskExtMapper.updateByTaskId(
  296 + new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));
  297 + } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) {
  298 + // 3.2 情况二:处理向后加签
  299 + handleParentTaskForAfterSign(parentTask);
  300 + }
  301 +
  302 + // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签
  303 + // 再查询一次的原因是避免报错:Task was updated by another transaction concurrently
  304 + // 因为前面处理后可能会导致 parentTask rev 字段被修改,需要重新获取最新的
  305 + parentTask = getTask(parentTaskId);
  306 + if (parentTask == null) {
  307 + // 为空的情况是:已经通过 handleAfterSign 方法将任务完成了,所以 ru_task 表会查不到数据
  308 + return;
  309 + }
  310 + clearTaskScopeTypeAndSave(parentTask);
312 } 311 }
313 312
314 - // TODO @海:可以把这个方法名,改成 handleParentTaskForAfterSign。= = 虽然这个名字也有点丑,但是目的是体现出它是 handleParentTask 的一种衍生 313 +
315 /** 314 /**
316 * 处理后加签任务 315 * 处理后加签任务
317 * 316 *
318 * @param parentTask 当前审批任务的父任务 317 * @param parentTask 当前审批任务的父任务
319 */ 318 */
320 // TODO @海:这个逻辑,怎么感觉可以是 parentTask 的 parent,再去调用 handleParentTask 方法;可以微信聊下; 319 // TODO @海:这个逻辑,怎么感觉可以是 parentTask 的 parent,再去调用 handleParentTask 方法;可以微信聊下;
321 - private void handleAfterSign(Task parentTask) { 320 + private void handleParentTaskForAfterSign(Task parentTask) {
322 String parentTaskId = parentTask.getId(); 321 String parentTaskId = parentTask.getId();
323 // 1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己 322 // 1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己
324 BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId()); 323 BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId());
@@ -363,7 +362,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -363,7 +362,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
363 continue; 362 continue;
364 } 363 }
365 // 3.2 没有子任务,判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成 364 // 3.2 没有子任务,判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成
366 - if (BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult().equals(parentTaskExt.getResult())) { 365 + if (BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult().equals(parentTaskExt.getResult())) {
367 // 3.3 需要修改该任务状态为处理中 366 // 3.3 需要修改该任务状态为处理中
368 taskService.resolveTask(parentTaskExt.getTaskId()); 367 taskService.resolveTask(parentTaskExt.getTaskId());
369 parentTaskExt.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); 368 parentTaskExt.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
@@ -731,7 +730,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -731,7 +730,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
731 // 2.3 更新扩展表状态 730 // 2.3 更新扩展表状态
732 taskExtMapper.updateByTaskId( 731 taskExtMapper.updateByTaskId(
733 new BpmTaskExtDO().setTaskId(taskEntity.getId()) 732 new BpmTaskExtDO().setTaskId(taskEntity.getId())
734 - .setResult(BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult()) 733 + .setResult(BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult())
735 .setReason(reqVO.getReason())); 734 .setReason(reqVO.getReason()));
736 } 735 }
737 // 2.4 记录加签方式,完成任务时需要用到判断 736 // 2.4 记录加签方式,完成任务时需要用到判断
@@ -740,11 +739,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -740,11 +739,11 @@ public class BpmTaskServiceImpl implements BpmTaskService {
740 taskService.saveTask(taskEntity); 739 taskService.saveTask(taskEntity);
741 740
742 // 3. 创建加签任务 741 // 3. 创建加签任务
743 - createAddSignChildrenTasks(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity); 742 + createSignTask(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity);
744 743
745 // 4. 记录加签 comment,拼接结果为: [当前用户]向前加签/向后加签给了[多个用户],理由为:reason 744 // 4. 记录加签 comment,拼接结果为: [当前用户]向前加签/向后加签给了[多个用户],理由为:reason
746 AdminUserRespDTO currentUser = adminUserApi.getUser(userId); 745 AdminUserRespDTO currentUser = adminUserApi.getUser(userId);
747 - String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getTemplateComment(), currentUser.getNickname(), 746 + String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), currentUser.getNickname(),
748 BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); 747 BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason());
749 taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(), 748 taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(),
750 BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment); 749 BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment);
@@ -783,14 +782,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -783,14 +782,13 @@ public class BpmTaskServiceImpl implements BpmTaskService {
783 return taskEntity; 782 return taskEntity;
784 } 783 }
785 784
786 - // TODO @海:方法名,要不改成 createSignTask;  
787 /** 785 /**
788 * 创建加签子任务 786 * 创建加签子任务
789 * 787 *
790 * @param addSingUserIdList 被加签的用户 ID 788 * @param addSingUserIdList 被加签的用户 ID
791 * @param taskEntity 被加签的任务 789 * @param taskEntity 被加签的任务
792 */ 790 */
793 - private void createAddSignChildrenTasks(List<String> addSingUserIdList, TaskEntityImpl taskEntity) { 791 + private void createSignTask(List<String> addSingUserIdList, TaskEntityImpl taskEntity) {
794 if (CollUtil.isEmpty(addSingUserIdList)) { 792 if (CollUtil.isEmpty(addSingUserIdList)) {
795 return; 793 return;
796 } 794 }
@@ -799,18 +797,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -799,18 +797,17 @@ public class BpmTaskServiceImpl implements BpmTaskService {
799 if (StrUtil.isBlank(addSignId)) { 797 if (StrUtil.isBlank(addSignId)) {
800 continue; 798 continue;
801 } 799 }
802 - createChildrenTask(taskEntity, addSignId); 800 + createSignTask(taskEntity, addSignId);
803 } 801 }
804 } 802 }
805 803
806 - // TODO @海:注释要不改成,创建加签子任务;然后方法名,就是 createSignTask;因为它还是在创建加签任务,目前哈;  
807 /** 804 /**
808 - * 创建子任务 805 + * 创建加签子任务
809 * 806 *
810 * @param parentTask 父任务 807 * @param parentTask 父任务
811 * @param assignee 子任务的执行人 808 * @param assignee 子任务的执行人
812 */ 809 */
813 - private void createChildrenTask(TaskEntityImpl parentTask, String assignee) { 810 + private void createSignTask(TaskEntityImpl parentTask, String assignee) {
814 // 1. 生成子任务 811 // 1. 生成子任务
815 TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID()); 812 TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID());
816 task = BpmTaskConvert.INSTANCE.convert(task, parentTask); 813 task = BpmTaskConvert.INSTANCE.convert(task, parentTask);
@@ -832,8 +829,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -832,8 +829,6 @@ public class BpmTaskServiceImpl implements BpmTaskService {
832 public void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO) { 829 public void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO) {
833 // 1.1 校验 task 可以被减签 830 // 1.1 校验 task 可以被减签
834 Task task = validateSubSign(reqVO.getId()); 831 Task task = validateSubSign(reqVO.getId());
835 - // TODO @海:adminUserApi.getUser(userId) 是不是应该放到 3. 那;  
836 - AdminUserRespDTO user = adminUserApi.getUser(userId);  
837 // 1.2 校验取消人存在 832 // 1.2 校验取消人存在
838 AdminUserRespDTO cancelUser = null; 833 AdminUserRespDTO cancelUser = null;
839 if (StrUtil.isNotBlank(task.getAssignee())) { 834 if (StrUtil.isNotBlank(task.getAssignee())) {
@@ -844,20 +839,22 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -844,20 +839,22 @@ public class BpmTaskServiceImpl implements BpmTaskService {
844 } 839 }
845 Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误"); 840 Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误");
846 841
847 - // TODO @海:1. 和 2. 可以写一行注释;其实就是删除任务,和它的子任务;本质上,1. 和 2. 还有 3. 是一块逻辑,写成 1.1 1.2 1.3 会更易懂  
848 - // 1. 获取所有需要删除的任务 ID ,包含当前任务和所有子任务 842 + // 2. 删除任务和对应子任务
  843 + // 2.1 获取所有需要删除的任务 ID ,包含当前任务和所有子任务
849 List<String> allTaskIdList = getAllChildTaskIds(task.getId()); 844 List<String> allTaskIdList = getAllChildTaskIds(task.getId());
850 - // 2. 删除任务和所有子任务 845 + // 2.2 删除任务和所有子任务
851 taskService.deleteTasks(allTaskIdList); 846 taskService.deleteTasks(allTaskIdList);
852 - // 3. 修改扩展表状态为取消 847 + // 2.3 修改扩展表状态为取消
  848 + AdminUserRespDTO user = adminUserApi.getUser(userId);
853 taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) 849 taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult())
854 .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname()))); 850 .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname())));
855 851
856 - // 4. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录  
857 - String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getTemplateComment(), user.getNickname(), cancelUser.getNickname()); 852 + // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录
  853 + String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname());
858 taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), 854 taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(),
859 BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment); 855 BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment);
860 - // 5. 处理当前任务的父任务 856 +
  857 + // 4. 处理当前任务的父任务
861 handleParentTask(task); 858 handleParentTask(task);
862 } 859 }
863 860
@@ -869,15 +866,29 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -869,15 +866,29 @@ public class BpmTaskServiceImpl implements BpmTaskService {
869 */ 866 */
870 private Task validateSubSign(String id) { 867 private Task validateSubSign(String id) {
871 Task task = validateTaskExist(id); 868 Task task = validateTaskExist(id);
872 - // 必须有 parentId  
873 - // TODO @海:是不是通过 scopeType 去判断更合适哈?因为别的情况下,也可能有 parentId  
874 - if (StrUtil.isEmpty(task.getParentTaskId())) { 869 +
  870 + // 必须有 scopeType
  871 + String scopeType = task.getScopeType();
  872 + if (StrUtil.isEmpty(scopeType)) {
  873 + throw exception(TASK_SUB_SIGN_NO_PARENT);
  874 + }
  875 + // 并且值为 向前和向后加签
  876 + if (!validateSignType(scopeType)) {
875 throw exception(TASK_SUB_SIGN_NO_PARENT); 877 throw exception(TASK_SUB_SIGN_NO_PARENT);
876 } 878 }
877 return task; 879 return task;
878 } 880 }
879 881
880 /** 882 /**
  883 + * 判断当前类型是否为加签
  884 + * @param scopeType 任务的 scopeType
  885 + * @return 当前 scopeType 为加签则返回 true
  886 + */
  887 + private boolean validateSignType(String scopeType){
  888 + return StrUtil.equalsAny(scopeType,BpmTaskAddSignTypeEnum.BEFORE.getType(),scopeType, BpmTaskAddSignTypeEnum.AFTER.getType());
  889 + }
  890 +
  891 + /**
881 * 获取所有要被取消的删除的任务 ID 集合 892 * 获取所有要被取消的删除的任务 ID 集合
882 * 893 *
883 * @param parentTaskId 父级任务ID 894 * @param parentTaskId 父级任务ID
@@ -885,69 +896,75 @@ public class BpmTaskServiceImpl implements BpmTaskService { @@ -885,69 +896,75 @@ public class BpmTaskServiceImpl implements BpmTaskService {
885 */ 896 */
886 public List<String> getAllChildTaskIds(String parentTaskId) { 897 public List<String> getAllChildTaskIds(String parentTaskId) {
887 List<String> allChildTaskIds = new ArrayList<>(); 898 List<String> allChildTaskIds = new ArrayList<>();
888 - // TODO @海:这里可以把递归改成 for 循环,可以试试看哈;整体思路,是一层一层查询;然后判断某一层查不出来了,就是结束了;  
889 - // 最好不用无限递归,一般是 for (int i = 0; i < Short.MAX),避免脏数据导致无限递归;  
890 - //1. 先将自己放入  
891 - allChildTaskIds.add(parentTaskId);  
892 - //2. 递归获取子级  
893 - recursiveGetChildTaskIds(parentTaskId, allChildTaskIds); 899 + // 1. 递归获取子级
  900 + Stack<String> stack = new Stack<>();
  901 + // 1.1 将根任务ID入栈
  902 + stack.push(parentTaskId);
  903 + //控制遍历的次数不超过 Byte.MAX_VALUE,避免脏数据造成死循环
  904 + int count = 0;
  905 + while (!stack.isEmpty() && count<Byte.MAX_VALUE) {
  906 + // 1.2 弹出栈顶任务ID
  907 + String taskId = stack.pop();
  908 + // 1.3 将任务ID添加到结果集合中
  909 + allChildTaskIds.add(taskId);
  910 + // 1.4 获取该任务的子任务列表
  911 + List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);
  912 + if (CollUtil.isNotEmpty(childrenTaskIdList)) {
  913 + for (String childTaskId : childrenTaskIdList) {
  914 + // 1.5 将子任务ID入栈,以便后续处理
  915 + stack.push(childTaskId);
  916 + }
  917 + }
  918 + count++;
  919 + }
894 return allChildTaskIds; 920 return allChildTaskIds;
895 } 921 }
896 922
  923 +
897 /** 924 /**
898 - * 递归处理子级任务 925 + * 获取指定父级任务的所有子任务 ID 集合
899 * 926 *
900 - * @param taskId 当前任务ID  
901 - * @param taskIds 结果 927 + * @param parentTaskId 父任务 ID
  928 + * @return 所有子任务的 ID 集合
902 */ 929 */
903 - private void recursiveGetChildTaskIds(String taskId, List<String> taskIds) {  
904 - List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);  
905 - for (String childTaskId : childrenTaskIdList) {  
906 - taskIds.add(childTaskId); // 将子任务的ID添加到集合中  
907 - recursiveGetChildTaskIds(childTaskId, taskIds); // 递归获取子任务的子任务  
908 - } 930 + private List<String> getChildrenTaskIdList(String parentTaskId) {
  931 + return convertList(getChildrenTaskList0(parentTaskId), Task::getId);
909 } 932 }
910 933
911 - // TODO @海:一般情况下,除非对性能特别有要求,才只查询 ID_ 单字段;一般层级不多,数据量不大;其实整查就好啦,无非是带宽稍微浪费电,但是基本看不出啥性能差距;  
912 /** 934 /**
913 * 获取指定父级任务的所有子任务 ID 集合 935 * 获取指定父级任务的所有子任务 ID 集合
914 * 936 *
915 * @param parentTaskId 父任务 ID 937 * @param parentTaskId 父任务 ID
916 * @return 所有子任务的 ID 集合 938 * @return 所有子任务的 ID 集合
917 */ 939 */
918 - private List<String> getChildrenTaskIdList(String parentTaskId) { 940 + private List<Task> getChildrenTaskList0(String parentTaskId) {
919 String tableName = managementService.getTableName(TaskEntity.class); 941 String tableName = managementService.getTableName(TaskEntity.class);
920 - String sql = "select ID_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";  
921 - List<Task> childrenTaskList = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();  
922 - return convertList(childrenTaskList, Task::getId); 942 + // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询
  943 + String sql = "select ID_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
  944 + return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list();
923 } 945 }
924 946
  947 +
925 @Override 948 @Override
926 - public List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId) {  
927 - // 1. 只查询进行中的任务  
928 - List<String> childrenTaskIdList = getChildrenTaskIdList(taskId);  
929 - if (CollUtil.isEmpty(childrenTaskIdList)) { 949 + public List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId) {
  950 + // 1. 只查询进行中的任务 后加签的任务,可能不存在 assignee,所以还需要查询 owner
  951 + List<Task> taskList = getChildrenTaskList0(parentId);
  952 + if (CollUtil.isEmpty(taskList)) {
930 return Collections.emptyList(); 953 return Collections.emptyList();
931 } 954 }
932 - // TODO @海:bpmTaskExtDOList 可以改成 taskExtList;因为当前已经在 bpm 模块,不用前缀;然后,DO 一般情况下不用带;  
933 - List<BpmTaskExtDO> bpmTaskExtDOList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList); 955 + List<String> childrenTaskIdList = convertList(taskList, Task::getId);
934 956
935 - // 2. 后加签的任务,可能不存在 assignee,所以还需要查询 owner  
936 - // TODO @海:1. 和 2. 是不是有点重复哈;1. 先查询到了子节点,然后返回了 ids 集合;然后又去 in 查询了一次。。。。按道理,taskService 查询 taskList 就完事?  
937 - List<Task> taskList = taskService.createTaskQuery().taskIds(childrenTaskIdList).list();  
938 - Map<String, Task> idTaskMap = convertMap(taskList, TaskInfo::getId);  
939 957
940 - // 3. 将 owner 和 assignee 统一到一个集合中  
941 - // TODO @海:下面 userId 的获取,可以考虑抽个小方法;  
942 - List<Long> userIds = taskList.stream()  
943 - .flatMap(control ->  
944 - Stream.of(control.getAssignee(), control.getOwner())  
945 - .filter(Objects::nonNull))  
946 - .distinct()  
947 - .map(NumberUtils::parseLong)  
948 - .collect(Collectors.toList()); 958 + // 2. 将 owner 和 assignee 统一到一个集合中
  959 + List<Long> userIds = convertListByMultiAttr(taskList,control ->
  960 + Stream.of(NumberUtils.parseLong(control.getAssignee()), NumberUtils.parseLong(control.getOwner()))
  961 + .filter(Objects::nonNull));
  962 +
  963 + // 3. 组装数据
949 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); 964 Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
950 - return BpmTaskConvert.INSTANCE.convertList(bpmTaskExtDOList, userMap, idTaskMap); 965 + List<BpmTaskExtDO> taskExtList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList);
  966 + Map<String, Task> idTaskMap = convertMap(taskList, TaskInfo::getId);
  967 + return BpmTaskConvert.INSTANCE.convertList(taskExtList, userMap, idTaskMap);
951 } 968 }
952 969
953 } 970 }