Search in sources :

Example 1 with WfTaskBo

use of com.ruoyi.workflow.domain.bo.WfTaskBo in project RuoYi-Flowable-Plus by KonBAI-Q.

the class WfTaskServiceImpl method taskReject.

/**
 * 驳回任务
 *
 * @param bo
 */
@Override
public void taskReject(WfTaskBo bo) {
    if (taskService.createTaskQuery().taskId(bo.getTaskId()).singleResult().isSuspended()) {
        throw new RuntimeException("任务处于挂起状态");
    }
    // 当前任务 task
    Task task = taskService.createTaskQuery().taskId(bo.getTaskId()).singleResult();
    // 获取流程定义信息
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
    // 获取所有节点信息
    Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0);
    // 获取全部节点列表,包含子节点
    Collection<FlowElement> allElements = FlowableUtils.getAllElements(process.getFlowElements(), null);
    // 获取当前任务节点元素
    FlowElement source = null;
    if (allElements != null) {
        for (FlowElement flowElement : allElements) {
            // 类型为用户节点
            if (flowElement.getId().equals(task.getTaskDefinitionKey())) {
                // 获取节点信息
                source = flowElement;
            }
        }
    }
    // 目的获取所有跳转到的节点 targetIds
    // 获取当前节点的所有父级用户任务节点
    // 深度优先算法思想:延边迭代深入
    List<UserTask> parentUserTaskList = FlowableUtils.iteratorFindParentUserTasks(source, null, null);
    if (parentUserTaskList == null || parentUserTaskList.size() == 0) {
        throw new RuntimeException("当前节点为初始任务节点,不能驳回");
    }
    // 获取活动 ID 即节点 Key
    List<String> parentUserTaskKeyList = new ArrayList<>();
    parentUserTaskList.forEach(item -> parentUserTaskKeyList.add(item.getId()));
    // 获取全部历史节点活动实例,即已经走过的节点历史,数据采用开始时间升序
    List<HistoricTaskInstance> historicTaskInstanceList = historyService.createHistoricTaskInstanceQuery().processInstanceId(task.getProcessInstanceId()).orderByHistoricTaskInstanceStartTime().asc().list();
    // 数据清洗,将回滚导致的脏数据清洗掉
    List<String> lastHistoricTaskInstanceList = FlowableUtils.historicTaskInstanceClean(allElements, historicTaskInstanceList);
    // 此时历史任务实例为倒序,获取最后走的节点
    List<String> targetIds = new ArrayList<>();
    // 循环结束标识,遇到当前目标节点的次数
    int number = 0;
    StringBuilder parentHistoricTaskKey = new StringBuilder();
    for (String historicTaskInstanceKey : lastHistoricTaskInstanceList) {
        // 当会签时候会出现特殊的,连续都是同一个节点历史数据的情况,这种时候跳过
        if (parentHistoricTaskKey.toString().equals(historicTaskInstanceKey)) {
            continue;
        }
        parentHistoricTaskKey = new StringBuilder(historicTaskInstanceKey);
        if (historicTaskInstanceKey.equals(task.getTaskDefinitionKey())) {
            number++;
        }
        // number == 2,第二次遇到,代表最后一次的循环范围
        if (number == 2) {
            break;
        }
        // 如果当前历史节点,属于父级的节点,说明最后一次经过了这个点,需要退回这个点
        if (parentUserTaskKeyList.contains(historicTaskInstanceKey)) {
            targetIds.add(historicTaskInstanceKey);
        }
    }
    // 目的获取所有需要被跳转的节点 currentIds
    // 取其中一个父级任务,因为后续要么存在公共网关,要么就是串行公共线路
    UserTask oneUserTask = parentUserTaskList.get(0);
    // 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务
    List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
    List<String> runTaskKeyList = new ArrayList<>();
    runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
    // 需驳回任务列表
    List<String> currentIds = new ArrayList<>();
    // 通过父级网关的出口连线,结合 runTaskList 比对,获取需要撤回的任务
    List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(oneUserTask, runTaskKeyList, null, null);
    currentUserTaskList.forEach(item -> currentIds.add(item.getId()));
    // 规定:并行网关之前节点必须需存在唯一用户任务节点,如果出现多个任务节点,则并行网关节点默认为结束节点,原因为不考虑多对多情况
    if (targetIds.size() > 1 && currentIds.size() > 1) {
        throw new RuntimeException("任务出现多对多情况,无法撤回");
    }
    // 循环获取那些需要被撤回的节点的ID,用来设置驳回原因
    List<String> currentTaskIds = new ArrayList<>();
    currentIds.forEach(currentId -> runTaskList.forEach(runTask -> {
        if (currentId.equals(runTask.getTaskDefinitionKey())) {
            currentTaskIds.add(runTask.getId());
        }
    }));
    // 设置驳回意见
    currentTaskIds.forEach(item -> taskService.addComment(item, task.getProcessInstanceId(), FlowComment.REJECT.getType(), bo.getComment()));
    try {
        // 如果父级任务多于 1 个,说明当前节点不是并行节点,原因为不考虑多对多情况
        if (targetIds.size() > 1) {
            // 1 对 多任务跳转,currentIds 当前节点(1),targetIds 跳转到的节点(多)
            runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId()).moveSingleActivityIdToActivityIds(currentIds.get(0), targetIds).changeState();
        }
        // 如果父级任务只有一个,因此当前任务可能为网关中的任务
        if (targetIds.size() == 1) {
            // 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetIds.get(0) 跳转到的节点(1)
            runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId()).moveActivityIdsToSingleActivityId(currentIds, targetIds.get(0)).changeState();
        }
    } catch (FlowableObjectNotFoundException e) {
        throw new RuntimeException("未找到流程实例,流程可能已发生变化");
    } catch (FlowableException e) {
        throw new RuntimeException("无法取消或开始活动");
    }
}
Also used : JsonUtils(com.ruoyi.common.utils.JsonUtils) ProcessDiagramGenerator(org.flowable.image.ProcessDiagramGenerator) ServiceException(com.ruoyi.common.exception.ServiceException) WfFormVo(com.ruoyi.workflow.domain.vo.WfFormVo) ListUtil(cn.hutool.core.collection.ListUtil) RequiredArgsConstructor(lombok.RequiredArgsConstructor) ProcessEngineConfiguration(org.flowable.engine.ProcessEngineConfiguration) StringUtils(org.apache.commons.lang3.StringUtils) WfNextDto(com.ruoyi.workflow.domain.dto.WfNextDto) HistoricProcessInstanceQuery(org.flowable.engine.history.HistoricProcessInstanceQuery) IWfTaskService(com.ruoyi.workflow.service.IWfTaskService) Authentication(org.flowable.common.engine.impl.identity.Authentication) WfTaskVo(com.ruoyi.workflow.domain.vo.WfTaskVo) org.flowable.bpmn.model(org.flowable.bpmn.model) Comment(org.flowable.engine.task.Comment) Predicate(java.util.function.Predicate) FlowComment(com.ruoyi.flowable.common.enums.FlowComment) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Deployment(org.flowable.engine.repository.Deployment) Task(org.flowable.task.api.Task) LoginHelper(com.ruoyi.common.helper.LoginHelper) CustomProcessDiagramGenerator(com.ruoyi.flowable.flow.CustomProcessDiagramGenerator) WfViewerVo(com.ruoyi.workflow.domain.vo.WfViewerVo) Process(org.flowable.bpmn.model.Process) Collectors(java.util.stream.Collectors) Slf4j(lombok.extern.slf4j.Slf4j) FlowableUtils(com.ruoyi.flowable.flow.FlowableUtils) FlowableObjectNotFoundException(org.flowable.common.engine.api.FlowableObjectNotFoundException) HistoricTaskInstanceQuery(org.flowable.task.api.history.HistoricTaskInstanceQuery) HistoricIdentityLink(org.flowable.identitylink.api.history.HistoricIdentityLink) R(com.ruoyi.common.core.domain.R) java.util(java.util) SysUser(com.ruoyi.common.core.domain.entity.SysUser) TableDataInfo(com.ruoyi.common.core.page.TableDataInfo) ProcessDefinition(org.flowable.engine.repository.ProcessDefinition) ObjectUtil(cn.hutool.core.util.ObjectUtil) TaskQuery(org.flowable.task.api.TaskQuery) WfTaskBo(com.ruoyi.workflow.domain.bo.WfTaskBo) IWfDeployFormService(com.ruoyi.workflow.service.IWfDeployFormService) ProcessInstance(org.flowable.engine.runtime.ProcessInstance) Function(java.util.function.Function) CollectionUtils(org.apache.commons.collections4.CollectionUtils) HistoricProcessInstance(org.flowable.engine.history.HistoricProcessInstance) PageQuery(com.ruoyi.common.core.domain.PageQuery) FlowableException(org.flowable.common.engine.api.FlowableException) DelegationState(org.flowable.task.api.DelegationState) Execution(org.flowable.engine.runtime.Execution) HistoricActivityInstanceQuery(org.flowable.engine.history.HistoricActivityInstanceQuery) Lists(com.google.common.collect.Lists) ProcessConstants(com.ruoyi.flowable.common.constant.ProcessConstants) Service(org.springframework.stereotype.Service) ISysRoleService(com.ruoyi.system.service.ISysRoleService) FindNextNodeUtil(com.ruoyi.flowable.flow.FindNextNodeUtil) FlowServiceFactory(com.ruoyi.flowable.factory.FlowServiceFactory) HistoricActivityInstance(org.flowable.engine.history.HistoricActivityInstance) WfCommentDto(com.ruoyi.workflow.domain.dto.WfCommentDto) Page(com.baomidou.mybatisplus.extension.plugins.pagination.Page) CollUtil(cn.hutool.core.collection.CollUtil) ISysUserService(com.ruoyi.system.service.ISysUserService) SysRole(com.ruoyi.common.core.domain.entity.SysRole) HistoricTaskInstance(org.flowable.task.api.history.HistoricTaskInstance) Transactional(org.springframework.transaction.annotation.Transactional) InputStream(java.io.InputStream) Task(org.flowable.task.api.Task) HistoricTaskInstance(org.flowable.task.api.history.HistoricTaskInstance) ProcessDefinition(org.flowable.engine.repository.ProcessDefinition) Process(org.flowable.bpmn.model.Process) FlowableObjectNotFoundException(org.flowable.common.engine.api.FlowableObjectNotFoundException) FlowableException(org.flowable.common.engine.api.FlowableException)

