flowable 流程动态设置监听器(非xml中定义)及发起时从驳回节点开始审批实现

一、flowable 使用代码动态修改监听器

1、配置类

复制代码
@Configuration
public class FlowableGlobListenerConfig {


   @Lazy
   @Autowired
   private TaskStartListener taskStartListener;

   @Lazy
   @Autowired
   private TaskCompleteListener taskCompletedListener;

   @Lazy
   @Autowired
   private ActivityCompletedListener activityCompletedListener;

   @Bean
   @Primary
   public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> globalListenerConfigurer() {
      return engineConfiguration -> engineConfiguration.setTypedEventListeners(this.customFlowableListeners());
   }

   /**
    * 监听类配置 flowable监听器级别
    *
    * @return java.util.Map<java.lang.String, java.util.List < org.flowable.common.engine.api.delegate.event.FlowableEventListener>>
    */
   private Map<String, List<FlowableEventListener>> customFlowableListeners() {
      Map<String, List<FlowableEventListener>> listenerMap = Maps.newHashMap();
      listenerMap.put(FlowableEngineEventType.TASK_CREATED.name(),
         new ArrayList<>(Collections.singletonList(taskStartListener)));
      listenerMap.put(FlowableEngineEventType.TASK_COMPLETED.name(),
         new ArrayList<>(Collections.singletonList(taskCompletedListener)));
      listenerMap.put(FlowableEngineEventType.ACTIVITY_COMPLETED.name(),
         new ArrayList<>(Collections.singletonList(activityCompletedListener)));
      return listenerMap;
   }
}
复制代码

说明:通过注册关注的事件,实现对应的监听逻辑实现相应业务逻辑

2、流程节点创建时的监听逻辑

复制代码
import cn.hutool.core.collection.CollUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.landray.kmss.sys.notify.webservice.NotifyTodoSendContextVo;

import cn.as.geekbidder.crm.contract.entity.ContractEntity;
import cn.as.geekbidder.crm.contract.mapper.ContractMapper;
import cn.as.geekbidder.crm.contract.service.ContractNewServiceImpl;
import cn.as.geekbidder.crm.contract.util.TitleUtil;
import cn.as.maple.message.api.enums.MessageType;
import cn.as.maple.message.api.enums.ReadState;
import cn.as.maple.message.api.model.Message;
import cn.as.maple.message.api.model.Recipient;
import cn.as.maple.message.api.service.MessageService;
import cn.as.maple.platform.api.model.User;
import cn.as.maple.platform.api.service.UserService;
import cn.as.maple.process.TaskStartInvoker;
import cn.as.maple.process.api.model.ProcessMessage;
import cn.as.maple.process.api.util.SpringContextUtil;
import cn.as.oa.TaskQueryService;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.common.engine.impl.event.FlowableEntityEventImpl;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("taskStartListener")
public class TaskStartListener implements FlowableEventListener {
   private static final Logger log = LoggerFactory.getLogger(TaskStartListener.class);
   @Autowired
   private TaskService taskService;
   @Autowired
   private MessageService messageService;
   @Autowired
   private RepositoryService repositoryService;
   @Autowired
   private UserService userService;
   @Autowired
   private ObjectMapper objectMapper;

   @Autowired
   private TaskQueryService taskQueryService;

   @Autowired
   private HistoryService historyService;

   @Value("${system.url}")
   private String url;

   @Autowired
   private ContractMapper contractMapper;

   @Autowired
   private ContractNewServiceImpl contractNewService;


   /**
    * 流程发起时统一通知逻辑
    * process-task/processVariables/33a9feee-65a6-11ef-8ac0-024204500072
    */
   public TaskStartListener() {
   }

