Commit c1884c31967a616e55235d749638761e612c8a1e
1 parent
d30bf060
工作流 Flowable 通过任务,拒绝任务 实现
Showing
8 changed files
with
158 additions
and
24 deletions
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java
| ... | ... | @@ -2,9 +2,7 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; | |
| 6 | -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; | |
| 7 | -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; | |
| 5 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; | |
| 8 | 6 | import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService; |
| 9 | 7 | import io.swagger.annotations.Api; |
| 10 | 8 | import io.swagger.annotations.ApiImplicitParam; |
| ... | ... | @@ -13,10 +11,7 @@ import org.flowable.bpmn.model.BpmnModel; |
| 13 | 11 | import org.flowable.engine.TaskService; |
| 14 | 12 | import org.springframework.security.access.prepost.PreAuthorize; |
| 15 | 13 | import org.springframework.validation.annotation.Validated; |
| 16 | -import org.springframework.web.bind.annotation.GetMapping; | |
| 17 | -import org.springframework.web.bind.annotation.RequestMapping; | |
| 18 | -import org.springframework.web.bind.annotation.RequestParam; | |
| 19 | -import org.springframework.web.bind.annotation.RestController; | |
| 14 | +import org.springframework.web.bind.annotation.*; | |
| 20 | 15 | |
| 21 | 16 | import javax.annotation.Resource; |
| 22 | 17 | import javax.validation.Valid; |
| ... | ... | @@ -50,4 +45,20 @@ public class BpmTaskController { |
| 50 | 45 | @RequestParam("processInstanceId") String processInstanceId) { |
| 51 | 46 | return success(taskService.getTaskListByProcessInstanceId(processInstanceId)); |
| 52 | 47 | } |
| 48 | + | |
| 49 | + @PutMapping("/approve") | |
| 50 | + @ApiOperation("通过任务") | |
| 51 | + @PreAuthorize("@ss.hasPermission('bpm:task:update')") | |
| 52 | + public CommonResult<Boolean> approveTask(@Valid @RequestBody BpmTaskApproveReqVO reqVO) { | |
| 53 | + taskService.approveTask(getLoginUserId(), reqVO); | |
| 54 | + return success(true); | |
| 55 | + } | |
| 56 | + | |
| 57 | + @PutMapping("/reject") | |
| 58 | + @ApiOperation("不通过任务") | |
| 59 | + @PreAuthorize("@ss.hasPermission('bpm:task:update')") | |
| 60 | + public CommonResult<Boolean> rejectTask(@Valid @RequestBody BpmTaskRejectReqVO reqVO) { | |
| 61 | + taskService.rejectTask(getLoginUserId(), reqVO); | |
| 62 | + return success(true); | |
| 63 | + } | |
| 53 | 64 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmProcessInstanceConvert.java
| 1 | 1 | package cn.iocoder.yudao.module.bpm.convert.task; |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; | |
| 4 | 5 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO; |
| 5 | 6 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; |
| 6 | 7 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; |
| 7 | 8 | import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; |
| 8 | 9 | import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent; |
| 9 | 10 | import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; |
| 11 | +import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO; | |
| 10 | 12 | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| 11 | 13 | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| 12 | 14 | import org.flowable.engine.history.HistoricProcessInstance; |
| ... | ... | @@ -87,13 +89,28 @@ public interface BpmProcessInstanceConvert { |
| 87 | 89 | return event; |
| 88 | 90 | } |
| 89 | 91 | |
| 92 | + default BpmProcessInstanceResultEvent convert(Object source, ProcessInstance instance, Integer result) { | |
| 93 | + BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source); | |
| 94 | + event.setId(instance.getId()); | |
| 95 | + event.setProcessDefinitionKey(instance.getProcessDefinitionKey()); | |
| 96 | + event.setBusinessKey(instance.getBusinessKey()); | |
| 97 | + event.setResult(result); | |
| 98 | + return event; | |
| 99 | + } | |
| 100 | + | |
| 90 | 101 | default BpmMessageSendWhenProcessInstanceApproveReqDTO convert2ApprovedReq(ProcessInstance instance){ |
| 91 | - Long startUserId = instance.getStartUserId() == null ? null : Long.valueOf(instance.getStartUserId()); | |
| 92 | - BpmMessageSendWhenProcessInstanceApproveReqDTO reqDTO = new BpmMessageSendWhenProcessInstanceApproveReqDTO() | |
| 93 | - .setStartUserId(startUserId) | |
| 102 | + return new BpmMessageSendWhenProcessInstanceApproveReqDTO() | |
| 103 | + .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())) | |
| 94 | 104 | .setProcessInstanceId(instance.getId()) |
| 95 | 105 | .setProcessInstanceName(instance.getName()); |
| 96 | - return reqDTO; | |
| 106 | + } | |
| 107 | + | |
| 108 | + default BpmMessageSendWhenProcessInstanceRejectReqDTO convert2RejectReq(ProcessInstance instance, String comment) { | |
| 109 | + return new BpmMessageSendWhenProcessInstanceRejectReqDTO() | |
| 110 | + .setProcessInstanceName(instance.getName()) | |
| 111 | + .setProcessInstanceId(instance.getId()) | |
| 112 | + .setComment(comment) | |
| 113 | + .setStartUserId(NumberUtils.parseLong(instance.getStartUserId())); | |
| 97 | 114 | } |
| 98 | 115 | |
| 99 | 116 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/convert/task/BpmTaskConvert.java
| ... | ... | @@ -102,10 +102,9 @@ public interface BpmTaskConvert { |
| 102 | 102 | BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, AdminUserRespDTO startUser); |
| 103 | 103 | |
| 104 | 104 | default BpmTaskExtDO convert2TaskExt(Task task){ |
| 105 | - Long assigneeUserId = task.getAssignee() == null ? null : Long.valueOf(task.getAssignee()); | |
| 106 | 105 | BpmTaskExtDO taskExtDO = new BpmTaskExtDO() |
| 107 | 106 | .setTaskId(task.getId()) |
| 108 | - .setAssigneeUserId(assigneeUserId) | |
| 107 | + .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee())) | |
| 109 | 108 | .setName(task.getName()) |
| 110 | 109 | .setProcessDefinitionId(task.getProcessDefinitionId()) |
| 111 | 110 | .setProcessInstanceId(task.getProcessInstanceId()); | ... | ... |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java
| ... | ... | @@ -42,6 +42,6 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener { |
| 42 | 42 | |
| 43 | 43 | @Override |
| 44 | 44 | protected void taskCompleted(FlowableEngineEntityEvent event) { |
| 45 | - super.taskCompleted(event); | |
| 45 | + taskService.updateTaskExtComplete((Task)event.getEntity()); | |
| 46 | 46 | } |
| 47 | 47 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java
| ... | ... | @@ -110,5 +110,13 @@ public interface BpmProcessInstanceService { |
| 110 | 110 | */ |
| 111 | 111 | void updateProcessInstanceExtComplete(ProcessInstance instance); |
| 112 | 112 | |
| 113 | + /** | |
| 114 | + * 更新 ProcessInstance 拓展记录为不通过 | |
| 115 | + * | |
| 116 | + * @param id 流程编号 | |
| 117 | + * @param comment 理由。例如说,审批不通过时,需要传递该值 | |
| 118 | + */ | |
| 119 | + void updateProcessInstanceExtReject(String id, String comment); | |
| 120 | + | |
| 113 | 121 | |
| 114 | 122 | } | ... | ... |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.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.lang.Assert; |
| 5 | +import cn.hutool.core.util.StrUtil; | |
| 5 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 7 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 7 | 8 | import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; |
| ... | ... | @@ -29,6 +30,7 @@ import org.flowable.engine.runtime.ProcessInstance; |
| 29 | 30 | import org.flowable.task.api.Task; |
| 30 | 31 | import org.springframework.context.annotation.Lazy; |
| 31 | 32 | import org.springframework.stereotype.Service; |
| 33 | +import org.springframework.transaction.annotation.Transactional; | |
| 32 | 34 | import org.springframework.validation.annotation.Validated; |
| 33 | 35 | |
| 34 | 36 | import javax.annotation.Resource; |
| ... | ... | @@ -155,7 +157,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 155 | 157 | |
| 156 | 158 | // 通过删除流程实例,实现流程实例的取消, |
| 157 | 159 | // 删除流程实例,正则执行任务ACT_RU_TASK. 任务会被删除。通过历史表查询 |
| 158 | - runtimeService.deleteProcessInstance(cancelReqVO.getId(), | |
| 160 | + deleteProcessInstance(cancelReqVO.getId(), | |
| 159 | 161 | BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); |
| 160 | 162 | } |
| 161 | 163 | |
| ... | ... | @@ -232,6 +234,33 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 232 | 234 | BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); |
| 233 | 235 | } |
| 234 | 236 | |
| 237 | + @Transactional(rollbackFor = Exception.class) | |
| 238 | + public void updateProcessInstanceExtReject(String id, String comment) { | |
| 239 | + // 需要主动查询,因为 instance 只有 id 属性 | |
| 240 | + ProcessInstance processInstance = getProcessInstance(id); | |
| 241 | + // 删除流程实例,以实现驳回任务时,取消整个审批流程 | |
| 242 | + deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(comment))); | |
| 243 | + | |
| 244 | + // 更新 status + result | |
| 245 | + // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, | |
| 246 | + // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 | |
| 247 | + BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id) | |
| 248 | + .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) | |
| 249 | + .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); | |
| 250 | + processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); | |
| 251 | + | |
| 252 | + // 发送流程被不通过的消息 | |
| 253 | + messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, comment)); | |
| 254 | + | |
| 255 | + // 发送流程实例的状态事件 | |
| 256 | + processInstanceResultEventPublisher.sendProcessInstanceResultEvent( | |
| 257 | + BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); | |
| 258 | + } | |
| 259 | + | |
| 260 | + private void deleteProcessInstance(String id, String reason) { | |
| 261 | + runtimeService.deleteProcessInstance(id, reason); | |
| 262 | + } | |
| 263 | + | |
| 235 | 264 | private String createProcessInstance0(Long userId, ProcessDefinition definition, |
| 236 | 265 | Map<String, Object> variables, String businessKey) { |
| 237 | 266 | // 校验流程定义 | ... | ... |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java
| ... | ... | @@ -2,12 +2,11 @@ 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.controller.admin.task.vo.task.BpmTaskRespVO; | |
| 6 | -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; | |
| 7 | -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; | |
| 5 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; | |
| 8 | 6 | import org.flowable.task.api.Task; |
| 9 | 7 | |
| 10 | 8 | |
| 9 | +import javax.validation.Valid; | |
| 11 | 10 | import java.util.List; |
| 12 | 11 | import java.util.Map; |
| 13 | 12 | |
| ... | ... | @@ -55,6 +54,22 @@ public interface BpmTaskService { |
| 55 | 54 | List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId); |
| 56 | 55 | |
| 57 | 56 | /** |
| 57 | + * 通过任务 | |
| 58 | + * | |
| 59 | + * @param userId 用户编号 | |
| 60 | + * @param reqVO 通过请求 | |
| 61 | + */ | |
| 62 | + void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO); | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * 不通过任务 | |
| 66 | + * | |
| 67 | + * @param userId 用户编号 | |
| 68 | + * @param reqVO 不通过请求 | |
| 69 | + */ | |
| 70 | + void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO); | |
| 71 | + | |
| 72 | + /** | |
| 58 | 73 | * 创建 Task 拓展记录 |
| 59 | 74 | * |
| 60 | 75 | * @param task 任务实体 | ... | ... |
yudao-module-bpm/yudao-module-bpm-impl-flowable/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| ... | ... | @@ -5,9 +5,7 @@ import cn.hutool.core.util.StrUtil; |
| 5 | 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | 6 | import cn.iocoder.yudao.framework.common.util.number.NumberUtils; |
| 7 | 7 | import cn.iocoder.yudao.framework.common.util.object.PageUtils; |
| 8 | -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; | |
| 9 | -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO; | |
| 10 | -import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO; | |
| 8 | +import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*; | |
| 11 | 9 | import cn.iocoder.yudao.module.bpm.convert.task.BpmTaskConvert; |
| 12 | 10 | import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmTaskExtDO; |
| 13 | 11 | import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; |
| ... | ... | @@ -27,16 +25,19 @@ import org.flowable.task.api.history.HistoricTaskInstance; |
| 27 | 25 | import org.springframework.stereotype.Service; |
| 28 | 26 | |
| 29 | 27 | import javax.annotation.Resource; |
| 28 | +import javax.validation.Valid; | |
| 30 | 29 | import java.util.*; |
| 31 | 30 | |
| 31 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 32 | 32 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; |
| 33 | 33 | import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; |
| 34 | +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; | |
| 34 | 35 | |
| 35 | 36 | /** |
| 36 | 37 | * 流程任务实例 Service 实现类 |
| 37 | 38 | * |
| 38 | - * @author jason | |
| 39 | 39 | * @author 芋道源码 |
| 40 | + * @author jason | |
| 40 | 41 | */ |
| 41 | 42 | @Slf4j |
| 42 | 43 | @Service |
| ... | ... | @@ -124,6 +125,41 @@ public class BpmTaskServiceImpl implements BpmTaskService{ |
| 124 | 125 | } |
| 125 | 126 | |
| 126 | 127 | @Override |
| 128 | + public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) { | |
| 129 | + // 校验任务存在 | |
| 130 | + Task task = checkTask(userId, reqVO.getId()); | |
| 131 | + // 校验流程实例存在 | |
| 132 | + ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); | |
| 133 | + if (instance == null) { | |
| 134 | + throw exception(PROCESS_INSTANCE_NOT_EXISTS); | |
| 135 | + } | |
| 136 | + | |
| 137 | + // 完成任务,审批通过 | |
| 138 | + taskService.complete(task.getId(), instance.getProcessVariables()); | |
| 139 | + // 更新任务拓展表为通过 | |
| 140 | + taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId()) | |
| 141 | + .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()).setComment(reqVO.getComment())); | |
| 142 | + } | |
| 143 | + | |
| 144 | + @Override | |
| 145 | + public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) { | |
| 146 | + Task task = checkTask(userId, reqVO.getId()); | |
| 147 | + // 校验流程实例存在 | |
| 148 | + ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId()); | |
| 149 | + if (instance == null) { | |
| 150 | + throw exception(PROCESS_INSTANCE_NOT_EXISTS); | |
| 151 | + } | |
| 152 | + | |
| 153 | + // 更新流程实例为不通过 | |
| 154 | + processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getComment()); | |
| 155 | + | |
| 156 | + // 更新任务拓展表为不通过 | |
| 157 | + taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId()) | |
| 158 | + .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setComment(reqVO.getComment())); | |
| 159 | + } | |
| 160 | + | |
| 161 | + | |
| 162 | + @Override | |
| 127 | 163 | public void createTaskExt(Task task) { |
| 128 | 164 | BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) |
| 129 | 165 | .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); |
| ... | ... | @@ -133,8 +169,27 @@ public class BpmTaskServiceImpl implements BpmTaskService{ |
| 133 | 169 | @Override |
| 134 | 170 | public void updateTaskExtComplete(Task task) { |
| 135 | 171 | BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) |
| 136 | - .setEndTime(new Date()) // 此时不能使用 task 的 completeData,因为还是空的。 | |
| 137 | - .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); | |
| 172 | + .setEndTime(new Date()); | |
| 138 | 173 | taskExtMapper.updateByTaskId(taskExtDO); |
| 139 | 174 | } |
| 175 | + | |
| 176 | + /** | |
| 177 | + * 校验任务是否存在, 并且是否是分配给自己的任务 | |
| 178 | + * @param userId 用户 id | |
| 179 | + * @param taskId task id | |
| 180 | + */ | |
| 181 | + private Task checkTask(Long userId, String taskId) { | |
| 182 | + Task task = getTask(taskId); | |
| 183 | + if (task == null) { | |
| 184 | + throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS); | |
| 185 | + } | |
| 186 | + if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) { | |
| 187 | + throw exception(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF); | |
| 188 | + } | |
| 189 | + return task; | |
| 190 | + } | |
| 191 | + | |
| 192 | + private Task getTask(String id) { | |
| 193 | + return taskService.createTaskQuery().taskId(id).singleResult(); | |
| 194 | + } | |
| 140 | 195 | } | ... | ... |