Explorar el Código

BPM:调整抄送逻辑的实现,改成审批通过、不通过时,可选择抄送

YunaiV hace 1 año
padre
commit
ba502fc528
Se han modificado 17 ficheros con 315 adiciones y 762 borrados
  1. 13 9
      yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java
  2. 27 25
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java
  3. 4 49
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
  4. 40 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java
  5. 0 20
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyCreateReqVO.java
  6. 0 45
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageItemRespVO.java
  7. 1 4
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java
  8. 5 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
  9. 0 40
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/cc/BpmProcessInstanceCopyConvert.java
  10. 80 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
  11. 8 15
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java
  12. 3 3
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java
  13. 12 9
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java
  14. 83 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java
  15. 39 32
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
  16. 0 71
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java
  17. 0 439
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/dto/BpmDelegateExecutionDTO.java

+ 13 - 9
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java

@@ -4,25 +4,29 @@ import lombok.AllArgsConstructor;
 import lombok.Getter;
 
 /**
- * 流程任务 -- comment类型枚举
+ * 流程任务的 Comment 评论类型枚举
+ *
+ * @author kehaiyou
  */
 @Getter
 @AllArgsConstructor
 public enum BpmCommentTypeEnum {
 
-    APPROVE(1, "通过", ""),
-    REJECT(2, "不通过", ""),
-    CANCEL(3, "已取消", ""),
-    BACK(4, "退回", ""),
-    DELEGATE(5, "委派", ""),
-    ADD_SIGN(6, "加签", "[{}]{}给了[{}],理由为:{}"),
-    SUB_SIGN(7, "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"),
+    APPROVE("1", "审批通过", ""), // 理由:直接使用用户的评论
+    REJECT("2", "不通过", ""),
+    CANCEL("3", "已取消", ""),
+    BACK("4", "退回", ""),
+    DELEGATE("5", "委派", ""),
+    ADD_SIGN("6", "加签", "[{}]{}给了[{}],理由为:{}"),
+    SUB_SIGN("7", "减签", "[{}]操作了【减签】,审批人[{}]的任务被取消"),
     ;
 
     /**
      * 操作类型
+     *
+     * 由于 BPM Comment 类型为 String,所以这里就不使用 Integer
      */
-    private final Integer type;
+    private final String type;
     /**
      * 操作名字
      */

+ 27 - 25
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java

@@ -3,23 +3,27 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task;
 import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageItemRespVO;
-import cn.iocoder.yudao.module.bpm.convert.cc.BpmProcessInstanceCopyConvert;
+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.object.BeanUtils;
+import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc.BpmProcessInstanceCopyRespVO;
+import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
+import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceCopyService;
 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
-import cn.iocoder.yudao.module.bpm.service.task.cc.BpmProcessInstanceCopyService;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.annotation.Resource;
 import jakarta.validation.Valid;
+import org.flowable.engine.history.HistoricProcessInstance;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import java.util.Map;
 import java.util.stream.Stream;
@@ -31,35 +35,27 @@ import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUti
 
 @Tag(name = "管理后台 - 流程实例抄送")
 @RestController
-@RequestMapping("/bpm/process-instance/cc")
+@RequestMapping("/bpm/process-instance/copy")
 @Validated
 public class BpmProcessInstanceCopyController {
 
     @Resource
     private BpmProcessInstanceCopyService processInstanceCopyService;
     @Resource
-    private BpmProcessInstanceService bpmProcessInstanceService;
-
-    @Resource
-    private AdminUserApi adminUserApi;
-
+    private BpmProcessInstanceService processInstanceService;
     @Resource
     private BpmTaskService bpmTaskService;
 
-    @PostMapping("/create")
-    @Operation(summary = "抄送流程")
-    @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:create')")
-    public CommonResult<Boolean> createProcessInstanceCopy(@Valid @RequestBody BpmProcessInstanceCopyCreateReqVO createReqVO) {
-        processInstanceCopyService.createProcessInstanceCopy(getLoginUserId(), createReqVO);
-        return success(true);
-    }
+    @Resource
+    private AdminUserApi adminUserApi;
 
-    @GetMapping("/my-page")
+    @GetMapping("/page")
     @Operation(summary = "获得抄送流程分页列表")
     @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:query')")
-    public CommonResult<PageResult<BpmProcessInstanceCopyPageItemRespVO>> getProcessInstanceCopyPage(
-            @Valid BpmProcessInstanceCopyMyPageReqVO pageReqVO) {
-        PageResult<BpmProcessInstanceCopyDO> pageResult = processInstanceCopyService.getMyProcessInstanceCopyPage(getLoginUserId(), pageReqVO);
+    public CommonResult<PageResult<BpmProcessInstanceCopyRespVO>> getProcessInstanceCopyPage(
+            @Valid BpmProcessInstanceCopyPageReqVO pageReqVO) {
+        PageResult<BpmProcessInstanceCopyDO> pageResult = processInstanceCopyService.getProcessInstanceCopyPage(
+                getLoginUserId(), pageReqVO);
         if (CollUtil.isEmpty(pageResult.getList())) {
             return success(new PageResult<>(pageResult.getTotal()));
         }
@@ -67,11 +63,17 @@ public class BpmProcessInstanceCopyController {
         // 拼接返回
         Map<String, String> taskNameMap = bpmTaskService.getTaskNameByTaskIds(
                 convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getTaskId));
-        Map<String, String> processNameMap = bpmProcessInstanceService.getProcessInstanceNameMap(
+        Map<String, HistoricProcessInstance> processInstanceMap = processInstanceService.getHistoricProcessInstanceMap(
                 convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessInstanceId));
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(),
                 copy -> Stream.of(copy.getStartUserId(), Long.parseLong(copy.getCreator()))));
-        return success(BpmProcessInstanceCopyConvert.INSTANCE.convertPage(pageResult, taskNameMap, processNameMap, userMap));
+        return success(BeanUtils.toBean(pageResult, BpmProcessInstanceCopyRespVO.class, copyVO -> {
+            MapUtils.findAndThen(userMap, Long.valueOf(copyVO.getCreator()), user -> copyVO.setCreatorName(user.getNickname()));
+            MapUtils.findAndThen(userMap, copyVO.getStartUserId(), user -> copyVO.setStartUserName(user.getNickname()));
+            MapUtils.findAndThen(taskNameMap, copyVO.getTaskId(), copyVO::setTaskName);
+            MapUtils.findAndThen(processInstanceMap, copyVO.getProcessInstanceId(),
+                    processInstance -> copyVO.setProcessInstanceStartTime(DateUtils.of(processInstance.getStartTime())));
+        }));
     }
 
 }