   public void onEvent(FlowableEvent event) {
      TaskEntity taskEntity = (TaskEntity)((FlowableEntityEventImpl)event).getEntity();
      String taskId = taskEntity.getId();
      List<IdentityLink> idList = this.taskService.getIdentityLinksForTask(taskId);
      if (!CollectionUtils.isEmpty(idList)) {
         List<Recipient> recipientList = new ArrayList();
         idList.stream().distinct().forEach((identityLink) -> {
            Recipient recipient;
            if (StringUtils.isNotBlank(identityLink.getUserId()) && "assignee".equals(identityLink.getType())) {
               recipient = new Recipient();
               recipient.setId(identityLink.getUserId());
               recipientList.add(recipient);
            }

            if (StringUtils.isNotBlank(identityLink.getUserId()) && "candidate".equals(identityLink.getType())) {
               recipient = new Recipient();
               recipient.setId(identityLink.getUserId());
               recipientList.add(recipient);
            } else if (StringUtils.isNotBlank(identityLink.getGroupId()) && "candidate".equals(identityLink.getType())) {
               List<User> userList = this.userService.getUserByRole(identityLink.getGroupId());
               userList.forEach((obj) -> {
                  Recipient r = new Recipient();
                  r.setId(obj.getId());
                  recipientList.add(r);
               });
            }

            this.sendMessage(taskEntity, recipientList);
         });
         /**
          * 流程通知oa系统相关人逻辑
          * process-task/processVariables/33a9feee-65a6-11ef-8ac0-024204500072
          * //todo 需确认与oa系统对应用户的关系、及连接点击时token信息的有效性
          */
         List<String> ids = recipientList.stream().map(Recipient::getId).collect(Collectors.toList());
         List<String> taskUsers = this.userService.getUsersByIds(ids).stream().map(User::getName).collect(Collectors.toList());
         String instId = taskEntity.getProcessInstanceId();
         HistoricProcessInstance instance =
            historyService.createHistoricProcessInstanceQuery().processInstanceId(instId).singleResult();
         List<HistoricVariableInstance> list =
            historyService.createHistoricVariableInstanceQuery().processInstanceId(instId).list();
         String definitionKey = instance.getProcessDefinitionKey();
         ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey(definitionKey)
            .active()
            .singleResult();
         String deploymentId = processDefinition.getDeploymentId();
         Map<String, Object> map = list.stream().filter(e->Objects.nonNull(e.getValue())).collect(Collectors.toMap(HistoricVariableInstance::getVariableName, HistoricVariableInstance::getValue, (o1, o2)->o2));
         String processName = processDefinition.getName();
         String activeTab = processDefinition.getCategory();
         String businessKey = instance.getBusinessKey();
         // String activeTab = OAConstant.PROCESS_MAP.get(definitionKey).get(1);
         ContractEntity contractEntity;
         if((contractEntity=contractMapper.selectById(businessKey))!=null) {
            contractEntity.setCurrentApprovalUser(String.join(",", taskUsers));
            contractMapper.updateById(contractEntity);
         }
         //根据规则创建subject
         CompletableFuture.runAsync(()-> {
            if(CollUtil.isEmpty(map)) {
               return;
            }
            log.info("==================BEGIN异步同步oa代办BEGIN=================");
            NotifyTodoSendContextVo vo = new NotifyTodoSendContextVo();
            vo.setBusinessKey(instId);
            vo.setModelId(instId);
            vo.setType(2);
            vo.setSubject(TitleUtil.buildSubject(map, processName));
            // vo.setLink(url + "/process-task/processVariables/"+ instId);
            vo.setLink(buildLink(deploymentId, instId, taskId, activeTab));
            taskQueryService.syncAgency(vo, taskUsers);
            log.info("==================END异步同步oa代办END=================");
         });
      }
      Map<String, TaskStartInvoker> type = SpringContextUtil.getBeansOfType(TaskStartInvoker.class);
      type.values().parallelStream().forEach(
         (invoker) -> {
            invoker.consume(event);
         }
      );
   }

   private String buildLink(String deployId, String procInsId, String taskId, String activeTab) {
      return url+ "/process/record?deployId="+deployId+"&procInsId=="+procInsId+"&taskId="+taskId+"&activeTab="+activeTab;
   }

   public boolean isFailOnException() {
      return false;
   }

   public boolean isFireOnTransactionLifecycleEvent() {
      return false;
   }

   public String getOnTransaction() {
      return null;
   }