Example 2 with WfTaskBo

use of com.ruoyi.workflow.domain.bo.WfTaskBo in project RuoYi-Flowable-Plus by KonBAI-Q.

the class WfTaskServiceImpl method taskReturn.

/**
 * 退回任务
 *
 * @param bo 请求实体参数
 */
@Transactional(rollbackFor = Exception.class)
@Override
public void taskReturn(WfTaskBo bo) {
    if (taskService.createTaskQuery().taskId(bo.getTaskId()).singleResult().isSuspended()) {
        throw new RuntimeException("任务处于挂起状态");
    }
    // 当前任务 task
    Task task = taskService.createTaskQuery().taskId(bo.getTaskId()).singleResult();
    // 获取流程定义信息
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(task.getProcessDefinitionId()).singleResult();
    // 获取所有节点信息
    Process process = repositoryService.getBpmnModel(processDefinition.getId()).getProcesses().get(0);
    // 获取全部节点列表,包含子节点
    Collection<FlowElement> allElements = FlowableUtils.getAllElements(process.getFlowElements(), null);
    // 获取当前任务节点元素
    FlowElement source = null;
    // 获取跳转的节点元素
    FlowElement target = null;
    if (allElements != null) {
        for (FlowElement flowElement : allElements) {
            // 当前任务节点元素
            if (flowElement.getId().equals(task.getTaskDefinitionKey())) {
                source = flowElement;
            }
            // 跳转的节点元素
            if (flowElement.getId().equals(bo.getTargetKey())) {
                target = flowElement;
            }
        }
    }
    // 从当前节点向前扫描
    // 如果存在路线上不存在目标节点,说明目标节点是在网关上或非同一路线上,不可跳转
    // 否则目标节点相对于当前节点,属于串行
    Boolean isSequential = FlowableUtils.iteratorCheckSequentialReferTarget(source, bo.getTargetKey(), null, null);
    if (!isSequential) {
        throw new RuntimeException("当前节点相对于目标节点,不属于串行关系,无法回退");
    }
    // 获取所有正常进行的任务节点 Key,这些任务不能直接使用,需要找出其中需要撤回的任务
    List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
    List<String> runTaskKeyList = new ArrayList<>();
    runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
    // 需退回任务列表
    List<String> currentIds = new ArrayList<>();
    // 通过父级网关的出口连线,结合 runTaskList 比对,获取需要撤回的任务
    List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target, runTaskKeyList, null, null);
    currentUserTaskList.forEach(item -> currentIds.add(item.getId()));
    // 循环获取那些需要被撤回的节点的ID,用来设置驳回原因
    List<String> currentTaskIds = new ArrayList<>();
    currentIds.forEach(currentId -> runTaskList.forEach(runTask -> {
        if (currentId.equals(runTask.getTaskDefinitionKey())) {
            currentTaskIds.add(runTask.getId());
        }
    }));
    // 设置回退意见
    for (String currentTaskId : currentTaskIds) {
        taskService.addComment(currentTaskId, task.getProcessInstanceId(), FlowComment.REBACK.getType(), bo.getComment());
    }
    try {
        // 1 对 1 或 多 对 1 情况,currentIds 当前要跳转的节点列表(1或多),targetKey 跳转到的节点(1)
        runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId()).moveActivityIdsToSingleActivityId(currentIds, bo.getTargetKey()).changeState();
    } catch (FlowableObjectNotFoundException e) {
        throw new RuntimeException("未找到流程实例,流程可能已发生变化");
    } catch (FlowableException e) {
        throw new RuntimeException("无法取消或开始活动");
    }
}
Also used : JsonUtils(com.ruoyi.common.utils.JsonUtils) ProcessDiagramGenerator(org.flowable.image.ProcessDiagramGenerator) ServiceException(com.ruoyi.common.exception.ServiceException) WfFormVo(com.ruoyi.workflow.domain.vo.WfFormVo) ListUtil(cn.hutool.core.collection.ListUtil) RequiredArgsConstructor(lombok.RequiredArgsConstructor) ProcessEngineConfiguration(org.flowable.engine.ProcessEngineConfiguration) StringUtils(org.apache.commons.lang3.StringUtils) WfNextDto(com.ruoyi.workflow.domain.dto.WfNextDto) HistoricProcessInstanceQuery(org.flowable.engine.history.HistoricProcessInstanceQuery) IWfTaskService(com.ruoyi.workflow.service.IWfTaskService) Authentication(org.flowable.common.engine.impl.identity.Authentication) WfTaskVo(com.ruoyi.workflow.domain.vo.WfTaskVo) org.flowable.bpmn.model(org.flowable.bpmn.model) Comment(org.flowable.engine.task.Comment) Predicate(java.util.function.Predicate) FlowComment(com.ruoyi.flowable.common.enums.FlowComment) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Deployment(org.flowable.engine.repository.Deployment) Task(org.flowable.task.api.Task) LoginHelper(com.ruoyi.common.helper.LoginHelper) CustomProcessDiagramGenerator(com.ruoyi.flowable.flow.CustomProcessDiagramGenerator) WfViewerVo(com.ruoyi.workflow.domain.vo.WfViewerVo) Process(org.flowable.bpmn.model.Process) Collectors(java.util.stream.Collectors) Slf4j(lombok.extern.slf4j.Slf4j) FlowableUtils(com.ruoyi.flowable.flow.FlowableUtils) FlowableObjectNotFoundException(org.flowable.common.engine.api.FlowableObjectNotFoundException) HistoricTaskInstanceQuery(org.flowable.task.api.history.HistoricTaskInstanceQuery) HistoricIdentityLink(org.flowable.identitylink.api.history.HistoricIdentityLink) R(com.ruoyi.common.core.domain.R) java.util(java.util) SysUser(com.ruoyi.common.core.domain.entity.SysUser) TableDataInfo(com.ruoyi.common.core.page.TableDataInfo) ProcessDefinition(org.flowable.engine.repository.ProcessDefinition) ObjectUtil(cn.hutool.core.util.ObjectUtil) TaskQuery(org.flowable.task.api.TaskQuery) WfTaskBo(com.ruoyi.workflow.domain.bo.WfTaskBo) IWfDeployFormService(com.ruoyi.workflow.service.IWfDeployFormService) ProcessInstance(org.flowable.engine.runtime.ProcessInstance) Function(java.util.function.Function) CollectionUtils(org.apache.commons.collections4.CollectionUtils) HistoricProcessInstance(org.flowable.engine.history.HistoricProcessInstance) PageQuery(com.ruoyi.common.core.domain.PageQuery) FlowableException(org.flowable.common.engine.api.FlowableException) DelegationState(org.flowable.task.api.DelegationState) Execution(org.flowable.engine.runtime.Execution) HistoricActivityInstanceQuery(org.flowable.engine.history.HistoricActivityInstanceQuery) Lists(com.google.common.collect.Lists) ProcessConstants(com.ruoyi.flowable.common.constant.ProcessConstants) Service(org.springframework.stereotype.Service) ISysRoleService(com.ruoyi.system.service.ISysRoleService) FindNextNodeUtil(com.ruoyi.flowable.flow.FindNextNodeUtil) FlowServiceFactory(com.ruoyi.flowable.factory.FlowServiceFactory) HistoricActivityInstance(org.flowable.engine.history.HistoricActivityInstance) WfCommentDto(com.ruoyi.workflow.domain.dto.WfCommentDto) Page(com.baomidou.mybatisplus.extension.plugins.pagination.Page) CollUtil(cn.hutool.core.collection.CollUtil) ISysUserService(com.ruoyi.system.service.ISysUserService) SysRole(com.ruoyi.common.core.domain.entity.SysRole) HistoricTaskInstance(org.flowable.task.api.history.HistoricTaskInstance) Transactional(org.springframework.transaction.annotation.Transactional) InputStream(java.io.InputStream) Task(org.flowable.task.api.Task) ProcessDefinition(org.flowable.engine.repository.ProcessDefinition) Process(org.flowable.bpmn.model.Process) FlowableObjectNotFoundException(org.flowable.common.engine.api.FlowableObjectNotFoundException) FlowableException(org.flowable.common.engine.api.FlowableException) Transactional(org.springframework.transaction.annotation.Transactional)

