Commit 41e4283f992d951944b185ed3e6e66cd88263ebf

Authored by jason
1 parent c1884c31

工作流 Flowable 转办任务的实现

yudao-module-bpm/yudao-module-bpm-impl-activiti/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
... ... @@ -37,7 +37,7 @@ public class BpmTaskController {
37 37 @GetMapping("done-page")
38 38 @ApiOperation("获取 Done 已办任务分页")
39 39 @PreAuthorize("@ss.hasPermission('bpm:task:query')")
40   - public CommonResult<PageResult<BpmTaskDonePageItemRespVO>> getTodoTaskPage(@Valid BpmTaskDonePageReqVO pageVO) {
  40 + public CommonResult<PageResult<BpmTaskDonePageItemRespVO>> getDoneTaskPage(@Valid BpmTaskDonePageReqVO pageVO) {
41 41 return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO));
42 42 }
43 43  
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/api/task/FlowableProcessInstanceApiImpl.java renamed to yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/api/task/BpmProcessInstanceApiImpl.java
1 1 package cn.iocoder.yudao.module.bpm.api.task;
2 2  
3 3 import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
  4 +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
4 5 import org.springframework.stereotype.Service;
5 6 import org.springframework.validation.annotation.Validated;
6 7  
... ... @@ -14,11 +15,13 @@ import javax.validation.Valid;
14 15 */
15 16 @Service
16 17 @Validated
17   -public class FlowableProcessInstanceApiImpl implements BpmProcessInstanceApi {
  18 +public class BpmProcessInstanceApiImpl implements BpmProcessInstanceApi {
  19 +
  20 + @Resource
  21 + private BpmProcessInstanceService processInstanceService;
18 22  
19 23 @Override
20 24 public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO reqDTO) {
21   - //TODO
22   - return null;
  25 + return processInstanceService.createProcessInstance(userId, reqDTO);
23 26 }
24 27 }
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
... ... @@ -37,6 +37,13 @@ public class BpmTaskController {
37 37 return success(taskService.getTodoTaskPage(getLoginUserId(), pageVO));
38 38 }
39 39  
  40 + @GetMapping("done-page")
  41 + @ApiOperation("获取 Done 已办任务分页")
  42 + @PreAuthorize("@ss.hasPermission('bpm:task:query')")
  43 + public CommonResult<PageResult<BpmTaskDonePageItemRespVO>> getDoneTaskPage(@Valid BpmTaskDonePageReqVO pageVO) {
  44 + return success(taskService.getDoneTaskPage(getLoginUserId(), pageVO));
  45 + }
  46 +
40 47 @GetMapping("/list-by-process-instance-id")
41 48 @ApiOperation(value = "获得指定流程实例的任务列表", notes = "包括完成的、未完成的")
42 49 @ApiImplicitParam(name = "processInstanceId", value = "流程实例的编号", required = true, dataTypeClass = String.class)
... ... @@ -61,4 +68,12 @@ public class BpmTaskController {
61 68 taskService.rejectTask(getLoginUserId(), reqVO);
62 69 return success(true);
63 70 }
  71 +
  72 + @PutMapping("/update-assignee")
  73 + @ApiOperation(value = "更新任务的负责人", notes = "用于【流程详情】的【转派】按钮")
  74 + @PreAuthorize("@ss.hasPermission('bpm:task:update')")
  75 + public CommonResult<Boolean> updateTaskAssignee(@Valid @RequestBody BpmTaskUpdateAssigneeReqVO reqVO) {
  76 + taskService.updateTaskAssignee(getLoginUserId(), reqVO);
  77 + return success(true);
  78 + }
64 79 }
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
... ... @@ -53,6 +53,24 @@ public interface BpmTaskConvert {
53 53 SuspensionState.ACTIVE.getStateCode();
54 54 }
55 55  
  56 + default List<BpmTaskDonePageItemRespVO> convertList2(List<HistoricTaskInstance> tasks, Map<String, BpmTaskExtDO> bpmTaskExtDOMap,
  57 + Map<String, HistoricProcessInstance> historicProcessInstanceMap,
  58 + Map<Long, AdminUserRespDTO> userMap) {
  59 + return CollectionUtils.convertList(tasks, task -> {
  60 + BpmTaskDonePageItemRespVO respVO = convert2(task);
  61 + BpmTaskExtDO taskExtDO = bpmTaskExtDOMap.get(task.getId());
  62 + copyTo(taskExtDO, respVO);
  63 + HistoricProcessInstance processInstance = historicProcessInstanceMap.get(task.getProcessInstanceId());
  64 + if (processInstance != null) {
  65 + AdminUserRespDTO startUser = userMap.get(NumberUtils.parseLong(processInstance.getStartUserId()));
  66 + respVO.setProcessInstance(convert(processInstance, startUser));
  67 + }
  68 + return respVO;
  69 + });
  70 + }
  71 +
  72 + BpmTaskDonePageItemRespVO convert2(HistoricTaskInstance bean);
  73 +