   public void sendMessage(TaskEntity taskEntity, List<Recipient> recipientList) {
      ProcessMessage processMessage = new ProcessMessage();
      ProcessDefinition pd =
         this.repositoryService.createProcessDefinitionQuery().processDefinitionId(taskEntity.getProcessDefinitionId()).singleResult();
      processMessage.setDeployId(pd.getDeploymentId());
      processMessage.setProcInsId(taskEntity.getProcessInstanceId());
      processMessage.setRouterName("审批详情路由");
      processMessage.setTaskId(taskEntity.getId());
      processMessage.setCheckUrl("/process-task/runing/" + taskEntity.getId());
      Message message = new Message();
      message.setCreateTime(LocalDateTime.now());
      message.setMessage("您有新的流程待办消息,请及时处理!");
      message.setRecipients(recipientList);
      message.setTitle("流程待办提醒");
      message.setReadState(ReadState.NOT_READ);
      message.setType(MessageType.MESSAGE);
      message.setMessageType("PROCESS_TODO_MESSAGE");
      String transmissionText = null;

      try {
         transmissionText = this.objectMapper.writeValueAsString(processMessage);
      } catch (JsonProcessingException var8) {
         log.error(var8.getMessage(), var8);
      }

      message.setTransmissionText(transmissionText);
      this.messageService.sendMessage(message);
   }
}
复制代码

3、流程节点结束时逻辑

复制代码
import cn.as.maple.process.TaskComplateInvoker;
import cn.as.maple.process.api.util.SpringContextUtil;

import java.util.Map;

import org.flowable.common.engine.api.delegate.event.FlowableEvent;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component("taskCompleteListener")
public class TaskCompleteListener implements FlowableEventListener {
   private static final Logger log = LoggerFactory.getLogger(TaskCompleteListener.class);

   public TaskCompleteListener() {
   }

   public void onEvent(FlowableEvent event) {
      Map<String, TaskComplateInvoker> type = SpringContextUtil.getBeansOfType(TaskComplateInvoker.class);
      type.values().parallelStream().forEach(
         (invoker) -> {
            invoker.consume(event);
         }
      );
   }

   public boolean isFailOnException() {
      return false;
   }

   public boolean isFireOnTransactionLifecycleEvent() {
      return false;
   }

   public String getOnTransaction() {
      return null;
   }


}
复制代码

4、流程任意节点结束时

复制代码
@Slf4j
@Component("activityCompletedListener")
public class ActivityCompletedListener implements FlowableEventListener {

   @Autowired
   private RepositoryService repositoryService;
   @Autowired
   private RuntimeService runtimeService;
   @Autowired
   private TaskService taskService;
   @Autowired
   private HistoryService historyService;
   @Autowired
   private ApplicationEventPublisher applicationEventPublisher;

   @Override
   public void onEvent(FlowableEvent event) {
      if(event instanceof FlowableActivityEventImpl) {
         FlowableActivityEventImpl activityEvent = (FlowableActivityEventImpl) event;
         String activityType = activityEvent.getActivityType();

         if(!"userTask".equals(activityType)) {
            return;
         }

         String processDefinitionId = activityEvent.getProcessDefinitionId();
         String processInstanceId = activityEvent.getProcessInstanceId();

         ProcessInstance processInstance =
            runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();

         ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);

         List<HistoricActivityInstance> allProcessNodes = historyService.createHistoricActivityInstanceQuery()
            .activityId(processInstance.getActivityId())
            .processInstanceId(processInstanceId)
            .list();
         List<HistoricActivityInstance> userTaskList =
            allProcessNodes.stream().filter(e -> e.getActivityType().equals("userTask")).collect(Collectors.toList());
         //判断节点列表中是否大于两个节点、第一个必为填报节点、第二个必为审批节点
         String businessKey = processInstance.getBusinessKey();
         if(userTaskList.size() >= 2) {

            ListenerEvent listenerEvent = new ListenerEvent();
            listenerEvent.setApprovalResults("PROGRESS_IN");
            listenerEvent.setBusinessKey(businessKey);
            listenerEvent.setDefinitionId(processDefinitionId);
            listenerEvent.setProcessInstanceId(processInstanceId);
            listenerEvent.setDefinitionKey(processDefinition.getKey());
            listenerEvent.setDefinitionName(processDefinition.getName());
            this.applicationEventPublisher.publishEvent(new ListenerEventSource(listenerEvent));
         }
      }
   }

   @Override
   public boolean isFailOnException() {
      return false;
   }

   @Override
   public boolean isFireOnTransactionLifecycleEvent() {
      return false;
   }

   @Override
   public String getOnTransaction() {
      return null;
   }
}
复制代码

 

