工作流 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.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.*;
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.service.task.BpmTaskService; import cn.iocoder.yudao.module.bpm.service.task.BpmTaskService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParam;
@ -13,10 +11,7 @@ import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.TaskService; import org.flowable.engine.TaskService;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid; import javax.validation.Valid;
@ -50,4 +45,20 @@ public class BpmTaskController {
@RequestParam("processInstanceId") String processInstanceId) { @RequestParam("processInstanceId") String processInstanceId) {
return success(taskService.getTaskListByProcessInstanceId(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; package cn.iocoder.yudao.module.bpm.convert.task;
import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.BpmProcessInstancePageItemRespVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceRespVO; 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.definition.BpmProcessDefinitionExtDO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; 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.framework.bpm.core.event.BpmProcessInstanceResultEvent;
import cn.iocoder.yudao.module.bpm.service.message.dto.BpmMessageSendWhenProcessInstanceApproveReqDTO; 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.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.history.HistoricProcessInstance;
@ -87,13 +89,28 @@ public interface BpmProcessInstanceConvert {
return event; 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){ default BpmMessageSendWhenProcessInstanceApproveReqDTO convert2ApprovedReq(ProcessInstance instance){
Long startUserId = instance.getStartUserId() == null ? null : Long.valueOf(instance.getStartUserId()); return new BpmMessageSendWhenProcessInstanceApproveReqDTO()
BpmMessageSendWhenProcessInstanceApproveReqDTO reqDTO = new BpmMessageSendWhenProcessInstanceApproveReqDTO() .setStartUserId(NumberUtils.parseLong(instance.getStartUserId()))
.setStartUserId(startUserId)
.setProcessInstanceId(instance.getId()) .setProcessInstanceId(instance.getId())
.setProcessInstanceName(instance.getName()); .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); BpmTaskTodoPageItemRespVO.ProcessInstance convert(HistoricProcessInstance processInstance, AdminUserRespDTO startUser);
default BpmTaskExtDO convert2TaskExt(Task task){ default BpmTaskExtDO convert2TaskExt(Task task){
Long assigneeUserId = task.getAssignee() == null ? null : Long.valueOf(task.getAssignee());
BpmTaskExtDO taskExtDO = new BpmTaskExtDO() BpmTaskExtDO taskExtDO = new BpmTaskExtDO()
.setTaskId(task.getId()) .setTaskId(task.getId())
.setAssigneeUserId(assigneeUserId) .setAssigneeUserId(NumberUtils.parseLong(task.getAssignee()))
.setName(task.getName()) .setName(task.getName())
.setProcessDefinitionId(task.getProcessDefinitionId()) .setProcessDefinitionId(task.getProcessDefinitionId())
.setProcessInstanceId(task.getProcessInstanceId()); .setProcessInstanceId(task.getProcessInstanceId());

View File

@ -42,6 +42,6 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
@Override @Override
protected void taskCompleted(FlowableEngineEntityEvent event) { 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); 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.collection.CollUtil;
import cn.hutool.core.lang.Assert; 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.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; 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.flowable.task.api.Task;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -155,7 +157,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
// 通过删除流程实例实现流程实例的取消, // 通过删除流程实例实现流程实例的取消,
// 删除流程实例正则执行任务ACT_RU_TASK. 任务会被删除通过历史表查询 // 删除流程实例正则执行任务ACT_RU_TASK. 任务会被删除通过历史表查询
runtimeService.deleteProcessInstance(cancelReqVO.getId(), deleteProcessInstance(cancelReqVO.getId(),
BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason()));
} }
@ -232,6 +234,33 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); 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, private String createProcessInstance0(Long userId, ProcessDefinition definition,
Map<String, Object> variables, String businessKey) { 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.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; 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.*;
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 org.flowable.task.api.Task; import org.flowable.task.api.Task;
import javax.validation.Valid;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -54,6 +53,22 @@ public interface BpmTaskService {
*/ */
List<BpmTaskRespVO> getTaskListByProcessInstanceId(String processInstanceId); 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 拓展记录 * 创建 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.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.PageUtils; 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.*;
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.convert.task.BpmTaskConvert; 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.dataobject.task.BpmTaskExtDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmTaskExtMapper; 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 org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.*; 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.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
/** /**
* 流程任务实例 Service 实现类 * 流程任务实例 Service 实现类
* *
* @author jason
* @author 芋道源码 * @author 芋道源码
* @author jason
*/ */
@Slf4j @Slf4j
@Service @Service
@ -123,6 +124,41 @@ public class BpmTaskServiceImpl implements BpmTaskService{
return BpmTaskConvert.INSTANCE.convertList3(tasks, bpmTaskExtDOMap, processInstance, userMap, deptMap); 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 @Override
public void createTaskExt(Task task) { public void createTaskExt(Task task) {
BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
@ -133,8 +169,27 @@ public class BpmTaskServiceImpl implements BpmTaskService{
@Override @Override
public void updateTaskExtComplete(Task task) { public void updateTaskExtComplete(Task task) {
BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task) BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
.setEndTime(new Date()) // 此时不能使用 task completeData因为还是空的 .setEndTime(new Date());
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
taskExtMapper.updateByTaskId(taskExtDO); 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();
}
} }