提交审批撤回操作
parent
a2581d63e9
commit
71b3c744ea
|
@ -16,8 +16,8 @@ public enum FlowComment {
|
||||||
REJECT("3", "驳回意见"),
|
REJECT("3", "驳回意见"),
|
||||||
DELEGATE("4", "委派意见"),
|
DELEGATE("4", "委派意见"),
|
||||||
ASSIGN("5", "转办意见"),
|
ASSIGN("5", "转办意见"),
|
||||||
STOP("6", "终止流程");
|
STOP("6", "终止流程"),
|
||||||
|
REVOKE("7", "撤回");
|
||||||
/**
|
/**
|
||||||
* 类型
|
* 类型
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.ruoyi.flowable.domain.enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程意见类型
|
||||||
|
*
|
||||||
|
* @author Xuan xuan
|
||||||
|
* @date 2021/4/19
|
||||||
|
*/
|
||||||
|
public enum FlowComment {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说明
|
||||||
|
*/
|
||||||
|
NORMAL("1", "正常"),
|
||||||
|
REBACK("2", "退回"),
|
||||||
|
REJECT("3", "驳回"),
|
||||||
|
DELEGATE("4", "委派"),
|
||||||
|
TRANSFER("5", "转办"),
|
||||||
|
STOP("6", "终止"),
|
||||||
|
REVOKE("7", "撤回");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类型
|
||||||
|
*/
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 说明
|
||||||
|
*/
|
||||||
|
private final String remark;
|
||||||
|
|
||||||
|
FlowComment(String type, String remark) {
|
||||||
|
this.type = type;
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRemark() {
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.ruoyi.flowable.domain.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author KonBAI
|
||||||
|
* @createTime 2022/6/28 9:51
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum FormType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 流程表单
|
||||||
|
*/
|
||||||
|
PROCESS(0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外置表单
|
||||||
|
*/
|
||||||
|
EXTERNAL(1),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 节点独立表单
|
||||||
|
*/
|
||||||
|
INDEPENDENT(2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表单类型
|
||||||
|
*/
|
||||||
|
private final Integer type;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package com.ruoyi.flowable.domain.enums;
|
||||||
|
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author konbai
|
||||||
|
* @since 2023/3/9 00:45
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum ProcessStatus {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 进行中(审批中)
|
||||||
|
*/
|
||||||
|
RUNNING("running"),
|
||||||
|
/**
|
||||||
|
* 已终止
|
||||||
|
*/
|
||||||
|
TERMINATED("terminated"),
|
||||||
|
/**
|
||||||
|
* 已完成
|
||||||
|
*/
|
||||||
|
COMPLETED("completed"),
|
||||||
|
/**
|
||||||
|
* 已取消
|
||||||
|
*/
|
||||||
|
CANCELED("canceled");
|
||||||
|
|
||||||
|
private final String status;
|
||||||
|
|
||||||
|
public static ProcessStatus getProcessStatus(String str) {
|
||||||
|
if (StringUtils.isNotBlank(str)) {
|
||||||
|
for (ProcessStatus value : values()) {
|
||||||
|
if (StringUtils.equalsIgnoreCase(str, value.getStatus())) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,373 @@
|
||||||
|
package com.ruoyi.flowable.flow;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import org.flowable.bpmn.converter.BpmnXMLConverter;
|
||||||
|
import org.flowable.bpmn.model.Process;
|
||||||
|
import org.flowable.bpmn.model.*;
|
||||||
|
import org.flowable.common.engine.impl.util.io.StringStreamSource;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author KonBAI
|
||||||
|
* @createTime 2022/3/26 19:04
|
||||||
|
*/
|
||||||
|
public class ModelUtils {
|
||||||
|
|
||||||
|
private static final BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xml转bpmnModel对象
|
||||||
|
*
|
||||||
|
* @param xml xml
|
||||||
|
* @return bpmnModel对象
|
||||||
|
*/
|
||||||
|
public static BpmnModel getBpmnModel(String xml) {
|
||||||
|
return bpmnXMLConverter.convertToBpmnModel(new StringStreamSource(xml), false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bpmnModel转xml字符串
|
||||||
|
*
|
||||||
|
* @deprecated 存在会丢失 bpmn 连线问题
|
||||||
|
* @param bpmnModel bpmnModel对象
|
||||||
|
* @return xml字符串
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static String getBpmnXmlStr(BpmnModel bpmnModel) {
|
||||||
|
return StrUtil.utf8Str(getBpmnXml(bpmnModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bpmnModel转xml对象
|
||||||
|
*
|
||||||
|
* @deprecated 存在丢失 bpmn 连线问题
|
||||||
|
* @param bpmnModel bpmnModel对象
|
||||||
|
* @return xml
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public static byte[] getBpmnXml(BpmnModel bpmnModel) {
|
||||||
|
return bpmnXMLConverter.convertToXML(bpmnModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据节点,获取入口连线
|
||||||
|
*
|
||||||
|
* @param source 起始节点
|
||||||
|
* @return 入口连线列表
|
||||||
|
*/
|
||||||
|
public static List<SequenceFlow> getElementIncomingFlows(FlowElement source) {
|
||||||
|
List<SequenceFlow> sequenceFlows = new ArrayList<>();
|
||||||
|
if (source instanceof FlowNode) {
|
||||||
|
sequenceFlows = ((FlowNode) source).getIncomingFlows();
|
||||||
|
}
|
||||||
|
return sequenceFlows;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据节点,获取出口连线
|
||||||
|
*
|
||||||
|
* @param source 起始节点
|
||||||
|
* @return 出口连线列表
|
||||||
|
*/
|
||||||
|
public static List<SequenceFlow> getElementOutgoingFlows(FlowElement source) {
|
||||||
|
List<SequenceFlow> sequenceFlows = new ArrayList<>();
|
||||||
|
if (source instanceof FlowNode) {
|
||||||
|
sequenceFlows = ((FlowNode) source).getOutgoingFlows();
|
||||||
|
}
|
||||||
|
return sequenceFlows;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取开始节点
|
||||||
|
*
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @return 开始节点(未找到开始节点,返回null)
|
||||||
|
*/
|
||||||
|
public static StartEvent getStartEvent(BpmnModel model) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
FlowElement startElement = process.getInitialFlowElement();
|
||||||
|
if (startElement instanceof StartEvent) {
|
||||||
|
return (StartEvent) startElement;
|
||||||
|
}
|
||||||
|
return getStartEvent(process.getFlowElements());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取开始节点
|
||||||
|
*
|
||||||
|
* @param flowElements 流程元素集合
|
||||||
|
* @return 开始节点(未找到开始节点,返回null)
|
||||||
|
*/
|
||||||
|
public static StartEvent getStartEvent(Collection<FlowElement> flowElements) {
|
||||||
|
for (FlowElement flowElement : flowElements) {
|
||||||
|
if (flowElement instanceof StartEvent) {
|
||||||
|
return (StartEvent) flowElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取结束节点
|
||||||
|
*
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @return 结束节点(未找到开始节点,返回null)
|
||||||
|
*/
|
||||||
|
public static EndEvent getEndEvent(BpmnModel model) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
return getEndEvent(process.getFlowElements());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取结束节点
|
||||||
|
*
|
||||||
|
* @param flowElements 流程元素集合
|
||||||
|
* @return 结束节点(未找到开始节点,返回null)
|
||||||
|
*/
|
||||||
|
public static EndEvent getEndEvent(Collection<FlowElement> flowElements) {
|
||||||
|
for (FlowElement flowElement : flowElements) {
|
||||||
|
if (flowElement instanceof EndEvent) {
|
||||||
|
return (EndEvent) flowElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UserTask getUserTaskByKey(BpmnModel model, String taskKey) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
FlowElement flowElement = process.getFlowElement(taskKey);
|
||||||
|
if (flowElement instanceof UserTask) {
|
||||||
|
return (UserTask) flowElement;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取流程元素信息
|
||||||
|
*
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @param flowElementId 元素ID
|
||||||
|
* @return 元素信息
|
||||||
|
*/
|
||||||
|
public static FlowElement getFlowElementById(BpmnModel model, String flowElementId) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
return process.getFlowElement(flowElementId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取元素表单Key(限开始节点和用户节点可用)
|
||||||
|
*
|
||||||
|
* @param flowElement 元素
|
||||||
|
* @return 表单Key
|
||||||
|
*/
|
||||||
|
public static String getFormKey(FlowElement flowElement) {
|
||||||
|
if (flowElement != null) {
|
||||||
|
if (flowElement instanceof StartEvent) {
|
||||||
|
return ((StartEvent) flowElement).getFormKey();
|
||||||
|
} else if (flowElement instanceof UserTask) {
|
||||||
|
return ((UserTask) flowElement).getFormKey();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取开始节点属性值
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @param name 属性名
|
||||||
|
* @return 属性值
|
||||||
|
*/
|
||||||
|
public static String getStartEventAttributeValue(BpmnModel model, String name) {
|
||||||
|
StartEvent startEvent = getStartEvent(model);
|
||||||
|
return getElementAttributeValue(startEvent, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取结束节点属性值
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @param name 属性名
|
||||||
|
* @return 属性值
|
||||||
|
*/
|
||||||
|
public static String getEndEventAttributeValue(BpmnModel model, String name) {
|
||||||
|
EndEvent endEvent = getEndEvent(model);
|
||||||
|
return getElementAttributeValue(endEvent, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户任务节点属性值
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @param taskKey 任务Key
|
||||||
|
* @param name 属性名
|
||||||
|
* @return 属性值
|
||||||
|
*/
|
||||||
|
public static String getUserTaskAttributeValue(BpmnModel model, String taskKey, String name) {
|
||||||
|
UserTask userTask = getUserTaskByKey(model, taskKey);
|
||||||
|
return getElementAttributeValue(userTask, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取元素属性值
|
||||||
|
* @param baseElement 流程元素
|
||||||
|
* @param name 属性名
|
||||||
|
* @return 属性值
|
||||||
|
*/
|
||||||
|
public static String getElementAttributeValue(BaseElement baseElement, String name) {
|
||||||
|
if (baseElement != null) {
|
||||||
|
List<ExtensionAttribute> attributes = baseElement.getAttributes().get(name);
|
||||||
|
if (attributes != null && !attributes.isEmpty()) {
|
||||||
|
attributes.iterator().next().getValue();
|
||||||
|
Iterator<ExtensionAttribute> attrIterator = attributes.iterator();
|
||||||
|
if(attrIterator.hasNext()) {
|
||||||
|
ExtensionAttribute attribute = attrIterator.next();
|
||||||
|
return attribute.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isMultiInstance(BpmnModel model, String taskKey) {
|
||||||
|
UserTask userTask = getUserTaskByKey(model, taskKey);
|
||||||
|
if (ObjectUtil.isNotNull(userTask)) {
|
||||||
|
return userTask.hasMultiInstanceLoopCharacteristics();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有用户任务节点
|
||||||
|
*
|
||||||
|
* @param model bpmnModel对象
|
||||||
|
* @return 用户任务节点列表
|
||||||
|
*/
|
||||||
|
public static Collection<UserTask> getAllUserTaskEvent(BpmnModel model) {
|
||||||
|
Process process = model.getMainProcess();
|
||||||
|
Collection<FlowElement> flowElements = process.getFlowElements();
|
||||||
|
return getAllUserTaskEvent(flowElements, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有用户任务节点
|
||||||
|
* @param flowElements 流程元素集合
|
||||||
|
* @param allElements 所有流程元素集合
|
||||||
|
* @return 用户任务节点列表
|
||||||
|
*/
|
||||||
|
public static Collection<UserTask> getAllUserTaskEvent(Collection<FlowElement> flowElements, Collection<UserTask> allElements) {
|
||||||
|
allElements = allElements == null ? new ArrayList<>() : allElements;
|
||||||
|
for (FlowElement flowElement : flowElements) {
|
||||||
|
if (flowElement instanceof UserTask) {
|
||||||
|
allElements.add((UserTask) flowElement);
|
||||||
|
}
|
||||||
|
if (flowElement instanceof SubProcess) {
|
||||||
|
// 继续深入子流程,进一步获取子流程
|
||||||
|
allElements = getAllUserTaskEvent(((SubProcess) flowElement).getFlowElements(), allElements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return allElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找起始节点下一个用户任务列表列表
|
||||||
|
* @param source 起始节点
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static List<UserTask> findNextUserTasks(FlowElement source) {
|
||||||
|
return findNextUserTasks(source, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找起始节点下一个用户任务列表列表
|
||||||
|
* @param source 起始节点
|
||||||
|
* @param hasSequenceFlow 已经经过的连线的 ID,用于判断线路是否重复
|
||||||
|
* @param userTaskList 用户任务列表
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static List<UserTask> findNextUserTasks(FlowElement source, Set<String> hasSequenceFlow, List<UserTask> userTaskList) {
|
||||||
|
hasSequenceFlow = Optional.ofNullable(hasSequenceFlow).orElse(new HashSet<>());
|
||||||
|
userTaskList = Optional.ofNullable(userTaskList).orElse(new ArrayList<>());
|
||||||
|
// 获取出口连线
|
||||||
|
List<SequenceFlow> sequenceFlows = getElementOutgoingFlows(source);
|
||||||
|
if (!sequenceFlows.isEmpty()) {
|
||||||
|
for (SequenceFlow sequenceFlow : sequenceFlows) {
|
||||||
|
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||||
|
if (hasSequenceFlow.contains(sequenceFlow.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 添加已经走过的连线
|
||||||
|
hasSequenceFlow.add(sequenceFlow.getId());
|
||||||
|
FlowElement targetFlowElement = sequenceFlow.getTargetFlowElement();
|
||||||
|
if (targetFlowElement instanceof UserTask) {
|
||||||
|
// 若节点为用户任务,加入到结果列表中
|
||||||
|
userTaskList.add((UserTask) targetFlowElement);
|
||||||
|
} else {
|
||||||
|
// 若节点非用户任务,继续递归查找下一个节点
|
||||||
|
findNextUserTasks(targetFlowElement, hasSequenceFlow, userTaskList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return userTaskList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 迭代从后向前扫描,判断目标节点相对于当前节点是否是串行
|
||||||
|
* 不存在直接回退到子流程中的情况,但存在从子流程出去到父流程情况
|
||||||
|
* @param source 起始节点
|
||||||
|
* @param target 目标节点
|
||||||
|
* @param visitedElements 已经经过的连线的 ID,用于判断线路是否重复
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public static boolean isSequentialReachable(FlowElement source, FlowElement target, Set<String> visitedElements) {
|
||||||
|
visitedElements = visitedElements == null ? new HashSet<>() : visitedElements;
|
||||||
|
if (source instanceof StartEvent && isInEventSubprocess(source)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据类型,获取入口连线
|
||||||
|
List<SequenceFlow> sequenceFlows = getElementIncomingFlows(source);
|
||||||
|
if (sequenceFlows != null && sequenceFlows.size() > 0) {
|
||||||
|
// 循环找到目标元素
|
||||||
|
for (SequenceFlow sequenceFlow: sequenceFlows) {
|
||||||
|
// 如果发现连线重复,说明循环了,跳过这个循环
|
||||||
|
if (visitedElements.contains(sequenceFlow.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 添加已经走过的连线
|
||||||
|
visitedElements.add(sequenceFlow.getId());
|
||||||
|
FlowElement sourceFlowElement = sequenceFlow.getSourceFlowElement();
|
||||||
|
// 这条线路存在目标节点,这条线路完成,进入下个线路
|
||||||
|
if (target.getId().equals(sourceFlowElement.getId())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// 如果目标节点为并行网关,则不继续
|
||||||
|
if (sourceFlowElement instanceof ParallelGateway) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 否则就继续迭代
|
||||||
|
boolean isSequential = isSequentialReachable(sourceFlowElement, target, visitedElements);
|
||||||
|
if (!isSequential) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static boolean isInEventSubprocess(FlowElement flowElement) {
|
||||||
|
FlowElementsContainer flowElementsContainer = flowElement.getParentContainer();
|
||||||
|
while (flowElementsContainer != null) {
|
||||||
|
if (flowElementsContainer instanceof EventSubProcess) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flowElementsContainer instanceof FlowElement) {
|
||||||
|
flowElementsContainer = ((FlowElement) flowElementsContainer).getParentContainer();
|
||||||
|
} else {
|
||||||
|
flowElementsContainer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
package com.ruoyi.flowable.service.impl;
|
package com.ruoyi.flowable.service.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import cn.hutool.core.collection.CollUtil;
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
import com.alibaba.fastjson2.JSONObject;
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
@ -25,6 +27,7 @@ import com.ruoyi.flowable.factory.FlowServiceFactory;
|
||||||
import com.ruoyi.flowable.flow.CustomProcessDiagramGenerator;
|
import com.ruoyi.flowable.flow.CustomProcessDiagramGenerator;
|
||||||
import com.ruoyi.flowable.flow.FindNextNodeUtil;
|
import com.ruoyi.flowable.flow.FindNextNodeUtil;
|
||||||
import com.ruoyi.flowable.flow.FlowableUtils;
|
import com.ruoyi.flowable.flow.FlowableUtils;
|
||||||
|
import com.ruoyi.flowable.flow.ModelUtils;
|
||||||
import com.ruoyi.flowable.service.IFlowTaskService;
|
import com.ruoyi.flowable.service.IFlowTaskService;
|
||||||
import com.ruoyi.flowable.service.ISysDeployFormService;
|
import com.ruoyi.flowable.service.ISysDeployFormService;
|
||||||
import com.ruoyi.flowable.service.ISysFormService;
|
import com.ruoyi.flowable.service.ISysFormService;
|
||||||
|
@ -631,61 +634,71 @@ public class FlowTaskServiceImpl extends FlowServiceFactory implements IFlowTask
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 撤回流程 目前存在错误
|
* 撤回流程
|
||||||
*
|
*
|
||||||
* @param flowTaskVo
|
* @param flowTaskVo 请求实体参数
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional()
|
||||||
public AjaxResult revokeProcess(FlowTaskVo flowTaskVo) {
|
public AjaxResult revokeProcess(FlowTaskVo flowTaskVo) {
|
||||||
Task task = taskService.createTaskQuery().processInstanceId(flowTaskVo.getInstanceId()).singleResult();
|
String procInsId = flowTaskVo.getInstanceId();
|
||||||
if (task == null) {
|
String taskId = flowTaskVo.getTaskId();
|
||||||
throw new CustomException("流程未启动或已执行完成,无法撤回");
|
// 校验流程是否结束
|
||||||
|
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
|
||||||
|
.processInstanceId(procInsId)
|
||||||
|
.active()
|
||||||
|
.singleResult();
|
||||||
|
if(ObjectUtil.isNull(processInstance)) {
|
||||||
|
throw new RuntimeException("流程已结束或已挂起,无法执行撤回操作");
|
||||||
}
|
}
|
||||||
|
// 获取待撤回任务实例
|
||||||
|
HistoricTaskInstance currTaskIns = historyService.createHistoricTaskInstanceQuery()
|
||||||
|
.taskId(taskId)
|
||||||
|
.taskAssignee(flowTaskVo.getUserId())
|
||||||
|
.singleResult();
|
||||||
|
if (ObjectUtil.isNull(currTaskIns)) {
|
||||||
|
throw new RuntimeException("当前任务不存在,无法执行撤回操作");
|
||||||
|
}
|
||||||
|
// 获取 bpmn 模型
|
||||||
|
BpmnModel bpmnModel = repositoryService.getBpmnModel(currTaskIns.getProcessDefinitionId());
|
||||||
|
UserTask currUserTask = ModelUtils.getUserTaskByKey(bpmnModel, currTaskIns.getTaskDefinitionKey());
|
||||||
|
// 查找下一级用户任务列表
|
||||||
|
List<UserTask> nextUserTaskList = ModelUtils.findNextUserTasks(currUserTask);
|
||||||
|
List<String> nextUserTaskKeys = nextUserTaskList.stream().map(UserTask::getId).collect(Collectors.toList());
|
||||||
|
|
||||||
SysUser loginUser = SecurityUtils.getLoginUser().getUser();
|
// 获取当前节点之后已完成的流程历史节点
|
||||||
List<HistoricTaskInstance> htiList = historyService.createHistoricTaskInstanceQuery()
|
List<HistoricTaskInstance> finishedTaskInsList = historyService.createHistoricTaskInstanceQuery()
|
||||||
.processInstanceId(task.getProcessInstanceId())
|
.processInstanceId(procInsId)
|
||||||
.orderByTaskCreateTime()
|
.taskCreatedAfter(currTaskIns.getEndTime())
|
||||||
.asc()
|
.finished()
|
||||||
.list();
|
.list();
|
||||||
String myTaskId = null;
|
for (HistoricTaskInstance finishedTaskInstance : finishedTaskInsList) {
|
||||||
HistoricTaskInstance myTask = null;
|
// 检查已完成流程历史节点是否存在下一级中
|
||||||
for (HistoricTaskInstance hti : htiList) {
|
if (CollUtil.contains(nextUserTaskKeys, finishedTaskInstance.getTaskDefinitionKey())) {
|
||||||
if (loginUser.getUserId().toString().equals(hti.getAssignee())) {
|
throw new RuntimeException("下一流程已处理,无法执行撤回操作");
|
||||||
myTaskId = hti.getId();
|
|
||||||
myTask = hti;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (null == myTaskId) {
|
// 获取所有激活的任务节点,找到需要撤回的任务
|
||||||
throw new CustomException("该任务非当前用户提交,无法撤回");
|
List<Task> activateTaskList = taskService.createTaskQuery().processInstanceId(procInsId).list();
|
||||||
}
|
List<String> revokeExecutionIds = new ArrayList<>();
|
||||||
|
for (Task task : activateTaskList) {
|
||||||
String processDefinitionId = myTask.getProcessDefinitionId();
|
// 检查激活的任务节点是否存在下一级中,如果存在,则加入到需要撤回的节点
|
||||||
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
|
if (CollUtil.contains(nextUserTaskKeys, task.getTaskDefinitionKey())) {
|
||||||
|
// 添加撤回审批信息
|
||||||
//变量
|
taskService.setAssignee(task.getId(), flowTaskVo.getUserId());
|
||||||
// Map<String, VariableInstance> variables = runtimeService.getVariableInstances(currentTask.getExecutionId());
|
taskService.addComment(task.getId(), task.getProcessInstanceId(), FlowComment.REVOKE.getType(), flowTaskVo.getAssignee() + "撤回流程审批");
|
||||||
String myActivityId = null;
|
revokeExecutionIds.add(task.getExecutionId());
|
||||||
List<HistoricActivityInstance> haiList = historyService.createHistoricActivityInstanceQuery()
|
|
||||||
.executionId(myTask.getExecutionId()).finished().list();
|
|
||||||
for (HistoricActivityInstance hai : haiList) {
|
|
||||||
if (myTaskId.equals(hai.getTaskId())) {
|
|
||||||
myActivityId = hai.getActivityId();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FlowNode myFlowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(myActivityId);
|
try {
|
||||||
|
runtimeService.createChangeActivityStateBuilder()
|
||||||
Execution execution = runtimeService.createExecutionQuery().executionId(task.getExecutionId()).singleResult();
|
.processInstanceId(procInsId)
|
||||||
String activityId = execution.getActivityId();
|
.moveExecutionsToSingleActivityId(revokeExecutionIds, currTaskIns.getTaskDefinitionKey()).changeState();
|
||||||
FlowNode flowNode = (FlowNode) bpmnModel.getMainProcess().getFlowElement(activityId);
|
} catch (FlowableObjectNotFoundException e) {
|
||||||
|
throw new RuntimeException("未找到流程实例,流程可能已发生变化");
|
||||||
//记录原活动方向
|
} catch (FlowableException e) {
|
||||||
List<SequenceFlow> oriSequenceFlows = new ArrayList<>(flowNode.getOutgoingFlows());
|
throw new RuntimeException("执行撤回操作失败");
|
||||||
|
}
|
||||||
|
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="finishedList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="finishedList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column label="项目名称" align="center" prop="businessKeyName" width="220" :show-overflow-tooltip="true"/>
|
<el-table-column label="项目名称" align="center" prop="businessKeyName" width="220" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="任务编号" align="center" prop="taskId" width="80" :show-overflow-tooltip="true"/>
|
<el-table-column label="流程编号" align="center" prop="taskId" width="80" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="流程名称" align="center" prop="procDefName" :show-overflow-tooltip="true"/>
|
<el-table-column label="流程名称" align="center" prop="procDefName" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="流程类别" align="center" prop="category" width="130">
|
<el-table-column label="流程类别" align="center" prop="category" width="130">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
@ -85,10 +85,15 @@
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="任务节点" align="center" prop="taskName" width="110"/>
|
<el-table-column label="流程节点" align="center" prop="taskName" width="110">
|
||||||
<el-table-column label="流程发起人" align="center" width="180">
|
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<label>{{scope.row.startUserName}} <el-tag type="info" size="mini">{{scope.row.startDeptName}}</el-tag></label>
|
<div v-if="scope.row.finishTime == null">{{ scope.row.taskName }}</div>
|
||||||
|
<div v-if="scope.row.finishTime != null">流程结束</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="发起人" align="center" width="180">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<label>{{scope.row.startUserName}}<br/><el-tag type="info" size="mini">{{scope.row.startDeptName}}</el-tag></label>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="接收时间" align="center" prop="createTime" width="160"/>
|
<el-table-column label="接收时间" align="center" prop="createTime" width="160"/>
|
||||||
|
@ -282,7 +287,11 @@ export default {
|
||||||
/** 撤回任务 */
|
/** 撤回任务 */
|
||||||
handleRevoke(row){
|
handleRevoke(row){
|
||||||
const params = {
|
const params = {
|
||||||
instanceId: row.procInsId
|
procInsId: row.procInsId,
|
||||||
|
instanceId: row.procInsId,
|
||||||
|
taskId:row.taskId,
|
||||||
|
userId:row.startUserId,
|
||||||
|
assignee:row.startUserName
|
||||||
}
|
}
|
||||||
this.$confirm('是否确认撤回当前任务流程?', '提示', {
|
this.$confirm('是否确认撤回当前任务流程?', '提示', {
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
<el-table v-loading="loading" :data="myProcessList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="myProcessList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column label="项目名称" align="center" prop="businessKeyName" width="160" :show-overflow-tooltip="true"/>
|
<el-table-column label="项目名称" align="center" prop="businessKeyName" width="160" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="流程编号" align="center" prop="procInsId" width="120" :show-overflow-tooltip="true"/>
|
<el-table-column label="申请编号" align="center" prop="procInsId" width="120" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="流程名称" align="center" prop="procDefName" width="120" :show-overflow-tooltip="true"/>
|
<el-table-column label="流程名称" align="center" prop="procDefName" width="120" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="流程类别" align="center" prop="category" >
|
<el-table-column label="流程类别" align="center" prop="category" >
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
@ -110,13 +110,13 @@
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-tag v-if="scope.row.finishTime == null" size="mini">进行中</el-tag>
|
<el-tag v-if="scope.row.finishTime == null" size="mini">进行中</el-tag>
|
||||||
<el-tag type="success" v-if="scope.row.finishTime != null && scope.row.assigneeId != null" size="mini">已完成</el-tag>
|
<el-tag type="success" v-if="scope.row.finishTime != null && scope.row.assigneeId != null" size="mini">已完成</el-tag>
|
||||||
<el-tag type="danger" v-if="scope.row.finishTime != null && scope.row.assigneeId == null" size="mini">已撤销</el-tag>
|
<el-tag type="danger" v-if="scope.row.finishTime != null && scope.row.assigneeId == null" size="mini">已终止</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="当前节点" align="center" prop="taskName">
|
<el-table-column label="当前节点" align="center" prop="taskName">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<div v-if="scope.row.finishTime == null">{{ scope.row.taskName }}</div>
|
<div v-if="scope.row.finishTime == null">{{ scope.row.taskName }}</div>
|
||||||
<div v-if="scope.row.finishTime != null">结束</div>
|
<div v-if="scope.row.finishTime != null">流程结束</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="处理耗时" align="center" prop="duration" width="150">
|
<el-table-column label="处理耗时" align="center" prop="duration" width="150">
|
||||||
|
@ -132,8 +132,8 @@
|
||||||
<el-table-column label="操作" width="150" align="center" fixed="right" class-name="small-padding fixed-width">
|
<el-table-column label="操作" width="150" align="center" fixed="right" class-name="small-padding fixed-width">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button v-if="getActivate(scope.row)" @click="handleActivate(scope.row)" type="text" size="small" icon="el-icon-edit-outline">处理</el-button>
|
<el-button v-if="getActivate(scope.row)" @click="handleActivate(scope.row)" type="text" size="small" icon="el-icon-edit-outline">处理</el-button>
|
||||||
<el-button @click="handleFlowRecord(scope.row)" type="text" size="small" icon="el-icon-finished">查看详情</el-button>
|
<el-button v-if="scope.row.finishTime == null" @click="handleStop(scope.row)" type="text" size="small" icon="el-icon-switch-button">终止</el-button>
|
||||||
<el-button v-if="scope.row.finishTime == null" @click="handleStop(scope.row)" type="text" size="small" icon="el-icon-refresh-left">撤销</el-button>
|
<el-button @click="handleFlowRecord(scope.row)" type="text" size="small" icon="el-icon-finished">详情</el-button>
|
||||||
<el-button v-if="scope.row.finishTime == null" @click="handleDelete(scope.row)" type="text" size="small" icon="el-icon-delete" v-hasPermi="['system:deployment:remove']">删除</el-button>
|
<el-button v-if="scope.row.finishTime == null" @click="handleDelete(scope.row)" type="text" size="small" icon="el-icon-delete" v-hasPermi="['system:deployment:remove']">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
|
|
||||||
<el-table v-loading="loading" :data="todoList" @selection-change="handleSelectionChange">
|
<el-table v-loading="loading" :data="todoList" @selection-change="handleSelectionChange">
|
||||||
<el-table-column label="项目名称" align="center" prop="businessKeyName" width="250" :show-overflow-tooltip="true"/>
|
<el-table-column label="项目名称" align="center" prop="businessKeyName" width="250" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="任务编号" align="center" prop="taskId" width="120" :show-overflow-tooltip="true"/>
|
<el-table-column label="流程编号" align="center" prop="taskId" width="120" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="流程名称" align="center" prop="procDefName" width="180" :show-overflow-tooltip="true"/>
|
<el-table-column label="流程名称" align="center" prop="procDefName" width="180" :show-overflow-tooltip="true"/>
|
||||||
<el-table-column label="流程类别" align="center" prop="category" width="180">
|
<el-table-column label="流程类别" align="center" prop="category" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
|
@ -62,7 +62,9 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="流程发起人" align="center" width="180">
|
<el-table-column label="流程发起人" align="center" width="180">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<label>{{scope.row.startUserName}} <el-tag type="info" size="mini">{{scope.row.startDeptName}}</el-tag></label>
|
<label>{{scope.row.startUserName}} <br/>
|
||||||
|
<el-tag type="info" size="mini">{{scope.row.startDeptName}}</el-tag>
|
||||||
|
</label>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="接收时间" align="center" prop="createTime" width="180"/>
|
<el-table-column label="接收时间" align="center" prop="createTime" width="180"/>
|
||||||
|
|
Loading…
Reference in New Issue