二、流程跳过逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
   * 对已驳回的流程发起时选择从驳回节点开始审批
   * @param oldInstId
   * @param newInstId
   */
  public void skipPreAgreeNodes(String oldInstId, String newInstId){
     HistoricProcessInstance processInstance =
        historyService.createHistoricProcessInstanceQuery().processInstanceId(oldInstId).singleResult();
     String deployId = Optional.ofNullable(processInstance)
        .map(HistoricProcessInstance::getProcessDefinitionId)
        .map(item -> item.substring(item.lastIndexOf(":") + 1))
        .orElse(null);
     Map<String, Object> record = this.flowTaskService.flowRecord(oldInstId, deployId);
     List<FlowTask> flowList = (List<FlowTask>) record.getOrDefault("flowList", Lists.newArrayList());
     if(flowList.size()<2) {
        return;
     }
     FlowTask flowTask = flowList.get(0);
     String rejectTaskKey = flowTask.getTaskDefKey();
     List<FlowTask> agrees = flowList.stream().skip(1).limit(flowList.size() - 2).collect(Collectors.toList());
     List<String> allNodes = agrees.stream()
        .map(FlowTask::getTaskDefKey)
        .distinct().collect(Collectors.toList());
     for(String taskDefKey : allNodes) {
        List<Task> list = taskService.createTaskQuery().processInstanceId(newInstId).list();
        if(list.stream().anyMatch(e->rejectTaskKey.equals(e.getTaskDefinitionKey()))) {
           if(agrees.stream().noneMatch(e->rejectTaskKey.equals(e.getTaskDefKey()))) {
              break;
           }
        }
        for(Task task : list) {
           //筛选办理记录中节点定义id与当前id一致的记录
           List<FlowTask> allTasks = agrees.stream()
              .filter(e -> e.getTaskDefKey().equals(task.getTaskDefinitionKey()))
              .collect(Collectors.toList());
           String assignee = task.getAssignee();
           boolean preJb = false;
           for(int i = allTasks.size()-1; i >-1 ; i--) {
              FlowTask curTask = allTasks.get(i);
              String curAssignee = curTask.getAssigneeId();
              FlowComment comment = curTask.getComment();
              String rjAssignee = flowTask.getAssigneeId();
              boolean willJb = comment.getType().equals("11");
              FlowTaskVo add = new FlowTaskVo();
              if(willJb && allTasks.size() == 1) {
                 add.setTaskId(task.getId());
                 add.setInstanceId(newInstId);
                 add.setUserId(curAssignee);
                 add.setAcceptUserId(rjAssignee);
                 add.setComment(comment.getComment());
                 flowTaskService.beforeAddSign(add);
                 break;
              }
              String nextAssignee = i-1<0? rjAssignee: allTasks.get(i - 1).getAssigneeId();
              //下一个也是加办、说明当前加办的基础上有有新的加办且当前加办未审核
              boolean nextJb = i - 1 >= 0 && allTasks.get(i - 1).getComment().getType().equals("11");
              if(!willJb) {
                 //多实例节点时assignee不可能为空,需根据审批记录中的审批人id 判断需不需要跳过该用户
                 if(assignee !=null && !assignee.equals(curAssignee)) {
                    continue;
                 }
              } else {
                 add.setTaskId(task.getId());
                 add.setInstanceId(newInstId);
                 add.setUserId(curAssignee);
                 add.setAcceptUserId(nextAssignee);
                 add.setComment(comment.getComment());
                 flowTaskService.beforeAddSign(add);
                 if(nextJb) {
                    continue;
                 }
              }
              if(preJb) {
                 preJb = false;
                 continue;
              }
              FlowTaskVo flowTaskVo = new FlowTaskVo();
              BeanUtils.copyProperties(task, flowTaskVo);
              flowTaskVo.setInstanceId(newInstId);
              flowTaskVo.setComment(comment.getComment());
              flowTaskVo.setAssignee(willJb? nextAssignee : curAssignee);
              flowTaskVo.setUserId(willJb? nextAssignee : curAssignee);
              flowTaskVo.setTaskId(task.getId());
              List<Attachment> attachmentList = curTask.getAttachmentList();
              if(CollUtil.isNotEmpty(attachmentList)) {
                 List<MultipartFile> files = attachmentList.stream().map(f -> {
                    InputStream attachmentContent = taskService.getAttachmentContent(f.getId());
                    try {
                       return new MockMultipartFile(f.getName(), f.getName(), f.getType(), attachmentContent);
                    }
                    catch(Exception e) {
                       e.printStackTrace();
                       return null;
                    }
                 }).filter(Objects::nonNull).collect(Collectors.toList());
                 flowTaskVo.setFiles(files);
              }
              this.flowTaskService.complete(flowTaskVo);
              preJb = willJb;
           }
        }
     }
  }

  

