Selaa lähdekoodia

!849 流程抄送Review
Merge pull request !849 from 云开/feature/BPM_CC_develop

芋道源码 1 vuosi sitten
vanhempi
commit
986f953319
20 muutettua tiedostoa jossa 411 lisäystä ja 401 poistoa
  1. 0 21
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java
  2. 83 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceCopyController.java
  3. 0 47
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCCReqVO.java
  4. 25 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyCreateReqVO.java
  5. 1 2
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyMyPageReqVO.java
  6. 2 14
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageItemRespVO.java
  7. 2 6
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmProcessInstanceCopyVO.java
  8. 17 33
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/convert/cc/BpmProcessInstanceCopyConvert.java
  9. 15 5
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/cc/BpmProcessInstanceCopyDO.java
  10. 4 3
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/cc/BpmProcessInstanceCopyMapper.java
  11. 2 7
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java
  12. 0 53
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyService.java
  13. 0 165
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyServiceImpl.java
  14. 20 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
  15. 30 5
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
  16. 41 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyService.java
  17. 165 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/BpmProcessInstanceCopyServiceImpl.java
  18. 1 1
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/cc/dto/BpmDelegateExecutionDTO.java
  19. 2 38
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/util/FlowableUtils.java
  20. 1 0
      yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyServiceTest.java

+ 0 - 21
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmProcessInstanceController.java

@@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task;
 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.*;
-import cn.iocoder.yudao.module.bpm.service.cc.BpmProcessInstanceCopyService;
 import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
@@ -26,9 +25,6 @@ public class BpmProcessInstanceController {
     @Resource
     private BpmProcessInstanceService processInstanceService;
 
-    @Resource
-    private BpmProcessInstanceCopyService processInstanceCopyService;
-
     @GetMapping("/my-page")
     @Operation(summary = "获得我的实例分页列表", description = "在【我的流程】菜单中,进行调用")
     @PreAuthorize("@ss.hasPermission('bpm:process-instance:query')")
@@ -60,21 +56,4 @@ public class BpmProcessInstanceController {
         return success(true);
     }
 
-    // TODO @kyle:抄送要不单独 controller?
-
-    @PostMapping("/cc/create")
-    @Operation(summary = "抄送流程")
-    @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:create')")
-    public CommonResult<Boolean> createProcessInstanceCC(@Valid @RequestBody BpmProcessInstanceCCReqVO createReqVO) {
-        return success(processInstanceCopyService.ccProcessInstance(getLoginUserId(), createReqVO));
-    }
-
-    @GetMapping("/cc/my-page")
-    @Operation(summary = "获得抄送流程分页列表")
-    @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:query')")
-    public CommonResult<PageResult<BpmProcessInstanceCCPageItemRespVO>> getProcessInstanceCCPage(
-            @Valid BpmProcessInstanceCCMyPageReqVO pageReqVO) {
-        return success(processInstanceCopyService.getMyProcessInstanceCCPage(getLoginUserId(), pageReqVO));
-    }
-
 }

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

@@ -0,0 +1,83 @@
+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.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
+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.springframework.context.annotation.Lazy;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "管理后台 - 流程实例抄送")
+@RestController
+@RequestMapping("/bpm/process-instance/cc")
+@Validated
+public class BpmProcessInstanceCopyController {
+
+    @Resource
+    private BpmProcessInstanceCopyService processInstanceCopyService;
+    @Resource
+    private BpmProcessInstanceService bpmProcessInstanceService;
+    @Resource
+    private AdminUserApi adminUserApi;
+
+    @Resource
+    private BpmTaskService bpmTaskService;
+
+    @PostMapping("/create")
+    @Operation(summary = "抄送流程")
+    @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:create')")
+    public CommonResult<Void> createProcessInstanceCC(@Valid @RequestBody BpmProcessInstanceCopyCreateReqVO createReqVO) {
+        return success(processInstanceCopyService.createProcessInstanceCopy(getLoginUserId(), createReqVO));
+    }
+
+    @GetMapping("/my-page")
+    @Operation(summary = "获得抄送流程分页列表")
+    @PreAuthorize("@ss.hasPermission('bpm:process-instance-cc:query')")
+    public CommonResult<PageResult<BpmProcessInstanceCopyPageItemRespVO>> getProcessInstanceCCPage(
+            @Valid BpmProcessInstanceCopyMyPageReqVO pageReqVO) {
+        PageResult<BpmProcessInstanceCopyDO> pageResult = processInstanceCopyService.getMyProcessInstanceCopyPage(getLoginUserId(), pageReqVO);
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return success(new PageResult<>(pageResult.getTotal()));
+        }
+
+        Map<String, String> taskNameByTaskIds = bpmTaskService.getTaskNameByTaskIds(convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getTaskId));
+        Map<String, String> processInstanceNameByProcessInstanceIds = bpmTaskService.getProcessInstanceNameByProcessInstanceIds(convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessInstanceId));
+
+        Set<Long/* userId */> userIds = new HashSet<>();
+        for (BpmProcessInstanceCopyDO doItem : pageResult.getList()) {
+            userIds.add(doItem.getStartUserId());
+            Long userId = Long.valueOf(doItem.getCreator());
+            userIds.add(userId);
+        }
+        Map<Long, String> userMap = adminUserApi.getUserList(userIds).stream().collect(Collectors.toMap(
+                AdminUserRespDTO::getId, AdminUserRespDTO::getNickname));
+
+        // 转换返回
+        return success(BpmProcessInstanceCopyConvert.INSTANCE.convertPage(pageResult, taskNameByTaskIds, processInstanceNameByProcessInstanceIds, userMap));
+    }
+
+}

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

