feat(bpm): 支持流程评论接口

- 新增流程评论创建、列表查询接口
- 封装 BpmCommentService 统一复用 Flowable Comment
- 评论列表返回评论人和对应任务信息
- 新增 BPM 评论类型字典与评论枚举
- 补充任务校验与历史任务 Map 查询能力
This commit is contained in:
YunaiV
2026-07-03 07:52:22 +08:00
parent 28f547915d
commit 7b35b16240
3 changed files with 56 additions and 5 deletions
@@ -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<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap(
convertSet(pageResult.getList(), HistoricTaskInstance::getProcessDefinitionId));
return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, null, processDefinitionInfoMap));
Map<String, List<Attachment>> 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<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap = processDefinitionService.getProcessDefinitionInfoMap(
convertSet(pageResult.getList(), HistoricTaskInstance::getProcessDefinitionId));
return success(BpmTaskConvert.INSTANCE.buildTaskPage(pageResult, processInstanceMap, userMap, deptMap, processDefinitionInfoMap));
Map<String, List<Attachment>> 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<Long, BpmFormDO> formMap = formService.getFormMap(
convertSet(taskList, task -> NumberUtils.parseLong(task.getFormKey())));
Map<String, List<Attachment>> 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<String, List<Attachment>> getTaskAttachmentMap(List<HistoricTaskInstance> taskList) {
// 1.1 获得流程实例的任务 Map
Map<String, List<HistoricTaskInstance>> processTaskMap = convertMultiMap(taskList,
HistoricTaskInstance::getProcessInstanceId);
// 1.2 获得任务附件列表
List<Attachment> 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);
}
}
@@ -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<String> attachments;
@Schema(description = "任务负责人编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "2048")
@JsonIgnore // 不返回,只是方便后续读取,赋值给 ownerUser
private Long owner;
@@ -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<String, HistoricProcessInstance> processInstanceMap,
Map<Long, AdminUserRespDTO> userMap,
Map<Long, DeptRespDTO> deptMap,
Map<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap) {
Map<String, BpmProcessDefinitionInfoDO> processDefinitionInfoMap,
Map<String, List<Attachment>> taskAttachmentMap) {
List<BpmTaskRespVO> 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<BpmTaskRespVO> buildTaskListByProcessInstanceId(List<HistoricTaskInstance> taskList,
Map<Long, BpmFormDO> formMap,
Map<Long, AdminUserRespDTO> userMap,
Map<Long, DeptRespDTO> deptMap) {
Map<Long, DeptRespDTO> deptMap,
Map<String, List<Attachment>> 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) {
@@ -195,6 +200,20 @@ public interface BpmTaskConvert {
}
}
/**
* 构建任务审批证据
*
* @param taskVO 任务 VO
* @param task 历史任务
* @param taskAttachmentMap 任务附件 Map
*/
default void buildTaskEvidence(BpmTaskRespVO taskVO, HistoricTaskInstance task,
Map<String, List<Attachment>> taskAttachmentMap) {
taskVO.setSignPicUrl(FlowableUtils.getTaskSignPicUrl(task));
taskVO.setAttachments(convertList(
taskAttachmentMap != null ? taskAttachmentMap.get(task.getId()) : null, Attachment::getUrl));
}
/**
* 将父任务的属性,拷贝到子任务(加签任务)
* <p>