三、流程结束时遇到的问题(结束了但业务表状态未修改成功)

复制代码
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import cn.as.foundation.web.api.BusinessCode;
import cn.as.foundation.web.exception.BusinessException;
import cn.as.geekbidder.crm.contract.entity.ContractEntity;
import cn.as.geekbidder.crm.contract.enums.ApprovalState;
import cn.as.geekbidder.crm.contract.mapper.ContractNewMapper;
import cn.as.maple.process.api.enums.FlowCommentEnum;
import cn.as.maple.process.api.model.ListenerEvent;
import cn.as.maple.process.api.model.ListenerEventSource;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;

import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.core.annotation.Order;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;


@Component
@AllArgsConstructor
@Slf4j
public class ContractFlowEventListener implements ApplicationListener<ListenerEventSource> {

   @Autowired
   private RuntimeService runtimeService;
   @Autowired
   private RepositoryService repositoryService;
   @Autowired
   private ContractNewMapper contractNewMapper;
   @Autowired
   private HistoryService historyService;
   /**
    * 流程结束监听
    *
    * @param event
    */
   @Override
   public void onApplicationEvent(ListenerEventSource event) {
      callBackWithStateCal(event);
   }

   public synchronized void callBackWithStateCal(ListenerEventSource event){
      log.info("------------------流程结束回调--------------------");
      HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery()
         .processInstanceId(event.getListenerEvent().getProcessInstanceId())
         .singleResult();

      if(Objects.isNull(processInstance)) {
         return;
      }
      String deploymentId = processInstance.getDeploymentId();
      ProcessDefinition processDefinition =
         repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
      if(Objects.isNull(processDefinition)) {
         return;
      }
      String defKey = processDefinition.getKey();
      //只对发布的事件中关注的事件进行处理
      boolean needDeal = Arrays.stream(ContractApproveGlobal.values())
         .map(ContractApproveGlobal::getDefKey)
         .anyMatch(e -> e.equals(defKey));
      log.info("------------------needDeal{}--------------------"+needDeal);
      if(needDeal) {
         String id = processInstance.getBusinessKey();
         ListenerEvent listenerEvent = event.getListenerEvent();
         String approvalResults = listenerEvent.getApprovalResults();
         log.info("------------------approvalResults{}--------------------"+approvalResults);
         ContractEntity contractEntity = contractNewMapper.selectById(id);
         Assert.notNull(contractEntity, () -> {
            throw new BusinessException(BusinessCode.CLIENT_ERROR.getCode(), String.format(
               "合同id为"+ id + "的合同不存在,可能已被删除,请检查!!!"));
         });
         if(FlowCommentEnum.NORMAL.getType().equals(approvalResults)) {
            ContractApproveGlobal dbNode = ContractApproveGlobal.getByCode(contractEntity.getApprovalNode());
            ContractApproveGlobal nextNode = dbNode.getNearNode()[1];
            contractEntity.setCurrentApprovalUser("无");
            //上一个流程节点结束时将全局流程节点改为下一个节点
            if(nextNode!=null && Integer.parseInt(nextNode.getCode()) <=3) {
               // 审批通过
               contractEntity.setApprovalState("0");
               contractEntity.setApprovalNode(nextNode.getCode());
            } else {
               contractEntity.setApprovalState(ApprovalState.CHANGE.getCode());
            }
         }
         else if(FlowCommentEnum.REJECT.getType().equals(approvalResults)) {
            // 审批驳回
            Integer rejectCnt = contractEntity.getRejectCnt();
            contractEntity.setCurrentApprovalUser("无");
            rejectCnt = rejectCnt == null ? 0 : rejectCnt;
            contractEntity.setRejectCnt(rejectCnt+1);
            contractEntity.setApprovalState(ApprovalState.TERMINATION.getCode());
         }
         else if("PROGRESS_IN".equals(approvalResults)) {
            contractEntity.setApprovalState(ApprovalState.EXECUTE.getCode());
         } else if(FlowCommentEnum.REBACK.getType().equals(approvalResults)) {
            // 审批退回
            contractEntity.setApprovalState(ApprovalState.UN_SUBMIT.getCode());
         }
         contractNewMapper.updateById(contractEntity);
      }
   }
}
复制代码

