(企业内部)工作流实战_22_flowable 驳回/回退 并行网关驳回 多实例驳回 子流程驳回
(企业内部)工作流实战_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;
}