diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java index 4a6e64e..14742b6 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java +++ b/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.*; import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmAttachmentTypeEnum; import cn.iocoder.yudao.module.bpm.service.definition.BpmFormService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; @@ -24,12 +25,14 @@ import jakarta.validation.Valid; import org.flowable.bpmn.model.UserTask; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.engine.task.Attachment; import org.flowable.task.api.Task; 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.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -95,7 +98,9 @@ public class BpmTaskController { convertSet(processInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId()))); Map processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap( convertSet(pageResult.getList(), HistoricTaskInstance::getProcessDefinitionId)); - return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, null, processDefinitionInfoMap)); + Map> taskAttachmentMap = getTaskAttachmentMap(pageResult.getList()); + return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, null, + processDefinitionInfoMap, taskAttachmentMap)); } @GetMapping("manager-page") @@ -118,7 +123,9 @@ public class BpmTaskController { convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); Map processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap( convertSet(pageResult.getList(), HistoricTaskInstance::getProcessDefinitionId)); - return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, deptMap, processDefinitionInfoMap)); + Map> taskAttachmentMap = getTaskAttachmentMap(pageResult.getList()); + return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, deptMap, + processDefinitionInfoMap, taskAttachmentMap)); } @GetMapping("/list-by-process-instance-id") @@ -141,8 +148,9 @@ public class BpmTaskController { // 获得 Form Map Map formMap = formService.getFormMap( convertSet(taskList, task -> NumberUtils.parseLong(task.getFormKey()))); + Map> taskAttachmentMap = getTaskAttachmentMap(taskList); return success(BpmTaskConvert.INSTANCE.buildTaskListByProcessInstanceId(taskList, - formMap, userMap, deptMap)); + formMap, userMap, deptMap, taskAttachmentMap)); } @PutMapping("/approve") @@ -244,4 +252,22 @@ public class BpmTaskController { return success(BpmTaskConvert.INSTANCE.buildTaskListByParentTaskId(taskList, userMap, deptMap)); } + /** + * 获得任务附件 Map + * + * @param taskList 历史任务列表 + * @return 任务附件 Map,key 为任务编号 + */ + private Map> getTaskAttachmentMap(List taskList) { + // 1.1 获得流程实例的任务 Map + Map> processTaskMap = convertMultiMap(taskList, + HistoricTaskInstance::getProcessInstanceId); + // 1.2 获得任务附件列表 + List attachments = new ArrayList<>(); + processTaskMap.forEach((processInstanceId, tasks) -> attachments.addAll(taskService.getAttachments( + processInstanceId, convertSet(tasks, HistoricTaskInstance::getId), BpmAttachmentTypeEnum.TASK_ATTACHMENT))); + // 2. 返回 Map + return convertMultiMap(attachments, Attachment::getTaskId); + } + } diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java index fce72a4..43cf0dc 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRespVO.java +++ b/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 { @Schema(description = "审批理由", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") private String reason; + @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png") + private String signPicUrl; + + @Schema(description = "附件", example = "[https://test.yudao.iocoder.cn/20260609/test.txt]") + private List attachments; + @Schema(description = "任务负责人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048") @JsonIgnore // 不返回,只是方便后续读取,赋值给 ownerUser private Long owner; diff --git a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java b/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java index dfb76c8..15f01d4 100644 --- a/yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java +++ b/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; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.engine.task.Attachment; import org.flowable.task.api.Task; import org.flowable.task.api.history.HistoricTaskInstance; import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl; @@ -64,10 +65,12 @@ public interface BpmTaskConvert { Map processInstanceMap, Map userMap, Map deptMap, - Map processDefinitionInfoMap) { + Map processDefinitionInfoMap, + Map> taskAttachmentMap) { List taskVOList = CollectionUtils.convertList(pageResult.getList(), task -> { BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); taskVO.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)); + buildTaskEvidence(taskVO, task, taskAttachmentMap); // 用户信息 AdminUserRespDTO assignUser = userMap.get(NumberUtils.parseLong(task.getAssignee())); if (assignUser != null) { @@ -92,7 +95,8 @@ public interface BpmTaskConvert { default List buildTaskListByProcessInstanceId(List taskList, Map formMap, Map userMap, - Map deptMap) { + Map deptMap, + Map> taskAttachmentMap) { return CollectionUtils.convertList(taskList, task -> { // 特殊:已取消的任务,不返回 BpmTaskRespVO taskVO = BeanUtils.toBean(task, BpmTaskRespVO.class); @@ -101,6 +105,7 @@ public interface BpmTaskConvert { return null; } taskVO.setStatus(taskStatus).setReason(FlowableUtils.getTaskReason(task)); + buildTaskEvidence(taskVO, task, taskAttachmentMap); // 表单信息 BpmFormDO form = MapUtil.get(formMap, NumberUtils.parseLong(task.getFormKey()), BpmFormDO.class); if (form != null) { @@ -196,6 +201,20 @@ public interface BpmTaskConvert { } /** + * 构建任务审批证据 + * + * @param taskVO 任务 VO + * @param task 历史任务 + * @param taskAttachmentMap 任务附件 Map + */ + default void buildTaskEvidence(BpmTaskRespVO taskVO, HistoricTaskInstance task, + Map> taskAttachmentMap) { + taskVO.setSignPicUrl(FlowableUtils.getTaskSignPicUrl(task)); + taskVO.setAttachments(convertList( + taskAttachmentMap != null ? taskAttachmentMap.get(task.getId()) : null, Attachment::getUrl)); + } + + /** * 将父任务的属性,拷贝到子任务(加签任务) *

* 为什么不使用 mapstruct 映射?因为 TaskEntityImpl 还有很多其他属性,这里我们只设置我们需要的。