+ 4 - 49
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java

@@ -1,15 +1,13 @@
 package cn.iocoder.yudao.module.bpm.controller.admin.task;
 
 import cn.hutool.core.collection.CollUtil;
-import cn.hutool.core.util.StrUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO;
 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
-import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants;
+import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
@@ -66,15 +64,7 @@ public class BpmTaskController {
                 convertSet(pageResult.getList(), Task::getProcessInstanceId));
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                 convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
-        return success(BeanUtils.toBean(pageResult, BpmTaskRespVO.class, taskVO -> {
-            ProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId());
-            if (processInstance == null) {
-                return;
-            }
-            AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
-            taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class,
-                    processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class))));
-        }));
+        return success(BpmTaskConvert.INSTANCE.buildTodoTaskPage(pageResult, processInstanceMap, userMap));
     }
 
     @GetMapping("done-page")
@@ -87,18 +77,9 @@ public class BpmTaskController {
                 convertSet(pageResult.getList(), HistoricTaskInstance::getProcessInstanceId));
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                 convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
-        return success(BeanUtils.toBean(pageResult, BpmTaskRespVO.class, taskVO -> {
-            HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId());
-            if (processInstance == null) {
-                return;
-            }
-            AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
-            taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class,
-                    processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class))));
-        }));
+        return success(BpmTaskConvert.INSTANCE.buildDoneTaskPage(pageResult, processInstanceMap, userMap));
     }
 
-    // TODO @芋艿:怎么优化下
     @GetMapping("/list-by-process-instance-id")
     @Operation(summary = "获得指定流程实例的任务列表", description = "包括完成的、未完成的")
     @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true)
@@ -118,33 +99,7 @@ public class BpmTaskController {
         Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(userIds);
         Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(
                 convertSet(userMap.values(), AdminUserRespDTO::getDeptId));
-        List<BpmTaskRespVO> taskVOList = CollectionUtils.convertList(taskList, task -> {
-            BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class);
-            taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS));
-            // 流程实例
-            AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
-            taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class,
-                    processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class))));
-            // 用户信息
-            AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee()));
-            if (assignUser != null) {
-                taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class));
-                DeptRespDTO dept = deptMap.get(assignUser.getDeptId());
-                if (dept != null) {
-                    taskVO.getAssigneeUser().setDeptName(dept.getName());
-                }
-            }
-            return taskVO;
-        });
-
-        // 拼接父子关系
-        Map<String, List<BpmTaskRespVO>> childrenTaskMap = convertMultiMap(
-                filterList(taskVOList, r -> StrUtil.isNotEmpty(r.getParentTaskId())),
-                BpmTaskRespVO::getParentTaskId);
-        for (BpmTaskRespVO taskVO : taskVOList) {
-            taskVO.setChildren(childrenTaskMap.get(taskVO.getId()));
-        }
-        return success(filterList(taskVOList, r -> StrUtil.isEmpty(r.getParentTaskId())));
+        return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, processInstance, userMap, deptMap));
     }
 
     @PutMapping("/approve")

+ 40 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/cc/BpmProcessInstanceCopyRespVO.java