原因总结:由于流程结束时使用了 runtimeService 取流程实例已经取不到了,导致后续的操作都失败了,使用 historyService 则可以避免此问题

 

四、流程前加签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
  public void beforeAddSign(FlowTaskVo flowTaskVo) {
     TaskEntity currTask = (TaskEntity) taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
     if(Objects.nonNull(currTask)) {
        String userId = this.userService.getUserIdByToken();
        TaskEntity task = this.createSubTask(currTask, flowTaskVo.getAcceptUserId());
        // 保存附件
        FlowTaskVo subTaskVO = new FlowTaskVo();
        subTaskVO.setFileIds(flowTaskVo.getFileIds());
        subTaskVO.setFiles(flowTaskVo.getFiles());
        subTaskVO.setTaskId(task.getId());
        subTaskVO.setInstanceId(task.getProcessInstanceId());
        this.saveAttachment(subTaskVO);
 
        this.deleteJob(flowTaskVo.getInstanceId());
        this.taskService.addComment(task.getId(), flowTaskVo.getInstanceId(), FlowCommentEnum.ADD_SIGN.getType(),
           flowTaskVo.getComment());
        this.taskService.saveTask(task);
        this.taskService.setAssignee(task.getId(), userId);
        this.taskService.complete(task.getId());
 
        this.taskService.delegateTask(flowTaskVo.getTaskId(), flowTaskVo.getAcceptUserId());
        this.taskService.deleteCandidateUser(flowTaskVo.getTaskId(), userId);
        TaskEntity oldTask = (TaskEntity) taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
        oldTask.setName(oldTask.getName() + "-加办");
        this.taskService.saveTask(oldTask);
     }
     else {
        throw new BusinessException(BusinessCode.CLIENT_ERROR.getCode(), "没有运行时的任务实例,请确认!");
     }
  }

 思路:前加签阶段生成一个子任务在子任务创建时设置办理人为指定的加签用户(创建阶段会触发TASK_CREATE事件、该事件中需要修改业务数据当前办理人),办理完结时设置办理人为当前用户(加签实际是当前用户办理的,这样在记录中查看时就能看到加签处理人),并办理完该子任务、 将原任务的办理人设置为指定的加签用户、并为原任务设置加签标识

 

