工作流 Flowable 取消流程实例实现

pull/2/head
jason 2022-02-14 15:47:39 +08:00
parent 075dd83b5f
commit d30bf0601c
9 changed files with 182 additions and 37 deletions

View File

@ -2,10 +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.instance.BpmProcessInstanceCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO;
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.*;
import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
@ -50,4 +47,12 @@ public class BpmProcessInstanceController {
public CommonResult<BpmProcessInstanceRespVO> getProcessInstance(@RequestParam("id") String id) {
return success(processInstanceService.getProcessInstanceVO(id));
}
@DeleteMapping("/cancel")
@ApiOperation(value = "取消流程实例", notes = "撤回发起的流程")
@PreAuthorize("@ss.hasPermission('bpm:process-instance:cancel')")
public CommonResult<Boolean> cancelProcessInstance(@Valid @RequestBody BpmProcessInstanceCancelReqVO cancelReqVO) {
processInstanceService.cancelProcessInstance(getLoginUserId(), cancelReqVO);
return success(true);
}
}

View File

@ -5,18 +5,23 @@ import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessI
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.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.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingTarget;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* Convert
@ -73,7 +78,22 @@ public interface BpmProcessInstanceConvert {
BpmProcessInstanceRespVO.User convert2(AdminUserRespDTO bean);
default BpmProcessInstanceResultEvent convert(Object source, HistoricProcessInstance 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)
.setProcessInstanceId(instance.getId())
.setProcessInstanceName(instance.getName());
return reqDTO;
}
}

View File

@ -101,7 +101,17 @@ 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)
.setName(task.getName())
.setProcessDefinitionId(task.getProcessDefinitionId())
.setProcessInstanceId(task.getProcessInstanceId());
taskExtDO.setCreateTime(task.getCreateTime());
return taskExtDO;
}
}

View File

@ -28,8 +28,8 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent
public static final Set<FlowableEngineEventType> PROCESS_INSTANCE_EVENTS = ImmutableSet.<FlowableEngineEventType>builder()
.add(FlowableEngineEventType.PROCESS_CREATED)
.add(FlowableEngineEventType.PROCESS_STARTED)
.add(FlowableEngineEventType.PROCESS_CANCELLED)
.add(FlowableEngineEventType.PROCESS_COMPLETED)
.build();
public BpmProcessInstanceEventListener(){
@ -42,13 +42,12 @@ public class BpmProcessInstanceEventListener extends AbstractFlowableEngineEvent
}
@Override
protected void processStarted(FlowableProcessStartedEvent event) {
super.processStarted(event);
protected void processCancelled(FlowableCancelledEvent event) {
processInstanceService.updateProcessInstanceExtCancel(event);
}
@Override
protected void processCancelled(FlowableCancelledEvent event) {
super.processCancelled(event);
protected void processCompleted(FlowableEngineEntityEvent event) {
processInstanceService.updateProcessInstanceExtComplete((ProcessInstance)event.getEntity());
}
}

View File

@ -39,4 +39,9 @@ public class BpmTaskEventListener extends AbstractFlowableEngineEventListener {
protected void taskCreated(FlowableEngineEntityEvent event) {
taskService.createTaskExt((Task) event.getEntity());
}
@Override
protected void taskCompleted(FlowableEngineEntityEvent event) {
super.taskCompleted(event);
}
}

View File

@ -2,11 +2,9 @@ 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.instance.BpmProcessInstanceCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO;
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.*;
import org.flowable.common.engine.api.delegate.event.FlowableEngineEntityEvent;
import org.flowable.engine.delegate.event.FlowableCancelledEvent;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
@ -22,6 +20,14 @@ import java.util.Set;
*/
public interface BpmProcessInstanceService {
/**
*
*
* @param id
* @return
*/
ProcessInstance getProcessInstance(String id);
/**
*
*
@ -67,6 +73,14 @@ public interface BpmProcessInstanceService {
*/
BpmProcessInstanceRespVO getProcessInstanceVO(String id);
/**
*
*
* @param userId
* @param cancelReqVO
*/
void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO);
/**
*
*
@ -81,4 +95,20 @@ public interface BpmProcessInstanceService {
* @param instance
*/
void createProcessInstanceExt(ProcessInstance instance);
/**
* ProcessInstance
*
* @param event
*/
void updateProcessInstanceExtCancel(FlowableCancelledEvent event);
/**
* ProcessInstance
*
* @param instance
*/
void updateProcessInstanceExtComplete(ProcessInstance instance);
}

