Commit c7649efa459fabf44d34dbcc0d46cc3fa6670668
1 parent
d97b85bb
feat: 审批,拒绝任务时允许添加附件
Showing
8 changed files
with
105 additions
and
18 deletions
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/instance/BpmApprovalDetailRespVO.java
| ... | ... | @@ -107,6 +107,9 @@ public class BpmApprovalDetailRespVO { |
| 107 | 107 | @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png") |
| 108 | 108 | private String signPicUrl; |
| 109 | 109 | |
| 110 | + @Schema(description = "附件", example = "[https://test.yudao.iocoder.cn/20260609/test.txt]") | |
| 111 | + private List<String> attachments; | |
| 112 | + | |
| 110 | 113 | } |
| 111 | 114 | |
| 112 | 115 | } | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskApproveReqVO.java
| ... | ... | @@ -21,6 +21,9 @@ public class BpmTaskApproveReqVO { |
| 21 | 21 | @Schema(description = "签名", example = "https://www.iocoder.cn/sign.png") |
| 22 | 22 | private String signPicUrl; |
| 23 | 23 | |
| 24 | + @Schema(description = "附件", example = "[https://test.yudao.iocoder.cn/20260609/test.txt]") | |
| 25 | + private List<String> attachments; | |
| 26 | + | |
| 24 | 27 | @Schema(description = "变量实例(动态表单)", requiredMode = Schema.RequiredMode.REQUIRED) |
| 25 | 28 | private Map<String, Object> variables; |
| 26 | 29 | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/vo/task/BpmTaskRejectReqVO.java
| ... | ... | @@ -5,6 +5,8 @@ import lombok.Data; |
| 5 | 5 | |
| 6 | 6 | import jakarta.validation.constraints.NotEmpty; |
| 7 | 7 | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 8 | 10 | @Schema(description = "管理后台 - 不通过流程任务的 Request VO") |
| 9 | 11 | @Data |
| 10 | 12 | public class BpmTaskRejectReqVO { |
| ... | ... | @@ -16,4 +18,7 @@ public class BpmTaskRejectReqVO { |
| 16 | 18 | @Schema(description = "审批意见", requiredMode = Schema.RequiredMode.REQUIRED, example = "不错不错!") |
| 17 | 19 | private String reason; |
| 18 | 20 | |
| 21 | + @Schema(description = "附件", example = "[https://test.yudao.iocoder.cn/20260609/test.txt]") | |
| 22 | + private List<String> attachments; | |
| 23 | + | |
| 19 | 24 | } | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
| ... | ... | @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.common.util.collection.SetUtils; |
| 9 | 9 | import cn.iocoder.yudao.framework.common.util.date.DateUtils; |
| 10 | 10 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 11 | 11 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| 12 | +import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent; | |
| 12 | 13 | import cn.iocoder.yudao.module.bpm.controller.admin.base.user.UserSimpleBaseVO; |
| 13 | 14 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.BpmModelMetaInfoVO; |
| 14 | 15 | import cn.iocoder.yudao.module.bpm.controller.admin.definition.vo.model.simple.BpmSimpleModelNodeVO; |
| ... | ... | @@ -21,7 +22,6 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; |
| 21 | 22 | import cn.iocoder.yudao.module.bpm.convert.definition.BpmProcessDefinitionConvert; |
| 22 | 23 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmCategoryDO; |
| 23 | 24 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| 24 | -import cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEvent; | |
| 25 | 25 | import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; |
| 26 | 26 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; |
| 27 | 27 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmnModelUtils; |
| ... | ... | @@ -34,6 +34,7 @@ import org.flowable.bpmn.model.BpmnModel; |
| 34 | 34 | import org.flowable.engine.history.HistoricProcessInstance; |
| 35 | 35 | import org.flowable.engine.repository.ProcessDefinition; |
| 36 | 36 | import org.flowable.engine.runtime.ProcessInstance; |
| 37 | +import org.flowable.engine.task.Attachment; | |
| 37 | 38 | import org.flowable.task.api.Task; |
| 38 | 39 | import org.flowable.task.api.history.HistoricTaskInstance; |
| 39 | 40 | import org.mapstruct.Mapper; |
| ... | ... | @@ -82,7 +83,7 @@ public interface BpmProcessInstanceConvert { |
| 82 | 83 | if (CollUtil.isNotEmpty(respVO.getTasks())) { |
| 83 | 84 | respVO.getTasks().forEach(task -> { |
| 84 | 85 | AdminUserRespDTO assigneeUser = userMap.get(task.getAssignee()); |
| 85 | - if (assigneeUser!= null) { | |
| 86 | + if (assigneeUser != null) { | |
| 86 | 87 | task.setAssigneeUser(BeanUtils.toBean(assigneeUser, UserSimpleBaseVO.class)); |
| 87 | 88 | MapUtils.findAndThen(deptMap, assigneeUser.getDeptId(), dept -> task.getAssigneeUser().setDeptName(dept.getName())); |
| 88 | 89 | } |
| ... | ... | @@ -137,10 +138,10 @@ public interface BpmProcessInstanceConvert { |
| 137 | 138 | |
| 138 | 139 | default BpmMessageSendWhenProcessInstanceRejectReqDTO buildProcessInstanceRejectMessage(ProcessInstance instance, String reason) { |
| 139 | 140 | return new BpmMessageSendWhenProcessInstanceRejectReqDTO() |
| 140 | - .setProcessInstanceName(instance.getName()) | |
| 141 | - .setProcessInstanceId(instance.getId()) | |
| 142 | - .setReason(reason) | |
| 143 | - .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())); | |
| 141 | + .setProcessInstanceName(instance.getName()) | |
| 142 | + .setProcessInstanceId(instance.getId()) | |
| 143 | + .setReason(reason) | |
| 144 | + .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())); | |
| 144 | 145 | } |
| 145 | 146 | |
| 146 | 147 | default BpmProcessInstanceBpmnModelViewRespVO buildProcessInstanceBpmnModelView(HistoricProcessInstance processInstance, |
| ... | ... | @@ -183,8 +184,8 @@ public interface BpmProcessInstanceConvert { |
| 183 | 184 | } |
| 184 | 185 | |
| 185 | 186 | default UserSimpleBaseVO buildUser(Long userId, |
| 186 | - Map<Long, AdminUserRespDTO> userMap, | |
| 187 | - Map<Long, DeptRespDTO> deptMap) { | |
| 187 | + Map<Long, AdminUserRespDTO> userMap, | |
| 188 | + Map<Long, DeptRespDTO> deptMap) { | |
| 188 | 189 | if (userId == null) { |
| 189 | 190 | return null; |
| 190 | 191 | } |
| ... | ... | @@ -200,13 +201,14 @@ public interface BpmProcessInstanceConvert { |
| 200 | 201 | return userVO; |
| 201 | 202 | } |
| 202 | 203 | |
| 203 | - default BpmApprovalDetailRespVO.ActivityNodeTask buildApprovalTaskInfo(HistoricTaskInstance task) { | |
| 204 | + default BpmApprovalDetailRespVO.ActivityNodeTask buildApprovalTaskInfo(HistoricTaskInstance task, List<Attachment> attachments) { | |
| 204 | 205 | if (task == null) { |
| 205 | 206 | return null; |
| 206 | 207 | } |
| 207 | 208 | return BeanUtils.toBean(task, BpmApprovalDetailRespVO.ActivityNodeTask.class) |
| 208 | 209 | .setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task)) |
| 209 | - .setSignPicUrl(FlowableUtils.getTaskSignPicUrl(task)); | |
| 210 | + .setSignPicUrl(FlowableUtils.getTaskSignPicUrl(task)) | |
| 211 | + .setAttachments(convertList(attachments, Attachment::getUrl)); | |
| 210 | 212 | } |
| 211 | 213 | |
| 212 | 214 | default Set<Long> parseUserIds(HistoricProcessInstance processInstance, | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/enums/task/BpmAttachmentTypeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.bpm.enums.task; | |
| 2 | + | |
| 3 | +import lombok.AllArgsConstructor; | |
| 4 | +import lombok.Getter; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * 附件类型枚举 | |
| 8 | + * | |
| 9 | + * @author jason | |
| 10 | + */ | |
| 11 | +@Getter | |
| 12 | +@AllArgsConstructor | |
| 13 | +public enum BpmAttachmentTypeEnum { | |
| 14 | + | |
| 15 | + TASK_ATTACHMENT("1", "用户任务附件"); | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 操作类型 | |
| 19 | + * <p> | |
| 20 | + * 由于 BPM attachment 类型为 String,所以这里就不使用 Integer | |
| 21 | + */ | |
| 22 | + private final String type; | |
| 23 | + /** | |
| 24 | + * 操作名字 | |
| 25 | + */ | |
| 26 | + private final String name; | |
| 27 | +} | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
| ... | ... | @@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.bpm.dal.redis.BpmProcessIdRedisDAO; |
| 25 | 25 | import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; |
| 26 | 26 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum; |
| 27 | 27 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeTypeEnum; |
| 28 | +import cn.iocoder.yudao.module.bpm.enums.task.BpmAttachmentTypeEnum; | |
| 28 | 29 | import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; |
| 29 | 30 | import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; |
| 30 | 31 | import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; |
| ... | ... | @@ -57,6 +58,7 @@ import org.flowable.engine.repository.ProcessDefinition; |
| 57 | 58 | import org.flowable.engine.runtime.Execution; |
| 58 | 59 | import org.flowable.engine.runtime.ProcessInstance; |
| 59 | 60 | import org.flowable.engine.runtime.ProcessInstanceBuilder; |
| 61 | +import org.flowable.engine.task.Attachment; | |
| 60 | 62 | import org.flowable.task.api.Task; |
| 61 | 63 | import org.flowable.task.api.history.HistoricTaskInstance; |
| 62 | 64 | import org.springframework.context.annotation.Lazy; |
| ... | ... | @@ -404,8 +406,13 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 404 | 406 | // 遍历 tasks 列表,只处理已结束的 UserTask |
| 405 | 407 | // 为什么不通过 activities 呢?因为,加签场景下,它只存在于 tasks,没有 activities,导致如果遍历 activities 的话,它无法成为一个节点 |
| 406 | 408 | List<HistoricTaskInstance> endTasks = filterList(tasks, task -> task.getEndTime() != null); |
| 409 | + // 获取已完成节点的附件 | |
| 410 | + Set<String> endTaskIds = convertSet(endTasks, HistoricTaskInstance::getId); | |
| 411 | + List<Attachment> attachments = taskService.getAttachments(historicProcessInstance.getId(), endTaskIds, BpmAttachmentTypeEnum.TASK_ATTACHMENT); | |
| 412 | + Map<String, List<Attachment>> taskAttachmentMap = convertMultiMap(attachments, Attachment::getTaskId); | |
| 407 | 413 | List<ActivityNode> approvalNodes = convertList(endTasks, task -> { |
| 408 | 414 | FlowElement flowNode = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey()); |
| 415 | + List<Attachment> taskAttachments = taskAttachmentMap.get(task.getId()); | |
| 409 | 416 | ActivityNode activityNode = new ActivityNode().setId(task.getTaskDefinitionKey()).setName(task.getName()) |
| 410 | 417 | .setNodeType(START_USER_NODE_ID.equals(task.getTaskDefinitionKey()) |
| 411 | 418 | ? BpmSimpleModelNodeTypeEnum.START_USER_NODE.getType() |
| ... | ... | @@ -414,7 +421,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 414 | 421 | .setStatus(getEndActivityNodeStatus(task)) |
| 415 | 422 | .setCandidateStrategy(BpmnModelUtils.parseCandidateStrategy(flowNode)) |
| 416 | 423 | .setStartTime(DateUtils.of(task.getCreateTime())).setEndTime(DateUtils.of(task.getEndTime())) |
| 417 | - .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task))); | |
| 424 | + .setTasks(singletonList(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task, taskAttachments))); | |
| 418 | 425 | // 如果是取消状态,则跳过 |
| 419 | 426 | if (BpmTaskStatusEnum.isCancelStatus(activityNode.getStatus())) { |
| 420 | 427 | return null; |
| ... | ... | @@ -528,14 +535,14 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 528 | 535 | if (task == null) { |
| 529 | 536 | continue; |
| 530 | 537 | } |
| 531 | - activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task)); | |
| 538 | + activityNode.getTasks().add(BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(task, null)); | |
| 532 | 539 | // 加签子任务,需要过滤掉已经完成的加签子任务 |
| 533 | 540 | List<HistoricTaskInstance> childrenTasks = filterList( |
| 534 | 541 | taskService.getAllChildrenTaskListByParentTaskId(activity.getTaskId(), tasks), |
| 535 | 542 | childTask -> childTask.getEndTime() == null); |
| 536 | 543 | if (CollUtil.isNotEmpty(childrenTasks)) { |
| 537 | 544 | activityNode.getTasks().addAll( |
| 538 | - convertList(childrenTasks, BpmProcessInstanceConvert.INSTANCE::buildApprovalTaskInfo)); | |
| 545 | + convertList(childrenTasks, item->BpmProcessInstanceConvert.INSTANCE.buildApprovalTaskInfo(item, null))); | |
| 539 | 546 | } |
| 540 | 547 | } |
| 541 | 548 | // 处理每个任务的 candidateUsers 属性:如果是依次审批,需要预测它的后续审批人。因为 Task 是审批完一个,创建一个新的 Task | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
| ... | ... | @@ -4,9 +4,11 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; |
| 5 | 5 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; |
| 6 | 6 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmUserTaskTimeoutHandlerTypeEnum; |
| 7 | +import cn.iocoder.yudao.module.bpm.enums.task.BpmAttachmentTypeEnum; | |
| 7 | 8 | import jakarta.validation.Valid; |
| 8 | 9 | import org.flowable.bpmn.model.UserTask; |
| 9 | 10 | import org.flowable.engine.history.HistoricActivityInstance; |
| 11 | +import org.flowable.engine.task.Attachment; | |
| 10 | 12 | import org.flowable.task.api.Task; |
| 11 | 13 | import org.flowable.task.api.TaskInfo; |
| 12 | 14 | import org.flowable.task.api.history.HistoricTaskInstance; |
| ... | ... | @@ -14,6 +16,7 @@ import org.flowable.task.api.history.HistoricTaskInstance; |
| 14 | 16 | import java.util.Collection; |
| 15 | 17 | import java.util.List; |
| 16 | 18 | import java.util.Map; |
| 19 | +import java.util.Set; | |
| 17 | 20 | |
| 18 | 21 | /** |
| 19 | 22 | * 流程任务实例 Service 接口 |
| ... | ... | @@ -184,6 +187,17 @@ public interface BpmTaskService { |
| 184 | 187 | */ |
| 185 | 188 | List<HistoricTaskInstance> getFinishedTaskListByProcessInstanceIdWithoutCancel(String processInstanceId); |
| 186 | 189 | |
| 190 | + | |
| 191 | + /** | |
| 192 | + * 根据条件获取附件 | |
| 193 | + * | |
| 194 | + * @param processInstanceId 流程 id | |
| 195 | + * @param taskIds 任务 id 集合 | |
| 196 | + * @param attachmentType 附件类型 | |
| 197 | + * @return 附件集合 | |
| 198 | + */ | |
| 199 | + List<Attachment> getAttachments(String processInstanceId, Set<String> taskIds, BpmAttachmentTypeEnum attachmentType); | |
| 200 | + | |
| 187 | 201 | // ========== Update 写入相关方法 ========== |
| 188 | 202 | |
| 189 | 203 | /** | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| ... | ... | @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.task; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.convert.Convert; |
| 5 | +import cn.hutool.core.io.FileUtil; | |
| 5 | 6 | import cn.hutool.core.lang.Assert; |
| 6 | 7 | import cn.hutool.core.util.*; |
| 7 | 8 | import cn.hutool.extra.spring.SpringUtil; |
| ... | ... | @@ -19,10 +20,7 @@ import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; |
| 19 | 20 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmFormDO; |
| 20 | 21 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| 21 | 22 | import cn.iocoder.yudao.module.bpm.enums.definition.*; |
| 22 | -import cn.iocoder.yudao.module.bpm.enums.task.BpmCommentTypeEnum; | |
| 23 | -import cn.iocoder.yudao.module.bpm.enums.task.BpmReasonEnum; | |
| 24 | -import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskSignTypeEnum; | |
| 25 | -import cn.iocoder.yudao.module.bpm.enums.task.BpmTaskStatusEnum; | |
| 23 | +import cn.iocoder.yudao.module.bpm.enums.task.*; | |
| 26 | 24 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmTaskCandidateStrategyEnum; |
| 27 | 25 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnVariableConstants; |
| 28 | 26 | import cn.iocoder.yudao.module.bpm.framework.flowable.core.util.BpmHttpRequestUtils; |
| ... | ... | @@ -49,6 +47,7 @@ import org.flowable.engine.history.HistoricActivityInstance; |
| 49 | 47 | import org.flowable.engine.runtime.ActivityInstance; |
| 50 | 48 | import org.flowable.engine.runtime.Execution; |
| 51 | 49 | import org.flowable.engine.runtime.ProcessInstance; |
| 50 | +import org.flowable.engine.task.Attachment; | |
| 52 | 51 | import org.flowable.task.api.DelegationState; |
| 53 | 52 | import org.flowable.task.api.Task; |
| 54 | 53 | import org.flowable.task.api.TaskInfo; |
| ... | ... | @@ -510,6 +509,18 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 510 | 509 | .orderByHistoricTaskInstanceStartTime().asc().list(); |
| 511 | 510 | } |
| 512 | 511 | |
| 512 | + @Override | |
| 513 | + public List<Attachment> getAttachments(String processInstanceId, Set<String> taskIds, BpmAttachmentTypeEnum attachmentType) { | |
| 514 | + List<Attachment> result = taskService.getProcessInstanceAttachments(processInstanceId); | |
| 515 | + if (CollUtil.isNotEmpty(taskIds)) { | |
| 516 | + result = filterList(result, attachment -> taskIds.contains(attachment.getTaskId())); | |
| 517 | + } | |
| 518 | + if (attachmentType != null) { | |
| 519 | + result = filterList(result, attachment -> attachmentType.getType().equals(attachment.getType())); | |
| 520 | + } | |
| 521 | + return result; | |
| 522 | + } | |
| 523 | + | |
| 513 | 524 | /** |
| 514 | 525 | * 判断指定用户,是否是当前任务的审批人 |
| 515 | 526 | * |
| ... | ... | @@ -592,6 +603,13 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 592 | 603 | // 2.2 添加评论 |
| 593 | 604 | taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.APPROVE.getType(), |
| 594 | 605 | BpmCommentTypeEnum.APPROVE.formatComment(reqVO.getReason())); |
| 606 | + // 2.3 添加附件 | |
| 607 | + if (CollUtil.isNotEmpty(reqVO.getAttachments())) { | |
| 608 | + reqVO.getAttachments().forEach(attachment -> { | |
| 609 | + taskService.createAttachment(BpmAttachmentTypeEnum.TASK_ATTACHMENT.getType(), task.getId(), task.getProcessInstanceId(), | |
| 610 | + FileUtil.getName(URLUtil.getPath(attachment)), null, attachment); | |
| 611 | + }); | |
| 612 | + } | |
| 595 | 613 | |
| 596 | 614 | // 3. 设置流程变量。如果流程变量前端传空,需要从历史实例中获取,原因:前端表单如果在当前节点无可编辑的字段时 variables 一定会为空 |
| 597 | 615 | // 场景一:A 节点发起,B 节点表单无可编辑字段,审批通过时,C 节点需要流程变量获取下一个执行节点,但因为 B 节点无可编辑的字段,variables 为空,流程可能出现问题。 |
| ... | ... | @@ -817,7 +835,15 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 817 | 835 | // 2.2 添加流程评论 |
| 818 | 836 | taskService.addComment(task.getId(), task.getProcessInstanceId(), BpmCommentTypeEnum.REJECT.getType(), |
| 819 | 837 | BpmCommentTypeEnum.REJECT.formatComment(reqVO.getReason())); |
| 820 | - // 2.3 如果当前任务时被加签的,则加它的根任务也标记成未通过 | |
| 838 | + // 2.3 添加附件 | |
| 839 | + if (CollUtil.isNotEmpty(reqVO.getAttachments())) { | |
| 840 | + reqVO.getAttachments().forEach(attachment -> { | |
| 841 | + taskService.createAttachment(BpmAttachmentTypeEnum.TASK_ATTACHMENT.getType(), task.getId(), task.getProcessInstanceId(), | |
| 842 | + FileUtil.getName(URLUtil.getPath(attachment)), null, attachment); | |
| 843 | + }); | |
| 844 | + } | |
| 845 | + | |
| 846 | + // 2.4 如果当前任务时被加签的,则加它的根任务也标记成未通过 | |
| 821 | 847 | // 疑问:为什么要标记未通过呢? |
| 822 | 848 | // 回答:例如说 A 任务被向前加签除 B 任务时,B 任务被审批不通过,此时 A 会被取消。而 yudao-ui-admin-vue3 不展示“已取消”的任务,导致展示不出审批不通过的细节。 |
| 823 | 849 | if (task.getParentTaskId() != null) { | ... | ... |