工作流 Flowable 通过任务,拒绝任务 实现

This commit is contained in:
jason 2022-02-14 18:11:11 +08:00
parent d30bf0601c
commit c1884c3196
8 changed files with 158 additions and 24 deletions

View File

@ -2,9 +2,7 @@ package cn.iocoder.yudao.module.bpm.controller.admin.task;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
@ -13,10 +11,7 @@ import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.TaskService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
@ -50,4 +45,20 @@ public class BpmTaskController {
@RequestParam("processInstanceId") String processInstanceId) {
return success(taskService.getTaskListByProcessInstanceId(processInstanceId));
}
@PutMapping("/approve")
@ApiOperation("通过任务")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
public CommonResult<Boolean> approveTask(@Valid @RequestBody BpmTaskApproveReqVO reqVO) {
taskService.approveTask(getLoginUserId(), reqVO);
return success(true);
}
@PutMapping("/reject")
@ApiOperation("不通过任务")
@PreAuthorize("@ss.hasPermission('bpm:task:update')")
public CommonResult<Boolean> rejectTask(@Valid @RequestBody BpmTaskRejectReqVO reqVO) {
taskService.rejectTask(getLoginUserId(), reqVO);
return success(true);
}
}

View File

@ -1,12 +1,14 @@
package cn.iocoder.yudao.module.bpm.convert.task;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstancePageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO;
import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceRejectReqDTO;
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;
@ -87,13 +89,28 @@ public interface BpmProcessInstanceConvert {
return event;
}
default BpmProcessInstanceResultEvent convert(Object source, ProcessInstance instance, Integer result) {
BpmProcessInstanceResultEvent event = new BpmProcessInstanceResultEvent(source);
event.setId(instance.getId());
event.setProcessDefinitionKey(instance.getProcessDefinitionKey());
event.setBusinessKey(instance.getBusinessKey());
event.setResult(result);
return event;
}
default BpmMessageSendWhenProcessInstanceApproveReqDTO convert2ApprovedReq(ProcessInstance instance){
Long startUserId = instance.getStartUserId() == null ? null : Long.valueOf(instance.getStartUserId());
BpmMessageSendWhenProcessInstanceApproveReqDTO reqDTO = new BpmMessageSendWhenProcessInstanceApproveReqDTO()
.setStartUserId(startUserId)
return new BpmMessageSendWhenProcessInstanceApproveReqDTO()
.setStartUserId(NumberUtils.parseLong(instance.getStartUserId()))
.setProcessInstanceId(instance.getId())
.setProcessInstanceName(instance.getName());
return reqDTO;
}
default BpmMessageSendWhenProcessInstanceRejectReqDTO convert2RejectReq(ProcessInstance instance, String comment) {
return new BpmMessageSendWhenProcessInstanceRejectReqDTO()
.setProcessInstanceName(instance.getName())
.setProcessInstanceId(instance.getId())
.setComment(comment)
.setStartUserId(NumberUtils.parseLong(instance.getStartUserId()));
}
}

View File

@ -102,10 +102,9 @@ public interface BpmTaskConvert {
BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, AdminUserRespDTO startUser);
default BpmTaskExtDO convert2TaskExt(Task task){
Long assigneeUserId = task.getAssignee() == null ? null : Long.valueOf(task.getAssignee());
BpmTaskExtDO taskExtDO = new BpmTaskExtDO()
.setTaskId(task.getId())
.setAssigneeUserId(assigneeUserId)
.setAssigneeUserId(NumberUtils.parseLong(task.getAssignee()))
.setName(task.getName())
.setProcessDefinitionId(task.getProcessDefinitionId())
.setProcessInstanceId(task.getProcessInstanceId());

View File

@ -42,6 +42,6 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
@Override
protected void taskCompleted(FlowableEngineEntityEvent event) {
super.taskCompleted(event);
taskService.updateTaskExtComplete((Task)event.getEntity());
}
}

View File

@ -110,5 +110,13 @@ public interface BpmProcessInstanceService {
*/
void updateProcessInstanceExtComplete(ProcessInstance instance);
/**
* 更新 ProcessInstance 拓展记录为不通过
*
* @param id 流程编号
* @param comment 理由例如说审批不通过时需要传递该值
*/
void updateProcessInstanceExtReject(String id, String comment);
}

View File