View File

@ -4,17 +4,17 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
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.BpmProcessInstanceCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.BpmProcessInstanceMyPageReqVO;
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.*;
import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert;
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.mysql.task.BpmProcessInstanceExtMapper;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher;
import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService;
import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
@ -22,6 +22,7 @@ import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.delegate.event.FlowableCancelledEvent;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
@ -32,15 +33,12 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_IS_SUSPENDED;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_DEFINITION_NOT_EXISTS;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF;
/**
* Service
@ -74,6 +72,15 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
private AdminUserApi adminUserApi;
@Resource
private DeptApi deptApi;
@Resource
private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher;
@Resource
private BpmMessageService messageService;
@Override
public ProcessInstance getProcessInstance(String id) {
return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult();
}
@Override
public List<ProcessInstance> getProcessInstances(Set<String> ids) {
return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list();
@ -134,6 +141,24 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
processDefinition, processDefinitionExt, bpmnXml, startUser, dept);
}
@Override
public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) {
// 校验流程实例存在
ProcessInstance instance = getProcessInstance(cancelReqVO.getId());
if (instance == null) {
throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS);
}
// 只能取消自己的
if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) {
throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF);
}
// 通过删除流程实例,实现流程实例的取消,
// 删除流程实例正则执行任务ACT_RU_TASK. 任务会被删除。通过历史表查询
runtimeService.deleteProcessInstance(cancelReqVO.getId(),
BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason()));
}
/**
*
*
@ -162,6 +187,51 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
processInstanceExtMapper.insert(instanceExtDO);
}
@Override
public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) {
// 判断是否为 Reject 不通过。如果是,则不进行更新
if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String)event.getCause())) {
return;
}
// 需要主动查询,因为 instance 只有 id 属性
// 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance
HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId());
// 更新拓展表
BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO()
.setProcessInstanceId(event.getProcessInstanceId())
.setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime所以这里设置
.setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
.setResult(BpmProcessInstanceResultEnum.CANCEL.getResult());
processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
// 发送流程实例的状态事件
processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult()));
}
@Override
public void updateProcessInstanceExtComplete(ProcessInstance instance) {
// 需要主动查询,因为 instance 只有 id 属性
// 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance
HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId());
// 更新拓展表
BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO()
.setProcessInstanceId(instance.getProcessInstanceId())
.setEndTime(new Date()) // 由于 ProcessInstance 里没有办法拿到 endTime所以这里设置
.setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus())
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过
processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO);
// 发送流程被通过的消息
messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance));
// 发送流程实例的状态事件
processInstanceResultEventPublisher.sendProcessInstanceResultEvent(
BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult()));
}
private String createProcessInstance0(Long userId, ProcessDefinition definition,
Map<String, Object> variables, String businessKey) {
// 校验流程定义
@ -181,7 +251,6 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId())
.setFormVariables(variables));
return instance.getId();
}
}

View File

@ -61,4 +61,11 @@ public interface BpmTaskService {
*/
void createTaskExt(Task task);
/**
* Task
*
* @param task
*/
void updateTaskExtComplete(Task task);
}

View File

@ -27,10 +27,7 @@ import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
@ -128,13 +125,16 @@ public class BpmTaskServiceImpl implements BpmTaskService{
@Override
public void createTaskExt(Task task) {
BpmTaskExtDO taskExtDO = new BpmTaskExtDO()
.setTaskId(task.getId())
.setAssigneeUserId(task.getAssignee() == null ? null : Long.valueOf(task.getAssignee()))
.setProcessDefinitionId(task.getProcessDefinitionId())
.setProcessInstanceId(task.getProcessInstanceId())
.setName(task.getName())
BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
taskExtMapper.insert(taskExtDO);
}
@Override
public void updateTaskExtComplete(Task task) {
BpmTaskExtDO taskExtDO = BpmTaskConvert.INSTANCE.convert2TaskExt(task)
.setEndTime(new Date()) // 此时不能使用 task 的 completeData因为还是空的。
.setResult(BpmProcessInstanceResultEnum.APPROVE.getResult());
taskExtMapper.updateByTaskId(taskExtDO);
}
}