56 74 @Mappings({
57 75 @Mapping(source = "processInstance.id", target = "id"),
58 76 @Mapping(source = "processInstance.name", target = "name"),
... ... @@ -111,6 +129,18 @@ public interface BpmTaskConvert {
111 129 taskExtDO.setCreateTime(task.getCreateTime());
112 130 return taskExtDO;
113 131 }
  132 +
  133 + default BpmMessageSendWhenTaskCreatedReqDTO convert(ProcessInstance processInstance, AdminUserRespDTO startUser, Task task) {
  134 + BpmMessageSendWhenTaskCreatedReqDTO reqDTO = new BpmMessageSendWhenTaskCreatedReqDTO();
  135 + reqDTO.setProcessInstanceId(processInstance.getProcessInstanceId())
  136 + .setProcessInstanceName(processInstance.getName())
  137 + .setStartUserId(startUser.getId())
  138 + .setStartUserNickname(startUser.getNickname())
  139 + .setTaskId(task.getId())
  140 + .setTaskName(task.getName())
  141 + .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee()));
  142 + return reqDTO;
  143 + }
114 144 }
115 145  
116 146  
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
... ... @@ -44,4 +44,9 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
44 44 protected void taskCompleted(FlowableEngineEntityEvent event) {
45 45 taskService.updateTaskExtComplete((Task)event.getEntity());
46 46 }
  47 +
  48 + @Override
  49 + protected void taskAssigned(FlowableEngineEntityEvent event) {
  50 + taskService.updateTaskExtAssign((Task)event.getEntity());
  51 + }
47 52 }
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.task;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 4 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  5 +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
5 6 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*;
6 7 import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
7 8 import org.flowable.engine.delegate.event.FlowableCancelledEvent;
... ... @@ -55,7 +56,6 @@ public interface BpmProcessInstanceService {
55 56 */
56 57 PageResult<BpmProcessInstancePageItemRespVO> getMyProcessInstancePage(Long userId,
57 58 @Valid BpmProcessInstanceMyPageReqVO pageReqVO);
58   -
59 59 /**
60 60 * 创建流程实例(提供给前端)
61 61 *
... ... @@ -66,6 +66,15 @@ public interface BpmProcessInstanceService {
66 66 String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO);
67 67  
68 68 /**
  69 + * 创建流程实例(提供给内部)
  70 + *
  71 + * @param userId 用户编号
  72 + * @param createReqDTO 创建信息
  73 + * @return 实例的编号
  74 + */
  75 + String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO);
  76 +
  77 + /**
69 78 * 获得流程实例 VO 信息
70 79 *
71 80 * @param id 流程实例的编号
... ... @@ -90,6 +99,24 @@ public interface BpmProcessInstanceService {
90 99 HistoricProcessInstance getHistoricProcessInstance(String id);
91 100  
92 101 /**
  102 + * 获得历史的流程实例列表
  103 + *
  104 + * @param ids 流程实例的编号集合
  105 + * @return 历史的流程实例列表
  106 + */
  107 + List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids);
  108 +
  109 + /**
  110 + * 获得历史的流程实例 Map
  111 + *
  112 + * @param ids 流程实例的编号集合
  113 + * @return 历史的流程实例列表 Map
  114 + */
  115 + default Map<String, HistoricProcessInstance> getHistoricProcessInstanceMap(Set<String> ids) {
  116 + return CollectionUtils.convertMap(getHistoricProcessInstances(ids), HistoricProcessInstance::getId);
  117 + }
  118 +
  119 + /**
93 120 * 创建 ProcessInstance 拓展记录
94 121 *
95 122 * @param instance 流程任务
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
... ... @@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert;
5 5 import cn.hutool.core.util.StrUtil;
6 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 7 import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
  8 +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
8 9 import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*;
9 10 import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert;
10 11 import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
... ... @@ -113,6 +114,14 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
113 114 }
114 115  
115 116 @Override
  117 + public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) {
  118 + // 获得流程定义
  119 + ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey());
  120 + // 发起流程
  121 + return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey());
  122 + }
  123 +
  124 + @Override
116 125 public BpmProcessInstanceRespVO getProcessInstanceVO(String id) {
117 126 // 获得流程实例
118 127 HistoricProcessInstance processInstance = getHistoricProcessInstance(id);
... ... @@ -173,6 +182,11 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
173 182 }
174 183  
175 184 @Override
  185 + public List<HistoricProcessInstance> getHistoricProcessInstances(Set<String> ids) {
  186 + return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list();
  187 + }
  188 +
  189 + @Override
176 190 public void createProcessInstanceExt(ProcessInstance instance) {
177 191 // 获得流程定义
178 192 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId());
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
... ... @@ -25,6 +25,14 @@ public interface BpmTaskService {
25 25 * @return 流程任务分页
26 26 */
27 27 PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageReqVO);
  28 + /**
  29 + * 获得已办的流程任务分页
  30 + *
  31 + * @param userId 用户编号
  32 + * @param pageReqVO 分页请求
  33 + * @return 流程任务分页
  34 + */
  35 + PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageReqVO);
