Activiti6.0 驳回到任意节点(跳回驳回节点)

3,608 阅读3分钟

最近接手公司的crm系统,针对原先的工作流模块方面进行业务拓展 新增了转办、驳回到任意节点(跳回驳回节点)、跳过相同审批人等业务。

原系统activiti版本是6.0,之前只接触过5.x版本。acitviti6.x版本把pvm包都删了,执行计划的代码也进行了改造
参考了segmentfault.com/a/119000001… 大侠的博客

1:获取历史执行节点

/**
 * 记录当前操作人为节点审批人 记录审批时长
 * @Author:         ruiwu
 * @param           param 转办他人参数
 * @return          状态值
 * @CreateDate:     2021/2/20 10:17
 * @version:        1.0
 * @status:         done
*/
public List<HisNodeVo> getRunNodes(String procInstId) {
    //procInstId 流程实例id
    //查询流程运行到哪个节点了
    Execution execution = runtimeService.createExecutionQuery()
        .processInstanceId(procInstId)
        .orderByProcessInstanceId()
        .desc()
        .list().get(0);
    String activityId = execution.getActivityId();


    Map<String,String> map= new LinkedHashMap<>();
    // 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
    List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
        .processInstanceId(procInstId)
        //用户任务
        .activityType("userTask")
        //已经执行的任务节点
        .finished()
        .orderByHistoricActivityInstanceEndTime()
        .asc()
        .list();

    // 已执行的节点ID集合
    if(CollUtil.isNotEmpty(historicActivityInstanceList)){
        for (HistoricActivityInstance historicActivityInstance:historicActivityInstanceList){
            String hisActId = historicActivityInstance.getActivityId();
            if (hisActId.equals(activityId)){
                break;
            }
            if(!map.containsKey(historicActivityInstance.getActivityId())){
                map.put(historicActivityInstance.getActivityId(),historicActivityInstance.getActivityName());
            }
        }
    }
    if (CollUtil.isNotEmpty(map)){
        return map.entrySet()
            .stream()
            .map(HisNodeVo::new)
            .collect(Collectors.toList());
    }
    return Collections.emptyList();
}

此处引用了lombox

@Data
@ApiModel("历史节点")
@NoArgsConstructor
public class HisNodeVo {
  @ApiModelProperty("节点id")
  private String activityId;
  @ApiModelProperty("节点名")
  private String activityName;

  public HisNodeVo(Entry<String, String> node) {
      this.activityId = node.getKey();
      this.activityName = node.getValue();
  }
}

实现效果

2:驳回

public BaseResult<String> approve(ApproveParam param) {
    // 办理人userId
    String taskId = param.getTaskId();
    // 审核意见
    String opinion = param.getOpinion();
    // 审批人的姓名+审批意见
    Map<String, Object> map = new LinkedHashMap<>();
    // 设置审批人
    map.put(Constants.APPROVER_KEY,
        Optional.ofNullable(SecurityUser.getUserId()).orElse(""));
    // 审批 批准
    if (param.getApproveStatus() == 0) {
        //当前任务
        Task currentTask = taskService.createTaskQuery().taskId(taskId).singleResult();
        String executionId = currentTask.getExecutionId();
        //获取流程定义
        Object variable = runtimeService.getVariable(executionId,"turnDownNode");
        if (variable != null){
            String nodeAssign = runtimeService
                .getVariable(executionId,"turnDownNodeAssign").toString();
            map.put(Constants.COMMENTS_KEY, "【批准】" + opinion);
            //设置流程变量
            setVariablesByTaskIdAsMap(taskId, map);
            //驳回重新提交
            String targetNodeId = String.valueOf(variable);
            managementService.executeCommand(new SetFlowNodeAndGoCmd(
                currentTask.getId(), targetNodeId,nodeAssign));
            runtimeService.removeVariable (executionId, "turnDownNode");
        }else{
            //审批结果
            map.put(Constants.COMMENTS_KEY, "【批准】" + opinion);
            map.put("approvalResult", "同意");
            boolean mark = StringUtils.isNotBlank(param.getProcInstType()) &&
                (param.getProcInstType().contains(Constants.KEY_NEWCLASS) ||
                    param.getProcInstType().contains(Constants.KEY_PRECLASS));
            taskService.setAssignee(taskId,SecurityUser.getUserId());
            // 设置流程变量
            setVariablesByTaskIdAsMap(taskId, map);
            setVariablesByTaskId(taskId, "批准");

            //审批结果添加到缓存
            cacheService.set(Constants.COMMENTS_KEY + param.getProcInstId(), Constant.ONE + "");
            //完成任务
            completeMyPersonalTask(taskId);
        }
    } else {
        //驳回
        map.put(Constants.COMMENTS_KEY, "【驳回】" + opinion);
        map.put("approvalResult", "驳回");
        //设置流程变量
        setVariablesByTaskIdAsMap(taskId, map);
        if (param.getApproveType() == Constant.FAIL){
            setVariablesByTaskId(taskId, "驳回");
            //审批结果添加到缓存
            cacheService.set(Constants.COMMENTS_KEY + param.getProcInstId(), Constant.FAIL + "");
            //完成任务
            completeMyPersonalTask(taskId);
            //记录流程状态-可忽略
            this.updateProcessStatus(param.getProcInstId(),Constant.TWO);
        }else{
            //驳回到任意节点
            //历史节点执行人
            String targetNodeAssign = this.getRunNodes(param.getProcInstId(), param.getRunNodeId());
            log.info("驳回 历史节点执行人= " + targetNodeAssign);
            //当前任务
            if (param.getTurnType() == Constant.ONE){
                Task currentTask = taskService.createTaskQuery().taskId(taskId).singleResult();
                String executionId = currentTask.getExecutionId();

                //驳回到目标节点携带参数,标记当前节点,然后直接跳转
                runtimeService.setVariable (executionId, "turnDownNode",
                    currentTask.getTaskDefinitionKey());
                runtimeService.setVariable (executionId, "turnDownNodeAssign",
                    currentTask.getAssignee());
            }
            managementService.executeCommand(new SetFlowNodeAndGoCmd(
                param.getTaskId(), param.getRunNodeId() ,targetNodeAssign));
        }

        //驳回推送钉钉消息-可忽略
        ruTaskService.sendRejectProcessNotice(param.getProcInstId());
    }

    return new BaseResult<String>().ok();
}


