diff --git a/sql/mysql/ruoyi-vue-pro.sql b/sql/mysql/ruoyi-vue-pro.sql index 4d34a54..b7eee5e 100644 --- a/sql/mysql/ruoyi-vue-pro.sql +++ b/sql/mysql/ruoyi-vue-pro.sql @@ -462,7 +462,7 @@ CREATE TABLE `system_dict_data` ( `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1061137 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1061147 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典数据表'; -- ---------------------------- -- Records of system_dict_data @@ -814,6 +814,16 @@ INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `st INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1512, 6, '委派中', '6', 'bpm_task_status', 0, 'primary', '', '', '1', '2024-03-17 10:06:22', '1', '2024-03-08 22:41:40', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1513, 7, '审批通过中', '7', 'bpm_task_status', 0, 'success', '', '', '1', '2024-03-17 10:06:47', '1', '2024-03-08 22:41:41', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1514, 0, '待审批', '0', 'bpm_task_status', 0, 'info', '', '', '1', '2024-03-17 10:07:11', '1', '2024-03-08 22:41:42', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061137, 0, '评论', '0', 'bpm_comment_type', 0, 'primary', '', '流程评论类型 - 评论', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061138, 1, '审批通过', '1', 'bpm_comment_type', 0, 'success', '', '流程评论类型 - 审批通过', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061139, 2, '不通过', '2', 'bpm_comment_type', 0, 'danger', '', '流程评论类型 - 不通过', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061140, 3, '已取消', '3', 'bpm_comment_type', 0, 'info', '', '流程评论类型 - 已取消', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061141, 4, '退回', '4', 'bpm_comment_type', 0, 'warning', '', '流程评论类型 - 退回', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061142, 5, '委派发起', '5', 'bpm_comment_type', 0, 'primary', '', '流程评论类型 - 委派发起', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061143, 6, '委派完成', '6', 'bpm_comment_type', 0, 'primary', '', '流程评论类型 - 委派完成', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061144, 7, '转派', '7', 'bpm_comment_type', 0, 'warning', '', '流程评论类型 - 转派', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061145, 8, '加签', '8', 'bpm_comment_type', 0, 'primary', '', '流程评论类型 - 加签', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); +INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1061146, 9, '减签', '9', 'bpm_comment_type', 0, 'info', '', '流程评论类型 - 减签', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1515, 35, '发起人自选', '35', 'bpm_task_candidate_strategy', 0, '', '', '', '1', '2024-03-22 19:45:16', '1', '2024-03-22 19:45:16', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1516, 1, '执行监听器', 'execution', 'bpm_process_listener_type', 0, 'primary', '', '', '1', '2024-03-23 12:54:03', '1', '2024-03-23 19:14:19', b'0'); INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) VALUES (1517, 1, '任务监听器', 'task', 'bpm_process_listener_type', 0, 'success', '', '', '1', '2024-03-23 12:54:13', '1', '2024-03-23 19:14:24', b'0'); @@ -1513,7 +1523,7 @@ CREATE TABLE `system_dict_type` ( `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted_time` datetime NULL DEFAULT NULL COMMENT '删除时间', PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1061099 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; +) ENGINE = InnoDB AUTO_INCREMENT = 1061100 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '字典类型表'; -- ---------------------------- -- Records of system_dict_type @@ -1726,6 +1736,7 @@ INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creat INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061096, 'IM 通话参与角色', 'im_rtc_participant_role', 0, '1=发起人;2=被邀请者;3=主动加入者', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061097, 'IM 通话参与状态', 'im_rtc_participant_status', 0, '10=邀请中;20=已加入;30=已拒绝;40=未应答;50=已离开', 'admin', '2026-05-18 03:36:12', 'admin', '2026-05-18 03:36:12', b'0', NULL); INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061098, 'IM 频道素材内容类型', 'im_channel_material_type', 0, '1=站内富文本 / 2=外链', '1', '2026-05-19 14:09:25', '1', '2026-05-19 14:09:25', b'0', NULL); +INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`) VALUES (1061099, '流程评论类型', 'bpm_comment_type', 0, 'Flowable 评论类型', '1', '2026-07-02 09:20:00', '1', '2026-07-02 09:20:00', b'0', NULL); COMMIT; -- ---------------------------- diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/comment/BpmCommentController.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/comment/BpmCommentController.java new file mode 100644 index 0000000..f9e5216 --- /dev/null +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/comment/BpmCommentController.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.comment; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +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.base.user.UserSimpleBaseVO; +import cn.iocoder.yudao.module.bpm.controller.admin.comment.vo.BpmCommentCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.comment.vo.BpmCommentRespVO; +import cn.iocoder.yudao.module.bpm.service.comment.BpmCommentService; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +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.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.flowable.engine.task.Comment; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - 流程评论") +@RestController +@RequestMapping("/bpm/comment") +@Validated +public class BpmCommentController { + + @Resource + private BpmCommentService commentService; + @Resource + private BpmTaskService taskService; + + @Resource + private AdminUserApi adminUserApi; + + @GetMapping("/list-by-process-instance-id") + @Operation(summary = "获得指定流程实例的评论列表") + @Parameter(name = "processInstanceId", description = "流程实例的编号", required = true) + @PreAuthorize("@ss.hasPermission('bpm:task:query')") + public CommonResult> getCommentListByProcessInstanceId( + @RequestParam("processInstanceId") String processInstanceId) { + // 获得评论列表 + List commentList = commentService.getCommentListByProcessInstanceId(processInstanceId); + if (CollUtil.isEmpty(commentList)) { + return success(Collections.emptyList()); + } + + // 拼接 VO + Map taskMap = taskService.getHistoricTaskMap( + convertSet(commentList, Comment::getTaskId)); + Map userMap = adminUserApi.getUserMap( + convertSet(commentList, comment -> NumberUtils.parseLong(comment.getUserId()))); + return success(convertList(commentList, comment -> BeanUtils.toBean(comment, BpmCommentRespVO.class, commentVO -> { + commentVO.setMessage(comment.getFullMessage()) + .setCreateTime(DateUtils.of(comment.getTime())) + .setTask(BeanUtils.toBean(taskMap.get(comment.getTaskId()), BpmCommentRespVO.Task.class)) + .setUser(BeanUtils.toBean(userMap.get(NumberUtils.parseLong(comment.getUserId())), UserSimpleBaseVO.class)); + }))); + } + + @PostMapping("/create") + @Operation(summary = "创建流程评论") + @PreAuthorize("@ss.hasPermission('bpm:task:update')") + public CommonResult createComment(@Valid @RequestBody BpmCommentCreateReqVO reqVO) { + commentService.createComment(reqVO); + return success(true); + } + +} diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/comment/vo/BpmCommentCreateReqVO.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/comment/vo/BpmCommentCreateReqVO.java new file mode 100644 index 0000000..17de5c7 --- /dev/null +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/comment/vo/BpmCommentCreateReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.comment.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Schema(description = "管理后台 - 流程评论创建 Request VO") +@Data +public class BpmCommentCreateReqVO { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + @NotEmpty(message = "任务编号不能为空") + private String taskId; + + @Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "请关注报销发票附件") + @NotBlank(message = "评论内容不能为空") + @Size(max = 500, message = "评论内容不能超过 500 个字符") + private String message; + +} diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/comment/vo/BpmCommentRespVO.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/comment/vo/BpmCommentRespVO.java new file mode 100644 index 0000000..16b15a0 --- /dev/null +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/comment/vo/BpmCommentRespVO.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.comment.vo; + +import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 流程评论 Response VO") +@Data +public class BpmCommentRespVO { + + @Schema(description = "评论编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private String id; + + @Schema(description = "任务编号", example = "2048") + private String taskId; + + @Schema(description = "任务") + private Task task; + + @Schema(description = "流程实例编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096") + private String processInstanceId; + + @Schema(description = "评论类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + private String type; + + @Schema(description = "评论内容", requiredMode = Schema.RequiredMode.REQUIRED, example = "请关注报销发票附件") + private String message; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "创建人") + private UserSimpleBaseVO user; + + @Schema(description = "任务") + @Data + public static class Task { + + @Schema(description = "任务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048") + private String id; + + @Schema(description = "任务名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "经理审批") + private String name; + + @Schema(description = "任务定义的标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "Activity_one") + private String taskDefinitionKey; + + } + +} diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java index c006386..b90dc55 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/DictTypeConstants.java @@ -7,4 +7,6 @@ package cn.iocoder.yudao.module.bpm.enums; */ public interface DictTypeConstants { + String COMMENT_TYPE = "bpm_comment_type"; + } diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java index 8b7b7ce..3eda5f9 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmCommentTypeEnum.java @@ -13,6 +13,7 @@ import lombok.Getter; @AllArgsConstructor public enum BpmCommentTypeEnum { + COMMENT("0", "评论", "{}"), APPROVE("1", "审批通过", "审批通过,原因是:{}"), REJECT("2", "不通过", "审批不通过:原因是:{}"), CANCEL("3", "已取消", "系统自动取消,原因是:{}"), @@ -40,7 +41,7 @@ public enum BpmCommentTypeEnum { private final String comment; public String formatComment(Object... params) { - return StrUtil.format(comment, params); + return StrUtil.format(comment, params); } } diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/comment/BpmCommentService.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/comment/BpmCommentService.java new file mode 100644 index 0000000..1eb75e8 --- /dev/null +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/comment/BpmCommentService.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.bpm.service.comment; + +import cn.iocoder.yudao.module.bpm.controller.admin.comment.vo.BpmCommentCreateReqVO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; +import jakarta.validation.Valid; +import org.flowable.engine.task.Comment; + +import java.util.List; + +/** + * 流程评论 Service 接口 + * + * @author 芋道源码 + */ +public interface BpmCommentService { + + /** + * 获得指定流程实例的评论列表 + * + * @param processInstanceId 流程实例的编号 + * @return 评论列表 + */ + List getCommentListByProcessInstanceId(String processInstanceId); + + /** + * 创建流程评论 + * + * @param reqVO 评论请求 + */ + void createComment(@Valid BpmCommentCreateReqVO reqVO); + + /** + * 创建流程评论 + * + * @param taskId 任务编号 + * @param processInstanceId 流程实例编号 + * @param type 评论类型 + * @param params 评论模板参数 + */ + void createComment(String taskId, String processInstanceId, BpmCommentTypeEnum type, Object... params); + +} diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/comment/BpmCommentServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/comment/BpmCommentServiceImpl.java new file mode 100644 index 0000000..2082a6d --- /dev/null +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/comment/BpmCommentServiceImpl.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.bpm.service.comment; + +import cn.iocoder.yudao.module.bpm.controller.admin.comment.vo.BpmCommentCreateReqVO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; +import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.flowable.engine.TaskService; +import org.flowable.engine.task.Comment; +import org.flowable.task.api.Task; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 流程评论 Service 实现类 + * + * @author 芋道源码 + */ +@Service +public class BpmCommentServiceImpl implements BpmCommentService { + + @Resource + private TaskService taskService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmTaskService bpmTaskService; + + @Override + public List getCommentListByProcessInstanceId(String processInstanceId) { + return taskService.getProcessInstanceComments(processInstanceId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void createComment(@Valid BpmCommentCreateReqVO reqVO) { + Task task = bpmTaskService.validateTaskExists(reqVO.getTaskId()); + createComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.COMMENT, reqVO.getMessage()); + } + + @Override + public void createComment(String taskId, String processInstanceId, BpmCommentTypeEnum type, Object... params) { + taskService.addComment(taskId, processInstanceId, type.getType(), type.formatComment(params)); + } + +} diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java index 36a35b3..0e3ecfa 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java @@ -104,6 +104,14 @@ public interface BpmTaskService { Task validateTask(Long userId, String taskId); /** + * 校验任务是否存在 + * + * @param id 任务编号 + * @return 任务 + */ + Task validateTaskExists(String id); + + /** * 获取任务 * * @param id 任务编号 @@ -128,6 +136,16 @@ public interface BpmTaskService { List getHistoricTasks(Collection taskIds); /** + * 获取历史任务 Map + * + * @param taskIds 任务编号集合 + * @return 历史任务 Map + */ + default Map getHistoricTaskMap(Collection taskIds) { + return CollectionUtils.convertMap(getHistoricTasks(taskIds), HistoricTaskInstance::getId); + } + + /** * 根据条件查询正在进行中的任务 * * @param processInstanceId 流程实例编号,不允许为空 diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java index 73f8a01..5b8aa4a 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java +++ b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java @@ -27,6 +27,7 @@ import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableCon import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmHttpRequestUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.FlowableUtils; +import cn.iocoder.yudao.module.bpm.service.comment.BpmCommentService; import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; @@ -57,6 +58,7 @@ import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.api.history.HistoricTaskInstanceQuery; import org.flowable.task.service.impl.persistence.entity.TaskEntity; import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionSynchronization; @@ -97,6 +99,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Resource private BpmProcessInstanceCopyService processInstanceCopyService; @Resource + @Lazy // 延迟加载,避免循环依赖 + private BpmCommentService commentService; + @Resource private BpmModelService modelService; @Resource private BpmMessageService messageService; @@ -310,7 +315,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override public Task validateTask(Long userId, String taskId) { - Task task = validateTaskExist(taskId); + Task task = validateTaskExists(taskId); // 为什么判断 assignee 非空的情况下? // 例如说:在审批人为空时,我们会有“自动审批通过”的策略,此时 userId 为 null,允许通过 if (StrUtil.isNotBlank(task.getAssignee()) @@ -320,7 +325,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { return task; } - private Task validateTaskExist(String id) { + @Override + public Task validateTaskExists(String id) { Task task = getTask(id); if (task == null) { throw exception(TASK_NOT_EXISTS); @@ -340,6 +346,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override public List getHistoricTasks(Collection taskIds) { + if (CollUtil.isEmpty(taskIds)) { + return Collections.emptyList(); + } return historyService.createHistoricTaskInstanceQuery().taskIds(taskIds).includeTaskLocalVariables().list(); } @@ -362,7 +371,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { @Override public List getUserTaskListByReturn(String id) { // 1.1 校验当前任务 task 存在 - Task task = validateTaskExist(id); + Task task = validateTaskExists(id); // 1.2 根据流程定义获取流程模型信息 BpmnModel bpmnModel = modelService.getBpmnModelByDefinitionId(task.getProcessDefinitionId()); FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); @@ -602,8 +611,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { taskService.setVariableLocal(task.getId(), BpmnVariableConstants.TASK_SIGN_PIC_URL, reqVO.getSignPicUrl()); } // 2.2 添加评论 - taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), - BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); + commentService.createComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE, + reqVO.getReason()); // 2.3 添加附件 if (CollUtil.isNotEmpty(reqVO.getAttachments())) { reqVO.getAttachments().forEach(attachment -> taskService.createAttachment(BpmAttachmentTypeEnum.TASK_ATTACHMENT.getType(), @@ -767,7 +776,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { return; } // 1.2 只处理加签的父任务 - Task parentTask = validateTaskExist(parentTaskId); + Task parentTask = validateTaskExists(parentTaskId); String scopeType = parentTask.getScopeType(); if (BpmTaskSignTypeEnum.of(scopeType) == null) { return; @@ -812,8 +821,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { AdminUserRespDTO currentUser = adminUserApi.getUser(WebFrameworkUtils.getLoginUserId()); AdminUserRespDTO ownerUser = adminUserApi.getUser(NumberUtils.parseLong(task.getOwner())); // 发起委托的用户 Assert.notNull(ownerUser, "委派任务找不到原审批人,需要检查数据"); - taskService.addComment(reqVO.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_END.getType(), - BpmCommentTypeEnum.DELEGATE_END.formatComment(currentUser.getNickname(), ownerUser.getNickname(), reqVO.getReason())); + commentService.createComment(reqVO.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_END, + currentUser.getNickname(), ownerUser.getNickname(), reqVO.getReason()); // 2.1 调用 resolveTask 完成任务。 // 底层调用 TaskHelper.changeTaskAssignee(task, task.getOwner()):将 owner 设置为 assignee @@ -837,8 +846,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2.1 更新流程任务为不通过 updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.REJECT.getStatus(), reqVO.getReason()); // 2.2 添加流程评论 - taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(), - BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); + commentService.createComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT, + reqVO.getReason()); // 2.3 添加附件 if (CollUtil.isNotEmpty(reqVO.getAttachments())) { reqVO.getAttachments().forEach(attachment -> taskService.createAttachment(BpmAttachmentTypeEnum.TASK_ATTACHMENT.getType(), @@ -852,8 +861,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { String rootParentId = getTaskRootParentId(task); updateTaskStatusAndReason(rootParentId, BpmTaskStatusEnum.REJECT.getStatus(), BpmCommentTypeEnum.REJECT.formatComment("加签任务不通过")); - taskService.addComment(rootParentId, task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(), - BpmCommentTypeEnum.REJECT.formatComment("加签任务不通过")); + commentService.createComment(rootParentId, task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT, + "加签任务不通过"); } // 3. 根据不同的 RejectHandler 处理策略 @@ -966,8 +975,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 判断是否分配给自己任务,因为会签任务,一个节点会有多个任务 if (isAssignUserTask(userId, task)) { // 情况一:自己的任务,进行 RETURN 标记 // 2.1.1 添加评论 - taskService.addComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.RETURN.getType(), - BpmCommentTypeEnum.RETURN.formatComment(reqVO.getReason())); + commentService.createComment(task.getId(), currentTask.getProcessInstanceId(), BpmCommentTypeEnum.RETURN, + reqVO.getReason()); // 2.1.2 更新 task 状态 + 原因 updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.RETURN.getStatus(), reqVO.getReason()); } else { // 情况二:别人的任务,进行 CANCEL 标记 @@ -1045,8 +1054,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2. 添加委托意见 AdminUserRespDTO currentUser = adminUserApi.getUser(userId); - taskService.addComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_START.getType(), - BpmCommentTypeEnum.DELEGATE_START.formatComment(currentUser.getNickname(), delegateUser.getNickname(), reqVO.getReason())); + commentService.createComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.DELEGATE_START, + currentUser.getNickname(), delegateUser.getNickname(), reqVO.getReason()); // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee) // 特殊:如果已经被委派(owner 非空),则不需要更新 owner:https://gitee.com/zhijiantianya/yudao-cloud/issues/ICJ153 @@ -1076,8 +1085,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 2. 添加委托意见 AdminUserRespDTO currentUser = adminUserApi.getUser(userId); - taskService.addComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.TRANSFER.getType(), - BpmCommentTypeEnum.TRANSFER.formatComment(currentUser.getNickname(), assigneeUser.getNickname(), reqVO.getReason())); + commentService.createComment(taskId, task.getProcessInstanceId(), BpmCommentTypeEnum.TRANSFER, + currentUser.getNickname(), assigneeUser.getNickname(), reqVO.getReason()); // 3.1 设置任务所有人 (owner) 为原任务的处理人 (assignee) // 特殊:如果已经被转派(owner 非空),则不需要更新 owner:https://gitee.com/zhijiantianya/yudao-cloud/issues/ICJ153 @@ -1162,10 +1171,9 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 4. 记录加签的评论到 task 任务 AdminUserRespDTO currentUser = adminUserApi.getUser(userId); - String comment = StrUtil.format(BpmCommentTypeEnum.ADD_SIGN.getComment(), + commentService.createComment(reqVO.getId(), taskEntity.getProcessInstanceId(), BpmCommentTypeEnum.ADD_SIGN, currentUser.getNickname(), BpmTaskSignTypeEnum.nameOfType(reqVO.getType()), String.join(",", convertList(userList, AdminUserRespDTO::getNickname)), reqVO.getReason()); - taskService.addComment(reqVO.getId(), taskEntity.getProcessInstanceId(), BpmCommentTypeEnum.ADD_SIGN.getType(), comment); } /** @@ -1273,8 +1281,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { // 3. 记录日志到父任务中。先记录日志是因为,通过 handleParentTask 方法之后,任务可能被完成了,并且不存在了,会报异常,所以先记录 AdminUserRespDTO user = adminUserApi.getUser(userId); - taskService.addComment(task.getParentTaskId(), task.getProcessInstanceId(), BpmCommentTypeEnum.SUB_SIGN.getType(), - StrUtil.format(BpmCommentTypeEnum.SUB_SIGN.getComment(), user.getNickname(), cancelUser.getNickname())); + commentService.createComment(task.getParentTaskId(), task.getProcessInstanceId(), BpmCommentTypeEnum.SUB_SIGN, + user.getNickname(), cancelUser.getNickname()); // 4. 处理当前任务的父任务 handleParentTaskIfSign(task.getParentTaskId()); @@ -1331,8 +1339,8 @@ public class BpmTaskServiceImpl implements BpmTaskService { List withdrawExecutionIds = new ArrayList<>(); for (Task task : runningTasks) { // 标记撤回任务为取消 - taskService.addComment(task.getId(), taskInstance.getProcessInstanceId(), BpmCommentTypeEnum.CANCEL.getType(), - BpmCommentTypeEnum.CANCEL.formatComment("前一节点撤回")); + commentService.createComment(task.getId(), taskInstance.getProcessInstanceId(), BpmCommentTypeEnum.CANCEL, + "前一节点撤回"); updateTaskStatusAndReason(task.getId(), BpmTaskStatusEnum.CANCEL.getStatus(), BpmReasonEnum.CANCEL_BY_WITHDRAW.getReason()); withdrawExecutionIds.add(task.getExecutionId()); } @@ -1350,7 +1358,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { * @return 任务信息 */ private Task validateTaskCanSignDelete(String id) { - Task task = validateTaskExist(id); + Task task = validateTaskExists(id); if (task.getParentTaskId() == null) { throw exception(TASK_SIGN_DELETE_NO_PARENT); } @@ -1468,7 +1476,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { return; } updateTaskStatusAndReason(taskId, BpmTaskStatusEnum.CANCEL.getStatus(), BpmReasonEnum.CANCEL_BY_SYSTEM.getReason()); - // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 taskService.addComment 添加理由,所以无法存储具体的取消理由 + // 补充说明:由于 Task 被删除成 HistoricTask 后,无法通过 Flowable Comment 添加理由,所以无法存储具体的取消理由 } @Override