28 36  
29 37 /**
30 38 * 获得流程任务 Map
... ... @@ -70,6 +78,22 @@ public interface BpmTaskService {
70 78 void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
71 79  
72 80 /**
  81 + * 将流程任务分配给指定用户
  82 + *
  83 + * @param userId 用户编号
  84 + * @param reqVO 分配请求
  85 + */
  86 + void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO);
  87 +
  88 + /**
  89 + * 将流程任务分配给指定用户
  90 + *
  91 + * @param id 流程任务编号
  92 + * @param userId 用户编号
  93 + */
  94 + void updateTaskAssignee(String id, Long userId);
  95 +
  96 + /**
73 97 * 创建 Task 拓展记录
74 98 *
75 99 * @param task 任务实体
... ... @@ -83,4 +107,11 @@ public interface BpmTaskService {
83 107 */
84 108 void updateTaskExtComplete(Task task);
85 109  
  110 + /**
  111 + * 更新 Task 拓展记录,并发送通知
  112 + *
  113 + * @param task 任务实体
  114 + */
  115 + void updateTaskExtAssign(Task task);
  116 +
86 117 }
... ...
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
... ... @@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert;
10 10 import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO;
11 11 import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
12 12 import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
  13 +import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
13 14 import cn.iocoder.yudao.module.system.api.dept.DeptApi;
14 15 import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
15 16 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
... ... @@ -22,7 +23,10 @@ import org.flowable.engine.runtime.ProcessInstance;
22 23 import org.flowable.task.api.Task;
23 24 import org.flowable.task.api.TaskQuery;
24 25 import org.flowable.task.api.history.HistoricTaskInstance;
  26 +import org.flowable.task.api.history.HistoricTaskInstanceQuery;
25 27 import org.springframework.stereotype.Service;
  28 +import org.springframework.transaction.support.TransactionSynchronization;
  29 +import org.springframework.transaction.support.TransactionSynchronizationManager;
