bug修复

This commit is contained in:
pengjie 2024-12-16 10:59:39 +08:00
parent 38dca48323
commit 14b3c88d57

View File

@ -7,6 +7,7 @@ import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.wflow.workflow.bean.process.ProcessNode;
import com.wflow.workflow.bean.process.enums.ApprovalModeEnum;
import com.wflow.workflow.bean.process.enums.ApprovalTypeEnum;
import com.wflow.workflow.bean.process.enums.ConditionModeEnum;
import com.wflow.workflow.bean.process.enums.NodeTypeEnum;
@ -29,6 +30,7 @@ import java.util.stream.Collectors;
/**
* json -> bpmn核心转换器
*
* @author : willian fu
* @date : 2022/8/19
*/
@ -54,6 +56,7 @@ public class WFlowToBpmnCreator {
private boolean isSub;
private final static List<FlowableListener> taskListeners = new ArrayList<>();
static {
System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");
FlowableListener taskListener = new FlowableListener();
@ -65,13 +68,14 @@ public class WFlowToBpmnCreator {
/**
* wflow -> bpmnModel 转换
* @param id 表单流程模型id
* @param name 流程名
* @param root 根节点
*
* @param id 表单流程模型id
* @param name 流程名
* @param root 根节点
* @param isSub 是否是子流程
* @return 返回转换后的bpmnModel数据
*/
public BpmnModel loadBpmnFlowXmlByProcess(String id, String name, ProcessNode<?> root, boolean isSub){
public BpmnModel loadBpmnFlowXmlByProcess(String id, String name, ProcessNode<?> root, boolean isSub) {
this.isSub = isSub;
StartEvent startEvent = new StartEvent();
startEvent.setId("start");
@ -92,7 +96,7 @@ public class WFlowToBpmnCreator {
lastNode.ifPresent(node -> {
SequenceFlow line = createdConnectLine(node, endNode.getId());
FlowElement element = elementMap.get(node);
if (element instanceof Gateway){
if (element instanceof Gateway) {
((Gateway) element).setOutgoingFlows(CollectionUtil.newArrayList(line));
}
process.addFlowElement(line);
@ -112,7 +116,7 @@ public class WFlowToBpmnCreator {
/**
* 加载结束节点
*/
private void loadProcessEndNode(){
private void loadProcessEndNode() {
endNode.setId("process-end");
endNode.setName("审批流程结束");
cancelEndNode.setId("cancel-end");
@ -130,12 +134,13 @@ public class WFlowToBpmnCreator {
/**
* 节点props属性强制转换
*
* @param node 节点
*/
public synchronized static void coverProps(ProcessNode<?> node){
if (node.getType().getTypeClass() != Object.class){
public synchronized static void coverProps(ProcessNode<?> node) {
if (node.getType().getTypeClass() != Object.class) {
JSONObject props = (JSONObject) node.getProps();
if (props.get("listeners") instanceof JSONArray){
if (props.get("listeners") instanceof JSONArray) {
//兼容旧版本旧版本是数组新版本是对象
props.put("listeners", "{}");
}
@ -145,23 +150,24 @@ public class WFlowToBpmnCreator {
/**
* 判断并加载分支末端所有的节点
*
* @param node 当前节点
*/
private void loadBranchEndNodes(ProcessNode<?> node){
if (!hasChildren(node) && currentBranchStack.size() > 0){
private void loadBranchEndNodes(ProcessNode<?> node) {
if (!hasChildren(node) && currentBranchStack.size() > 0) {
//没有后续节点代表该分支部分结束塞入末端缓存
Optional.ofNullable(currentBranchStack.peek()).ifPresent(bn -> {
List<String> endNodes = footerNode.get(bn.getId());
if (CollectionUtil.isEmpty(endNodes)){
if (CollectionUtil.isEmpty(endNodes)) {
endNodes = new ArrayList<>();
footerNode.put(bn.getId(), endNodes);
}
if (NodeTypeEnum.EMPTY.equals(node.getType())){
if (NodeTypeEnum.EMPTY.equals(node.getType())) {
currentBranchStack.pop();
if (currentBranchStack.size() > 0){
if (currentBranchStack.size() > 0) {
Optional.ofNullable(currentBranchStack.peek()).ifPresent(beforeBranch -> {
List<String> bfed = footerNode.get(beforeBranch.getId());
if (CollectionUtil.isEmpty(bfed)){
if (CollectionUtil.isEmpty(bfed)) {
bfed = new ArrayList<>();
footerNode.put(beforeBranch.getId(), bfed);
}
@ -169,7 +175,7 @@ public class WFlowToBpmnCreator {
});
}
currentBranchStack.push(bn);
}else {
} else {
endNodes.add(node.getId());
//末端如果是审批节点默认添加一条驳回的链接线
}
@ -179,6 +185,7 @@ public class WFlowToBpmnCreator {
/**
* 校验是否存在后续子节点
*
* @param node 当前节点
* @return 1/0
*/
@ -188,22 +195,23 @@ public class WFlowToBpmnCreator {
/**
* 递归加载所有流程树
*
* @param node 起始节点
*/
public void loadProcess(ProcessNode<?> node){
if (Objects.isNull(node) || Objects.isNull(node.getId())){
public void loadProcess(ProcessNode<?> node) {
if (Objects.isNull(node) || Objects.isNull(node.getId())) {
return;
}
loadBranchEndNodes(node);
coverProps(node);
nodeMap.put(node.getId(), node);
FlowElement element = null;
switch (node.getType()){
switch (node.getType()) {
case ROOT:
if (isSub){
if (isSub) {
//子流程的发起人节点换成初始化任务节点
element = createSubProcInitTask(node.getId());
}else {
} else {
element = createInitiatorNode(node.getId(), node.getName());
}
break;
@ -239,7 +247,7 @@ public class WFlowToBpmnCreator {
element = createTriggerTask((ProcessNode<TriggerProps>) node);
break;
case EMPTY:
if (NodeTypeEnum.CONCURRENTS.equals(node.getParentType())){
if (NodeTypeEnum.CONCURRENTS.equals(node.getParentType())) {
//并行网关成对存在因此再添加一个聚合节点
element = createConcurrentNode(node);
} else if (NodeTypeEnum.CONDITIONS.equals(node.getParentType())) {
@ -250,7 +258,7 @@ public class WFlowToBpmnCreator {
}
break;
}
if (Objects.nonNull(element)){
if (Objects.nonNull(element)) {
addFlowEl(element);
}
addAndCreateConnLine(node);
@ -267,9 +275,9 @@ public class WFlowToBpmnCreator {
callActivity.setBehavior(WflowCallActivityBehavior.class);
//将主流程内子流程节点id绑定到子流程的业务key
callActivity.setBusinessKey(node.getId());
if (node.getProps().getSubAll()){
if (node.getProps().getSubAll()) {
callActivity.setInheritVariables(true);
}else {
} else {
//挨个设置输入变量
List<IOParameter> ioParams = getIoParams(node.getProps().getInVar(), false);
callActivity.setInParameters(ioParams);
@ -280,7 +288,7 @@ public class WFlowToBpmnCreator {
}
//发起人节点
private UserTask createInitiatorNode(String id, String name){
private UserTask createInitiatorNode(String id, String name) {
UserTask userTask = new UserTask();
userTask.setId(id);
userTask.setName(name);
@ -299,19 +307,19 @@ public class WFlowToBpmnCreator {
}
//将当前节点向上连接向上查找应该连接到本节点的所有父节点
private void addAndCreateConnLine(ProcessNode<?> node){
if (NodeTypeEnum.EMPTY.equals(node.getType())){
private void addAndCreateConnLine(ProcessNode<?> node) {
if (NodeTypeEnum.EMPTY.equals(node.getType())) {
//空节点代表一个分支结束缓存出栈
ProcessNode<?> branch = currentBranchStack.pop();
footerNode.get(branch.getId()).forEach(en -> {
SequenceFlow connectLine = createdConnectLine(en, node.getId());
ProcessNode<?> endNode = nodeMap.get(en);
if (NodeTypeEnum.CONDITION.equals(endNode.getType())
|| NodeTypeEnum.INCLUSIVE.equals(endNode.getType())){
|| NodeTypeEnum.INCLUSIVE.equals(endNode.getType())) {
//分支只有一个条件节点那么就直连排他网关
connectLine.setId(endNode.getId());
connectLine.setSourceRef(endNode.getParentId());
}else if (NodeTypeEnum.EMPTY.equals(endNode.getType())){
} else if (NodeTypeEnum.EMPTY.equals(endNode.getType())) {
//末端是网关要为其构建出口
Gateway gateway = (Gateway) elementMap.get(en);
gateway.setOutgoingFlows(CollectionUtil.newArrayList(connectLine));
@ -319,7 +327,7 @@ public class WFlowToBpmnCreator {
addFlowEl(connectLine);
});
if (NodeTypeEnum.CONDITIONS.equals(node.getParentType())
|| NodeTypeEnum.INCLUSIVES.equals(node.getParentType())){
|| NodeTypeEnum.INCLUSIVES.equals(node.getParentType())) {
//为条件网关构造出口及默认流
Gateway cdgw = (Gateway) elementMap.get(node.getParentId());
List<SequenceFlow> outgoing = branch.getBranchs().stream()
@ -335,17 +343,17 @@ public class WFlowToBpmnCreator {
.collect(Collectors.toList());
cdgw.setOutgoingFlows(outgoing);
}
}else if (Objects.nonNull(node.getParentId())){
} else if (Objects.nonNull(node.getParentId())) {
//非空节点特殊处理判断父级是啥子
ProcessNode<?> parentNode = nodeMap.get(node.getParentId());
if (Objects.isNull(parentNode)
|| NodeTypeEnum.CONDITION.equals(node.getType())
|| NodeTypeEnum.CONCURRENT.equals(node.getType())
|| NodeTypeEnum.INCLUSIVE.equals(node.getType())){
|| NodeTypeEnum.INCLUSIVE.equals(node.getType())) {
return;
}
SequenceFlow line = null;
switch (parentNode.getType()){
switch (parentNode.getType()) {
case CONCURRENT:
case CONDITION:
case INCLUSIVE:
@ -353,11 +361,11 @@ public class WFlowToBpmnCreator {
line = createdConnectLine(parentNode.getParentId(), node.getId());
line.setId(parentNode.getId());
line.setName(parentNode.getName());
if (parentNode.getProps() instanceof ConditionProps){
if (parentNode.getProps() instanceof ConditionProps) {
ConditionProps props = (ConditionProps) parentNode.getProps();
if (CollectionUtil.isNotEmpty(props.getGroups())){
if (CollectionUtil.isNotEmpty(props.getGroups())) {
String conditionExplainCreator = conditionExplainCreator(line.getId(), (ConditionProps) parentNode.getProps());
if (StrUtil.isNotBlank(conditionExplainCreator)){
if (StrUtil.isNotBlank(conditionExplainCreator)) {
line.setConditionExpression(conditionExplainCreator);
}
}
@ -367,7 +375,7 @@ public class WFlowToBpmnCreator {
case TASK:
//父级节点是审批/办理节点
line = createdConnectLine(parentNode.getId(), node.getId());
line.setName(NodeTypeEnum.APPROVAL.equals(parentNode.getType()) ? "同意": "提交");
line.setName(NodeTypeEnum.APPROVAL.equals(parentNode.getType()) ? "同意" : "提交");
break;
case EMPTY:
line = createdConnectLine(parentNode.getId(), node.getId());
@ -380,13 +388,13 @@ public class WFlowToBpmnCreator {
break;
}
addFlowEl(line);
}else if (NodeTypeEnum.ROOT.equals(node.getType())){
} else if (NodeTypeEnum.ROOT.equals(node.getType())) {
//发起人节点链接到开始节点
addFlowEl(createdConnectLine("start", node.getId()));
}
}
private void addFlowEl(FlowElement element){
private void addFlowEl(FlowElement element) {
elementMap.put(element.getId(), element);
}
@ -397,27 +405,27 @@ public class WFlowToBpmnCreator {
ApprovalProps props = node.getProps();
//全部按多人审批处理
userTask.setTaskListeners(taskListeners);
if(ApprovalTypeEnum.SELF.equals(props.getAssignedType())){
if (ApprovalTypeEnum.SELF.equals(props.getAssignedType())) {
//发起人自己审批
userTask.setAssignee("${" + WflowGlobalVarDef.INITIATOR + "}");
}else {
} else {
userTask.setAssignee("${assignee}");
userTask.setLoopCharacteristics(createAndOrMode(node.getId(), props));
}
userTask.setId(node.getId());
//处理审批超时添加定时器边界事件
ApprovalProps.TimeLimit timeLimit = props.getTimeLimit();
if (Objects.nonNull(timeLimit.getTimeout().getValue()) && timeLimit.getTimeout().getValue() > 0){
if (Objects.nonNull(timeLimit.getTimeout().getValue()) && timeLimit.getTimeout().getValue() > 0) {
BoundaryEvent boundaryEvent = new BoundaryEvent();
boundaryEvent.setId(node.getId() + "-timeout");
boundaryEvent.setName("审批超时");
TimerEventDefinition timerEventDefinition = new TimerEventDefinition();
String timeValue = getISO8601Time(timeLimit.getTimeout().getValue(), timeLimit.getTimeout().getUnit());
timerEventDefinition.setTimeDuration(timeValue);
if (ApprovalProps.TimeLimit.Handler.HandlerType.NOTIFY.equals(timeLimit.getHandler().getType())){
if (ApprovalProps.TimeLimit.Handler.HandlerType.NOTIFY.equals(timeLimit.getHandler().getType())) {
//根据是否循环提醒来修改定时规则
ApprovalProps.TimeLimit.Handler.Notify notify = timeLimit.getHandler().getNotify();
if (!notify.isOnce()){
if (!notify.isOnce()) {
timerEventDefinition.setTimeDuration(null);
//默认最大10次这里参考 https://en.wikipedia.org/wiki/ISO_8601#Repeating_intervals
timerEventDefinition.setTimeCycle("R10/" + timeValue);
@ -443,7 +451,7 @@ public class WFlowToBpmnCreator {
private ParallelGateway createConcurrentNode(ProcessNode<?> node) {
ParallelGateway parallelGateway = new ParallelGateway();
parallelGateway.setId(node.getId());
parallelGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "并行分支聚合":"并行分支");
parallelGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "并行分支聚合" : "并行分支");
return parallelGateway;
}
@ -491,7 +499,7 @@ public class WFlowToBpmnCreator {
ExclusiveGateway exclusiveGateway = new ExclusiveGateway();
exclusiveGateway.setExclusive(true);
exclusiveGateway.setId(node.getId());
exclusiveGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "条件分支聚合":"条件分支");
exclusiveGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "条件分支聚合" : "条件分支");
return exclusiveGateway;
}
@ -500,7 +508,7 @@ public class WFlowToBpmnCreator {
InclusiveGateway inclusiveGateway = new InclusiveGateway();
inclusiveGateway.setExclusive(true);
inclusiveGateway.setId(node.getId());
inclusiveGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "包容分支聚合":"包容分支");
inclusiveGateway.setName(NodeTypeEnum.EMPTY.equals(node.getType()) ? "包容分支聚合" : "包容分支");
return inclusiveGateway;
}
@ -514,12 +522,39 @@ public class WFlowToBpmnCreator {
//构建条件表达式
private String conditionExplainCreator(String nodeId, ConditionProps conditions) {
if (CollectionUtil.isNotEmpty(conditions.getGroups())){
return "${uelTools.conditionCompare('"+ nodeId + "', execution)}";
if (CollectionUtil.isNotEmpty(conditions.getGroups())) {
return "${uelTools.conditionCompare('" + nodeId + "', execution)}";
}
return null;
}
//多人签署设置-会签/或签
// private MultiInstanceLoopCharacteristics createAndOrMode(String nodeId, ApprovalProps props) {
// MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics();
// loopCharacteristics.setId(IdUtil.randomUUID());
// loopCharacteristics.setElementVariable("assignee");
// loopCharacteristics.setInputDataItem("${processTaskService.getNodeApprovalUsers(execution)}");
// //设置完成条件先判断会签还是或签
// String completionCondition = "";
// switch (props.getMode()) {
// case OR: //有任意一个人处理过就结束
// completionCondition = "nrOfCompletedInstances >= 1";
// loopCharacteristics.setSequential(false);
// break;
// case AND: //所有任务都结束
// completionCondition = "nrOfActiveInstances == 0";
// loopCharacteristics.setSequential(false);
// break;
// case NEXT:
// completionCondition = "nrOfActiveInstances == 0";
// loopCharacteristics.setSequential(true);
// break;
// }
// loopCharacteristics.setCompletionCondition("${" + completionCondition + "}");
// return loopCharacteristics;
// }
//多人签署设置-会签/或签
private MultiInstanceLoopCharacteristics createAndOrMode(String nodeId, ApprovalProps props) {
MultiInstanceLoopCharacteristics loopCharacteristics = new MultiInstanceLoopCharacteristics();
@ -527,54 +562,45 @@ public class WFlowToBpmnCreator {
loopCharacteristics.setElementVariable("assignee");
loopCharacteristics.setInputDataItem("${processTaskService.getNodeApprovalUsers(execution)}");
//设置完成条件先判断会签还是或签
String completionCondition = "";
switch (props.getMode()) {
case OR: //有任意一个人处理过就结束
completionCondition = "nrOfCompletedInstances >= 1";
loopCharacteristics.setSequential(false);
break;
case AND: //所有任务都结束
completionCondition = "nrOfActiveInstances == 0";
loopCharacteristics.setSequential(false);
break;
case NEXT:
completionCondition = "nrOfActiveInstances == 0";
loopCharacteristics.setSequential(true);
break;
}
loopCharacteristics.setCompletionCondition("${" + completionCondition + "}");
loopCharacteristics.setSequential(ApprovalModeEnum.NEXT.equals(props.getMode()));
loopCharacteristics.setCompletionCondition("${uelTools.nodeIsComplete(execution, '" + props.getMode().toString() + "')}");
return loopCharacteristics;
}
/**
* 获取ISO8601时间
*
* @param time
* @param unit 单位
* @return 格式化时间
*/
private String getISO8601Time(Integer time, String unit){
switch (unit){
case "D": return "P" + time + unit;
case "H": return "PT" + time + unit;
case "M": return "PT" + time + unit;
private String getISO8601Time(Integer time, String unit) {
switch (unit) {
case "D":
return "P" + time + unit;
case "H":
return "PT" + time + unit;
case "M":
return "PT" + time + unit;
}
return null;
}
/**
* 构造主子流程变量传递参数
* @param vars 参数
*
* @param vars 参数
* @param reverse 是否为逆向传递
* @return 参数列表
*/
private List<IOParameter> getIoParams(List<SubProcessProps.Var> vars, Boolean reverse){
private List<IOParameter> getIoParams(List<SubProcessProps.Var> vars, Boolean reverse) {
return vars.stream().filter(v -> StrUtil.isNotBlank(reverse ? v.getSKey() : v.getMKey()))
.map(v -> {
IOParameter ip = new IOParameter();
if (reverse){
if (reverse) {
ip.setSource(v.getSKey());
ip.setTarget(StrUtil.isNotBlank(v.getMKey()) ? v.getMKey() : v.getSKey());
}else {
} else {
ip.setSource(v.getMKey());
ip.setTarget(StrUtil.isNotBlank(v.getSKey()) ? v.getSKey() : v.getMKey());
}