@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.service.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*;
@ -29,6 +30,7 @@ import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@ -155,7 +157,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
// 通过删除流程实例实现流程实例的取消,
// 删除流程实例正则执行任务ACT_RU_TASK. 任务会被删除通过历史表查询
runtimeService.deleteProcessInstance(cancelReqVO.getId(),
deleteProcessInstance(cancelReqVO.getId(),
BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason()));
}
@ -232,6 +234,33 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult()));
}
@Transactional(rollbackFor = Exception.class)
public void updateProcessInstanceExtReject(String id, String comment) {
// 需要主动查询因为 instance 只有 id 属性
ProcessInstance processInstance = getProcessInstance(id);
// 删除流程实例以实现驳回任务时取消整个审批流程
deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(comment)));
// 更新 status + result
// 注意不能和上面的逻辑更换位置因为 deleteProcessInstance 会触发流程的取消进而调用 updateProcessInstanceExtCancel 方法
// 设置 result BpmProcessInstanceStatusEnum.CANCEL显然和 result 不一定是一致的
BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessInstanceId(id)
.setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
.setResult(BpmProcessInstanceResultEnum.REJECT.getResult());
processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
// 发送流程被不通过的消息
messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, comment));
// 发送流程实例的状态事件
processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult()));
}
private void deleteProcessInstance(String id, String reason) {
runtimeService.deleteProcessInstance(id, reason);
}
private String createProcessInstance0(Long userId, ProcessDefinition definition,
Map<String, Object> variables, String businessKey) {
// 校验流程定义

View File

@ -2,12 +2,11 @@ package cn.iocoder.yudao.module.bpm.service.task;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.*;
import org.flowable.task.api.Task;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
@ -54,6 +53,22 @@ public interface BpmTaskService {
*/
List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId);
/**
* 通过任务
*
* @param userId 用户编号
* @param reqVO 通过请求
*/
void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO);
/**
* 不通过任务
*
* @param userId 用户编号
* @param reqVO 不通过请求
*/
void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO);
/**
* 创建 Task 拓展记录
*

View File

@ -5,9 +5,7 @@ import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskTodoPageReqVO;
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.task.BpmTaskExtDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper;
@ -27,16 +25,19 @@ import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
/**
* 流程任务实例 Service 实现类
*
* @author jason
* @author 芋道源码
* @author jason
*/
@Slf4j
@Service
@ -123,6 +124,41 @@ public class BpmTaskServiceImpl implements BpmTaskService{
return BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap);
}
@Override
public void approveTask(Long userId, @Valid BpmTaskApproveReqVO reqVO) {
// 校验任务存在
Task task = checkTask(userId, reqVO.getId());
// 校验流程实例存在
ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
if (instance == null) {
throw exception(PROCESS_INSTANCE_NOT_EXISTS);
}
// 完成任务审批通过
taskService.complete(task.getId(), instance.getProcessVariables());
// 更新任务拓展表为通过
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()).setComment(reqVO.getComment()));
}
@Override
public void rejectTask(Long userId, @Valid BpmTaskRejectReqVO reqVO) {
Task task = checkTask(userId, reqVO.getId());
// 校验流程实例存在
ProcessInstance instance = processInstanceService.getProcessInstance(task.getProcessInstanceId());
if (instance == null) {
throw exception(PROCESS_INSTANCE_NOT_EXISTS);
}
// 更新流程实例为不通过
processInstanceService.updateProcessInstanceExtReject(instance.getProcessInstanceId(), reqVO.getComment());
// 更新任务拓展表为不通过
taskExtMapper.updateByTaskId(new BpmTaskExtDO().setTaskId(task.getId())
.setResult(BpmProcessInstanceResultEnum.REJECT.getResult()).setComment(reqVO.getComment()));
}
@Override
public void createTaskExt(Task task) {
BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
@ -133,8 +169,27 @@ public class BpmTaskServiceImpl implements BpmTaskService{
@Override
public void updateTaskExtComplete(Task task) {
BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
.setEndTime(new Date()) // 此时不能使用 task completeData因为还是空的
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
.setEndTime(new Date());
taskExtMapper.updateByTaskId(taskExtDO);
}
/**
* 校验任务是否存在 并且是否是分配给自己的任务
* @param userId 用户 id
* @param taskId task id
*/
private Task checkTask(Long userId, String taskId) {
Task task = getTask(taskId);
if (task == null) {
throw exception(TASK_COMPLETE_FAIL_NOT_EXISTS);
}
if (!Objects.equals(userId, NumberUtils.parseLong(task.getAssignee()))) {
throw exception(TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
}
return task;
}
private Task getTask(String id) {
return taskService.createTaskQuery().taskId(id).singleResult();
}
}