Aggregations

CollUtil (cn.hutool.core.collection.CollUtil)2 ListUtil (cn.hutool.core.collection.ListUtil)2 ObjectUtil (cn.hutool.core.util.ObjectUtil)2 Page (com.baomidou.mybatisplus.extension.plugins.pagination.Page)2 Lists (com.google.common.collect.Lists)2 PageQuery (com.ruoyi.common.core.domain.PageQuery)2 R (com.ruoyi.common.core.domain.R)2 SysRole (com.ruoyi.common.core.domain.entity.SysRole)2 SysUser (com.ruoyi.common.core.domain.entity.SysUser)2 TableDataInfo (com.ruoyi.common.core.page.TableDataInfo)2 ServiceException (com.ruoyi.common.exception.ServiceException)2 LoginHelper (com.ruoyi.common.helper.LoginHelper)2 JsonUtils (com.ruoyi.common.utils.JsonUtils)2 ProcessConstants (com.ruoyi.flowable.common.constant.ProcessConstants)2 FlowComment (com.ruoyi.flowable.common.enums.FlowComment)2 FlowServiceFactory (com.ruoyi.flowable.factory.FlowServiceFactory)2 CustomProcessDiagramGenerator (com.ruoyi.flowable.flow.CustomProcessDiagramGenerator)2 FindNextNodeUtil (com.ruoyi.flowable.flow.FindNextNodeUtil)2 FlowableUtils (com.ruoyi.flowable.flow.FlowableUtils)2 ISysRoleService (com.ruoyi.system.service.ISysRoleService)2