diff --git a/docs/add-flow-node-template.md b/docs/add-flow-node-template.md new file mode 100644 index 0000000..39dd4c2 --- /dev/null +++ b/docs/add-flow-node-template.md @@ -0,0 +1,113 @@ +# 新增 Flow 节点模板(基于当前重构版本) + +这份模板按你现在的代码结构整理,目标是:**新增节点只改最少文件**。 + +--- + +## 1. 最小接入步骤 + +新增一个普通节点(非 LOOP)通常只要 3 步: + +1. 新建节点组件(可先复用 `LocalNode` 风格) +2. 在 `nodeRegistry` 注册类型映射 +3. 在节点配置源(`localNodeData`)增加定义 + +> `useFlowCallbacks` 已统一走 `resolveNodeDefinition + buildRuntimeNode + ensureNodeTypeRegistered`,不需要再在多个入口手写创建逻辑。 + +--- + +## 2. 模板代码 + +### 2.1 新建节点组件 + +**路径示例**:`src/components/FlowEditor/node/httpNode/HttpNode.tsx` + +```tsx +import React from 'react'; +import LocalNode from '@/components/FlowEditor/node/localNode/LocalNode'; + +const HttpNode = (props: any) => { + // 第一版可以直接复用 LocalNode 渲染行为 + return ; +}; + +export default HttpNode; +``` + +--- + +### 2.2 注册节点类型映射(关键) + +**文件**:`src/utils/flow/nodeRegistry.ts` + +```ts +import HttpNode from '@/components/FlowEditor/node/httpNode/HttpNode'; + +export const resolveNodeComponent = (nodeType: string) => { + switch (nodeType) { + // ...已有 case + case 'HTTP': + return HttpNode; + default: + return LocalNode; + } +}; +``` + +--- + +### 2.3 增加节点定义(用于菜单与创建) + +**文件**:`src/pages/flowEditor/sideBar/config/localNodeData.ts` + +```ts +export const localNodeData = [ + // ...已有节点 + { + nodeType: 'HTTP', + nodeName: 'HTTP请求', + data: { + title: 'HTTP请求', + type: 'HTTP', + parameters: { + apiIns: [{ name: 'start', desc: '', dataType: '', defaultValue: '' }], + apiOuts: [{ name: 'done', desc: '', dataType: '', defaultValue: '' }], + dataIns: [], + dataOuts: [], + }, + component: { + type: 'HTTP', + customDef: '{}', + }, + }, + }, +]; +``` + +--- + +## 3. 可选:节点专用编辑器 + +如果你希望配置面板是独立 UI,再补: + +1. 新建编辑器组件(`src/components/FlowEditor/nodeEditors/...`) +2. 在编辑器路由/映射处按 `nodeType` 挂载 + +不做这一步也能先跑通新增节点。 + +--- + +## 4. 当前推荐的接入方式 + +新增节点时不要再手写分散逻辑,优先复用: + +- `resolveNodeDefinition(...)` +- `buildRuntimeNode(...)` +- `ensureNodeTypeRegistered(...)` + +这些已覆盖: + +- 侧栏拖拽到画布(onDrop) +- 画布空白处添加(addNodeOnPane) +- 在边上插入节点(addNodeOnEdge) + diff --git a/docs/add-loop-node-template.md b/docs/add-loop-node-template.md new file mode 100644 index 0000000..9c3ddb1 --- /dev/null +++ b/docs/add-loop-node-template.md @@ -0,0 +1,149 @@ +# 新增 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` 里只拼装调用,不再手写边结构。 +