五、配合完成时的操作修改当前任务审批人

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
@Transactional(rollbackFor = {Exception.class})
   public void complete(FlowTaskVo flowTaskVo) {
      Map<String, Object> values = Collections.singletonMap("PROCESS_END_STATUS", FlowCommentEnum.NORMAL.getType());
      TaskEntity task =
         (TaskEntity) ((TaskQuery) this.taskService.createTaskQuery().taskId(flowTaskVo.getTaskId())).singleResult();
      this.deleteJob(flowTaskVo.getInstanceId());
      String userId = flowTaskVo.getUserId();
      if(StringUtils.isBlank(userId)) {
         userId = this.userService.getUserIdByToken();
      }
      if(Objects.isNull(task)) {
         throw new BusinessException(BusinessCode.CLIENT_ERROR.getCode(), "任务不存在");
      }
      else {
         if(DelegationState.PENDING.equals(task.getDelegationState())) {
            userId = this.userService.getUserIdByToken();
            TaskEntity subTask = this.createSubTask(task, userId);
            this.taskService.addComment(subTask.getId(), flowTaskVo.getInstanceId(), FlowCommentEnum.DELEGATE.getType(),
               StringUtils.isBlank(flowTaskVo.getComment()) ? "同意" : flowTaskVo.getComment());
            this.taskService.saveTask(subTask);
 
            // 保存附件
            FlowTaskVo subTaskVO = new FlowTaskVo();
            subTaskVO.setFileIds(flowTaskVo.getFileIds());
            subTaskVO.setFiles(flowTaskVo.getFiles());
            subTaskVO.setTaskId(subTask.getId());
            subTaskVO.setInstanceId(subTask.getProcessInstanceId());
            this.saveAttachment(subTaskVO);
 
            this.taskService.setAssignee(subTask.getId(), userId);
            this.taskService.setOwner(subTask.getId(), userId);
            this.taskService.complete(subTask.getId());
 
            this.taskService.resolveTask(flowTaskVo.getTaskId(), values);
 
            TaskEntity oldTask = (TaskEntity) taskService.createTaskQuery().taskId(flowTaskVo.getTaskId()).singleResult();
            oldTask.setName(oldTask.getName().replace("-加办", ""));
            this.taskService.saveTask(oldTask);
         }
         else {
            this.saveAttachment(flowTaskVo);
            this.taskService.addComment(flowTaskVo.getTaskId(), flowTaskVo.getInstanceId(),
               FlowCommentEnum.NORMAL.getType(),
               StringUtils.isBlank(flowTaskVo.getComment()) ? "同意" : flowTaskVo.getComment());
            this.taskService.setAssignee(flowTaskVo.getTaskId(), userId);
            this.taskService.complete(flowTaskVo.getTaskId(), values);
         }
      }
      //加办阶段该值设置成了true
      CompletableFuture.runAsync(()->{
         try {
            boolean addOper = task.getName().contains("-加办");
            if(addOper) {
               TaskEntity cur = (TaskEntity)this.taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).singleResult();
               List<IdentityLink> ids = this.taskService.getIdentityLinksForTask(cur.getId());
               boolean specify = ids.stream().anyMatch(e -> "assignee".equals(e.getType()));
               String userNames = ids.stream().filter(e -> !specify || "assignee".equals(e.getType())).map(e -> {
                  if(specify) {
                     return userService.getUsersByIds(Collections.singletonList(e.getUserId()));
                  }
                  else {
                     return userService.getUserByRole(e.getGroupId());
                  }
               }).flatMap(Collection::stream).map(User::getName).distinct().collect(Collectors.joining(","));
               String instanceId = task.getProcessInstanceId();
               ProcessInstance instance = this.runtimeService.createProcessInstanceQuery()
                  .processInstanceId(instanceId)
                  .active()
                  .singleResult();
               Thread.sleep(2000);
               ContractEntity contractEntity = contractNewMapper.selectById(instance.getBusinessKey());
               if(contractEntity != null) {
                  contractEntity.setCurrentApprovalUser(userNames);
                  contractNewMapper.updateById(contractEntity);
               }
            }
         }
         catch(Exception e) {
            log.error(e.getMessage(), e);
         }
      });
   }

 

 六、查询阶段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
