在使用流程的时候,总是可能会有表单内容漏填的可能,那么就需要对流程进行驳回,甚至是连续驳回的功能。该文章目前只针对于单个流向的流程进行连续驳回的功能实现。
与自定义流程路径跳转到指定的节点不同的是,在有多个节点的情况下不需要专门对每个节点指定一条驳回的路径,且在驳回时会将上一个节点的代办人指定为上个节点的办理人(针对节点的办理人为候选组)。
最终实现思路:
1.取得所有历史任务按时间降序排序,获取当前节点
2.根据当前节点的模型节点id,查找到上一个节点id,获取上一个节点
根据上一个节点id 去历史任务中查询上一个节点的历史任务中的最后一个
根据模型节点的唯一标识 分组 并在组内根据创建时间降序排序
3、获取所在节点的流出方向,、记录所在节点的流出方向,并将所在节点的流出方向清空
4、根据创建新的方向
5、将新的方向set到所在节点的流出方向
6、完成当前任务
7、还原所在节点的流出方向
代码实现
/**
* 1.取得所有历史任务按时间降序排序,获取当前节点
* 2.根据当前节点的模型节点id,查找到上一个节点id,获取上一个节点
* 根据上一个节点id 去历史任务中查询上一个节点的历史任务中的最后一个(根据 模型节点的唯一标识 分组 并在组内根据创建时间降序排序)
* 3、获取所在节点的流出方向,、记录所在节点的流出方向,并将所在节点的流出方向清空
* 4、根据创建新的方向
* 5、将新的方向set到所在节点的流出方向
* 6、完成当前任务
* 7、还原所在节点的流出方向
*/
public String backProcess(String processInstanceId, String taskId) throws Exception {
// 取得所有历史任务按时间降序排序
List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId)
.orderByTaskCreateTime().desc().list();
Integer size = 2;
if (StringUtils.isEmpty(htiList) || htiList.size() < size) {
return "流程实例的首个节点不能驳回";
}
//所有历史任务根据 模型节点的唯一标识 分组 并在组内根据创建时间降序排序
Map<String, List<HistoricTaskInstance>> htiGroup = htiList.stream()
.collect(Collectors.groupingBy(
HistoricTaskInstance::getTaskDefinitionKey,
Collectors.collectingAndThen(Collectors.toList(),
list -> list.stream()
.sorted(Comparator.comparing(HistoricTaskInstance::getCreateTime))
.collect(Collectors.toList()))
));
// list里第一条代表当前任务
HistoricTaskInstance curTask = htiList.get(0);
// 当前节点的executionId:历史任务实例相关联的执行ID
String curExecutionId = curTask.getExecutionId();
//根据 历史任务实例所属流程的定义ID 查询 流程模型,ID通常是BPMN模型的ID与其版本号的组合 例如exampleDemo:1:77003
BpmnModel bpmnModel = repositoryService.getBpmnModel(curTask.getProcessDefinitionId());
//每个模型节点的唯一标识 例:ddfour
FlowElement currentElement = bpmnModel.getMainProcess().getFlowElement(curTask.getTaskDefinitionKey());
String lastTaskDefinitionKey = null;
if (currentElement != null && currentElement instanceof FlowNode) {
FlowNode currentNode = (FlowNode) currentElement;
// 获取入口连线
List<SequenceFlow> incomingFlows = currentNode.getIncomingFlows();
if (incomingFlows != null && !incomingFlows.isEmpty()) {
// 在大多数情况下,一个节点只有一个入口连线。
// 但是,如果存在多个连线,你需要根据你的需求来决定如何处理它们。
SequenceFlow incomingFlow = incomingFlows.get(0);
FlowNode previousNode = (FlowNode) incomingFlow.getSourceFlowElement();
//流程模型 当前节点的上一个节点的key
lastTaskDefinitionKey= previousNode.getId();
}
}
List<HistoricTaskInstance> lastTaskResult = htiGroup.get(lastTaskDefinitionKey);
//上一个任务
HistoricTaskInstance lastTask =lastTaskResult.get(lastTaskResult.size() - 1);
// 上一个任务的taskId
String lastTaskId = lastTask.getId();
if (null == lastTaskId) {
throw new Exception("LAST TASK IS NULL");
}
String lastActivityId = null;
List<HistoricActivityInstance> haiFinishedList = historyService.createHistoricActivityInstanceQuery()
.executionId(lastTask.getExecutionId()).finished().list();
for (HistoricActivityInstance hai : haiFinishedList) {
if (lastTaskId.equals(hai.getTaskId())) {
// 得到ActivityId,只有HistoricActivityInstance对象里才有此方法
lastActivityId = hai.getActivityId();
break;
}
}
// 得到上个节点的信息
FlowNode lastFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(lastActivityId);
// 取得当前节点的信息
Execution execution = runtimeService.createExecutionQuery().executionId(curExecutionId).singleResult();
String curActivityId = execution.getActivityId();
FlowNode curFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(curActivityId);
// 记录当前节点的原活动方向
List<SequenceFlow> oriSequenceFlows = new ArrayList<>();
oriSequenceFlows.addAll(curFlowNode.getOutgoingFlows());
// 清理活动方向
curFlowNode.getOutgoingFlows().clear();
// 建立新方向
List<SequenceFlow> newSequenceFlowList = new ArrayList<>();
SequenceFlow newSequenceFlow = new SequenceFlow();
newSequenceFlow.setId("flow4");
newSequenceFlow.setSourceFlowElement(curFlowNode);
newSequenceFlow.setTargetFlowElement(lastFlowNode);
newSequenceFlowList.add(newSequenceFlow);
curFlowNode.setOutgoingFlows(newSequenceFlowList);
// 完成任务
taskService.complete(taskId);
// 恢复原方向
curFlowNode.setOutgoingFlows(oriSequenceFlows);
// 设置执行人
Task nextTask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
if (nextTask != null) {
taskService.setAssignee(nextTask.getId(), lastTask.getAssignee());
}
return "驳回成功";
}
文章参考:activiti 节点驳回处理_activiti驳回任意节点-CSDN博客
本篇文章在该文章上进行了修改,很感谢该作者为我提供了实现思路!
还有,我讨厌vip文章,CSDN的vip太贵了!!!(无能狂怒(-᷅_-᷄))