mirror of
				https://github.com/YunaiV/ruoyi-vue-pro.git
				synced 2025-10-31 10:37:41 +08:00 
			
		
		
		
	!689 【工作流】--加签减签review
Merge pull request !689 from Youkehai/feature/bpm-addSignAndSubSign
This commit is contained in:
		| @ -3,11 +3,13 @@ package cn.iocoder.yudao.framework.common.util.collection; | |||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.hutool.core.collection.CollectionUtil; | import cn.hutool.core.collection.CollectionUtil; | ||||||
| import cn.hutool.core.util.ArrayUtil; | import cn.hutool.core.util.ArrayUtil; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||||
| import com.google.common.collect.ImmutableMap; | import com.google.common.collect.ImmutableMap; | ||||||
|  |  | ||||||
| import java.util.*; | import java.util.*; | ||||||
| import java.util.function.*; | import java.util.function.*; | ||||||
| import java.util.stream.Collectors; | import java.util.stream.Collectors; | ||||||
|  | import java.util.stream.Stream; | ||||||
|  |  | ||||||
| import static java.util.Arrays.asList; | import static java.util.Arrays.asList; | ||||||
|  |  | ||||||
| @ -267,4 +269,19 @@ public class CollectionUtils { | |||||||
|         return deptId == null ? Collections.emptyList() : Collections.singleton(deptId); |         return deptId == null ? Collections.emptyList() : Collections.singleton(deptId); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static <T, U> List<U> convertListByMultiAttr(Collection<T> from, | ||||||
|  |                                                       Function<T, ? extends Stream<? extends U>> func) { | ||||||
|  |         if (CollUtil.isEmpty(from)) { | ||||||
|  |             return new ArrayList<>(); | ||||||
|  |         } | ||||||
|  |         return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public static <T, U> Set<U> convertSetByMultiAttr(Collection<T> from, | ||||||
|  |                                                       Function<T, ? extends Stream<? extends U>> func) { | ||||||
|  |         if (CollUtil.isEmpty(from)) { | ||||||
|  |             return new HashSet<>(); | ||||||
|  |         } | ||||||
|  |         return from.stream().flatMap(func).filter(Objects::nonNull).collect(Collectors.toSet()); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -23,15 +23,13 @@ public enum BpmCommentTypeEnum { | |||||||
|      * 操作类型 |      * 操作类型 | ||||||
|      */ |      */ | ||||||
|     private final Integer type; |     private final Integer type; | ||||||
|     // TODO @海:desc 可以改成 name;相当于操作名; |  | ||||||
|     /** |     /** | ||||||
|      * 操作名字 |      * 操作名字 | ||||||
|      */ |      */ | ||||||
|     private final String desc; |     private final String name; | ||||||
|     // TODO @海:直接改成 comment 哈;简单一点; |  | ||||||
|     /** |     /** | ||||||
|      * 操作描述 |      * 操作描述 | ||||||
|      */ |      */ | ||||||
|     private final String templateComment; |     private final String comment; | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -30,13 +30,13 @@ public enum BpmProcessInstanceResultEnum { | |||||||
|      * 相当于是 通过 APPROVE 的特殊状态 |      * 相当于是 通过 APPROVE 的特殊状态 | ||||||
|      * 例如:A审批, A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成” |      * 例如:A审批, A 后加签了 B,并且审批通过了任务,但是 B 还未审批,则当前任务状态为“待后加签任务完成” | ||||||
|      */ |      */ | ||||||
|     ADD_SIGN_AFTER(7, "待后加签任务完成"), |     SIGN_AFTER(7, "待后加签任务完成"), | ||||||
|     /** |     /** | ||||||
|      * 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成” |      * 【加签】源任务未审批,但是向前加签了,所以源任务状态变为“待前加签任务完成” | ||||||
|      * 相当于是 处理中 PROCESS 的特殊状态 |      * 相当于是 处理中 PROCESS 的特殊状态 | ||||||
|      * 例如:A 审批, A 前加签了 B,B 还未审核 |      * 例如:A 审批, A 前加签了 B,B 还未审核 | ||||||
|      */ |      */ | ||||||
|     ADD_SIGN_BEFORE(8, "待前加签任务完成"), |     SIGN_BEFORE(8, "待前加签任务完成"), | ||||||
|     /** |     /** | ||||||
|      * 【加签】后加签任务被创建时的初始状态 |      * 【加签】后加签任务被创建时的初始状态 | ||||||
|      * 相当于是 处理中 PROCESS 的特殊状态 |      * 相当于是 处理中 PROCESS 的特殊状态 | ||||||
| @ -71,7 +71,7 @@ public enum BpmProcessInstanceResultEnum { | |||||||
|     public static boolean isEndResult(Integer result) { |     public static boolean isEndResult(Integer result) { | ||||||
|         return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(), |         return ObjectUtils.equalsAny(result, APPROVE.getResult(), REJECT.getResult(), | ||||||
|                 CANCEL.getResult(), BACK.getResult(), |                 CANCEL.getResult(), BACK.getResult(), | ||||||
|                 ADD_SIGN_AFTER.getResult()); |                 SIGN_AFTER.getResult()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -74,8 +74,7 @@ public class BpmTaskController { | |||||||
|         return success(true); |         return success(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO @海:/return-list,不用带 get; |     @GetMapping("/return-list") | ||||||
|     @GetMapping("/get-return-list") |  | ||||||
|     @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮") |     @Operation(summary = "获取所有可回退的节点", description = "用于【流程详情】的【回退】按钮") | ||||||
|     @Parameter(name = "taskId", description = "当前任务ID", required = true) |     @Parameter(name = "taskId", description = "当前任务ID", required = true) | ||||||
|     @PreAuthorize("@ss.hasPermission('bpm:task:update')") |     @PreAuthorize("@ss.hasPermission('bpm:task:update')") | ||||||
| @ -99,8 +98,7 @@ public class BpmTaskController { | |||||||
|         return success(true); |         return success(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO @海:create-sign?创建加签任务; |     @PutMapping("/create-sign") | ||||||
|     @PutMapping("/add-sign") |  | ||||||
|     @Operation(summary = "加签", description = "before 前加签,after 后加签") |     @Operation(summary = "加签", description = "before 前加签,after 后加签") | ||||||
|     @PreAuthorize("@ss.hasPermission('bpm:task:update')") |     @PreAuthorize("@ss.hasPermission('bpm:task:update')") | ||||||
|     public CommonResult<Boolean> addSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) { |     public CommonResult<Boolean> addSignTask(@Valid @RequestBody BpmTaskAddSignReqVO reqVO) { | ||||||
| @ -108,8 +106,7 @@ public class BpmTaskController { | |||||||
|         return success(true); |         return success(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO @海:delete-sign?删除加签任务;然后 @DeleteMapping;这样感觉可以保持统一; |     @DeleteMapping("/delete-sign") | ||||||
|     @PutMapping("/sub-sign") |  | ||||||
|     @Operation(summary = "减签") |     @Operation(summary = "减签") | ||||||
|     @PreAuthorize("@ss.hasPermission('bpm:task:update')") |     @PreAuthorize("@ss.hasPermission('bpm:task:update')") | ||||||
|     public CommonResult<Boolean> subSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) { |     public CommonResult<Boolean> subSignTask(@Valid @RequestBody BpmTaskSubSignReqVO reqVO) { | ||||||
| @ -117,13 +114,12 @@ public class BpmTaskController { | |||||||
|         return success(true); |         return success(true); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO @海:/children-list,不用带 task 和 get; |     @GetMapping("children-list") | ||||||
|     // TODO @海:taskId 是不是改成 parentId?另外,它的 swagger 注解也加下哈; |  | ||||||
|     @GetMapping("/get-children-task-list") |  | ||||||
|     @Operation(summary = "获取能被减签的任务") |     @Operation(summary = "获取能被减签的任务") | ||||||
|  |     @Parameter(name = "parentId", description = "父级任务ID", required = true) | ||||||
|     @PreAuthorize("@ss.hasPermission('bpm:task:update')") |     @PreAuthorize("@ss.hasPermission('bpm:task:update')") | ||||||
|     public CommonResult<List<BpmTaskSubSignRespVO>> getChildrenTaskList(@RequestParam("taskId") String taskId) { |     public CommonResult<List<BpmTaskSubSignRespVO>> getChildrenTaskList(@RequestParam("parentId") String parentId) { | ||||||
|         return success(taskService.getChildrenTaskList(taskId)); |         return success(taskService.getChildrenTaskList(parentId)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -2,8 +2,10 @@ package cn.iocoder.yudao.module.bpm.convert.task; | |||||||
|  |  | ||||||
| import cn.hutool.core.collection.CollUtil; | import cn.hutool.core.collection.CollUtil; | ||||||
| import cn.hutool.core.date.LocalDateTimeUtil; | import cn.hutool.core.date.LocalDateTimeUtil; | ||||||
|  | import cn.hutool.core.util.ObjectUtil; | ||||||
| import cn.hutool.core.util.StrUtil; | import cn.hutool.core.util.StrUtil; | ||||||
| import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||||||
|  | import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||||||
| import cn.iocoder.yudao.framework.common.util.date.DateUtils; | import cn.iocoder.yudao.framework.common.util.date.DateUtils; | ||||||
| import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | ||||||
| import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; | ||||||
| @ -168,20 +170,15 @@ public interface BpmTaskConvert { | |||||||
|                                                    Map<Long, AdminUserRespDTO> userMap, |                                                    Map<Long, AdminUserRespDTO> userMap, | ||||||
|                                                    Map<String, Task> idTaskMap){ |                                                    Map<String, Task> idTaskMap){ | ||||||
|         return CollectionUtils.convertList(bpmTaskExtDOList, task -> { |         return CollectionUtils.convertList(bpmTaskExtDOList, task -> { | ||||||
|             // TODO @海:setId、name,可以链式调用 |             BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO() | ||||||
|             BpmTaskSubSignRespVO bpmTaskSubSignRespVO = new BpmTaskSubSignRespVO(); |                     .setName(task.getName()) | ||||||
|             bpmTaskSubSignRespVO.setName(task.getName()); |                     .setId(task.getTaskId()); | ||||||
|             bpmTaskSubSignRespVO.setId(task.getTaskId()); |  | ||||||
|             Task sourceTask = idTaskMap.get(task.getTaskId()); |  | ||||||
|             // TODO @海:下面这行注释,应该放到 idTaskMap.get(task.getTaskId()) 上面;原因是,应该注释之后,下面的逻辑是个整体; |  | ||||||
|             // 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner |             // 后加签任务不会直接设置 assignee ,所以不存在 assignee 的情况,则去取 owner | ||||||
|             // TODO @海:可以使用 ObjUtil.default 方法 |             Task sourceTask = idTaskMap.get(task.getTaskId()); | ||||||
|             String assignee = StrUtil.isNotEmpty(sourceTask.getAssignee()) ? sourceTask.getAssignee() : sourceTask.getOwner(); |             String assignee = ObjectUtil.defaultIfBlank(sourceTask.getOwner(),sourceTask.getAssignee()); | ||||||
|             // TODO @海:这里可以使用 MapUtils.findAndThen 写起来更简单一点; |             MapUtils.findAndThen(userMap,NumberUtils.parseLong(assignee), | ||||||
|             AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(assignee)); |                     assignUser-> bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser))); | ||||||
|             if (assignUser != null) { |  | ||||||
|                 bpmTaskSubSignRespVO.setAssigneeUser(convert3(assignUser)); |  | ||||||
|             } |  | ||||||
|             return bpmTaskSubSignRespVO; |             return bpmTaskSubSignRespVO; | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -176,9 +176,9 @@ public interface BpmTaskService { | |||||||
|     /** |     /** | ||||||
|      * 获取指定任务的子任务和审批人信息 |      * 获取指定任务的子任务和审批人信息 | ||||||
|      * |      * | ||||||
|      * @param taskId 指定任务ID |      * @param parentId 指定任务ID | ||||||
|      * @return 子任务列表 |      * @return 子任务列表 | ||||||
|      */ |      */ | ||||||
|     List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId); |     List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId); | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -53,7 +53,6 @@ import javax.annotation.Resource; | |||||||
| import javax.validation.Valid; | import javax.validation.Valid; | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| import java.util.*; | import java.util.*; | ||||||
| import java.util.stream.Collectors; |  | ||||||
| import java.util.stream.Stream; | import java.util.stream.Stream; | ||||||
|  |  | ||||||
| import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | ||||||
| @ -240,11 +239,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|         handleParentTask(task); |         handleParentTask(task); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO @海:我们是不是加签统一认为是 SIGN,这样 SIGN_AFTER 就是后置;SIGN_BEFORE 就是前置; |  | ||||||
|     /** |     /** | ||||||
|      * 审批通过存在“后加签”的任务。 |      * 审批通过存在“后加签”的任务。 | ||||||
|      * <p> |      * <p> | ||||||
|      * 注意:该任务不能马上完成,需要一个中间状态(ADD_SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理 |      * 注意:该任务不能马上完成,需要一个中间状态(SIGN_AFTER),并激活剩余所有子任务(PROCESS)为可审批处理 | ||||||
|      * |      * | ||||||
|      * @param task  当前任务 |      * @param task  当前任务 | ||||||
|      * @param reqVO 前端请求参数 |      * @param reqVO 前端请求参数 | ||||||
| @ -252,7 +251,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|     private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) { |     private void approveAfterSignTask(Task task, BpmTaskApproveReqVO reqVO) { | ||||||
|         // 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态 |         // 1. 有向后加签,则该任务状态临时设置为 ADD_SIGN_AFTER 状态 | ||||||
|         taskExtMapper.updateByTaskId( |         taskExtMapper.updateByTaskId( | ||||||
|                 new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.ADD_SIGN_AFTER.getResult()) |                 new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.SIGN_AFTER.getResult()) | ||||||
|                         .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now())); |                         .setReason(reqVO.getReason()).setEndTime(LocalDateTime.now())); | ||||||
|  |  | ||||||
|         // 2. 激活子任务 |         // 2. 激活子任务 | ||||||
| @ -275,19 +274,20 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|         if (StrUtil.isBlank(parentTaskId)) { |         if (StrUtil.isBlank(parentTaskId)) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         // TODO @海洋:279 这个判断就不需要啦;括号层级少一级噢; |  | ||||||
|         if (StrUtil.isNotBlank(parentTaskId)) { |  | ||||||
|         // 1. 判断当前任务的父任务是否还有子任务 |         // 1. 判断当前任务的父任务是否还有子任务 | ||||||
|         Long childrenTaskCount = getChildrenTaskCount(parentTaskId); |         Long childrenTaskCount = getChildrenTaskCount(parentTaskId); | ||||||
|         if (childrenTaskCount > 0) { |         if (childrenTaskCount > 0) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|             // TODO @海:如果非向前、向后加签,就直接 return 掉;就是把 3. 那判断做次提前;万一有别的父子任务经过这个逻辑,其实我们是不处理的,对哇? |  | ||||||
|         // 2. 获取父任务 |         // 2. 获取父任务 | ||||||
|         Task parentTask = validateTaskExist(parentTaskId); |         Task parentTask = validateTaskExist(parentTaskId); | ||||||
|  |  | ||||||
|             // 3.1 情况一:处理向前加签 |         // 3. 处理加签情况 | ||||||
|         String scopeType = parentTask.getScopeType(); |         String scopeType = parentTask.getScopeType(); | ||||||
|  |         if(!validateSignType(scopeType)){ | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |         // 3.1 情况一:处理向前加签 | ||||||
|         if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) { |         if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) { | ||||||
|             // 3.1.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee,这样它就可以被审批 |             // 3.1.1 如果是向前加签的任务,则调用 resolveTask 指派父任务,将 owner 重新赋值给父任务的 assignee,这样它就可以被审批 | ||||||
|             taskService.resolveTask(parentTaskId); |             taskService.resolveTask(parentTaskId); | ||||||
| @ -296,7 +296,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|                     new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())); |                     new BpmTaskExtDO().setTaskId(parentTask.getId()).setResult(BpmProcessInstanceResultEnum.PROCESS.getResult())); | ||||||
|         } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) { |         } else if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(scopeType)) { | ||||||
|             // 3.2 情况二:处理向后加签 |             // 3.2 情况二:处理向后加签 | ||||||
|                 handleAfterSign(parentTask); |             handleParentTaskForAfterSign(parentTask); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签 |         // 4. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签 | ||||||
| @ -309,16 +309,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|         } |         } | ||||||
|         clearTaskScopeTypeAndSave(parentTask); |         clearTaskScopeTypeAndSave(parentTask); | ||||||
|     } |     } | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // TODO @海:可以把这个方法名,改成 handleParentTaskForAfterSign。= = 虽然这个名字也有点丑,但是目的是体现出它是 handleParentTask 的一种衍生 |  | ||||||
|     /** |     /** | ||||||
|      * 处理后加签任务 |      * 处理后加签任务 | ||||||
|      * |      * | ||||||
|      * @param parentTask 当前审批任务的父任务 |      * @param parentTask 当前审批任务的父任务 | ||||||
|      */ |      */ | ||||||
|     // TODO @海:这个逻辑,怎么感觉可以是 parentTask 的 parent,再去调用 handleParentTask 方法;可以微信聊下; |     // TODO @海:这个逻辑,怎么感觉可以是 parentTask 的 parent,再去调用 handleParentTask 方法;可以微信聊下; | ||||||
|     private void handleAfterSign(Task parentTask) { |     private void handleParentTaskForAfterSign(Task parentTask) { | ||||||
|         String parentTaskId = parentTask.getId(); |         String parentTaskId = parentTask.getId(); | ||||||
|         // 1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己 |         // 1. 更新 parentTask 的任务拓展表为通过,并调用 complete 完成自己 | ||||||
|         BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId()); |         BpmTaskExtDO currentTaskExt = taskExtMapper.selectByTaskId(parentTask.getId()); | ||||||
| @ -363,7 +362,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             // 3.2 没有子任务,判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成 |             // 3.2 没有子任务,判断当前任务状态是否为 ADD_SIGN_BEFORE 待前加签任务完成 | ||||||
|             if (BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult().equals(parentTaskExt.getResult())) { |             if (BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult().equals(parentTaskExt.getResult())) { | ||||||
|                 // 3.3 需要修改该任务状态为处理中 |                 // 3.3 需要修改该任务状态为处理中 | ||||||
|                 taskService.resolveTask(parentTaskExt.getTaskId()); |                 taskService.resolveTask(parentTaskExt.getTaskId()); | ||||||
|                 parentTaskExt.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); |                 parentTaskExt.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); | ||||||
| @ -731,7 +730,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|             // 2.3 更新扩展表状态 |             // 2.3 更新扩展表状态 | ||||||
|             taskExtMapper.updateByTaskId( |             taskExtMapper.updateByTaskId( | ||||||
|                     new BpmTaskExtDO().setTaskId(taskEntity.getId()) |                     new BpmTaskExtDO().setTaskId(taskEntity.getId()) | ||||||
|                             .setResult(BpmProcessInstanceResultEnum.ADD_SIGN_BEFORE.getResult()) |                             .setResult(BpmProcessInstanceResultEnum.SIGN_BEFORE.getResult()) | ||||||
|                             .setReason(reqVO.getReason())); |                             .setReason(reqVO.getReason())); | ||||||
|         } |         } | ||||||
|         // 2.4 记录加签方式,完成任务时需要用到判断 |         // 2.4 记录加签方式,完成任务时需要用到判断 | ||||||
| @ -740,11 +739,11 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|         taskService.saveTask(taskEntity); |         taskService.saveTask(taskEntity); | ||||||
|  |  | ||||||
|         // 3. 创建加签任务 |         // 3. 创建加签任务 | ||||||
|         createAddSignChildrenTasks(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity); |         createSignTask(convertList(reqVO.getUserIdList(), String::valueOf), taskEntity); | ||||||
|  |  | ||||||
|         // 4. 记录加签 comment,拼接结果为: [当前用户]向前加签/向后加签给了[多个用户],理由为:reason |         // 4. 记录加签 comment,拼接结果为: [当前用户]向前加签/向后加签给了[多个用户],理由为:reason | ||||||
|         AdminUserRespDTO currentUser = adminUserApi.getUser(userId); |         AdminUserRespDTO currentUser = adminUserApi.getUser(userId); | ||||||
|         String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getTemplateComment(), currentUser.getNickname(), |         String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), currentUser.getNickname(), | ||||||
|                 BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); |                 BpmTaskAddSignTypeEnum.formatDesc(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); | ||||||
|         taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(), |         taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(), | ||||||
|                 BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment); |                 BpmCommentTypeEnum.ADD_SIGN.getType().toString(), comment); | ||||||
| @ -783,14 +782,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|         return taskEntity; |         return taskEntity; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO @海:方法名,要不改成 createSignTask; |  | ||||||
|     /** |     /** | ||||||
|      * 创建加签子任务 |      * 创建加签子任务 | ||||||
|      * |      * | ||||||
|      * @param addSingUserIdList 被加签的用户 ID |      * @param addSingUserIdList 被加签的用户 ID | ||||||
|      * @param taskEntity        被加签的任务 |      * @param taskEntity        被加签的任务 | ||||||
|      */ |      */ | ||||||
|     private void createAddSignChildrenTasks(List<String> addSingUserIdList, TaskEntityImpl taskEntity) { |     private void createSignTask(List<String> addSingUserIdList, TaskEntityImpl taskEntity) { | ||||||
|         if (CollUtil.isEmpty(addSingUserIdList)) { |         if (CollUtil.isEmpty(addSingUserIdList)) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| @ -799,18 +797,17 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|             if (StrUtil.isBlank(addSignId)) { |             if (StrUtil.isBlank(addSignId)) { | ||||||
|                 continue; |                 continue; | ||||||
|             } |             } | ||||||
|             createChildrenTask(taskEntity, addSignId); |             createSignTask(taskEntity, addSignId); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // TODO @海:注释要不改成,创建加签子任务;然后方法名,就是 createSignTask;因为它还是在创建加签任务,目前哈; |  | ||||||
|     /** |     /** | ||||||
|      * 创建子任务 |      * 创建加签子任务 | ||||||
|      * |      * | ||||||
|      * @param parentTask 父任务 |      * @param parentTask 父任务 | ||||||
|      * @param assignee   子任务的执行人 |      * @param assignee   子任务的执行人 | ||||||
|      */ |      */ | ||||||
|     private void createChildrenTask(TaskEntityImpl parentTask, String assignee) { |     private void createSignTask(TaskEntityImpl parentTask, String assignee) { | ||||||
|         // 1. 生成子任务 |         // 1. 生成子任务 | ||||||
|         TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID()); |         TaskEntityImpl task = (TaskEntityImpl) taskService.newTask(IdUtil.fastSimpleUUID()); | ||||||
|         task = BpmTaskConvert.INSTANCE.convert(task, parentTask); |         task = BpmTaskConvert.INSTANCE.convert(task, parentTask); | ||||||
| @ -832,8 +829,6 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|     public void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO) { |     public void subSignTask(Long userId, BpmTaskSubSignReqVO reqVO) { | ||||||
|         // 1.1 校验 task 可以被减签 |         // 1.1 校验 task 可以被减签 | ||||||
|         Task task = validateSubSign(reqVO.getId()); |         Task task = validateSubSign(reqVO.getId()); | ||||||
|         // TODO @海:adminUserApi.getUser(userId) 是不是应该放到 3. 那; |  | ||||||
|         AdminUserRespDTO user = adminUserApi.getUser(userId); |  | ||||||
|         // 1.2 校验取消人存在 |         // 1.2 校验取消人存在 | ||||||
|         AdminUserRespDTO cancelUser = null; |         AdminUserRespDTO cancelUser = null; | ||||||
|         if (StrUtil.isNotBlank(task.getAssignee())) { |         if (StrUtil.isNotBlank(task.getAssignee())) { | ||||||
| @ -844,20 +839,22 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|         } |         } | ||||||
|         Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误"); |         Assert.notNull(cancelUser, "任务中没有所有者和审批人,数据错误"); | ||||||
|  |  | ||||||
|         // TODO @海:1. 和 2. 可以写一行注释;其实就是删除任务,和它的子任务;本质上,1. 和 2. 还有 3. 是一块逻辑,写成 1.1 1.2 1.3 会更易懂 |         // 2. 删除任务和对应子任务 | ||||||
|         // 1. 获取所有需要删除的任务 ID ,包含当前任务和所有子任务 |         // 2.1 获取所有需要删除的任务 ID ,包含当前任务和所有子任务 | ||||||
|         List<String> allTaskIdList = getAllChildTaskIds(task.getId()); |         List<String> allTaskIdList = getAllChildTaskIds(task.getId()); | ||||||
|         // 2. 删除任务和所有子任务 |         // 2.2 删除任务和所有子任务 | ||||||
|         taskService.deleteTasks(allTaskIdList); |         taskService.deleteTasks(allTaskIdList); | ||||||
|         // 3. 修改扩展表状态为取消 |         // 2.3 修改扩展表状态为取消 | ||||||
|  |         AdminUserRespDTO user = adminUserApi.getUser(userId); | ||||||
|         taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) |         taskExtMapper.updateBatchByTaskIdList(allTaskIdList, new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()) | ||||||
|                 .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname()))); |                 .setReason(StrUtil.format("由于{}操作[减签],任务被取消", user.getNickname()))); | ||||||
|  |  | ||||||
|         // 4. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录 |         // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录 | ||||||
|         String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getTemplateComment(), user.getNickname(), cancelUser.getNickname()); |         String comment = StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname()); | ||||||
|         taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), |         taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), | ||||||
|                 BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment); |                 BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment); | ||||||
|         // 5. 处理当前任务的父任务 |  | ||||||
|  |         // 4. 处理当前任务的父任务 | ||||||
|         handleParentTask(task); |         handleParentTask(task); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -869,14 +866,28 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|      */ |      */ | ||||||
|     private Task validateSubSign(String id) { |     private Task validateSubSign(String id) { | ||||||
|         Task task = validateTaskExist(id); |         Task task = validateTaskExist(id); | ||||||
|         // 必须有 parentId |  | ||||||
|         // TODO @海:是不是通过 scopeType 去判断更合适哈?因为别的情况下,也可能有 parentId |         // 必须有 scopeType | ||||||
|         if (StrUtil.isEmpty(task.getParentTaskId())) { |         String scopeType = task.getScopeType(); | ||||||
|  |         if (StrUtil.isEmpty(scopeType)) { | ||||||
|  |             throw exception(TASK_SUB_SIGN_NO_PARENT); | ||||||
|  |         } | ||||||
|  |         // 并且值为 向前和向后加签 | ||||||
|  |         if (!validateSignType(scopeType)) { | ||||||
|             throw exception(TASK_SUB_SIGN_NO_PARENT); |             throw exception(TASK_SUB_SIGN_NO_PARENT); | ||||||
|         } |         } | ||||||
|         return task; |         return task; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 判断当前类型是否为加签 | ||||||
|  |      * @param scopeType 任务的 scopeType | ||||||
|  |      * @return 当前 scopeType 为加签则返回 true | ||||||
|  |      */ | ||||||
|  |     private boolean validateSignType(String scopeType){ | ||||||
|  |         return StrUtil.equalsAny(scopeType,BpmTaskAddSignTypeEnum.BEFORE.getType(),scopeType, BpmTaskAddSignTypeEnum.AFTER.getType()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * 获取所有要被取消的删除的任务 ID 集合 |      * 获取所有要被取消的删除的任务 ID 集合 | ||||||
|      * |      * | ||||||
| @ -885,30 +896,31 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|      */ |      */ | ||||||
|     public List<String> getAllChildTaskIds(String parentTaskId) { |     public List<String> getAllChildTaskIds(String parentTaskId) { | ||||||
|         List<String> allChildTaskIds = new ArrayList<>(); |         List<String> allChildTaskIds = new ArrayList<>(); | ||||||
|         // TODO @海:这里可以把递归改成 for 循环,可以试试看哈;整体思路,是一层一层查询;然后判断某一层查不出来了,就是结束了; |         // 1. 递归获取子级 | ||||||
|         //  最好不用无限递归,一般是 for (int i = 0; i < Short.MAX),避免脏数据导致无限递归; |         Stack<String> stack = new Stack<>(); | ||||||
|         //1. 先将自己放入 |         // 1.1 将根任务ID入栈 | ||||||
|         allChildTaskIds.add(parentTaskId); |         stack.push(parentTaskId); | ||||||
|         //2. 递归获取子级 |         //控制遍历的次数不超过 Byte.MAX_VALUE,避免脏数据造成死循环 | ||||||
|         recursiveGetChildTaskIds(parentTaskId, allChildTaskIds); |         int count = 0; | ||||||
|  |         while (!stack.isEmpty() && count<Byte.MAX_VALUE) { | ||||||
|  |             // 1.2 弹出栈顶任务ID | ||||||
|  |             String taskId = stack.pop(); | ||||||
|  |             // 1.3 将任务ID添加到结果集合中 | ||||||
|  |             allChildTaskIds.add(taskId); | ||||||
|  |             // 1.4 获取该任务的子任务列表 | ||||||
|  |             List<String> childrenTaskIdList = getChildrenTaskIdList(taskId); | ||||||
|  |             if (CollUtil.isNotEmpty(childrenTaskIdList)) { | ||||||
|  |                 for (String childTaskId : childrenTaskIdList) { | ||||||
|  |                     // 1.5 将子任务ID入栈,以便后续处理 | ||||||
|  |                     stack.push(childTaskId); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             count++; | ||||||
|  |         } | ||||||
|         return allChildTaskIds; |         return allChildTaskIds; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /** |  | ||||||
|      * 递归处理子级任务 |  | ||||||
|      * |  | ||||||
|      * @param taskId  当前任务ID |  | ||||||
|      * @param taskIds 结果 |  | ||||||
|      */ |  | ||||||
|     private void recursiveGetChildTaskIds(String taskId, List<String> taskIds) { |  | ||||||
|         List<String> childrenTaskIdList = getChildrenTaskIdList(taskId); |  | ||||||
|         for (String childTaskId : childrenTaskIdList) { |  | ||||||
|             taskIds.add(childTaskId); // 将子任务的ID添加到集合中 |  | ||||||
|             recursiveGetChildTaskIds(childTaskId, taskIds); // 递归获取子任务的子任务 |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // TODO @海:一般情况下,除非对性能特别有要求,才只查询 ID_ 单字段;一般层级不多,数据量不大;其实整查就好啦,无非是带宽稍微浪费电,但是基本看不出啥性能差距; |  | ||||||
|     /** |     /** | ||||||
|      * 获取指定父级任务的所有子任务 ID 集合 |      * 获取指定父级任务的所有子任务 ID 集合 | ||||||
|      * |      * | ||||||
| @ -916,38 +928,43 @@ public class BpmTaskServiceImpl implements BpmTaskService { | |||||||
|      * @return 所有子任务的 ID 集合 |      * @return 所有子任务的 ID 集合 | ||||||
|      */ |      */ | ||||||
|     private List<String> getChildrenTaskIdList(String parentTaskId) { |     private List<String> getChildrenTaskIdList(String parentTaskId) { | ||||||
|         String tableName = managementService.getTableName(TaskEntity.class); |         return convertList(getChildrenTaskList0(parentTaskId), Task::getId); | ||||||
|         String sql = "select ID_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}"; |  | ||||||
|         List<Task> childrenTaskList = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list(); |  | ||||||
|         return convertList(childrenTaskList, Task::getId); |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * 获取指定父级任务的所有子任务 ID 集合 | ||||||
|  |      * | ||||||
|  |      * @param parentTaskId 父任务 ID | ||||||
|  |      * @return 所有子任务的 ID 集合 | ||||||
|  |      */ | ||||||
|  |     private List<Task> getChildrenTaskList0(String parentTaskId) { | ||||||
|  |         String tableName = managementService.getTableName(TaskEntity.class); | ||||||
|  |         // taskService.createTaskQuery() 没有 parentId 参数,所以写 sql 查询 | ||||||
|  |         String sql = "select ID_,OWNER_,ASSIGNEE_ from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}"; | ||||||
|  |         return taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).list(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|     @Override |     @Override | ||||||
|     public List<BpmTaskSubSignRespVO> getChildrenTaskList(String taskId) { |     public List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId) { | ||||||
|         // 1. 只查询进行中的任务 |         // 1. 只查询进行中的任务 后加签的任务,可能不存在 assignee,所以还需要查询 owner | ||||||
|         List<String> childrenTaskIdList = getChildrenTaskIdList(taskId); |         List<Task> taskList = getChildrenTaskList0(parentId); | ||||||
|         if (CollUtil.isEmpty(childrenTaskIdList)) { |         if (CollUtil.isEmpty(taskList)) { | ||||||
|             return Collections.emptyList(); |             return Collections.emptyList(); | ||||||
|         } |         } | ||||||
|         // TODO @海:bpmTaskExtDOList 可以改成 taskExtList;因为当前已经在 bpm 模块,不用前缀;然后,DO 一般情况下不用带; |         List<String> childrenTaskIdList = convertList(taskList, Task::getId); | ||||||
|         List<BpmTaskExtDO> bpmTaskExtDOList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList); |  | ||||||
|  |  | ||||||
|         // 2. 后加签的任务,可能不存在 assignee,所以还需要查询 owner |  | ||||||
|         // TODO @海:1. 和 2. 是不是有点重复哈;1. 先查询到了子节点,然后返回了 ids 集合;然后又去 in 查询了一次。。。。按道理,taskService 查询 taskList 就完事? |  | ||||||
|         List<Task> taskList = taskService.createTaskQuery().taskIds(childrenTaskIdList).list(); |  | ||||||
|         Map<String, Task> idTaskMap = convertMap(taskList, TaskInfo::getId); |  | ||||||
|  |  | ||||||
|         // 3. 将 owner 和 assignee 统一到一个集合中 |         // 2. 将 owner 和 assignee 统一到一个集合中 | ||||||
|         // TODO @海:下面 userId 的获取,可以考虑抽个小方法; |         List<Long> userIds = convertListByMultiAttr(taskList,control -> | ||||||
|         List<Long> userIds = taskList.stream() |                 Stream.of(NumberUtils.parseLong(control.getAssignee()), NumberUtils.parseLong(control.getOwner())) | ||||||
|                 .flatMap(control -> |                         .filter(Objects::nonNull)); | ||||||
|                         Stream.of(control.getAssignee(), control.getOwner()) |  | ||||||
|                                 .filter(Objects::nonNull)) |         // 3. 组装数据 | ||||||
|                 .distinct() |  | ||||||
|                 .map(NumberUtils::parseLong) |  | ||||||
|                 .collect(Collectors.toList()); |  | ||||||
|         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); |         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds); | ||||||
|         return BpmTaskConvert.INSTANCE.convertList(bpmTaskExtDOList, userMap, idTaskMap); |         List<BpmTaskExtDO> taskExtList = taskExtMapper.selectProcessListByTaskIds(childrenTaskIdList); | ||||||
|  |         Map<String, Task> idTaskMap = convertMap(taskList, TaskInfo::getId); | ||||||
|  |         return BpmTaskConvert.INSTANCE.convertList(taskExtList, userMap, idTaskMap); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 芋道源码
					芋道源码