|
|
# 新增 LOOP 类节点模板(基于当前重构版本)
|
|
|
|
|
|
这份模板用于你现在这套 Flow Core(`loopFactory + nodeRegistry + useFlowCallbacks`)下,新增“成对节点/分支类”能力。
|
|
|
|
|
|
> 适用场景:像 `LOOP_START/LOOP_END` 这种需要一次创建多个节点和连边的节点族。
|
|
|
|
|
|
---
|
|
|
|
|
|
## 1. 推荐做法(先看)
|
|
|
|
|
|
不要在 `useFlowCallbacks` 里直接手写大段节点/边构造。按现在的模式:
|
|
|
|
|
|
1. 在 `src/utils/flow/` 新增工厂(如 `xxxFactory.ts`)
|
|
|
2. 暴露:
|
|
|
- 节点对(或节点组)构造函数
|
|
|
- 组内连接边构造函数
|
|
|
- 外部插入连接边构造函数(可选)
|
|
|
3. 在 `useFlowCallbacks` 只负责调用工厂 + setNodes/setEdges + snapshot
|
|
|
|
|
|
---
|
|
|
|
|
|
## 2. 工厂模板
|
|
|
|
|
|
**路径示例**:`src/utils/flow/retryFactory.ts`
|
|
|
|
|
|
```ts
|
|
|
import { Edge } from '@xyflow/react';
|
|
|
|
|
|
export const createRetryNodePair = (position: { x: number; y: number }) => {
|
|
|
const retryStartNode: any = {
|
|
|
id: `RETRY_START-${Date.now()}`,
|
|
|
type: 'RETRY',
|
|
|
position: { x: position.x, y: position.y },
|
|
|
data: {
|
|
|
title: '重试开始',
|
|
|
type: 'RETRY_START',
|
|
|
parameters: {
|
|
|
apiIns: [{ name: 'start', desc: '', dataType: '', defaultValue: '' }],
|
|
|
apiOuts: [{ name: 'done', desc: '', dataType: '', defaultValue: '' }],
|
|
|
dataIns: [],
|
|
|
dataOuts: [],
|
|
|
},
|
|
|
component: {},
|
|
|
},
|
|
|
};
|
|
|
|
|
|
const retryEndNode: any = {
|
|
|
id: `RETRY_END-${Date.now()}`,
|
|
|
type: 'RETRY',
|
|
|
position: { x: position.x + 400, y: position.y },
|
|
|
data: {
|
|
|
title: '重试结束',
|
|
|
type: 'RETRY_END',
|
|
|
parameters: {
|
|
|
apiIns: [
|
|
|
{ name: 'continue', desc: '', dataType: '', defaultValue: '' },
|
|
|
],
|
|
|
apiOuts: [{ name: 'break', desc: '', dataType: '', defaultValue: '' }],
|
|
|
dataIns: [],
|
|
|
dataOuts: [],
|
|
|
},
|
|
|
component: {
|
|
|
type: 'RETRY_END',
|
|
|
customDef: JSON.stringify({ retryStartNodeId: retryStartNode.id }),
|
|
|
retryStartNodeId: retryStartNode.id,
|
|
|
},
|
|
|
},
|
|
|
};
|
|
|
|
|
|
retryStartNode.data.component = {
|
|
|
type: 'RETRY_START',
|
|
|
customDef: JSON.stringify({ retryEndNodeId: retryEndNode.id }),
|
|
|
};
|
|
|
|
|
|
return { retryStartNode, retryEndNode };
|
|
|
};
|
|
|
|
|
|
export const createRetryGroupEdge = (
|
|
|
retryStartId: string,
|
|
|
retryEndId: string
|
|
|
): Edge => ({
|
|
|
id: `${retryStartId}-${retryEndId}-group`,
|
|
|
source: retryStartId,
|
|
|
target: retryEndId,
|
|
|
sourceHandle: `${retryStartId}-group`,
|
|
|
targetHandle: `${retryEndId}-group`,
|
|
|
type: 'custom',
|
|
|
});
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## 3. useFlowCallbacks 接入模板
|
|
|
|
|
|
```ts
|
|
|
import {
|
|
|
createRetryNodePair,
|
|
|
createRetryGroupEdge,
|
|
|
} from '@/utils/flow/retryFactory';
|
|
|
import { ensureNodeTypeRegistered } from '@/utils/flow/nodeRegistry';
|
|
|
import { dispatchFlowSnapshotAsync } from '@/utils/flow/snapshot';
|
|
|
|
|
|
const addRetryNodeWithStartEnd = useCallback(
|
|
|
(position: { x: number; y: number }) => {
|
|
|
const { retryStartNode, retryEndNode } = createRetryNodePair(position);
|
|
|
const groupEdge = createRetryGroupEdge(retryStartNode.id, retryEndNode.id);
|
|
|
|
|
|
ensureNodeTypeRegistered('RETRY', '重试');
|
|
|
|
|
|
setNodes((nds) => {
|
|
|
const newNodes = [...nds, retryStartNode, retryEndNode];
|
|
|
dispatchFlowSnapshotAsync({
|
|
|
nodes: [...newNodes],
|
|
|
edges: [...edges, groupEdge],
|
|
|
});
|
|
|
return newNodes;
|
|
|
});
|
|
|
|
|
|
setEdges((eds) => [...eds, groupEdge]);
|
|
|
},
|
|
|
[edges]
|
|
|
);
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
## 4. 类型映射模板
|
|
|
|
|
|
**文件**:`src/utils/flow/nodeRegistry.ts`
|
|
|
|
|
|
```ts
|
|
|
case 'RETRY':
|
|
|
return LoopNode; // 或你自己的专用节点组件
|
|
|
```
|
|
|
|
|
|
> 早期可复用 `LoopNode/LocalNode`,后续再拆专用展示组件。
|
|
|
|
|
|
---
|
|
|
|
|
|
## 5. 新增“边上插入该类节点”的模板(可选)
|
|
|
|
|
|
如需在边上插入节点组,建议像 `LOOP` 一样提供工厂函数:
|
|
|
|
|
|
- `createXxxNodePair(position)`
|
|
|
- `createXxxGroupEdge(startId, endId)`
|
|
|
- `createXxxInsertConnectionEdges({ sourceId, sourceHandle, targetId, targetHandle, ... })`
|
|
|
|
|
|
这样 `addNodeOnEdge` 里只拼装调用,不再手写边结构。
|
|
|
|