我来分析你的前端代码架构,理解数据流模式后创建一个范式文档。
根据对你的前端代码的深入分析,我为你创建了一个完整的数据流范式文档:
你的应用采用 命令-事件分离(CQRS-like) 模式:
特征:不改变项目状态,直接返回数据
前端 UI/Hook
→ Service Layer (invoke)
→ 后端 Command Handler
→ 直接返回数据
→ 前端处理响应
适用场景:
- 数据查询(getProjectState, getNodes, getConnections)
- Schema 获取(getNodeDefinition)
- 项目路径查询(getProjectPath)
范式规则:
- Service 方法使用
async/await直接返回数据 - 不触发任何事件
- 前端直接使用返回值更新 UI 或临时状态
- 不更新全局 Store
示例:
// Service Layer
static async getProjectState(): Promise<ProjectData> {
const data = await invoke("get_project_data");
return convertData(data);
}
// 使用方
const projectData = await ProjectService.getProjectState();
// 直接使用 projectData,不触发状态更新特征:改变项目状态,通过事件推送更新
前端 UI/Hook
→ Service Layer (invoke)
→ 后端 Command Handler
→ 修改状态
→ emit Event
→ 前端 Event Listener (useProjectSync)
→ 更新 Store
→ UI 自动响应
适用场景:
- 项目操作(newProject, loadProject, saveProject)
- Graph 创建/删除(createEvent, createFunction, removeGraph)
- Node 创建/删除(createNode, deleteNode)
- Connection 创建/删除(createConnection, deleteConnection)
- Variable 创建/更新/删除
范式规则:
- Service 方法调用后端,通常返回
void或简单确认 - 后端执行操作后 emit 事件(如
EventCreated,NodeDeleted) - 前端通过
useProjectSync全局监听事件 - 事件处理器更新 Zustand Store
- React 组件通过 Store 订阅自动重渲染
示例:
// Service Layer - 只负责发送命令
static async createEvent(graphName: string): Promise<void> {
await invoke("create_event", { graphName });
// 不返回数据,等待事件
}
// Event Listener - 全局单例监听
useEffect(() => {
const unlisten = await listen('project-event', (event) => {
switch (event.payload.type) {
case 'EventCreated':
projectStore.addGraph(payload.id, payload.data);
break;
}
});
}, []);
// UI Component - 通过 Store 订阅
const graphs = useProjectStore(state => state.graphs);职责:封装后端 API 调用
规范:
- 使用
invoke()调用 Tauri 命令 - 只负责数据转换(DTO → Domain)
- 不包含业务逻辑
- 不直接操作 Store
- 命名:
XxxService.methodName()
文件位置:
src/services/
├── project/projectService.ts
├── graph/graphService.ts
├── graph/node/nodeService.ts
├── graph/connection/connectionService.ts
├── schema/SchemaService.ts
└── executor/executorService.ts
职责:管理全局应用状态
规范:
- 使用 Zustand 创建 Store
- 提供状态 + 操作方法
- 只负责状态管理,不调用后端
- 命名:
useXxxStore
Store 类型:
-
Project Store(项目级状态)
- 管理:variables, graphs, databases
- 同步:通过事件监听器自动更新
- 生命周期:应用全局
-
Node Store(编辑器状态)
- 管理:每个 tab 的 nodes 和 variables
- 同步:手动管理,支持 undo/redo
- 生命周期:编辑器会话
-
UI Store(界面状态)
- 管理:选中状态、模态框、Toast
- 同步:纯前端状态
- 生命周期:UI 交互
文件位置:
src/features/core/
├── dataStore/ # 项目数据(projectIO, graphMeta, graphData, variable, database)
├── editor/ # 编辑器状态(useEditorStore, useClipboardStore)
├── layout/layoutStore # 布局状态
├── ui/UIStore.ts
├── execution/ # useExecutionStore
└── settings/settingsStore.ts
职责:监听后端事件,同步状态到 Store
规范:
- 使用
listen()监听 Tauri 事件 - 全局单例模式(防止重复监听)
- 解析事件类型,调用 Store 方法
- 支持可选回调(onEventCreated 等)
核心实现:
// Core: ProjectListener + EventRegistry + Handlers(直接更新 Store)
// Handlers 负责更新 Store,callbacks 为可选的 UI 扩展(如打开新 Tab)
// Application: useProjectSync 协调监听器与 useEditor 回调
export function useProjectSync() {
const editor = useEditor();
const callbacks = useMemo(() => ({
onNodeCreated: editor.handleNodeCreated,
onNodeDeleted: editor.handleNodeDeleted,
// ...
}), [editor.handleNodeCreated, ...]);
useEffect(() => {
const listener = await SingletonManager.getInstance('project-listener', async () => {
const l = new ProjectListener(callbacks);
await l.start();
return l;
});
return () => SingletonManager.decrementRef('project-listener', l => l.stop());
}, []);
}文件位置:
src/features/core/sync/ # ProjectListener、EventRegistry、handlers(更新 Store)
src/features/application/initialization/useProjectSync.ts # 协调监听器与编辑器回调
src/features/domain/execution/hooks/useExecutionVisualization.ts # 执行事件监听
职责:组合 Service + Store,提供业务逻辑
规范:
- 组合多个 Service 调用
- 处理错误和加载状态
- 协调多个 Store 更新
- 命名:
useXxx
示例:
export function useProjectOperations() {
const projectStore = useProjectStore();
const createNewEvent = async (name: string) => {
try {
// 1. 调用 Service
await GraphService.createEvent(name);
// 2. 等待事件自动更新 Store
// 3. UI 自动响应
} catch (error) {
// 错误处理
}
};
return { createNewEvent };
}// 嵌套事件结构
Event::Event(EventEvent::EventCreated { id, data })
// 序列化为 JSON
{
"type": "Event",
"payload": {
"type": "EventCreated",
"payload": { "id": "...", "data": {...} }
}
}// 提取实际事件类型
const eventType = eventData.type; // "Event"
const eventPayload = eventData.payload;
let type: string;
let payload: any;
if (eventPayload && 'type' in eventPayload) {
// 嵌套事件
type = eventPayload.type; // "EventCreated"
payload = eventPayload.payload; // { id, data }
} else {
// 直接事件
type = eventType;
payload = eventPayload;
}项目级事件:
ProjectLoaded- 项目加载完成ProjectCleared- 项目清空ProjectSaved- 项目保存完成
Graph 事件:
EventCreated/EventUpdated/EventDeletedFunctionCreated/FunctionUpdated/FunctionDeletedMacroCreated/MacroUpdated/MacroDeleted
Variable 事件:
GlobalVariableCreated/GlobalVariableUpdated/GlobalVariableDeleted
DataFrame 事件:
DataFrameCreated/DataFrameDeleted
执行事件:
execution_start/execution_completenode_start/node_complete/node_errorconnection_active
-
查询操作直接返回
const data = await Service.getData(); setLocalState(data);
-
修改操作等待事件
await Service.createItem(name); // Store 会自动更新,无需手动处理
-
全局状态用 Store
const items = useGraphMetaStore(state => state.graphs); const nodes = useGraphDataStore(state => state.nodes);
-
局部状态用 useState
const [isOpen, setIsOpen] = useState(false);
-
事件监听全局单例
let globalUnlisten: (() => void) | null = null;
-
不要在 Service 中操作 Store
// ❌ 错误 static async createEvent() { await invoke(...); useGraphMetaStore.getState().addGraph(...); // 不要这样 }
-
不要重复监听事件
// ❌ 错误 - 每个组件都监听 useEffect(() => { listen('project-event', ...); }, []);
-
不要混淆命令和事件
// ❌ 错误 - 查询操作不应该触发事件 static async getNodes() { await invoke("get_nodes"); // 应该直接返回 }
-
不要在事件处理器中调用 Service
// ❌ 错误 - 可能导致循环 listen('project-event', async (event) => { await Service.updateData(...); // 不要这样 });
┌─────────────────────────────────────────────────────────────┐
│ 前端应用 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ UI Layer │───▶│ Hooks │───▶│ Services │──┐ │
│ └──────────┘ └──────────┘ └──────────┘ │ │
│ ▲ │ │ │
│ │ │ ▼ │
│ │ │ ┌──────────┐ │
│ │ └───────────────────▶│ invoke │ │
│ │ └──────────┘ │
│ │ │ │
│ ┌──────────┐ │ │
│ │ Stores │◀──────────────┐ │ │
│ └──────────┘ │ │ │
│ ▲ │ │ │
│ │ ┌──────────┐ │ │
│ │ │ Sync │ │ │
│ │ │ Layer │ │ │
│ │ └──────────┘ │ │
│ │ ▲ │ │
└───────┼─────────────────────┼───────────────────┼───────────┘
│ │ │
│ ┌──────────┐ │
│ │ listen │ │
│ └──────────┘ │
│ ▲ │
════════╪═════════════════════╪═══════════════════╪════════════
│ │ ▼
┌───────┼─────────────────────┼───────────────────────────────┐
│ │ │ 后端 │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ │
│ │ │ emit │◀─────│ Commands │ │
│ │ │ event │ └──────────┘ │
│ │ └──────────┘ │ │
│ │ ▲ │ │
│ │ │ ▼ │
│ │ │ ┌──────────┐ │
│ │ └───────────│ State │ │
│ │ └──────────┘ │
│ │ │ │
│ │ │ │
│ └───────────────────────────────────────┘ │
│ 直接返回(查询) │
└───────────────────────────────────────────────────────────┘