26 30  
27 31 import javax.annotation.Resource;
28 32 import javax.validation.Valid;
... ... @@ -56,6 +60,8 @@ public class BpmTaskServiceImpl implements BpmTaskService{
56 60 private DeptApi deptApi;
57 61 @Resource
58 62 private BpmTaskExtMapper taskExtMapper;
  63 + @Resource
  64 + private BpmMessageService messageService;
59 65  
60 66 @Override
61 67 public PageResult<BpmTaskTodoPageItemRespVO> getTodoTaskPage(Long userId, BpmTaskTodoPageReqVO pageVO) {
... ... @@ -90,6 +96,42 @@ public class BpmTaskServiceImpl implements BpmTaskService{
90 96 }
91 97  
92 98 @Override
  99 + public PageResult<BpmTaskDonePageItemRespVO> getDoneTaskPage(Long userId, BpmTaskDonePageReqVO pageVO) {
  100 + // 查询已办任务
  101 + HistoricTaskInstanceQuery taskQuery = historyService.createHistoricTaskInstanceQuery()
  102 + .finished() // 已完成
  103 + .taskAssignee(String.valueOf(userId)) // 分配给自己
  104 + .orderByHistoricTaskInstanceEndTime().desc(); // 审批时间倒序
  105 + if (StrUtil.isNotBlank(pageVO.getName())) {
  106 + taskQuery.taskNameLike("%" + pageVO.getName() + "%");
  107 + }
  108 + if (pageVO.getBeginCreateTime() != null) {
  109 + taskQuery.taskCreatedAfter(pageVO.getBeginCreateTime());
  110 + }
  111 + if (pageVO.getEndCreateTime() != null) {
  112 + taskQuery.taskCreatedBefore(pageVO.getEndCreateTime());
  113 + }
  114 + // 执行查询
  115 + List<HistoricTaskInstance> tasks = taskQuery.listPage(PageUtils.getStart(pageVO), pageVO.getPageSize());
  116 + if (CollUtil.isEmpty(tasks)) {
  117 + return PageResult.empty(taskQuery.count());
  118 + }
  119 +
  120 + // 获得 TaskExtDO Map
  121 + List<BpmTaskExtDO> bpmTaskExtDOs = taskExtMapper.selectListByTaskIds(convertSet(tasks, HistoricTaskInstance::getId));
  122 + Map<String, BpmTaskExtDO> bpmTaskExtDOMap = convertMap(bpmTaskExtDOs, BpmTaskExtDO::getTaskId);
  123 + // 获得 ProcessInstance Map
  124 + Map<String, HistoricProcessInstance> historicProcessInstanceMap = processInstanceService.getHistoricProcessInstanceMap(
  125 + convertSet(tasks, HistoricTaskInstance::getProcessInstanceId));
  126 + // 获得 User Map
  127 + Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
  128 + convertSet(historicProcessInstanceMap.values(), instance -> Long.valueOf(instance.getStartUserId())));
  129 + // 拼接结果
  130 + return new PageResult<>(BpmTaskConvert.INSTANCE.convertList2(tasks, bpmTaskExtDOMap, historicProcessInstanceMap, userMap),
  131 + taskQuery.count());
  132 + }
  133 +
  134 + @Override
93 135 public List<Task> getTasksByProcessInstanceIds(List<String> processInstanceIds) {
94 136 if (CollUtil.isEmpty(processInstanceIds)) {
95 137 return Collections.emptyList();
... ... @@ -158,6 +200,19 @@ public class BpmTaskServiceImpl implements BpmTaskService{
158 200 .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setComment(reqVO.getComment()));
159 201 }
160 202  
  203 + @Override
  204 + public void updateTaskAssignee(Long userId, BpmTaskUpdateAssigneeReqVO reqVO) {
  205 + // 校验任务存在
  206 + Task task = checkTask(userId, reqVO.getId());
  207 + // 更新负责人
  208 + updateTaskAssignee(task.getId(), reqVO.getAssigneeUserId());
  209 + }
  210 +
  211 + @Override
  212 + public void updateTaskAssignee(String id, Long userId) {
  213 + taskService.setAssignee(id, String.valueOf(userId));
  214 + }
  215 +
161 216  
162 217 @Override
163 218 public void createTaskExt(Task task) {
... ... @@ -173,6 +228,24 @@ public class BpmTaskServiceImpl implements BpmTaskService{
173 228 taskExtMapper.updateByTaskId(taskExtDO);
174 229 }
175 230  
  231 + @Override
  232 + public void updateTaskExtAssign(Task task) {
  233 + BpmTaskExtDO taskExtDO = new BpmTaskExtDO()
  234 + .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee()))
  235 + .setTaskId(task.getId());
  236 + taskExtMapper.updateByTaskId(taskExtDO);
  237 + //TODO 创建任务时候 也会调用 updateTaskExtAssign, processInstance 名称为空 校验不通过
  238 + // 发送通知。在事务提交时,批量执行操作,所以直接查询会无法查询到 ProcessInstance,所以这里是通过监听事务的提交来实现。
  239 +// TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
  240 +// @Override
  241 +// public void afterCommit() {
  242 +// ProcessInstance processInstance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
  243 +// AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(processInstance.getStartUserId()));
  244 +// messageService.sendMessageWhenTaskAssigned(BpmTaskConvert.INSTANCE.convert(processInstance, startUser, task));
  245 +// }
  246 +// });
  247 + }
  248 +
176 249 /**
177 250 * 校验任务是否存在, 并且是否是分配给自己的任务
178 251 * @param userId 用户 id
... ...