Skip to content

Commit 1b9687e

Browse files
committed
add error-trigger config modal
1 parent bc5f984 commit 1b9687e

8 files changed

Lines changed: 266 additions & 35 deletions

File tree

flow-engine-framework/src/main/java/com/codingapi/flow/manager/FlowNodeManager.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import java.util.stream.Stream;
1010

1111
/**
12-
* 流程节点管理器,主要获取流程节点信息
12+
* 流程节点管理器,主要获取流程节点信息
1313
*/
1414
public class FlowNodeManager {
1515

@@ -29,9 +29,9 @@ private IFlowNode fetchNodes(String nodeId, List<IFlowNode> nodes) {
2929
return node;
3030
}
3131
List<IFlowNode> blocks = node.blocks();
32-
if(blocks!=null && !blocks.isEmpty()){
33-
IFlowNode flowNode = this.fetchNodes(nodeId,blocks);
34-
if(flowNode!=null){
32+
if (blocks != null && !blocks.isEmpty()) {
33+
IFlowNode flowNode = this.fetchNodes(nodeId, blocks);
34+
if (flowNode != null) {
3535
return flowNode;
3636
}
3737
}
@@ -74,12 +74,13 @@ public List<IFlowNode> getNextNodes(IFlowNode current) {
7474

7575
/**
7676
* 加载下一节点
77-
* @param current 当前节点状态
78-
* @param iterator 当前遍历的节点列表
77+
*
78+
* @param current 当前节点状态
79+
* @param iterator 当前遍历的节点列表
7980
* @return 下一节点列表
8081
*/
8182
private List<IFlowNode> loadNextNodes(FlowNodeState current, Iterator<FlowNodeState> iterator) {
82-
if(current.isEndNode()){
83+
if (current.isEndNode()) {
8384
return new ArrayList<>();
8485
}
8586
while (iterator.hasNext()) {
@@ -89,7 +90,17 @@ private List<IFlowNode> loadNextNodes(FlowNodeState current, Iterator<FlowNodeSt
8990
return node.getBlocks();
9091
}
9192
if (node.isBranchNode()) {
92-
return node.getFirstBlocks();
93+
List<IFlowNode> nextNodes = node.getFirstBlocks();
94+
if(!nextNodes.isEmpty()){
95+
return nextNodes;
96+
}else {
97+
// 跳过大循环,直接进入下一节点
98+
if (this.nodes.hasNext()) {
99+
return Stream.of(this.nodes.next().getNode()).toList();
100+
} else {
101+
throw FlowStateException.edgeConfigError(current.getName());
102+
}
103+
}
93104
}
94105
if (iterator.hasNext()) {
95106
FlowNodeState next = iterator.next();
@@ -98,19 +109,20 @@ private List<IFlowNode> loadNextNodes(FlowNodeState current, Iterator<FlowNodeSt
98109
// 跳过大循环,直接进入下一节点
99110
if (this.nodes.hasNext()) {
100111
return Stream.of(this.nodes.next().getNode()).toList();
101-
}else {
112+
} else {
102113
throw FlowStateException.edgeConfigError(current.getName());
103114
}
104115
}
105116
}
106117

107118
if (node.isBlockNode() || node.isBranchNode()) {
108-
List<IFlowNode> nextNodes = this.loadNextNodes(current, node.getBlocks().stream().map(FlowNodeState::new).toList().iterator());
109-
if (!nextNodes.isEmpty()) {
110-
return nextNodes;
119+
if (node.getBlocks() != null) {
120+
List<IFlowNode> nextNodes = this.loadNextNodes(current, node.getBlocks().stream().map(FlowNodeState::new).toList().iterator());
121+
if (!nextNodes.isEmpty()) {
122+
return nextNodes;
123+
}
111124
}
112125
}
113-
114126
}
115127
return new ArrayList<>();
116128
}

flow-engine-framework/src/main/java/com/codingapi/flow/pojo/response/ProcessNode.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import java.util.ArrayList;
1111
import java.util.List;
12+
import java.util.Objects;
1213

1314
/**
1415
* 流程审批节点
@@ -81,6 +82,20 @@ public void setCurrentState() {
8182
}
8283

8384

85+
@Override
86+
public boolean equals(Object target) {
87+
if(target instanceof ProcessNode) {
88+
ProcessNode targetNode = (ProcessNode) target;
89+
return targetNode.getNodeId().equals(this.getNodeId());
90+
}
91+
return super.equals(target);
92+
}
93+
94+
@Override
95+
public int hashCode() {
96+
return Objects.hash(nodeId, nodeName, nodeType, state, operators);
97+
}
98+
8499
/**
85100
* 审批意见内容,仅当历史节点存在数据
86101
*/

flow-engine-framework/src/main/java/com/codingapi/flow/script/node/TriggerScript.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class TriggerScript {
1414
public static final String SCRIPT_DEFAULT = """
1515
// @SCRIPT_TITLE 示例触发节点(打印触发日志)
1616
def run(request){
17-
print('hello trigger node.');
17+
print('hello trigger node.\n');
1818
}
1919
""";
2020

flow-engine-framework/src/main/java/com/codingapi/flow/service/impl/FlowProcessNodeService.java

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import com.codingapi.flow.manager.NodeStrategyManager;
1111
import com.codingapi.flow.manager.OperatorManager;
1212
import com.codingapi.flow.node.IFlowNode;
13+
import com.codingapi.flow.node.NodeType;
1314
import com.codingapi.flow.node.nodes.StartNode;
1415
import com.codingapi.flow.operator.IFlowOperator;
1516
import com.codingapi.flow.pojo.request.FlowProcessNodeRequest;
@@ -21,6 +22,7 @@
2122
import com.codingapi.flow.session.FlowAdvice;
2223
import com.codingapi.flow.session.FlowSession;
2324
import com.codingapi.flow.workflow.Workflow;
25+
import lombok.Getter;
2426

2527
import java.util.ArrayList;
2628
import java.util.List;
@@ -45,6 +47,7 @@ public class FlowProcessNodeService {
4547
// 流程节点记录
4648
private final List<ProcessNode> nodeList;
4749

50+
4851
public FlowProcessNodeService(FlowProcessNodeRequest request) {
4952
this.request = request;
5053
this.currentOperator = RepositoryHolderContext.getInstance().getOperatorById(request.getOperatorId());
@@ -55,6 +58,7 @@ public FlowProcessNodeService(FlowProcessNodeRequest request) {
5558
this.loadWorkflow();
5659
}
5760

61+
5862
private void loadWorkflow() {
5963
String id = this.request.getId();
6064
if (this.request.isCreateWorkflow()) {
@@ -104,30 +108,70 @@ public List<ProcessNode> processNodes() {
104108
FlowAdvice.nullFlowAdvice()
105109
);
106110

107-
this.fetchNextNode(flowSession, List.of(this.currentNode));
111+
NextNodeLoader nextNodeLoader = new NextNodeLoader(this.currentNode);
112+
List<ProcessNode> nextNodes = nextNodeLoader.loadNextNode(flowSession);
108113

109-
// 推理后续
110-
return nodeList;
114+
this.nodeList.addAll(nextNodes);
115+
return this.nodeList;
111116
}
112117

113118

114-
private void fetchNextNode(FlowSession flowSession, List<IFlowNode> nexNodes) {
115-
for (IFlowNode flowNode : nexNodes) {
116-
List<IFlowOperator> operators = null;
117-
if(flowNode.getType().equals(StartNode.NODE_TYPE)){
118-
operators = List.of(flowSession.getCurrentOperator());
119-
}else {
120-
NodeStrategyManager nodeStrategyManager = flowNode.strategyManager();
121-
OperatorManager operatorManager = nodeStrategyManager.loadOperators(flowSession);
122-
operators = operatorManager.getOperators();
119+
private class NextNodeLoader {
120+
121+
@Getter
122+
private final List<ProcessNode> nodeList;
123+
private final IFlowNode currentNode;
124+
private final List<String> displayNodeTypes;
125+
126+
public NextNodeLoader(IFlowNode currentNode) {
127+
this.currentNode = currentNode;
128+
this.nodeList = new ArrayList<>();
129+
this.displayNodeTypes = new ArrayList<>();
130+
this.initDisplayNodeTypes();
131+
}
132+
133+
134+
private void initDisplayNodeTypes() {
135+
this.displayNodeTypes.add(NodeType.START.name());
136+
this.displayNodeTypes.add(NodeType.END.name());
137+
this.displayNodeTypes.add(NodeType.APPROVAL.name());
138+
this.displayNodeTypes.add(NodeType.NOTIFY.name());
139+
this.displayNodeTypes.add(NodeType.HANDLE.name());
140+
this.displayNodeTypes.add(NodeType.TRIGGER.name());
141+
this.displayNodeTypes.add(NodeType.SUB_PROCESS.name());
142+
}
143+
144+
private void fetchNextNode(FlowSession flowSession, List<IFlowNode> nexNodes) {
145+
for (IFlowNode flowNode : nexNodes) {
146+
List<IFlowOperator> operators = null;
147+
if (flowNode.getType().equals(StartNode.NODE_TYPE)) {
148+
operators = List.of(flowSession.getCurrentOperator());
149+
} else {
150+
NodeStrategyManager nodeStrategyManager = flowNode.strategyManager();
151+
OperatorManager operatorManager = nodeStrategyManager.loadOperators(flowSession);
152+
operators = operatorManager.getOperators();
153+
}
154+
ProcessNode processNode = new ProcessNode(flowNode, operators);
155+
if (processNode.isFlowNode(this.currentNode)) {
156+
processNode.setCurrentState();
157+
}
158+
this.nodeList.add(processNode);
159+
List<IFlowNode> nextNodes = workflow.nextNodes(flowNode);
160+
this.fetchNextNode(flowSession.updateSession(flowNode), nextNodes);
123161
}
124-
ProcessNode processNode = new ProcessNode(flowNode,operators);
125-
if(processNode.isFlowNode(this.currentNode)){
126-
processNode.setCurrentState();
162+
}
163+
164+
public List<ProcessNode> loadNextNode(FlowSession flowSession) {
165+
this.fetchNextNode(flowSession,List.of(this.currentNode));
166+
167+
List<ProcessNode> displayNodes = nodeList.stream().filter(node-> this.displayNodeTypes.contains(node.getNodeType())).toList();
168+
List<ProcessNode> processNodeList = new ArrayList<>();
169+
for (ProcessNode node:displayNodes){
170+
if(!processNodeList.contains(node)){
171+
processNodeList.add(node);
172+
}
127173
}
128-
this.nodeList.add(processNode);
129-
List<IFlowNode> nextNodes = workflow.nextNodes(flowNode);
130-
this.fetchNextNode(flowSession.updateSession(flowNode), nextNodes);
174+
return processNodeList;
131175
}
132176
}
133177

frontend/packages/flow-pc/flow-pc-design/src/components/design-editor/node-components/strategy/error-trigger.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React from "react";
2-
import {Button, Form,Input, Space} from "antd";
3-
import { Field, FieldRenderProps } from "@flowgram.ai/fixed-layout-editor";
2+
import {Button, Form, Space} from "antd";
3+
import {Field, FieldRenderProps} from "@flowgram.ai/fixed-layout-editor";
44
import {GroovyScriptPreview} from "@/components/script/components/groovy-script-preview";
5-
import { EditOutlined } from "@ant-design/icons";
5+
import {EditOutlined} from "@ant-design/icons";
6+
import {ErrorTriggerConfigModal} from "@/components/script/modal/error-trigger-config-modal";
67

78
/**
89
* 错误触发策略配置(没有匹配到人时)
@@ -11,6 +12,7 @@ import { EditOutlined } from "@ant-design/icons";
1112
export const ErrorTriggerStrategy: React.FC = () => {
1213

1314
const [form] = Form.useForm();
15+
const [visible,setVisible] = React.useState(false);
1416

1517
return (
1618
<Form
@@ -36,11 +38,19 @@ export const ErrorTriggerStrategy: React.FC = () => {
3638
<Button
3739
icon={<EditOutlined/>}
3840
onClick={() => {
41+
setVisible(true);
3942
}}
4043
style={{borderRadius: '0 6px 6px 0'}}
4144
>
4245
编辑
4346
</Button>
47+
48+
<ErrorTriggerConfigModal
49+
open={visible}
50+
onCancel={()=>{setVisible(false);}}
51+
onConfirm={(value)=>{onChange(value)}}
52+
script={value}
53+
/>
4454
</Space.Compact>
4555
)}
4656
/>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React from "react";
2+
import {GroovyVariableMapping, ScriptType} from "@/components/script/typings";
3+
import {GroovyScriptContent, GroovyScriptModal} from "@/components/script/components/groovy-script-modal";
4+
import {GroovyScriptConvertorUtil} from "@/components/script/utils/convertor";
5+
import {AdvancedScriptEditor} from "@/components/script/components/advanced-script-editor";
6+
import {DEFAULT_NODE_TITLE_SCRIPT} from "@/components/script/default-script";
7+
import {ErrorTriggerPluginView} from "@/components/script/plugins/view/error-trigger-view";
8+
9+
export interface ErrorTriggerConfigModalProps {
10+
/** 是否展示 **/
11+
open: boolean;
12+
/** 当前脚本 */
13+
script: string;
14+
/** 表单字段(用于动态生成变量) */
15+
variables?: GroovyVariableMapping[];
16+
/** 取消回调 */
17+
onCancel: () => void;
18+
/** 确认回调 */
19+
onConfirm: (script: string) => void;
20+
}
21+
22+
23+
24+
const ErrorTriggerConfigContent: React.FC<GroovyScriptContent> = (props) => {
25+
const isAdvance = GroovyScriptConvertorUtil.isCustomScript(props.script);
26+
27+
return (
28+
<>
29+
{isAdvance && (
30+
<AdvancedScriptEditor
31+
{...props}
32+
resetScript={()=>{
33+
return DEFAULT_NODE_TITLE_SCRIPT;
34+
}}
35+
/>
36+
)}
37+
{!isAdvance && (
38+
<ErrorTriggerPluginView {...props} />
39+
)}
40+
</>
41+
);
42+
}
43+
44+
export const ErrorTriggerConfigModal:React.FC<ErrorTriggerConfigModalProps> = (props) => {
45+
return (
46+
<GroovyScriptModal
47+
type={ScriptType.TITLE}
48+
open={props.open}
49+
script={props.script}
50+
variables={props.variables || []}
51+
onConfirm={props.onConfirm}
52+
onCancel={props.onCancel}
53+
title="异常配置"
54+
content={ErrorTriggerConfigContent}
55+
/>
56+
);
57+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {GroovyVariableMapping, ScriptType} from "@/components/script/typings";
2+
3+
export const VIEW_KEY = 'ErrorTriggerViewPlugin';
4+
5+
export interface ErrorTriggerViewPlugin {
6+
/** 脚本类型 */
7+
type: ScriptType;
8+
/** 当前脚本 */
9+
script: string;
10+
/** 变量映射列表 */
11+
variables: GroovyVariableMapping[];
12+
/** 确认回调 */
13+
onChange: (script: string) => void;
14+
}

0 commit comments

Comments
 (0)