@@ -1,47 +0,0 @@
-package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance;
-
-import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
-import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotBlank;
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
-import lombok.Data;
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
-// TODO @kyle:这个 VO 可以改成 BpmProcessInstanceCopyCreateReqVO
-@Schema(description = "管理后台 - 流程实例的抄送 Request VO")
-@Data
-@EqualsAndHashCode(callSuper = true)
-@ToString(callSuper = true)
-public class BpmProcessInstanceCCReqVO extends BpmTaskCandidateRuleVO {
-
-    @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    @NotEmpty(message = "任务编号不能为空")
-    private String taskKey;
-
-    @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    @NotEmpty(message = "任务名称不能为空")
-    private String taskName;
-
-    @Schema(description = "流程实例的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    @NotEmpty(message = "流程实例的编号不能为空")
-    private String processInstanceKey;
-
-    @Schema(description = "发起流程的用户的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    @NotNull(message = "发起流程的用户的编号不能为空")
-    private Long startUserId;
-
-    @Schema(description = "任务实例名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
-    @NotEmpty(message = "任务实例名称不能为空")
-    private String processInstanceName;
-
-    @Schema(description = "抄送原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "请帮忙审查下!")
-    @NotBlank(message = "抄送原因不能为空")
-    private String reason;
-
-    // TODO @kyle:看了下字段有点多,尽量不传递可推导的字段;
-    // 需要传递:taskId(任务编号)、reason、userIds(被抄送的人)
-    // 不需要传递:taskKey、taskName、processInstanceKey、startUserId、processInstanceName 因为这些可以后端查询到
-
-}

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

@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance;
+
+import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - 流程实例抄送的创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BpmProcessInstanceCopyCreateReqVO extends BpmTaskCandidateRuleVO {
+
+    @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;
+
+}

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

@@ -11,12 +11,11 @@ import java.time.LocalDateTime;
 
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
-// TODO @kyle:建议改成 BpmProcessInstanceCopyMyPageReqVO;cc 缩写不容易理解,所以改成 copy,虽然会长一点,但是可读性更重要;
 @Schema(description = "管理后台 - 流程实例抄送的分页 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
-public class BpmProcessInstanceCCMyPageReqVO extends PageParam {
+public class BpmProcessInstanceCopyMyPageReqVO extends PageParam {
 
     @Schema(description = "流程名称", example = "芋道")
     private String processInstanceName;

+ 2 - 14
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCCPageItemRespVO.java → yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmProcessInstanceCopyPageItemRespVO.java

@@ -7,35 +7,23 @@ import java.time.LocalDateTime;
 
 @Schema(description = "管理后台 - 流程实例抄送的分页 Item Response VO")
 @Data
-public class BpmProcessInstanceCCPageItemRespVO {
+public class BpmProcessInstanceCopyPageItemRespVO {
 
-    // TODO @kyle:如果已经写了 swagger 注解,可以不用写 java 注释哈;
-    /**
-     * 编号
-     */
     @Schema(description = "抄送主键")
     private Long id;
 
-    /**
-     * 发起人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;
 

+ 2 - 6
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyVO.java → yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmProcessInstanceCopyVO.java

@@ -1,16 +1,12 @@
-package cn.iocoder.yudao.module.bpm.service.cc;
+package cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task;
 
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
 import java.time.LocalDateTime;
 
-// TODO @kyle:看看是不是要删除
 /**
- * 流程抄送视图对象 wf_copy
- *
- * @author ruoyi
- * @date 2022-05-19
+ * 流程抄送视图对象
  */
 @Data
 public class BpmProcessInstanceCopyVO {

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

@@ -2,18 +2,18 @@ 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.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCPageItemRespVO;
+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.controller.admin.task.vo.task.BpmProcessInstanceCopyVO;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
-import cn.iocoder.yudao.module.bpm.service.cc.BpmProcessInstanceCopyVO;
 import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
 import java.util.Map;
 
-// TODO kyle:类注释不太对
 /**
- * 动态表单 Convert
+ * 流程抄送 Convert
  *
  * @author 芋艿
  */
@@ -22,39 +22,23 @@ public interface BpmProcessInstanceCopyConvert {
 
     BpmProcessInstanceCopyConvert INSTANCE = Mappers.getMapper(BpmProcessInstanceCopyConvert.class);
 
-    // TODO @kyle:可以使用 BeanUtils copy 替代这些简单的哈;
-    BpmProcessInstanceCopyDO copy(BpmProcessInstanceCopyDO bean);
-
     BpmProcessInstanceCopyVO convert(BpmProcessInstanceCopyDO bean);
 
-    List<BpmProcessInstanceCCPageItemRespVO> convertList(List<BpmProcessInstanceCopyDO> list);
+    List<BpmProcessInstanceCopyPageItemRespVO> convertList(List<BpmProcessInstanceCopyDO> list);
 
-    // TODO @kyle:/* taskId */ 这种注释一般不用写,可以一眼看明白的;避免变量看着略微不清晰哈
-    default PageResult<BpmProcessInstanceCCPageItemRespVO> convertPage(PageResult<BpmProcessInstanceCopyDO> page
-            , Map<String/* taskId */, String/* taskName */> taskMap
-            , Map<String/* processInstaneId */, String/* processInstaneName */> processInstaneMap
-            , Map<Long/* userId */, String/* userName */> userMap
+    default PageResult<BpmProcessInstanceCopyPageItemRespVO> convertPage(PageResult<BpmProcessInstanceCopyDO> page
+            , Map<String, String/* taskName */> taskMap
+            , Map<String, String/* processInstaneName */> processInstaneMap
+            , Map<Long, String/* userName */> userMap
     ) {
-        List<BpmProcessInstanceCCPageItemRespVO> list = convertList(page.getList());
-        for (BpmProcessInstanceCCPageItemRespVO vo : list) {
-            MapUtils.findAndThen(userMap, Long.valueOf(vo.getCreator()),
-                    vo::setCreatorNickname);
-            MapUtils.findAndThen(userMap, vo.getStartUserId(),
-                    vo::setStartUserNickname);
-            MapUtils.findAndThen(taskMap, vo.getTaskId(),
-                    vo::setTaskName);
-            MapUtils.findAndThen(processInstaneMap, vo.getProcessInstanceId(),
-                    vo::setProcessInstanceName);
-        }
-        // TODO @kyle:可以精简成下面的哈;
-//        List<BpmProcessInstanceCCPageItemRespVO> list2 = BeanUtils.toBean(page.getList(),
-//                BpmProcessInstanceCCPageItemRespVO.class,
-//                copy -> {
-//                    MapUtils.findAndThen(userMap, Long.valueOf(copy.getCreator()), copy::setCreatorNickname);
-//                    MapUtils.findAndThen(userMap, copy.getStartUserId(), copy::setStartUserNickname);
-//                    MapUtils.findAndThen(taskMap, copy.getTaskId(), copy::setTaskName);
-//                    MapUtils.findAndThen(processInstaneMap, copy.getProcessInstanceId(), copy::setProcessInstanceName);
-//                });
+        List<BpmProcessInstanceCopyPageItemRespVO> list = BeanUtils.toBean(page.getList(),
+                BpmProcessInstanceCopyPageItemRespVO.class,
+                copy -> {
+                    MapUtils.findAndThen(userMap, Long.valueOf(copy.getCreator()), copy::setCreatorNickname);
+                    MapUtils.findAndThen(userMap, copy.getStartUserId(), copy::setStartUserNickname);
+                    MapUtils.findAndThen(taskMap, copy.getTaskId(), copy::setTaskName);
+                    MapUtils.findAndThen(processInstaneMap, copy.getProcessInstanceId(), copy::setProcessInstanceName);
+                });
         return new PageResult<>(list, page.getTotal());
     }
 

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

@@ -9,7 +9,7 @@ import lombok.*;
  * 流程抄送 DO
  *
  * @author kyle
- * @date 2022-05-19 TODO @kyle:@date 不是标准 java doc,可以使用 @since 替代,然后日期是不是不对
+ * @since 2024-01-22
  */
 @TableName(value = "bpm_process_instance_copy", autoResultMap = true)
 @Data
@@ -26,34 +26,43 @@ public class BpmProcessInstanceCopyDO extends BaseDO {
     @TableId
     private Long id;
 
-    // TODO @kyle:字段如果是关联或者冗余,要写下注释。以 processInstanceId 举例子。
     /**
      * 发起人 Id
+     * <p>
+     * 关联 system_users 的 id 属性
      */
     private Long startUserId;
     /**
      * 流程名
+     * <p>
+     * 冗余字段
      */
     private String processInstanceName;
     /**
      * 流程实例的编号
-     *
+     * <p>
      * 关联 ProcessInstance 的 id 属性
      */
     private String processInstanceId;
 
     /**
      * 任务主键
+     * <p>
+     * 关联 task 的 id 属性
      */
     private String taskId;
 
     /**
      * 任务名称
+     * <p>
+     * 冗余字段
      */
     private String taskName;
 
     /**
      * 用户编号
+     * <p>
+     * 关联 system_users 的 id 属性
      */
     private Long userId;
 
@@ -62,10 +71,11 @@ public class BpmProcessInstanceCopyDO extends BaseDO {
      */
     private String reason;
 
-    // TODO @kyle:这个字段,可以用 category 简化点
     /**
      * 流程分类
+     * <p>
+     * 冗余字段
      */
-    private String processDefinitionCategory;
+    private String category;
 
 }

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

@@ -3,13 +3,14 @@ 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.BpmProcessInstanceCCMyPageReqVO;
+import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCopyMyPageReqVO;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.cc.BpmProcessInstanceCopyDO;
 import org.apache.ibatis.annotations.Mapper;
 
 @Mapper
-public interface BpmProcessInstanceCopyMapper extends BaseMapperX<BpmProcessInstanceCopyDO> { // TODO @kyle:方法和类之间要空行下;
-    default PageResult<BpmProcessInstanceCopyDO> selectPage(Long loginUserId, BpmProcessInstanceCCMyPageReqVO reqVO){
+public interface BpmProcessInstanceCopyMapper extends BaseMapperX<BpmProcessInstanceCopyDO> {
+
+    default PageResult<BpmProcessInstanceCopyDO> selectPage(Long loginUserId, BpmProcessInstanceCopyMyPageReqVO reqVO) {
         return selectPage(reqVO, new LambdaQueryWrapperX<BpmProcessInstanceCopyDO>()
                 .eqIfPresent(BpmProcessInstanceCopyDO::getUserId, loginUserId)
                 .eqIfPresent(BpmProcessInstanceCopyDO::getProcessInstanceId, reqVO.getProcessInstanceId())

+ 2 - 7
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/candidate/BpmCandidateSourceInfo.java

@@ -2,12 +2,12 @@ package cn.iocoder.yudao.module.bpm.service.candidate;
 
 import cn.iocoder.yudao.module.bpm.controller.admin.candidate.vo.BpmTaskCandidateRuleVO;
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
 import lombok.AllArgsConstructor;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import jakarta.validation.constraints.NotEmpty;
-import jakarta.validation.constraints.NotNull;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -18,11 +18,6 @@ import java.util.Set;
 @NoArgsConstructor
 @Data
 public class BpmCandidateSourceInfo {
-
-    @Schema(description = "流程id")
-    @NotNull
-    private String processInstanceId;
-
     @Schema(description = "当前任务ID")
     @NotNull
     private String taskId;

+ 0 - 53
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyService.java

@@ -1,53 +0,0 @@
-package cn.iocoder.yudao.module.bpm.service.cc;
-
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCMyPageReqVO;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCPageItemRespVO;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCReqVO;
-import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
-
-// TODO @kyle:这个 Service 要不挪到 task 包下;保持统一,task 下有流程、任务、抄送等;
-// TODO @kyle:中文和英文之间,有个空格,会更清晰点;例如说;流程抄送 Service 接口;中文写作习惯~
-/**
- * 流程抄送Service接口
- *
- * 现在是在审批的时候进行流程抄送
- */
-public interface BpmProcessInstanceCopyService {
-
-    // TODO @kyle:无用的方法,可以去掉哈;另外,考虑到避免过多的 VO,这里就可以返回 BpmProcessInstanceCopyDO
-    /**
-     * 查询流程抄送
-     *
-     * @param copyId 流程抄送主键
-     * @return 流程抄送
-     */
-    BpmProcessInstanceCopyVO queryById(Long copyId);
-
-    // TODO 芋艿:这块要 review 下;思考下~~
-    /**
-     * 抄送
-     * @param sourceInfo 抄送源信息,方便抄送处理
-     * @return
-     */
-    boolean makeCopy(BpmCandidateSourceInfo sourceInfo);
-
-    // TODO @kyle:可以方法名改成 createProcessInstanceCopy;现在项目一般新增都用 create 为主;
-    /**
-     * 流程实例的抄送
-     *
-     * @param userId 当前登录用户
-     * @param createReqVO 创建的抄送请求
-     * @return 是否抄送成功,抄送成功则返回true TODO @kyle:这里可以不用返回哈;目前一般是失败,就抛出业务异常;
-     */
-    boolean ccProcessInstance(Long userId, BpmProcessInstanceCCReqVO createReqVO);
-
-    /**
-     * 抄送的流程
-     * @param loginUserId 登录用户id
-     * @param pageReqVO 分页请求
-     * @return 抄送的分页结果
-     */
-    PageResult<BpmProcessInstanceCCPageItemRespVO> getMyProcessInstanceCCPage(Long loginUserId,
-                                                                              BpmProcessInstanceCCMyPageReqVO pageReqVO);
-}

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

@@ -1,165 +0,0 @@
-package cn.iocoder.yudao.module.bpm.service.cc;
-
-import cn.hutool.core.collection.CollUtil;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCMyPageReqVO;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCPageItemRespVO;
-import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceCCReqVO;
-import cn.iocoder.yudao.module.bpm.convert.cc.BpmProcessInstanceCopyConvert;
-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.service.candidate.BpmCandidateSourceInfo;
-import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessorChain;
-import cn.iocoder.yudao.module.bpm.service.cc.dto.BpmDelegateExecutionDTO;
-import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
-import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
-import cn.iocoder.yudao.module.bpm.util.FlowableUtils;
-import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
-import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import org.flowable.engine.RuntimeService;
-import org.flowable.engine.delegate.DelegateExecution;
-import org.flowable.engine.repository.ProcessDefinition;
-import org.flowable.engine.runtime.ProcessInstance;
-import org.springframework.context.annotation.Lazy;
-import org.springframework.stereotype.Service;
-import org.springframework.validation.annotation.Validated;
-
-import java.time.LocalDateTime;
-import java.util.*;
-import java.util.stream.Collectors;
-
-// TODO @kyle:类注释要写下
-@Slf4j // TODO @kyle:按照 @Service、@Validated、@Slf4j,从重要到不重要的顺序;
-@Service
-@Validated
-public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopyService {
-    @Resource // TODO @kyle:第一个变量,和类之间要有空行;
-    private BpmProcessInstanceCopyMapper processInstanceCopyMapper;
-
-    /**
-     * 和flowable有关的,查询流程名用的 TODO @kyle:可以不写哈注释;
-     */
-    @Resource
-    private RuntimeService runtimeService;
-
-    /**
-     * 找抄送人用的 TODO @kyle:可以不写哈注释;
-     */
-    @Resource
-    private BpmCandidateSourceInfoProcessorChain processorChain;
-
-    // TODO @kyle:多余的变量,可以去掉哈
-    @Resource
-    @Lazy // 解决循环依赖
-    private BpmTaskService bpmTaskService;
-    @Resource
-    @Lazy // 解决循环依赖
-    private BpmProcessInstanceService bpmProcessInstanceService;
-    @Resource
-    private AdminUserApi adminUserApi;
-
-    @Override
-    public BpmProcessInstanceCopyVO queryById(Long copyId) {
-        BpmProcessInstanceCopyDO bpmProcessInstanceCopyDO = processInstanceCopyMapper.selectById(copyId);
-        return BpmProcessInstanceCopyConvert.INSTANCE.convert(bpmProcessInstanceCopyDO);
-    }
-
-    // TODO @kyle:makeCopy 和 ccProcessInstance 的调用关系,感受上反了;
-    //  makeCopy 有点像基于规则,查找抄送人,然后创建;
-    // ccProcessInstance 是已经有了抄送人,然后创建;
-    // 建议的改造:独立基于 processInstanceCopyMapper 做 insert
-    @Override
-    public boolean makeCopy(BpmCandidateSourceInfo sourceInfo) {
-        if (null == sourceInfo) {
-            return false;
-        }
-
-        DelegateExecution executionEntity = new BpmDelegateExecutionDTO(sourceInfo.getProcessInstanceId());
-        Set<Long> ccCandidates = processorChain.calculateTaskCandidateUsers(executionEntity, sourceInfo);
-        if (CollUtil.isEmpty(ccCandidates)) {
-            log.warn("相关抄送人不存在 {}", sourceInfo.getTaskId());
-            return false;
-        } else {
-            BpmProcessInstanceCopyDO copyDO = new BpmProcessInstanceCopyDO();
-            // 调用
-            // 设置任务id
-            copyDO.setTaskId(sourceInfo.getTaskId());
-            copyDO.setTaskName(FlowableUtils.getTaskNameByTaskId(sourceInfo.getTaskId()));
-            copyDO.setProcessInstanceId(sourceInfo.getProcessInstanceId());
-            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
-                    .processInstanceId(sourceInfo.getProcessInstanceId())
-                    .singleResult();
-            if (null == processInstance) {
-                log.warn("相关流程实例不存在 {}", sourceInfo.getTaskId());
-                return false;
-            }
-            copyDO.setStartUserId(FlowableUtils.getStartUserIdFromProcessInstance(processInstance));
-            copyDO.setProcessInstanceName(processInstance.getName());
-            ProcessDefinition processDefinition = FlowableUtils.getProcessDefinition(processInstance.getProcessDefinitionId());
-            copyDO.setProcessDefinitionCategory(processDefinition.getCategory());
-            copyDO.setReason(sourceInfo.getReason());
-            copyDO.setCreator(sourceInfo.getCreator());
-            copyDO.setCreateTime(LocalDateTime.now());
-            List<BpmProcessInstanceCopyDO> copyList = new ArrayList<>(ccCandidates.size());
-            for (Long userId : ccCandidates) {
-                BpmProcessInstanceCopyDO copy = BpmProcessInstanceCopyConvert.INSTANCE.copy(copyDO);
-                copy.setUserId(userId);
-                copyList.add(copy);
-            }
-            return processInstanceCopyMapper.insertBatch(copyList);
-        }
-    }
-
-    @Override
-    public boolean ccProcessInstance(Long userId, BpmProcessInstanceCCReqVO reqVO) {
-        // 在能正常审批的情况下抄送流程
-        BpmCandidateSourceInfo sourceInfo = new BpmCandidateSourceInfo();
-        sourceInfo.setTaskId(reqVO.getTaskKey());
-        sourceInfo.setProcessInstanceId(reqVO.getProcessInstanceKey());
-        sourceInfo.addRule(reqVO);
-        sourceInfo.setCreator(String.valueOf(userId));
-        sourceInfo.setReason(reqVO.getReason());
-        if (!makeCopy(sourceInfo)) {
-            throw new RuntimeException("抄送任务失败");
-        }
-        return false;
-    }
-
-    //获取流程抄送分页 TODO @kyle:接口已经注释,这里不用注释了哈;
-    @Override
-    public PageResult<BpmProcessInstanceCCPageItemRespVO> getMyProcessInstanceCCPage(Long loginUserId, BpmProcessInstanceCCMyPageReqVO pageReqVO) {
-        // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页
-        // TODO @kyle:一般读逻辑,Service 返回 PageResult<BpmProcessInstanceCopyDO> 即可。关联数据的查询和拼接,交给 Controller;目的是:保证 Service 聚焦写逻辑,清晰简洁;
-        PageResult<BpmProcessInstanceCopyDO> pageResult = processInstanceCopyMapper.selectPage(loginUserId, pageReqVO);
-        if (CollUtil.isEmpty(pageResult.getList())) {
-            return new PageResult<>(pageResult.getTotal());
-        }
-
-        // TODO @kyle:这种可以简洁点;参考如下
-//        Map<String, ProcessInstance> processInstanceMap = bpmProcessInstanceService.getProcessInstanceMap(
-//                convertSet(pageResult.getList(), BpmProcessInstanceCopyDO::getProcessInstanceId));
-
-        Set<String/* taskId */> taskIds = new HashSet<>();
-        Set<String/* processInstaneId */> processInstaneIds = new HashSet<>();
-        Set<Long/* userId */> userIds = new HashSet<>();
-        for (BpmProcessInstanceCopyDO doItem : pageResult.getList()) {
-            taskIds.add(doItem.getTaskId());
-            processInstaneIds.add(doItem.getProcessInstanceId());
-            userIds.add(doItem.getStartUserId());
-            Long userId = Long.valueOf(doItem.getCreator());
-            userIds.add(userId);
-        }
-
-        Map<String, String> taskNameByTaskIds = FlowableUtils.getTaskNameByTaskIds(taskIds);
-        Map<String, String> processInstanceNameByTaskIds = FlowableUtils.getProcessInstanceNameByTaskIds(processInstaneIds);
-
-        Map<Long, String> userMap = adminUserApi.getUserList(userIds).stream().collect(Collectors.toMap(
-                AdminUserRespDTO::getId, AdminUserRespDTO::getNickname));
-
-        // 转换返回
-        return BpmProcessInstanceCopyConvert.INSTANCE.convertPage(pageResult, taskNameByTaskIds, processInstanceNameByTaskIds, userMap);
-    }
-
-}

+ 20 - 1
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java

@@ -4,11 +4,13 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
+import jakarta.validation.Valid;
 import org.flowable.task.api.Task;
 
-import jakarta.validation.Valid;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * 流程任务实例 Service 接口
@@ -132,6 +134,8 @@ public interface BpmTaskService {
      */
     void updateTaskExtAssign(Task task);
 
+    Task getTask(String id);
+
     /**
      * 获取当前任务的可回退的流程集合
      *
@@ -181,4 +185,19 @@ public interface BpmTaskService {
      */
     List<BpmTaskSubSignRespVO> getChildrenTaskList(String parentId);
 
+    /**
+     * 通过任务id查询任务名
+     *
+     * @param taskIds 任务id
+     * @return 对应的映射关系
+     */
+    Map<String/* taskId */, String/* taskName */> getTaskNameByTaskIds(Collection<String> taskIds);
+
+    /**
+     * 通过流程实例id获取到流程实例名
+     *
+     * @param processInstaneIds 流程实例Id
+     * @return 对应的映射关系
+     */
+    Map<String/* processInstaneId */, String/* processInstaneName */> getProcessInstanceNameByProcessInstanceIds(Set<String> processInstaneIds);
 }

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

@@ -19,14 +19,15 @@ import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum;
 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
 import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskAddSignTypeEnum;
-import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
-import cn.iocoder.yudao.module.bpm.service.cc.BpmProcessInstanceCopyService;
 import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService;
 import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
+import cn.iocoder.yudao.module.bpm.service.task.cc.BpmProcessInstanceCopyService;
 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
 import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
 import lombok.extern.slf4j.Slf4j;
 import org.flowable.bpmn.model.BpmnModel;
 import org.flowable.bpmn.model.FlowElement;
@@ -51,8 +52,6 @@ import org.springframework.transaction.support.TransactionSynchronization;
 import org.springframework.transaction.support.TransactionSynchronizationManager;
 import org.springframework.util.Assert;
 
-import jakarta.annotation.Resource;
-import jakarta.validation.Valid;
 import java.time.LocalDateTime;
 import java.util.*;
 import java.util.stream.Stream;
@@ -558,7 +557,8 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         return task;
     }
 
-    private Task getTask(String id) {
+    @Override
+    public Task getTask(String id) {
         return taskService.createTaskQuery().taskId(id).singleResult();
     }
 
@@ -971,4 +971,29 @@ public class BpmTaskServiceImpl implements BpmTaskService {
         return BpmTaskConvert.INSTANCE.convertList(taskExtList, userMap, idTaskMap);
     }
 
+    @Override
+    public Map<String/* taskId */, String/* taskName */> getTaskNameByTaskIds(Collection<String> taskIds) {
+        List<Task> tasks = taskService.createTaskQuery().taskIds(taskIds).list();
+        if (CollUtil.isNotEmpty(tasks)) {
+            Map<String/* taskId */, String/* taskName */> taskMap = new HashMap<>(tasks.size());
+            for (Task task : tasks) {
+                taskMap.putIfAbsent(task.getId(), task.getName());
+            }
+            return taskMap;
+        }
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public Map<String/* processInstaneId */, String/* processInstaneName */> getProcessInstanceNameByProcessInstanceIds(Set<String> processInstanceIds) {
+        List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery().processInstanceIds(processInstanceIds).list();
+        if (CollUtil.isNotEmpty(processInstances)) {
+            Map<String/* processInstaneId */, String/* processInstaneName */> processInstaneMap = new HashMap<>(processInstances.size());
+            for (ProcessInstance processInstance : processInstances) {
+                processInstaneMap.putIfAbsent(processInstance.getId(), processInstance.getName());
+            }
+            return processInstaneMap;
+        }
+        return Collections.emptyMap();
+    }
 }

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

@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.bpm.service.task.cc;
+
+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.dal.dataobject.cc.BpmProcessInstanceCopyDO;
+import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
+
+/**
+ * 流程抄送 Service 接口
+ *
+ * 现在是在审批的时候进行流程抄送
+ */
+public interface BpmProcessInstanceCopyService {
+
+    // TODO 芋艿:这块要 review 下;思考下~~
+    /**
+     * 抄送
+     * @param sourceInfo 抄送源信息,方便抄送处理
+     * @return
+     */
+    boolean makeCopy(BpmCandidateSourceInfo sourceInfo);
+
+    /**
+     * 流程实例的抄送
+     *
+     * @param userId      当前登录用户
+     * @param createReqVO 创建的抄送请求
+     */
+    Void createProcessInstanceCopy(Long userId, BpmProcessInstanceCopyCreateReqVO createReqVO);
+
+    /**
+     * 抄送的流程的分页
+     * @param loginUserId 登录用户id
+     * @param pageReqVO 分页请求
+     * @return 抄送的分页结果
+     */
+    PageResult<BpmProcessInstanceCopyDO> getMyProcessInstanceCopyPage(Long loginUserId,
+                                                                      BpmProcessInstanceCopyMyPageReqVO pageReqVO);
+}

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

@@ -0,0 +1,165 @@
+package cn.iocoder.yudao.module.bpm.service.task.cc;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+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.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.enums.definition.BpmTaskAssignRuleTypeEnum;
+import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfo;
+import cn.iocoder.yudao.module.bpm.service.candidate.BpmCandidateSourceInfoProcessorChain;
+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.dto.BpmDelegateExecutionDTO;
+import cn.iocoder.yudao.module.bpm.util.FlowableUtils;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.flowable.engine.RuntimeService;
+import org.flowable.engine.delegate.DelegateExecution;
+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.time.LocalDateTime;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+/**
+ * Flowable流程抄送实现
+ *
+ * @author kyle
+ */
+@Service
+@Validated
+@Slf4j
+public class BpmProcessInstanceCopyServiceImpl implements BpmProcessInstanceCopyService {
+
+    @Resource
+    private BpmProcessInstanceCopyMapper processInstanceCopyMapper;
+
+    @Resource
+    private RuntimeService runtimeService;
+
+    @Resource
+    private BpmCandidateSourceInfoProcessorChain processorChain;
+
+    @Resource
+    @Lazy
+    private BpmTaskService bpmTaskService;
+
+    @Override
+    public boolean makeCopy(BpmCandidateSourceInfo sourceInfo) {
+        if (null == sourceInfo) {
+            return false;
+        }
+
+        Task task = bpmTaskService.getTask(sourceInfo.getTaskId());
+        if (ObjectUtil.isNull(task)) {
+            return false;
+        }
+        String processInstanceId = task.getProcessInstanceId();
+        if (StrUtil.isBlank(processInstanceId)) {
+            return false;
+        }
+        DelegateExecution executionEntity = new BpmDelegateExecutionDTO(processInstanceId);
+        Set<Long> ccCandidates = processorChain.calculateTaskCandidateUsers(executionEntity, sourceInfo);
+        if (CollUtil.isEmpty(ccCandidates)) {
+            log.warn("相关抄送人不存在 {}", sourceInfo.getTaskId());
+            return false;
+        } else {
+            BpmProcessInstanceCopyDO copyDO = new BpmProcessInstanceCopyDO();
+            // 调用
+            // 设置任务id
+            copyDO.setTaskId(sourceInfo.getTaskId());
+            copyDO.setTaskName(FlowableUtils.getTaskNameByTaskId(sourceInfo.getTaskId()));
+            copyDO.setProcessInstanceId(processInstanceId);
+            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
+                    .processInstanceId(processInstanceId)
+                    .singleResult();
+            if (null == processInstance) {
+                log.warn("相关流程实例不存在 {}", sourceInfo.getTaskId());
+                return false;
+            }
+            copyDO.setStartUserId(FlowableUtils.getStartUserIdFromProcessInstance(processInstance));
+            copyDO.setProcessInstanceName(processInstance.getName());
+            ProcessDefinition processDefinition = FlowableUtils.getProcessDefinition(processInstance.getProcessDefinitionId());
+            copyDO.setCategory(processDefinition.getCategory());
+            copyDO.setReason(sourceInfo.getReason());
+            copyDO.setCreator(sourceInfo.getCreator());
+            copyDO.setCreateTime(LocalDateTime.now());
+            List<BpmProcessInstanceCopyDO> copyList = new ArrayList<>(ccCandidates.size());
+            for (Long userId : ccCandidates) {
+                BpmProcessInstanceCopyDO copy = BeanUtil.copyProperties(copyDO, BpmProcessInstanceCopyDO.class);
+                copy.setUserId(userId);
+                copyList.add(copy);
+            }
+            return processInstanceCopyMapper.insertBatch(copyList);
+        }
+    }
+
+    @Override
+    public Void createProcessInstanceCopy(Long userId, BpmProcessInstanceCopyCreateReqVO reqVO) {
+        if (!ObjectUtil.equal(reqVO.getType(), BpmTaskAssignRuleTypeEnum.USER.getType())) {
+            throw new IllegalArgumentException("业务仅支持USER");
+        }
+        Task task = bpmTaskService.getTask(reqVO.getTaskId());
+        if (ObjectUtil.isNull(task)) {
+            throw exception(ErrorCodeConstants.TASK_NOT_EXISTS);
+        }
+        String processInstanceId = task.getProcessInstanceId();
+        if (StrUtil.isBlank(processInstanceId)) {
+            throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS);
+        }
+        // 在能正常审批的情况下抄送流程
+        BpmProcessInstanceCopyDO copyDO = new BpmProcessInstanceCopyDO();
+        // 调用
+        // 设置任务id
+        copyDO.setTaskId(reqVO.getTaskId());
+        copyDO.setTaskName(FlowableUtils.getTaskNameByTaskId(reqVO.getTaskId()));
+        copyDO.setProcessInstanceId(processInstanceId);
+        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
+                .processInstanceId(processInstanceId)
+                .singleResult();
+        if (null == processInstance) {
+            log.warn("相关流程实例不存在 {}", reqVO.getTaskId());
+            throw exception(ErrorCodeConstants.PROCESS_INSTANCE_NOT_EXISTS);
+        }
+        copyDO.setStartUserId(FlowableUtils.getStartUserIdFromProcessInstance(processInstance));
+        copyDO.setProcessInstanceName(processInstance.getName());
+        ProcessDefinition processDefinition = FlowableUtils.getProcessDefinition(processInstance.getProcessDefinitionId());
+        copyDO.setCategory(processDefinition.getCategory());
+        copyDO.setReason(reqVO.getReason());
+        copyDO.setCreator(String.valueOf(userId));
+        copyDO.setCreateTime(LocalDateTime.now());
+        List<BpmProcessInstanceCopyDO> copyList = new ArrayList<>(reqVO.getOptions().size());
+        for (Long copyUserId : reqVO.getOptions()) {
+            BpmProcessInstanceCopyDO copy = BeanUtil.copyProperties(copyDO, BpmProcessInstanceCopyDO.class);
+            copy.setUserId(copyUserId);
+            copyList.add(copy);
+        }
+        processInstanceCopyMapper.insertBatch(copyList);
+        return null;
+    }
+
+    @Override
+    public PageResult<BpmProcessInstanceCopyDO> getMyProcessInstanceCopyPage(Long loginUserId, BpmProcessInstanceCopyMyPageReqVO pageReqVO) {
+        // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页
+        return processInstanceCopyMapper.selectPage(loginUserId, pageReqVO);
+    }
+
+}

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

@@ -1,4 +1,4 @@
-package cn.iocoder.yudao.module.bpm.service.cc.dto;
+package cn.iocoder.yudao.module.bpm.service.task.cc.dto;
 
 import org.flowable.bpmn.model.FlowElement;
 import org.flowable.bpmn.model.FlowableListener;

+ 2 - 38
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/util/FlowableUtils.java

@@ -1,7 +1,6 @@
 package cn.iocoder.yudao.module.bpm.util;
 
 
-import cn.hutool.core.collection.CollUtil;
 import cn.hutool.extra.spring.SpringUtil;
 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
 import org.flowable.bpmn.model.BpmnModel;
@@ -15,7 +14,8 @@ import org.flowable.engine.repository.ProcessDefinition;
 import org.flowable.engine.runtime.ProcessInstance;
 import org.flowable.task.api.Task;
 
-import java.util.*;
+import java.util.List;
+import java.util.Map;
 
 /**
  * 流程引擎工具类封装
@@ -88,40 +88,4 @@ public class FlowableUtils {
         return task.getName();
     }
 
-    // TODO @kyle:Utils 里不做查询;可以封装到 bpmTaskService 里
-    public static Map<String/* taskId */, String/* taskName */> getTaskNameByTaskIds(Collection<String> taskIds) {
-        TaskService taskService = SpringUtil.getBean(TaskService.class);
-        List<Task> tasks = taskService.createTaskQuery().taskIds(taskIds).list();
-        if (CollUtil.isNotEmpty(tasks)) {
-            Map<String/* taskId */, String/* taskName */> taskMap = new HashMap<>(tasks.size());
-            for (Task task : tasks) {
-                taskMap.putIfAbsent(task.getId(), task.getName());
-            }
-            return taskMap;
-        }
-        return Collections.emptyMap();
-    }
-
-    public static String getProcessInstanceNameByTaskId(String processInstanceId) {
-        RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class);
-        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
-                .processInstanceId(processInstanceId)
-                .singleResult();
-        return processInstance.getName();
-    }
-
-    // TODO @kyle:Utils 里不做查询;可以封装到 bpmTaskService 里
-    public static Map<String/* processInstaneId */, String/* processInstaneName */> getProcessInstanceNameByTaskIds(Set<String> taskIds) {
-        RuntimeService runtimeService = SpringUtil.getBean(RuntimeService.class);
-        List<ProcessInstance> processInstances = runtimeService.createProcessInstanceQuery().processInstanceIds(taskIds).list();
-        if (CollUtil.isNotEmpty(processInstances)) {
-            Map<String/* processInstaneId */, String/* processInstaneName */> processInstaneMap = new HashMap<>(processInstances.size());
-            for (ProcessInstance processInstance : processInstances) {
-                processInstaneMap.putIfAbsent(processInstance.getId(), processInstance.getName());
-            }
-            return processInstaneMap;
-        }
-        return Collections.emptyMap();
-    }
-
 }

+ 1 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/test/java/cn/iocoder/yudao/module/bpm/service/cc/BpmProcessInstanceCopyServiceTest.java

@@ -1,6 +1,7 @@
 package cn.iocoder.yudao.module.bpm.service.cc;
 
 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
+import cn.iocoder.yudao.module.bpm.service.task.cc.BpmProcessInstanceCopyServiceImpl;
 import jakarta.annotation.Resource;
 import org.junit.jupiter.api.Test;
 import org.springframework.context.annotation.Import;