(企業內部)工作流實戰_22_flowable 駁回/回退 並行網關駁回 多實例駁回 子流程駁回
| 項目地址 | https://gitee.com/lwj/flowable.git |
|---|---|
| 代碼分支 | flowable-base |
| 視頻講解地址 | https://www.bilibili.com/video/av78779999/ |
| 用戶名 | 密碼 |
|---|---|
| 0000001 | test |
| 0000002 | test |
| 0000003 | test |
| 0000004 | test |
1. 場景
駁回:當前處理人可以駁回歷史走過的任何一個節點
1、駁回任意普通節點
2、駁回多實例節點
3、駁回並行網關節點
4、駁回子流程節點
5、子流程節點駁回主流程節點
實際情況中,為了獲取可駁回的節點列表,我們做了一些規定,比方說並行網關節點,要求必須成對出現,也只能駁回到並行網關節點的 fork節點
2. 演示
由於情況很多,截圖反而不能重點講述駁回的事情,這里只截一張圖,如果想看詳情請查看視頻里面的講解
3. 代碼分享
3.1. 獲取可駁回節點
public List<FlowNodeVo> getBackNodesByProcessInstanceId(String taskId,String processInstanceId) {
List<FlowNodeVo> backNods = new ArrayList<>();
TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();
String currActId = taskEntity.getTaskDefinitionKey();
//獲取運行節點表中usertask
String sql = "select t.* from act_ru_actinst t where t.ACT_TYPE_ = 'userTask' " +
" and t.PROC_INST_ID_=#{processInstanceId} and t.END_TIME_ is not null ";
List<ActivityInstance> activityInstances = runtimeService.createNativeActivityInstanceQuery().sql(sql)
.parameter("processInstanceId", processInstanceId)
.list();
//獲取運行節點表的parallelGateway節點並出重
sql = "SELECT t.ID_, t.REV_,t.PROC_DEF_ID_,t.PROC_INST_ID_,t.EXECUTION_ID_,t.ACT_ID_, t.TASK_ID_, t.CALL_PROC_INST_ID_, t.ACT_NAME_, t.ACT_TYPE_, " +
" t.ASSIGNEE_, t.START_TIME_, max(t.END_TIME_) as END_TIME_, t.DURATION_, t.DELETE_REASON_, t.TENANT_ID_" +
" FROM act_ru_actinst t WHERE t.ACT_TYPE_ = 'parallelGateway' AND t.PROC_INST_ID_ = #{processInstanceId} and t.END_TIME_ is not null" +
" and t.ACT_ID_ <> #{actId} GROUP BY t.act_id_";
List<ActivityInstance> parallelGatewaies = runtimeService.createNativeActivityInstanceQuery().sql(sql)
.parameter("processInstanceId", processInstanceId)
.parameter("actId", currActId)
.list();
//排序
if (CollectionUtils.isNotEmpty(parallelGatewaies)) {
activityInstances.addAll(parallelGatewaies);
activityInstances.sort(Comparator.comparing(ActivityInstance::getEndTime));
}
//分組節點
int count = 0;
Map<ActivityInstance, List<ActivityInstance>> parallelGatewayUserTasks = new HashMap<>();
List<ActivityInstance> userTasks = new ArrayList<>();
ActivityInstance currActivityInstance = null;
for (ActivityInstance activityInstance : activityInstances) {
if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(activityInstance.getActivityType())) {
count++;
if (count % 2 != 0) {
List<ActivityInstance> datas = new ArrayList<>();
currActivityInstance = activityInstance;
parallelGatewayUserTasks.put(currActivityInstance, datas);
}
}
if (BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType())) {
if (count % 2 == 0) {
userTasks.add(activityInstance);
} else {
if (parallelGatewayUserTasks.containsKey(currActivityInstance)) {
parallelGatewayUserTasks.get(currActivityInstance).add(activityInstance);
}
}
}
}
//組裝人員名稱
List<HistoricTaskInstance> historicTaskInstances = historyService.createHistoricTaskInstanceQuery()
.processInstanceId(processInstanceId).finished().list();
Map<String, List<HistoricTaskInstance>> taskInstanceMap = new HashMap<>();
List<String> userCodes = new ArrayList<>();
historicTaskInstances.forEach(historicTaskInstance -> {
userCodes.add(historicTaskInstance.getAssignee());
String taskDefinitionKey = historicTaskInstance.getTaskDefinitionKey();
if (taskInstanceMap.containsKey(historicTaskInstance.getTaskDefinitionKey())) {
taskInstanceMap.get(taskDefinitionKey).add(historicTaskInstance);
} else {
List<HistoricTaskInstance> tasks = new ArrayList<>();
tasks.add(historicTaskInstance);
taskInstanceMap.put(taskDefinitionKey, tasks);
}
});
//組裝usertask的數據
List<User> userList = identityService.createUserQuery().userIds(userCodes).list();
Map<String, String> activityIdUserNames = this.getApplyers(processInstanceId, userList, taskInstanceMap);
if (CollectionUtils.isNotEmpty(userTasks)) {
userTasks.forEach(activityInstance -> {
FlowNodeVo node = new FlowNodeVo();
node.setNodeId(activityInstance.getActivityId());
node.setNodeName(activityInstance.getActivityName());
node.setEndTime(activityInstance.getEndTime());
node.setUserName(activityIdUserNames.get(activityInstance.getActivityId()));
backNods.add(node);
});
}
//組裝會簽節點數據
if (MapUtils.isNotEmpty(taskInstanceMap)) {
parallelGatewayUserTasks.forEach((activity, activities) -> {
FlowNodeVo node = new FlowNodeVo();
node.setNodeId(activity.getActivityId());
node.setEndTime(activity.getEndTime());
StringBuffer nodeNames = new StringBuffer("會簽:");
StringBuffer userNames = new StringBuffer("審批人員:");
if (CollectionUtils.isNotEmpty(activities)){
activities.forEach(activityInstance -> {
nodeNames.append(activityInstance.getActivityName()).append(",");
userNames.append(activityIdUserNames.get(activityInstance.getActivityId())).append(",");
});
node.setNodeName(nodeNames.toString());
node.setUserName(userNames.toString());
backNods.add(node);
}
});
}
//去重合並
List<FlowNodeVo> datas = backNods.stream().collect(
Collectors.collectingAndThen(Collectors.toCollection(() ->
new TreeSet<>(Comparator.comparing(nodeVo -> nodeVo.getNodeId()))), ArrayList::new));
//排序
datas.sort(Comparator.comparing(FlowNodeVo::getEndTime));
return datas;
}
3.2. 駁回代碼分享
public ReturnVo<String> backToStepTask(BackTaskVo backTaskVo) {
ReturnVo<String> returnVo = null;
TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(backTaskVo.getTaskId()).singleResult();
//1.把當前的節點設置為空
if (taskEntity != null) {
//2.設置審批人
taskEntity.setAssignee(backTaskVo.getUserCode());
taskService.saveTask(taskEntity);
//3.添加駁回意見
this.addComment(backTaskVo.getTaskId(), backTaskVo.getUserCode(), backTaskVo.getProcessInstanceId(),
CommentTypeEnum.BH.toString(), backTaskVo.getMessage());
//4.處理提交人節點
FlowNode distActivity = flowableBpmnModelService.findFlowNodeByActivityId(taskEntity.getProcessDefinitionId(), backTaskVo.getDistFlowElementId());
if (distActivity != null) {
if (FlowConstant.FLOW_SUBMITTER.equals(distActivity.getName())) {
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(taskEntity.getProcessInstanceId()).singleResult();
runtimeService.setVariable(backTaskVo.getProcessInstanceId(), FlowConstant.FLOW_SUBMITTER_VAR, processInstance.getStartUserId());
}
}
//5.刪除節點
this.deleteActivity(backTaskVo.getDistFlowElementId(), taskEntity.getProcessInstanceId());
List<String> executionIds = new ArrayList<>();
//6.判斷節點是不是子流程內部的節點
if (flowableBpmnModelService.checkActivitySubprocessByActivityId(taskEntity.getProcessDefinitionId(),
backTaskVo.getDistFlowElementId())
&& flowableBpmnModelService.checkActivitySubprocessByActivityId(taskEntity.getProcessDefinitionId(),
taskEntity.getTaskDefinitionKey())){
//6.1 子流程內部駁回
Execution executionTask = runtimeService.createExecutionQuery().executionId(taskEntity.getExecutionId()).singleResult();
String parentId = executionTask.getParentId();
List<Execution> executions = runtimeService.createExecutionQuery().parentId(parentId).list();
executions.forEach(execution -> executionIds.add(execution.getId()));
this.moveExecutionsToSingleActivityId(executionIds,backTaskVo.getDistFlowElementId());
}else {
//6.2 普通駁回
List<Execution> executions = runtimeService.createExecutionQuery().parentId(taskEntity.getProcessInstanceId()).list();
executions.forEach(execution -> executionIds.add(execution.getId()));
this.moveExecutionsToSingleActivityId(executionIds,backTaskVo.getDistFlowElementId());
}
returnVo = new ReturnVo<>(ReturnCode.SUCCESS, "駁回成功!");
} else {
returnVo = new ReturnVo<>(ReturnCode.FAIL, "不存在任務實例,請確認!");
}
return returnVo;
}