/**
 * 根据提供节点和执行对象id,进行跳转命令
 * @author yzyx
 */
@Slf4j
public class SetFlowNodeAndGoCmd implements Command<Void> {

    /**
     * 任务id
     */
    private String taskId;
    /**
     * 目标节点
     */
    private String runNodeId;
    /**
     * 目标节点审批人
     */
    private String targetNodeAssign;


    public SetFlowNodeAndGoCmd(String taskId,String runNodeId,String targetNodeAssign){
        this.taskId = taskId;
        this.runNodeId = runNodeId;
        this.targetNodeAssign = targetNodeAssign;
    }

    @Override
    public Void execute(CommandContext commandContext){
        ActivitiEngineAgenda agenda = commandContext.getAgenda();
        TaskEntityManager taskEntityManager = commandContext.getTaskEntityManager();
        TaskEntity taskEntity = taskEntityManager.findById(taskId);
        // 执行实例 id
        String executionId = taskEntity.getExecutionId();
        log.info("executionId = " + executionId);
        String processDefinitionId = taskEntity.getProcessDefinitionId();
        ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
        HistoryManager historyManager = commandContext.getHistoryManager();
        // 执行实例对象
        ExecutionEntity executionEntity = executionEntityManager.findById(executionId);
        Process process = ProcessDefinitionUtil.getProcess(processDefinitionId);
        FlowElement flowElement = process.getFlowElement(runNodeId);
        if (flowElement == null) {
            throw new RuntimeException("目标节点不存在");
        }
        executionEntity.setVariable("USER_ID",targetNodeAssign);
        //去掉无用的变量,不去掉,会导致很多莫名奇妙的问题
        executionEntity.removeVariable("loopCounter");
        //去掉多实例的变量,如果变量不知道是啥,自己从节点定义里查
        executionEntity.removeVariable("cdp_atuser");
        //要激活交路径
        executionEntity.setActive(true);
        // 将历史活动表更新
        historyManager.recordActivityEnd(executionEntity, "jump");
        // 设置当前流程
        executionEntity.setCurrentFlowElement(flowElement);
        // 跳转, 触发执行实例运转
        agenda.planContinueProcessInCompensation(executionEntity);

        // 从runtime 表中删除当前任务
        taskEntityManager.delete(taskId);
        // 将历史任务表更新, 历史任务标记为完成
        historyManager.recordTaskEnd(taskId, "jump");
        return null;
    }

}

 /***
 * 查询历史节点执行人
 * @param procInstId procInstId
 * @param targetNodeId 目标节点
 * @return 执行人
 */
private String getRunNodes(String procInstId, String targetNodeId) {
    String assignee =SecurityUser.getUserId();

    // 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
    List<HistoricActivityInstance> instanceList = historyService.createHistoricActivityInstanceQuery()
        .processInstanceId(procInstId)
        //用户任务
        .activityId(targetNodeId)
        //已经执行的任务节点
        .finished()
        .orderByHistoricActivityInstanceEndTime()
        .asc()
        .list();
    if (CollUtil.isNotEmpty(instanceList)){
        assignee = instanceList.get(0).getAssignee();
    }
    Date endTime = instanceList.get(0).getEndTime();
    if (CollUtil.isNotEmpty(instanceList)){
        for (HistoricActivityInstance activityInstance : instanceList) {
            if (activityInstance.getActivityType().equals("olduserTask")){
                assignee = activityInstance.getAssignee();
                break;
            }else{
                if (endTime.getTime() < activityInstance.getEndTime().getTime()){
                    endTime = activityInstance.getEndTime();
                    assignee = activityInstance.getAssignee();
                }
            }
        }
    }

    return assignee;
}

@Data
@ApiModel("审批参数")
public class ApproveParam {

    @ApiModelProperty("任务Id")
    private String taskId;

    @ApiModelProperty("流程实例id")
    private String procInstId;

    @ApiModelProperty("通过-0,拒绝-1")
    private int approveStatus;

    @ApiModelProperty("0 驳回到发起节点 即原先的驳回重新提交  1 驳回到非发起节点")
    private int approveType = 0;

    @ApiModelProperty("审核意见")
    private String opinion;

    @ApiModelProperty(value = "流程类型")
    private String procInstType;

    @ApiModelProperty("开班申请需-传教师Id")
    private String teacherId;

    @ApiModelProperty("驳回 指定的运行节点id")
    private String runNodeId;

    @ApiModelProperty("0 驳回重新流转 1驳回审批通过后返回本节点")
    private int turnType;

}