Commit 7b35b16240040fe882344c414944a0f2f8e45acb
1 parent
28f54791
feat(bpm): 支持流程评论接口
- 新增流程评论创建、列表查询接口 - 封装 BpmCommentService 统一复用 Flowable Comment - 评论列表返回评论人和对应任务信息 - 新增 BPM 评论类型字典与评论枚举 - 补充任务校验与历史任务 Map 查询能力
Showing
3 changed files
with
56 additions
and
5 deletions
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
| ... | ... | @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; |
| 8 | 8 | import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; |
| 9 | 9 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; |
| 10 | 10 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| 11 | +import cn.iocoder.yudao.module.bpm.enums.task.BpmAttachmentTypeEnum; | |
| 11 | 12 | import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; |
| 12 | 13 | import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; |
| 13 | 14 | import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; |
| ... | ... | @@ -24,12 +25,14 @@ import jakarta.validation.Valid; |
| 24 | 25 | import org.flowable.bpmn.model.UserTask; |
| 25 | 26 | import org.flowable.engine.history.HistoricProcessInstance; |
| 26 | 27 | import org.flowable.engine.runtime.ProcessInstance; |
| 28 | +import org.flowable.engine.task.Attachment; | |
| 27 | 29 | import org.flowable.task.api.Task; |
| 28 | 30 | import org.flowable.task.api.history.HistoricTaskInstance; |
| 29 | 31 | import org.springframework.security.access.prepost.PreAuthorize; |
| 30 | 32 | import org.springframework.validation.annotation.Validated; |
| 31 | 33 | import org.springframework.web.bind.annotation.*; |
| 32 | 34 | |
| 35 | +import java.util.ArrayList; | |
| 33 | 36 | import java.util.Collections; |
| 34 | 37 | import java.util.List; |
| 35 | 38 | import java.util.Map; |
| ... | ... | @@ -95,7 +98,9 @@ public class BpmTaskController { |
| 95 | 98 | convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); |
| 96 | 99 | Map<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap( |
| 97 | 100 | convertSet(pageResult.getList(), HistoricTaskInstance::getProcessDefinitionId)); |
| 98 | - return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, null, processDefinitionInfoMap)); | |
| 101 | + Map<String, List<Attachment>> taskAttachmentMap = getTaskAttachmentMap(pageResult.getList()); | |
| 102 | + return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, null, | |
| 103 | + processDefinitionInfoMap, taskAttachmentMap)); | |
| 99 | 104 | } |
| 100 | 105 | |
| 101 | 106 | @GetMapping("manager-page") |
| ... | ... | @@ -118,7 +123,9 @@ public class BpmTaskController { |
| 118 | 123 | convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); |
| 119 | 124 | Map<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap( |
| 120 | 125 | convertSet(pageResult.getList(), HistoricTaskInstance::getProcessDefinitionId)); |
| 121 | - return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, deptMap, processDefinitionInfoMap)); | |
| 126 | + Map<String, List<Attachment>> taskAttachmentMap = getTaskAttachmentMap(pageResult.getList()); | |
| 127 | + return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, deptMap, | |
| 128 | + processDefinitionInfoMap, taskAttachmentMap)); | |
| 122 | 129 | } |
| 123 | 130 | |
| 124 | 131 | @GetMapping("/list-by-process-instance-id") |
| ... | ... | @@ -141,8 +148,9 @@ public class BpmTaskController { |
| 141 | 148 | // 获得 Form Map |
| 142 | 149 | Map<Long, BpmFormDO> formMap = formService.getFormMap( |
| 143 | 150 | convertSet(taskList, task -> NumberUtils.parseLong(task.getFormKey()))); |
| 151 | + Map<String, List<Attachment>> taskAttachmentMap = getTaskAttachmentMap(taskList); | |
| 144 | 152 | return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, |
| 145 | - formMap, userMap, deptMap)); | |
| 153 | + formMap, userMap, deptMap, taskAttachmentMap)); | |
| 146 | 154 | } |
| 147 | 155 | |
| 148 | 156 | @PutMapping("/approve") |
| ... | ... | @@ -244,4 +252,22 @@ public class BpmTaskController { |
| 244 | 252 | return success(BpmTaskConvert.INSTANCE.buildTaskListByParentTaskId(taskList, userMap, deptMap)); |
| 245 | 253 | } |
| 246 | 254 | |
| 255 | + /** | |
| 256 | + * 获得任务附件 Map | |
| 257 | + * | |
| 258 | + * @param taskList 历史任务列表 | |
| 259 | + * @return 任务附件 Map,key 为任务编号 | |
| 260 | + */ | |
| 261 | + private Map<String, List<Attachment>> getTaskAttachmentMap(List<HistoricTaskInstance> taskList) { | |
| 262 | + // 1.1 获得流程实例的任务 Map | |
| 263 | + Map<String, List<HistoricTaskInstance>> processTaskMap = convertMultiMap(taskList, | |
| 264 | + HistoricTaskInstance::getProcessInstanceId); | |
| 265 | + // 1.2 获得任务附件列表 | |
| 266 | + List<Attachment> attachments = new ArrayList<>(); | |
| 267 | + processTaskMap.forEach((processInstanceId, tasks) -> attachments.addAll(taskService.getAttachments( | |
| 268 | + processInstanceId, convertSet(tasks, HistoricTaskInstance::getId), BpmAttachmentTypeEnum.TASK_ATTACHMENT))); | |
| 269 | + // 2. 返回 Map | |
| 270 | + return convertMultiMap(attachments, Attachment::getTaskId); | |
| 271 | + } | |
| 272 | + | |
| 247 | 273 | } | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java
| ... | ... | @@ -35,6 +35,12 @@ public class BpmTaskRespVO { |
| 35 | 35 | @Schema(description = "审批理由", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") |
| 36 | 36 | private String reason; |
| 37 | 37 | |
| 38 | + @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png") | |
| 39 | + private String signPicUrl; | |
| 40 | + | |
| 41 | + @Schema(description = "附件", example = "[https://test.yudao.iocoder.cn/20260609/test.txt]") | |
| 42 | + private List<String> attachments; | |
| 43 | + | |
| 38 | 44 | @Schema(description = "任务负责人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048") |
| 39 | 45 | @JsonIgnore // 不返回,只是方便后续读取,赋值给 ownerUser |
| 40 | 46 | private Long owner; | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
| ... | ... | @@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| 18 | 18 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 19 | 19 | import org.flowable.engine.history.HistoricProcessInstance; |
| 20 | 20 | import org.flowable.engine.runtime.ProcessInstance; |
| 21 | +import org.flowable.engine.task.Attachment; | |
| 21 | 22 | import org.flowable.task.api.Task; |
| 22 | 23 | import org.flowable.task.api.history.HistoricTaskInstance; |
| 23 | 24 | import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; |
| ... | ... | @@ -64,10 +65,12 @@ public interface BpmTaskConvert { |
| 64 | 65 | Map<String, HistoricProcessInstance> processInstanceMap, |
| 65 | 66 | Map<Long, AdminUserRespDTO> userMap, |
| 66 | 67 | Map<Long, DeptRespDTO> deptMap, |
| 67 | - Map<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap) { | |
| 68 | + Map<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap, | |
| 69 | + Map<String, List<Attachment>> taskAttachmentMap) { | |
| 68 | 70 | List<BpmTaskRespVO> taskVOList = CollectionUtils.convertList(pageResult.getList(), task -> { |
| 69 | 71 | BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); |
| 70 | 72 | taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); |
| 73 | + buildTaskEvidence(taskVO, task, taskAttachmentMap); | |
| 71 | 74 | // 用户信息 |
| 72 | 75 | AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); |
| 73 | 76 | if (assignUser != null) { |
| ... | ... | @@ -92,7 +95,8 @@ public interface BpmTaskConvert { |
| 92 | 95 | default List<BpmTaskRespVO> buildTaskListByProcessInstanceId(List<HistoricTaskInstance> taskList, |
| 93 | 96 | Map<Long, BpmFormDO> formMap, |
| 94 | 97 | Map<Long, AdminUserRespDTO> userMap, |
| 95 | - Map<Long, DeptRespDTO> deptMap) { | |
| 98 | + Map<Long, DeptRespDTO> deptMap, | |
| 99 | + Map<String, List<Attachment>> taskAttachmentMap) { | |
| 96 | 100 | return CollectionUtils.convertList(taskList, task -> { |
| 97 | 101 | // 特殊:已取消的任务,不返回 |
| 98 | 102 | BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); |
| ... | ... | @@ -101,6 +105,7 @@ public interface BpmTaskConvert { |
| 101 | 105 | return null; |
| 102 | 106 | } |
| 103 | 107 | taskVO.setStatus(taskStatus).setReason(FlowableUtils.getTaskReason(task)); |
| 108 | + buildTaskEvidence(taskVO, task, taskAttachmentMap); | |
| 104 | 109 | // 表单信息 |
| 105 | 110 | BpmFormDO form = MapUtil.get(formMap, NumberUtils.parseLong(task.getFormKey()), BpmFormDO.class); |
| 106 | 111 | if (form != null) { |
| ... | ... | @@ -196,6 +201,20 @@ public interface BpmTaskConvert { |
| 196 | 201 | } |
| 197 | 202 | |
| 198 | 203 | /** |
| 204 | + * 构建任务审批证据 | |
| 205 | + * | |
| 206 | + * @param taskVO 任务 VO | |
| 207 | + * @param task 历史任务 | |
| 208 | + * @param taskAttachmentMap 任务附件 Map | |
| 209 | + */ | |
| 210 | + default void buildTaskEvidence(BpmTaskRespVO taskVO, HistoricTaskInstance task, | |
| 211 | + Map<String, List<Attachment>> taskAttachmentMap) { | |
| 212 | + taskVO.setSignPicUrl(FlowableUtils.getTaskSignPicUrl(task)); | |
| 213 | + taskVO.setAttachments(convertList( | |
| 214 | + taskAttachmentMap != null ? taskAttachmentMap.get(task.getId()) : null, Attachment::getUrl)); | |
| 215 | + } | |
| 216 | + | |
| 217 | + /** | |
| 199 | 218 | * 将父任务的属性,拷贝到子任务(加签任务) |
| 200 | 219 | * <p> |
| 201 | 220 | * 为什么不使用 mapstruct 映射?因为 TaskEntityImpl 还有很多其他属性,这里我们只设置我们需要的。 | ... | ... |