@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.cc;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 流程实例抄送的分页 Item Response VO")
+@Data
+public class BpmProcessInstanceCopyRespVO {
+
+    @Schema(description = "抄送主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long id;
+
+    @Schema(description = "发起人编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888")
+    private Long startUserId;
+    @Schema(description = "发起人昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
+    private String startUserName;
+
+    @Schema(description = "流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "A233")
+    private String processInstanceId;
+    @Schema(description = "流程实例的名称")
+    private String processInstanceName;
+    @Schema(description = "流程实例的发起时间")
+    private LocalDateTime processInstanceStartTime;
+
+    @Schema(description = "发起抄送的任务编号")
+    private String taskId;
+    @Schema(description = "发起抄送的任务名称")
+    private String taskName;
+
+    @Schema(description = "抄送人")
+    private String creator;
+    @Schema(description = "抄送人昵称")
+    private String creatorName;
+
+    @Schema(description = "抄送时间")
+    private LocalDateTime createTime;
+
+}

+ 0 - 20
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyCreateReqVO.java

@@ -1,20 +0,0 @@
-package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotEmpty;
-import lombok.Data;
-
-@Schema(description = "管理后台 - 流程实例抄送的创建 Request VO")
-@Data
-public class BpmProcessInstanceCopyCreateReqVO {
-
-    @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    @NotEmpty(message = "任务编号不能为空")
-    private String taskId;
-
-    @Schema(description = "抄送原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "请帮忙审查下!")
-    @NotBlank(message = "抄送原因不能为空")
-    private String reason;
-
-}

+ 0 - 45
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageItemRespVO.java

@@ -1,45 +0,0 @@
-package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance;
-
-import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.Data;
-
-import java.time.LocalDateTime;
-
-@Schema(description = "管理后台 - 流程实例抄送的分页 Item Response VO")
-@Data
-public class BpmProcessInstanceCopyPageItemRespVO {
-
-    @Schema(description = "抄送主键")
-    private Long id;
-
-    @Schema(description = "发起人 ID")
-    private Long startUserId;
-
-    @Schema(description = "发起人别名")
-    private String startUserNickname;
-
-    @Schema(description = "流程实例的主键")
-    private String processInstanceId;
-
-    @Schema(description = "流程实例的名称")
-    private String processInstanceName;
-
-    @Schema(description = "发起抄送的任务编号")
-    private String taskId;
-
-    @Schema(description = "发起抄送的任务名称")
-    private String taskName;
-
-    @Schema(description = "抄送原因")
-    private String reason;
-
-    @Schema(description = "抄送人")
-    private String creator;
-
-    @Schema(description = "抄送人别名")
-    private String creatorNickname;
-
-    @Schema(description = "抄送时间")
-    private LocalDateTime createTime;
-
-}

+ 1 - 4
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyMyPageReqVO.java → yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageReqVO.java

@@ -15,14 +15,11 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
-public class BpmProcessInstanceCopyMyPageReqVO extends PageParam {
+public class BpmProcessInstanceCopyPageReqVO extends PageParam {
 
     @Schema(description = "流程名称", example = "芋道")
     private String processInstanceName;
 
-    @Schema(description = "流程编号", example = "123456768")
-    private String processInstanceId;
-
     @Schema(description = "创建时间")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;

+ 5 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java

@@ -1,9 +1,10 @@
 package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
 
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
 import lombok.Data;
 
-import jakarta.validation.constraints.NotEmpty;
+import java.util.Collection;
 
 @Schema(description = "管理后台 - 通过流程任务的 Request VO")
 @Data
@@ -17,4 +18,7 @@ public class BpmTaskApproveReqVO {
     @NotEmpty(message = "审批意见不能为空")
     private String reason;
 
+    @Schema(description = "抄送的用户编号数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "1,2")
+    private Collection<Long> copyUserIds;
+
 }

+ 0 - 40
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/cc/BpmProcessInstanceCopyConvert.java

@@ -1,40 +0,0 @@
-package cn.iocoder.yudao.module.bpm.convert.cc;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageItemRespVO;
-import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
-import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-import java.util.List;
-import java.util.Map;
-
-/**
- * 流程抄送 Convert
- *
- * @author 芋艿
- */
-@Mapper
-public interface BpmProcessInstanceCopyConvert {
-
-    BpmProcessInstanceCopyConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceCopyConvert.class);
-
-    default PageResult<BpmProcessInstanceCopyPageItemRespVO> convertPage(PageResult<BpmProcessInstanceCopyDO> page,
-                                                                         Map<String, String> taskNameMap,
-                                                                         Map<String, String> processInstaneNameMap,
-                                                                         Map<Long, AdminUserRespDTO> userMap) {
-        List<BpmProcessInstanceCopyPageItemRespVO> list = BeanUtils.toBean(page.getList(),
-                BpmProcessInstanceCopyPageItemRespVO.class,
-                copy -> {
-                    MapUtils.findAndThen(userMap, Long.valueOf(copy.getCreator()), user -> user.setNickname(user.getNickname()));
-                    MapUtils.findAndThen(userMap, copy.getStartUserId(), user -> copy.setStartUserNickname(user.getNickname()));
-                    MapUtils.findAndThen(taskNameMap, copy.getTaskId(), copy::setTaskName);
-                    MapUtils.findAndThen(processInstaneNameMap, copy.getProcessInstanceId(), copy::setProcessInstanceName);
-                });
-        return new PageResult<>(list, page.getTotal());
-    }
-
-}

+ 80 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java

@@ -1,16 +1,31 @@
 package cn.iocoder.yudao.module.bpm.convert.task;
 
+import cn.hutool.core.util.StrUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 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.object.BeanUtils;
+import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO;
+import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
+import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmConstants;
 import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenTaskCreatedReqDTO;
+import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import org.flowable.engine.history.HistoricProcessInstance;
 import org.flowable.engine.runtime.ProcessInstance;
 import org.flowable.task.api.Task;
+import org.flowable.task.api.history.HistoricTaskInstance;
 import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
 import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList;
 
 /**
  * Bpm 任务 Convert
@@ -22,6 +37,71 @@ public interface BpmTaskConvert {
 
     BpmTaskConvert INSTANCE = Mappers.getMapper(BpmTaskConvert.class);
 
+    default PageResult<BpmTaskRespVO> buildTodoTaskPage(PageResult<Task> pageResult,
+                                                        Map<String, ProcessInstance> processInstanceMap,
+                                                        Map<Long, AdminUserRespDTO> userMap) {
+        return BeanUtils.toBean(pageResult, BpmTaskRespVO.class, taskVO -> {
+            ProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId());
+            if (processInstance == null) {
+                return;
+            }
+            AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
+            taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class,
+                    processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class))));
+        });
+    }
+
+    default PageResult<BpmTaskRespVO> buildDoneTaskPage(PageResult<HistoricTaskInstance> pageResult,
+                                                        Map<String, HistoricProcessInstance> processInstanceMap,
+                                                        Map<Long, AdminUserRespDTO> userMap) {
+        List<BpmTaskRespVO> taskVOList = CollectionUtils.convertList(pageResult.getList(), task -> {
+            BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class);
+            taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS));
+            // 流程实例
+            HistoricProcessInstance processInstance = processInstanceMap.get(taskVO.getProcessInstanceId());
+            if (processInstance != null) {
+                AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
+                taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class,
+                        processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class))));
+            }
+            return taskVO;
+        });
+        return new PageResult<>(taskVOList, pageResult.getTotal());
+    }
+
+    default List<BpmTaskRespVO> buildTaskListByProcessInstanceId(List<HistoricTaskInstance> taskList,
+                                                                 HistoricProcessInstance processInstance,
+                                                                 Map<Long, AdminUserRespDTO> userMap,
+                                                                 Map<Long, DeptRespDTO> deptMap) {
+        List<BpmTaskRespVO> taskVOList = CollectionUtils.convertList(taskList, task -> {
+            BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class);
+            taskVO.setStatus((Integer) task.getTaskLocalVariables().get(BpmConstants.TASK_VARIABLE_STATUS));
+            // 流程实例
+            AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
+            taskVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmTaskRespVO.ProcessInstance.class,
+                    processInstanceVO -> processInstanceVO.setStartUser(BeanUtils.toBean(startUser, BpmProcessInstanceRespVO.User.class))));
+            // 用户信息
+            AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee()));
+            if (assignUser != null) {
+                taskVO.setAssigneeUser(BeanUtils.toBean(assignUser, BpmProcessInstanceRespVO.User.class));
+                DeptRespDTO dept = deptMap.get(assignUser.getDeptId());
+                if (dept != null) {
+                    taskVO.getAssigneeUser().setDeptName(dept.getName());
+                }
+            }
+            return taskVO;
+        });
+
+        // 拼接父子关系
+        Map<String, List<BpmTaskRespVO>> childrenTaskMap = convertMultiMap(
+                filterList(taskVOList, r -> StrUtil.isNotEmpty(r.getParentTaskId())),
+                BpmTaskRespVO::getParentTaskId);
+        for (BpmTaskRespVO taskVO : taskVOList) {
+            taskVO.setChildren(childrenTaskMap.get(taskVO.getId()));
+        }
+        return filterList(taskVOList, r -> StrUtil.isEmpty(r.getParentTaskId()));
+    }
+
     default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser,
                                                         Task task) {
         BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO();

+ 8 - 15
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java

@@ -29,7 +29,7 @@ public class BpmProcessInstanceCopyDO extends BaseDO {
     /**
      * 发起人 Id
      *
-     * 关联 system_users 的 id 属性
+     * 冗余 ProcessInstance 的 startUserId 字段
      */
     private Long startUserId;
     /**
@@ -44,6 +44,12 @@ public class BpmProcessInstanceCopyDO extends BaseDO {
      * 关联 ProcessInstance 的 id 属性
      */
     private String processInstanceId;
+    /**
+     * 流程分类
+     *
+     * 冗余 ProcessInstance 的 category 字段
+     */
+    private String category;
 
     /**
      * 任务主键
@@ -51,7 +57,6 @@ public class BpmProcessInstanceCopyDO extends BaseDO {
      * 关联 Task 的 id 属性
      */
     private String taskId;
-
     /**
      * 任务名称
      *
@@ -60,22 +65,10 @@ public class BpmProcessInstanceCopyDO extends BaseDO {
     private String taskName;
 
     /**
-     * 用户编号
+     * 用户编号(被抄送的用户编号)
      *
      * 关联 system_users 的 id 属性
      */
     private Long userId;
 
-    /**
-     * 抄送原因
-     */
-    private String reason;
-
-    /**
-     * 流程分类
-     *
-     * 冗余 ProcessInstance 的 category 字段
-     */
-    private String category;
-
 }

+ 3 - 3
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java

@@ -3,19 +3,19 @@ package cn.iocoder.yudao.module.bpm.dal.mysql.cc;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO;
+import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
 public interface BpmProcessInstanceCopyMapper extends BaseMapperX<BpmProcessInstanceCopyDO> {
 
-    default PageResult<BpmProcessInstanceCopyDO> selectPage(Long loginUserId, BpmProcessInstanceCopyMyPageReqVO reqVO) {
+    default PageResult<BpmProcessInstanceCopyDO> selectPage(Long loginUserId, BpmProcessInstanceCopyPageReqVO reqVO) {
         return selectPage(reqVO, new LambdaQueryWrapperX<BpmProcessInstanceCopyDO>()
                 .eqIfPresent(BpmProcessInstanceCopyDO::getUserId, loginUserId)
-                .eqIfPresent(BpmProcessInstanceCopyDO::getProcessInstanceId, reqVO.getProcessInstanceId())
                 .likeIfPresent(BpmProcessInstanceCopyDO::getProcessInstanceName, reqVO.getProcessInstanceName())
                 .betweenIfPresent(BpmProcessInstanceCopyDO::getCreateTime, reqVO.getCreateTime())
                 .orderByDesc(BpmProcessInstanceCopyDO::getId));
     }
+
 }

+ 12 - 9
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java → yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyService.java

@@ -1,10 +1,11 @@
-package cn.iocoder.yudao.module.bpm.service.task.cc;
+package cn.iocoder.yudao.module.bpm.service.task;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO;
+import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
 
+import java.util.Collection;
+
 /**
  * 流程抄送 Service 接口
  *
@@ -15,17 +16,19 @@ public interface BpmProcessInstanceCopyService {
     /**
      * 流程实例的抄送
      *
-     * @param userId      当前登录用户
-     * @param createReqVO 创建的抄送请求
+     * @param userIds 抄送的用户编号
+     * @param taskId 流程任务编号
      */
-    void createProcessInstanceCopy(Long userId, BpmProcessInstanceCopyCreateReqVO createReqVO);
+    void createProcessInstanceCopy(Collection<Long> userIds, String taskId);
 
     /**
-     * 抄送的流程的分页
+     * 获得抄送的流程的分页
+     *
      * @param userId 当前登录用户
      * @param pageReqVO 分页请求
      * @return 抄送的分页结果
      */
-    PageResult<BpmProcessInstanceCopyDO> getMyProcessInstanceCopyPage(Long userId,
-                                                                      BpmProcessInstanceCopyMyPageReqVO pageReqVO);
+    PageResult<BpmProcessInstanceCopyDO> getProcessInstanceCopyPage(Long userId,
+                                                                    BpmProcessInstanceCopyPageReqVO pageReqVO);
+
 }

+ 83 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceCopyServiceImpl.java

@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.module.bpm.service.task;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyPageReqVO;
+import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
+import cn.iocoder.yudao.module.bpm.dal.mysql.cc.BpmProcessInstanceCopyMapper;
+import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants;
+import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.engine.repository.ProcessDefinition;
+import org.flowable.engine.runtime.ProcessInstance;
+import org.flowable.task.api.Task;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.Collection;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+
+/**
+ * 流程抄送 Service 实现类
+ *
+ * @author kyle
+ */
+@Service
+@Validated
+@Slf4j
+public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopyService {
+
+    @Resource
+    private BpmProcessInstanceCopyMapper processInstanceCopyMapper;
+
+    @Resource
+    @Lazy // 延迟加载,避免循环依赖
+    private BpmTaskService taskService;
+
+    @Resource
+    @Lazy // 延迟加载,避免循环依赖
+    private BpmProcessInstanceService processInstanceService;
+    @Resource
+    @Lazy // 延迟加载,避免循环依赖
+    private BpmProcessDefinitionService processDefinitionService;
+
+    @Override
+    public void createProcessInstanceCopy(Collection<Long> userIds, String taskId) {
+        // 1.1 校验任务存在
+        Task task = taskService.getTask(taskId);
+        if (ObjectUtil.isNull(task)) {
+            throw exception(ErrorCodeConstants.TASK_NOT_EXISTS);
+        }
+        // 1.2 校验流程实例存在
+        String processInstanceId = task.getProcessInstanceId();
+        ProcessInstance processInstance = processInstanceService.getProcessInstance(processInstanceId);
+        if (processInstance == null) {
+            throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS);
+        }
+        // 1.3 校验流程定义存在
+        ProcessDefinition processDefinition = processDefinitionService.getProcessDefinition(
+                processInstance.getProcessDefinitionId());
+        if (processDefinition == null) {
+            throw exception(ErrorCodeConstants.PROCESS_DEFINITION_NOT_EXISTS);
+        }
+
+        // 2. 创建抄送流程
+        List<BpmProcessInstanceCopyDO> copyList = convertList(userIds, userId -> new BpmProcessInstanceCopyDO()
+                .setUserId(userId).setStartUserId(Long.valueOf(processInstance.getStartUserId()))
+                .setProcessInstanceId(processInstanceId).setProcessInstanceName(processInstance.getName())
+                .setCategory(processDefinition.getCategory()).setTaskId(taskId).setTaskName(task.getName()));
+        processInstanceCopyMapper.insertBatch(copyList);
+    }
+
+    @Override
+    public PageResult<BpmProcessInstanceCopyDO> getProcessInstanceCopyPage(Long userId,
+                                                                           BpmProcessInstanceCopyPageReqVO pageReqVO) {
+        return processInstanceCopyMapper.selectPage(userId, pageReqVO);
+    }
+
+}

+ 39 - 32
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java

@@ -68,10 +68,14 @@ public class BpmTaskServiceImpl implements BpmTaskService {
     private HistoryService historyService;
     @Resource
     private RuntimeService runtimeService;
+    @Resource
+    private ManagementService managementService;
 
     @Resource
     private BpmProcessInstanceService processInstanceService;
     @Resource
+    private BpmProcessInstanceCopyService processInstanceCopyService;
+    @Resource
     private BpmModelService bpmModelService;
     @Resource
     private BpmMessageService messageService;
@@ -79,12 +83,12 @@ public class BpmTaskServiceImpl implements BpmTaskService {
     @Resource
     private AdminUserApi adminUserApi;
 
-    @Resource
-    private ManagementService managementService;
-
     @Override
     public PageResult<Task> getTodoTaskPage(Long userId, BpmTaskPageReqVO pageVO) {
-        TaskQuery taskQuery = taskService.createTaskQuery().taskAssignee(String.valueOf(userId)) // 分配给自己
+        TaskQuery taskQuery = taskService.createTaskQuery()
+                .taskAssignee(String.valueOf(userId)) // 分配给自己
+                .active()
+                .includeProcessVariables()
                 .orderByTaskCreateTime().desc(); // 创建时间倒序
         if (StrUtil.isNotBlank(pageVO.getName())) {
             taskQuery.taskNameLike("%" + pageVO.getName() + "%");
@@ -103,9 +107,10 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 
     @Override
     public PageResult<HistoricTaskInstance> getDoneTaskPage(Long userId, BpmTaskPageReqVO pageVO) {
-        HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery().finished() // 已完成
-                .includeTaskLocalVariables()
+        HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery()
+                .finished() // 已完成
                 .taskAssignee(String.valueOf(userId)) // 分配给自己
+                .includeTaskLocalVariables()
                 .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序
         if (StrUtil.isNotBlank(pageVO.getName())) {
             taskQuery.taskNameLike("%" + pageVO.getName() + "%");
@@ -155,30 +160,34 @@ public class BpmTaskServiceImpl implements BpmTaskService {
             throw exception(PROCESS_INSTANCE_NOT_EXISTS);
         }
 
+        // 2. 抄送用户
+        if (CollUtil.isNotEmpty(reqVO.getCopyUserIds())) {
+            processInstanceCopyService.createProcessInstanceCopy(reqVO.getCopyUserIds(), reqVO.getId());
+        }
+
         // 情况一:被委派的任务,不调用 complete 去完成任务
         if (DelegationState.PENDING.equals(task.getDelegationState())) {
             approveDelegateTask(reqVO, task);
             return;
         }
 
-        // 情况二:后加签的任务
+        // 情况二:审批有【加签的任务
         if (BpmTaskAddSignTypeEnum.AFTER.getType().equals(task.getScopeType())) {
-            // 后加签处理
             approveAfterSignTask(task, reqVO);
             return;
         }
 
-        // 情况三:自己审批的任务,调用 complete 去完成任务
-        // 完成任务,审批通过
+        // 情况三:审批普通的任务。大多数情况下,都是这样
+        // 更新流程任务 status 为审批通过
         updateTaskStatus(task.getId(), BpmProcessInstanceResultEnum.APPROVE.getResult());
+        // 添加评论
+        taskService.addComment(task.getId(), task.getProcessInstanceId(),
+                BpmCommentTypeEnum.APPROVE.getType(), reqVO.getReason());
+        // 调用 BPM complete 去完成任务
         taskService.complete(task.getId(), instance.getProcessVariables());
-//        // 更新任务拓展表为通过
-//        taskExtMapper.updateByTaskId(
-//                new BpmTaskExtDO().setTaskId(task.getId()).setResult(BpmProcessInstanceResultEnum.APPROVE.getResult())
-//                        .setReason(reqVO.getReason()));
+
         // 处理加签任务
-//        handleParentTask(task);
-        handleParentTaskNew(task.getParentTaskId());
+        handleParentTaskIfSign(task.getParentTaskId());
     }
 
     /**
@@ -209,8 +218,15 @@ public class BpmTaskServiceImpl implements BpmTaskService {
 //                new BpmTaskExtDO().setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()));
     }
 
-    // TODO 芋艿:名字
-    private void handleParentTaskNew(String parentTaskId) {
+    /**
+     * 如果父任务是有前后【加签】的任务,如果它【加签】出来的子任务都被处理,需要处理父任务:
+     *
+     * 1. 如果是【向前】加签,则需要重新激活父任务,让它可以被审批
+     * 2. 如果是【向后】加签,则需要完成父任务,让它完成审批
+     *
+     * @param parentTaskId 父任务编号
+     */
+    private void handleParentTaskIfSign(String parentTaskId) {
         if (StrUtil.isBlank(parentTaskId)) {
             return;
         }
@@ -227,7 +243,9 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         }
 
         // 2. 子任务已处理完成,清空 scopeType 字段,修改 parentTask 信息,方便后续可以继续向前后向后加签
-        clearTaskScopeTypeAndSave(parentTask);
+        TaskEntityImpl parentTaskImpl = (TaskEntityImpl) parentTask;
+        parentTaskImpl.setScopeType(null);
+        taskService.saveTask(parentTaskImpl);
 
         // 3.1 情况一:处理向【向前】加签
         if (BpmTaskAddSignTypeEnum.BEFORE.getType().equals(scopeType)) {
@@ -243,18 +261,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         }
 
         // 4. 递归处理父任务
-        handleParentTaskNew(parentTask.getParentTaskId());
-    }
-
-    /**
-     * 清空 scopeType 字段,用于任务没有子任务时使用该方法,方便任务可以再次被不同的方式加签
-     *
-     * @param task 需要被清空的任务
-     */
-    private void clearTaskScopeTypeAndSave(Task task) {
-        TaskEntityImpl taskImpl = (TaskEntityImpl) task;
-        taskImpl.setScopeType(null);
-        taskService.saveTask(task);
+        handleParentTaskIfSign(parentTask.getParentTaskId());
     }
 
     /**
@@ -797,7 +804,7 @@ public class BpmTaskServiceImpl implements BpmTaskService {
                 BpmCommentTypeEnum.SUB_SIGN.getType().toString(), comment);
 
         // 4. 处理当前任务的父任务
-        handleParentTaskNew(task.getParentTaskId());
+        handleParentTaskIfSign(task.getParentTaskId());
     }
 
     /**

+ 0 - 71
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java

@@ -1,71 +0,0 @@
-package cn.iocoder.yudao.module.bpm.service.task.cc;
-
-import cn.hutool.core.util.ObjectUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyCreateReqVO;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO;
-import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
-import cn.iocoder.yudao.module.bpm.dal.mysql.cc.BpmProcessInstanceCopyMapper;
-import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants;
-import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
-import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.flowable.task.api.Task;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-
-/**
- * 流程抄送 Service 实现类
- *
- * @author kyle
- */
-@Service
-@Validated
-@Slf4j
-public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopyService {
-
-    @Resource
-    private BpmProcessInstanceCopyMapper processInstanceCopyMapper;
-
-    @Resource
-    @Lazy
-    private BpmTaskService bpmTaskService;
-    @Resource
-    @Lazy
-    private BpmProcessInstanceService bpmProcessInstanceService;
-
-    @Override
-    public void createProcessInstanceCopy(Long userId, BpmProcessInstanceCopyCreateReqVO reqVO) {
-        // 1.1 校验任务存在
-        Task task = bpmTaskService.getTask(reqVO.getTaskId());
-        if (ObjectUtil.isNull(task)) {
-            throw exception(ErrorCodeConstants.TASK_NOT_EXISTS);
-        }
-        // 1.2 校验流程存在
-        String processInstanceId = task.getProcessInstanceId();
-        ProcessInstance processInstance = bpmProcessInstanceService.getProcessInstance(processInstanceId);
-        if (processInstance == null) {
-            log.warn("[createProcessInstanceCopy][任务({}) 对应的流程不存在]", reqVO.getTaskId());
-            throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS);
-        }
-
-        // 2. 创建抄送流程
-        BpmProcessInstanceCopyDO copy = new BpmProcessInstanceCopyDO()
-                .setTaskId(reqVO.getTaskId()).setTaskName(task.getName())
-                .setProcessInstanceId(processInstanceId).setStartUserId(Long.valueOf(processInstance.getStartUserId()))
-                .setProcessInstanceName(processInstance.getName()).setCategory(processInstance.getProcessDefinitionCategory())
-                .setReason(reqVO.getReason());
-        processInstanceCopyMapper.insert(copy);
-    }
-
-    @Override
-    public PageResult<BpmProcessInstanceCopyDO> getMyProcessInstanceCopyPage(Long userId, BpmProcessInstanceCopyMyPageReqVO pageReqVO) {
-        return processInstanceCopyMapper.selectPage(userId, pageReqVO);
-    }
-
-}

+ 0 - 439
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/dto/BpmDelegateExecutionDTO.java

@@ -1,439 +0,0 @@
-package cn.iocoder.yudao.module.bpm.service.task.cc.dto;
-
-import org.flowable.bpmn.model.FlowElement;
-import org.flowable.bpmn.model.FlowableListener;
-import org.flowable.engine.delegate.DelegateExecution;
-import org.flowable.engine.delegate.ReadOnlyDelegateExecution;
-import org.flowable.variable.api.persistence.entity.VariableInstance;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * 仅为了传输processInstanceId
- */
-public class BpmDelegateExecutionDTO implements DelegateExecution {
-
-    public BpmDelegateExecutionDTO(String getProcessInstanceId) {
-        this.getProcessInstanceId = getProcessInstanceId;
-    }
-
-    private final String getProcessInstanceId;
-
-    @Override
-    public String getId() {
-        return null;
-    }
-
-    @Override
-    public String getProcessInstanceId() {
-        return null;
-    }
-
-    @Override
-    public String getRootProcessInstanceId() {
-        return null;
-    }
-
-    @Override
-    public String getEventName() {
-        return null;
-    }
-
-    @Override
-    public void setEventName(String eventName) {
-
-    }
-
-    @Override
-    public String getProcessInstanceBusinessKey() {
-        return null;
-    }
-
-    @Override
-    public String getProcessInstanceBusinessStatus() {
-        return null;
-    }
-
-    @Override
-    public String getProcessDefinitionId() {
-        return null;
-    }
-
-    @Override
-    public String getPropagatedStageInstanceId() {
-        return null;
-    }
-
-    @Override
-    public String getParentId() {
-        return null;
-    }
-
-    @Override
-    public String getSuperExecutionId() {
-        return null;
-    }
-
-    @Override
-    public String getCurrentActivityId() {
-        return null;
-    }
-
-    @Override
-    public String getTenantId() {
-        return null;
-    }
-
-    @Override
-    public FlowElement getCurrentFlowElement() {
-        return null;
-    }
-
-    @Override
-    public void setCurrentFlowElement(FlowElement flowElement) {
-
-    }
-
-    @Override
-    public FlowableListener getCurrentFlowableListener() {
-        return null;
-    }
-
-    @Override
-    public void setCurrentFlowableListener(FlowableListener currentListener) {
-
-    }
-
-    @Override
-    public ReadOnlyDelegateExecution snapshotReadOnly() {
-        return null;
-    }
-
-    @Override
-    public DelegateExecution getParent() {
-        return null;
-    }
-
-    @Override
-    public List<? extends DelegateExecution> getExecutions() {
-        return null;
-    }
-
-    @Override
-    public void setActive(boolean isActive) {
-
-    }
-
-    @Override
-    public boolean isActive() {
-        return false;
-    }
-
-    @Override
-    public boolean isEnded() {
-        return false;
-    }
-
-    @Override
-    public void setConcurrent(boolean isConcurrent) {
-
-    }
-
-    @Override
-    public boolean isConcurrent() {
-        return false;
-    }
-
-    @Override
-    public boolean isProcessInstanceType() {
-        return false;
-    }
-
-    @Override
-    public void inactivate() {
-
-    }
-
-    @Override
-    public boolean isScope() {
-        return false;
-    }
-
-    @Override
-    public void setScope(boolean isScope) {
-
-    }
-
-    @Override
-    public boolean isMultiInstanceRoot() {
-        return false;
-    }
-
-    @Override
-    public void setMultiInstanceRoot(boolean isMultiInstanceRoot) {
-
-    }
-
-    @Override
-    public Map<String, Object> getVariables() {
-        return null;
-    }
-
-    @Override
-    public Map<String, VariableInstance> getVariableInstances() {
-        return null;
-    }
-
-    @Override
-    public Map<String, Object> getVariables(Collection<String> collection) {
-        return null;
-    }
-
-    @Override
-    public Map<String, VariableInstance> getVariableInstances(Collection<String> collection) {
-        return null;
-    }
-
-    @Override
-    public Map<String, Object> getVariables(Collection<String> collection, boolean b) {
-        return null;
-    }
-
-    @Override
-    public Map<String, VariableInstance> getVariableInstances(Collection<String> collection, boolean b) {
-        return null;
-    }
-
-    @Override
-    public Map<String, Object> getVariablesLocal() {
-        return null;
-    }
-
-    @Override
-    public Map<String, VariableInstance> getVariableInstancesLocal() {
-        return null;
-    }
-
-    @Override
-    public Map<String, Object> getVariablesLocal(Collection<String> collection) {
-        return null;
-    }
-
-    @Override
-    public Map<String, VariableInstance> getVariableInstancesLocal(Collection<String> collection) {
-        return null;
-    }
-
-    @Override
-    public Map<String, Object> getVariablesLocal(Collection<String> collection, boolean b) {
-        return null;
-    }
-
-    @Override
-    public Map<String, VariableInstance> getVariableInstancesLocal(Collection<String> collection, boolean b) {
-        return null;
-    }
-
-    @Override
-    public Object getVariable(String s) {
-        return null;
-    }
-
-    @Override
-    public VariableInstance getVariableInstance(String s) {
-        return null;
-    }
-
-    @Override
-    public Object getVariable(String s, boolean b) {
-        return null;
-    }
-
-    @Override
-    public VariableInstance getVariableInstance(String s, boolean b) {
-        return null;
-    }
-
-    @Override
-    public Object getVariableLocal(String s) {
-        return null;
-    }
-
-    @Override
-    public VariableInstance getVariableInstanceLocal(String s) {
-        return null;
-    }
-
-    @Override
-    public Object getVariableLocal(String s, boolean b) {
-        return null;
-    }
-
-    @Override
-    public VariableInstance getVariableInstanceLocal(String s, boolean b) {
-        return null;
-    }
-
-    @Override
-    public <T> T getVariable(String s, Class<T> aClass) {
-        return null;
-    }
-
-    @Override
-    public <T> T getVariableLocal(String s, Class<T> aClass) {
-        return null;
-    }
-
-    @Override
-    public Set<String> getVariableNames() {
-        return null;
-    }
-
-    @Override
-    public Set<String> getVariableNamesLocal() {
-        return null;
-    }
-
-    @Override
-    public void setVariable(String s, Object o) {
-
-    }
-
-    @Override
-    public void setVariable(String s, Object o, boolean b) {
-
-    }
-
-    @Override
-    public Object setVariableLocal(String s, Object o) {
-        return null;
-    }
-
-    @Override
-    public Object setVariableLocal(String s, Object o, boolean b) {
-        return null;
-    }
-
-    @Override
-    public void setVariables(Map<String, ?> map) {
-
-    }
-
-    @Override
-    public void setVariablesLocal(Map<String, ?> map) {
-
-    }
-
-    @Override
-    public boolean hasVariables() {
-        return false;
-    }
-
-    @Override
-    public boolean hasVariablesLocal() {
-        return false;
-    }
-
-    @Override
-    public boolean hasVariable(String s) {
-        return false;
-    }
-
-    @Override
-    public boolean hasVariableLocal(String s) {
-        return false;
-    }
-
-    @Override
-    public void removeVariable(String s) {
-
-    }
-
-    @Override
-    public void removeVariableLocal(String s) {
-
-    }
-
-    @Override
-    public void removeVariables(Collection<String> collection) {
-
-    }
-
-    @Override
-    public void removeVariablesLocal(Collection<String> collection) {
-
-    }
-
-    @Override
-    public void removeVariables() {
-
-    }
-
-    @Override
-    public void removeVariablesLocal() {
-
-    }
-
-    @Override
-    public void setTransientVariable(String s, Object o) {
-
-    }
-
-    @Override
-    public void setTransientVariableLocal(String s, Object o) {
-
-    }
-
-    @Override
-    public void setTransientVariables(Map<String, Object> map) {
-
-    }
-
-    @Override
-    public Object getTransientVariable(String s) {
-        return null;
-    }
-
-    @Override
-    public Map<String, Object> getTransientVariables() {
-        return null;
-    }
-
-    @Override
-    public void setTransientVariablesLocal(Map<String, Object> map) {
-
-    }
-
-    @Override
-    public Object getTransientVariableLocal(String s) {
-        return null;
-    }
-
-    @Override
-    public Map<String, Object> getTransientVariablesLocal() {
-        return null;
-    }
-
-    @Override
-    public void removeTransientVariableLocal(String s) {
-
-    }
-
-    @Override
-    public void removeTransientVariable(String s) {
-
-    }
-
-    @Override
-    public void removeTransientVariables() {
-
-    }
-
-    @Override
-    public void removeTransientVariablesLocal() {
-
-    }
-}