public Page<FlowTask> todoList(ProcessTaskQuery query) {
     Page<FlowTask> page = new Page();
     String userId = this.userService.getUserIdByToken();
     List<String> roleIds = (List) this.roleService.getRolesByUserId(this.userService.getUserIdByToken())
        .stream()
        .map(Role::getId)
        .collect(Collectors.toList());
     if(!CollectionUtils.isEmpty(roleIds) && roleIds.size() != 0) {
        List list;
        if(StringUtils.isNotBlank(query.getProcessDefCategory())) {
           list = this.repositoryService.createProcessDefinitionQuery()
              .processDefinitionCategory(query.getProcessDefCategory())
              .list();
        }
        else {
           list = this.repositoryService.createProcessDefinitionQuery().list();
        }
 
        Map<String, ProcessDefinition> processDefinitionMap =
           (Map) list.stream().collect(Collectors.toMap(ProcessDefinition::getId, Function.identity()));
        List<String> processKeys =
           (List) processDefinitionMap.values().stream().map(ProcessDefinition::getKey).collect(Collectors.toList());
        TaskQuery taskQuery =
           (TaskQuery) ((TaskQuery) ((TaskQuery) ((TaskQuery) ((TaskQuery) ((TaskQuery) ((TaskQuery) ((TaskQuery) ((TaskQuery) this.taskService.createTaskQuery()
              .active()
              .includeProcessVariables()).or()).taskCandidateUser(userId)).taskAssignee(userId)).taskCandidateGroupIn(
              roleIds)).endOr()).processDefinitionKeyIn(processKeys)).orderByTaskCreateTime()).desc();
        long count = taskQuery.count();
        List<Task> taskList = taskQuery.listPage((query.getPage() - 1) * query.getSize(), query.getSize());
        List<FlowTask> flowList = new ArrayList();
        Iterator var11 = taskList.iterator();
 
        while(var11.hasNext()) {
           Task task = (Task) var11.next();
           ProcessDefinition pd = (ProcessDefinition) processDefinitionMap.get(task.getProcessDefinitionId());
           FlowTask flowTask = new FlowTask();
           flowTask.setVariable(
              Objects.nonNull(task.getProcessVariables()) ? this.filterVariables(task.getProcessVariables()) : null);
           flowTask.setTaskId(task.getId());
           flowTask.setTaskDefKey(task.getTaskDefinitionKey());
           flowTask.setCreateTime(task.getCreateTime());
           flowTask.setProcDefId(task.getProcessDefinitionId());
           flowTask.setTaskName(task.getName());
           flowTask.setProcDefId(task.getProcessDefinitionId());
           flowTask.setDueTime(task.getDueDate());
           if(Objects.nonNull(pd)) {
              flowTask.setDeployId(pd.getDeploymentId());
              flowTask.setProcDefName(pd.getName());
              flowTask.setProcDefVersion(pd.getVersion());
           }
 
           flowTask.setProcInsId(task.getProcessInstanceId());
           HistoricProcessInstance historicProcessInstance =
              (HistoricProcessInstance) this.historyService.createHistoricProcessInstanceQuery()
                 .processInstanceId(task.getProcessInstanceId())
                 .singleResult();
           User startUser = this.userService.getUser(historicProcessInstance.getStartUserId());
           flowTask.setStartUserId(Optional.ofNullable(startUser).map(User::getId).orElse("无"));
           flowTask.setStartUserName(Optional.ofNullable(startUser).map(User::getName).orElse("无"));
           flowTask.setStartDeptName(Optional.ofNullable(startUser).map(User::getOrganizationName).orElse("无"));
           flowList.add(flowTask);
        }
 
        page.setTotal(count);
        page.setRecords(flowList);
        page.setSize((long) query.getSize());
        page.setPages((long) query.getPage());
        return page;
     }
     else {
        throw new BusinessException(BusinessCode.LOGIN_EXPIRED.getCode(), "登录已过期,请重新登录");
     }
  }

 

七、查询当前流程所在节点是不是最后一个节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
@Override
   public boolean isLastingNode(String contractId) {
      try {
         ContractEntity contractEntity = contractNewMapper.selectById(contractId);
         String approvalNode = contractEntity.getApprovalNode();
         if(!ContractApproveGlobal.CONTRACT_PUBLISH_APPROVE.getCode().equals(approvalNode)) {
            return false;
         }
         String instanceIds = contractEntity.getInstanceIds();
         String inst = instanceIds.substring(instanceIds.lastIndexOf(",") + 1);
         Task task = taskService.createTaskQuery().processInstanceId(inst).active().singleResult();
         ExecutionEntity ee = (ExecutionEntity) runtimeService.createExecutionQuery()
            .executionId(task.getExecutionId()).singleResult();
         // 当前审批节点
         String currentActivityId = ee.getActivityId();
         BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
         FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(currentActivityId);
         // 输出连线
         List<SequenceFlow> outFlows = flowNode.getOutgoingFlows();
         boolean isLastNode = true;
         for (SequenceFlow sequenceFlow : outFlows) {
            // 下一个审批节点
            FlowElement targetFlow = sequenceFlow.getTargetFlowElement();
            if (targetFlow instanceof UserTask) {
               isLastNode = false;
               break;
            }
            // 如果下个审批节点为结束节点
            if (!(targetFlow instanceof EndEvent)) {
               isLastNode = false;
               break;
            }
         }
         return isLastNode;
      }
      catch(Exception e) {
         return false;
      }
   }

  

 

posted @   漂渡  阅读(1063)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
点击右上角即可分享
微信分享提示