前端 + AI 进阶 Day 12:可视化工作流编辑器
当然可以!以下是 严格按照你指定模板风格(含文件结构、学习目标、原理说明、完整代码、验证步骤等)编写的 Day 12 完整版。
前端 + AI 进阶学习路线|Week 11-12:智能工作流前端
Day 12:可视化工作流编辑器
学习时间:2026年1月5日(星期一)
关键词:可视化工作流、React Flow、拖拽节点、连线、节点配置、DAG
📁 项目文件结构
day12-workflow-editor/
├── src/
│ ├── components/
│ │ ├── WorkflowCanvas.jsx # 工作流画布(React Flow)
│ │ ├── NodeTypes/ # 自定义节点类型
│ │ │ ├── AINode.jsx # AI 节点
│ │ │ ├── InputNode.jsx # 输入节点
│ │ │ └── OutputNode.jsx # 输出节点
│ │ └── ControlsPanel.jsx # 控制面板(节点库 + 操作)
│ ├── lib/
│ │ └── workflowTemplates.js # 工作流模板
│ └── App.jsx # 主应用集成
└── public/
✅ 本日核心:构建可拖拽、可配置、可连线的可视化 AI 工作流编辑器
🎯 今日学习目标
- 使用 React Flow 实现 拖拽式工作流画布
- 创建 自定义节点类型(输入 / AI / 输出)
- 支持 节点连线 与 配置面板
- 实现 工作流模板加载/保存 基础能力
💡 为什么需要可视化工作流?
复杂 AI 任务常需多步协同:
- 数据预处理 → AI 分析 → 结果后处理
- 多模型串联(如:OCR → 翻译 → 摘要)
- 条件分支(如:检测到错误 → 触发修复流程)
✅ 可视化编排 降低使用门槛,让非程序员也能构建 AI 自动化流程
📚 核心技术选型
| 功能 | 技术 |
|---|---|
| 可视化画布 | react-flow(v11+,轻量、高性能) |
| 节点自定义 | React 组件 + useNodeId Hook |
| 状态管理 | React Flow 内置 useReactFlow |
| 持久化 | JSON 序列化(后续可对接 IndexedDB) |
npm install reactflow
⚠️ 注意:
react-flow已重命名为reactflow(v11+)
🔧 动手实践:构建可视化工作流编辑器
步骤 1:创建项目并安装依赖
npx create-react-app day12-workflow-editor
cd day12-workflow-editor
npm install reactflow
步骤 2:创建自定义节点类型
// src/components/NodeTypes/InputNode.jsx
import { Handle, Position } from 'reactflow';
export default function InputNode({ data }) {
return (
<div style={{
background: '#e6f7ff',
border: '2px solid #1890ff',
borderRadius: '8px',
padding: '12px 16px',
minWidth: '160px',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
}}>
<div style={{ fontWeight: '600', color: '#1890ff', marginBottom: '4px' }}>
📥 输入
</div>
<div style={{ fontSize: '12px', color: '#666' }}>
{data.label || '用户输入'}
</div>
<Handle type="source" position={Position.Right} />
</div>
);
}
// src/components/NodeTypes/AINode.jsx
import { Handle, Position } from 'reactflow';
export default function AINode({ data }) {
return (
<div style={{
background: '#f6ffed',
border: '2px solid #52c41a',
borderRadius: '8px',
padding: '12px 16px',
minWidth: '160px',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
}}>
<div style={{ fontWeight: '600', color: '#52c41a', marginBottom: '4px' }}>
🤖 AI 模型
</div>
<div style={{ fontSize: '12px', color: '#666', wordBreak: 'break-word' }}>
{data.label || 'LLM 分析'}
</div>
<Handle type="target" position={Position.Left} />
<Handle type="source" position={Position.Right} />
</div>
);
}
// src/components/NodeTypes/OutputNode.jsx
import { Handle, Position } from 'reactflow';
export default function OutputNode({ data }) {
return (
<div style={{
background: '#fff2e8',
border: '2px solid #fa8c16',
borderRadius: '8px',
padding: '12px 16px',
minWidth: '160px',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)'
}}>
<div style={{ fontWeight: '600', color: '#fa8c16', marginBottom: '4px' }}>
📤 输出
</div>
<div style={{ fontSize: '12px', color: '#666' }}>
{data.label || '最终结果'}
</div>
<Handle type="target" position={Position.Left} />
</div>
);
}
步骤 3:创建工作流画布
// src/components/WorkflowCanvas.jsx
import React, { useState, useCallback } from 'react';
import ReactFlow, {
Controls,
Background,
useNodesState,
useEdgesState,
addEdge,
MiniMap,
} from 'reactflow';
import 'reactflow/dist/style.css';
import InputNode from './NodeTypes/InputNode';
import AINode from './NodeTypes/AINode';
import OutputNode from './NodeTypes/OutputNode';
const nodeTypes = {
input: InputNode,
ai: AINode,
output: OutputNode,
};
const initialNodes = [
{ id: '1', type: 'input', position: { x: 50, y: 150 }, data: { label: '用户问题' } },
{ id: '2', type: 'ai', position: { x: 300, y: 150 }, data: { label: 'AI 回答生成' } },
{ id: '3', type: 'output', position: { x: 550, y: 150 }, data: { label: '聊天界面' } },
];
const initialEdges = [
{ id: 'e1-2', source: '1', target: '2', animated: true },
{ id: 'e2-3', source: '2', target: '3', animated: true },
];
export default function WorkflowCanvas({ onNodesChange, onEdgesChange }) {
const [nodes, setNodes, onNodesChangeHandler] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChangeHandler] = useEdgesState(initialEdges);
// 同步外部状态(用于保存)
React.useEffect(() => {
onNodesChange?.(nodes);
onEdgesChange?.(edges);
}, [nodes, edges, onNodesChange, onEdgesChange]);
const onConnect = useCallback(
(params) => setEdges((eds) => addEdge(params, eds)),
[setEdges]
);
return (
<div style={{ width: '100%', height: '100%' }}>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChangeHandler}
onEdgesChange={onEdgesChangeHandler}
onConnect={onConnect}
nodeTypes={nodeTypes}
fitView
attributionPosition="top-right"
>
<Controls />
<Background color="#aaa" gap={16} />
<MiniMap
nodeColor={(n) => {
if (n.type === 'input') return '#1890ff';
if (n.type === 'ai') return '#52c41a';
if (n.type === 'output') return '#fa8c16';
return '#666';
}}
/>
</ReactFlow>
</div>
);
}
步骤 4:创建控制面板(节点库)
// src/components/ControlsPanel.jsx
import { useReactFlow } from 'reactflow';
import { useCallback } from 'react';
export default function ControlsPanel() {
const { addNodes } = useReactFlow();
const onAddNode = useCallback((type, label) => {
const newNode = {
id: `${type}-${Date.now()}`,
type,
position: { x: 200, y: 200 }, // 后续可改进为鼠标位置
data: { label },
};
addNodes([newNode]);
}, [addNodes]);
return (
<div style={{
padding: '16px',
borderRight: '1px solid #e8e8e8',
backgroundColor: '#fafafa',
width: '200px',
display: 'flex',
flexDirection: 'column',
gap: '12px'
}}>
<h3 style={{ margin: 0, fontSize: '16px', fontWeight: '600' }}>🧩 节点库</h3>
<button
onClick={() => onAddNode('input', '新输入')}
style={{
padding: '8px',
backgroundColor: '#e6f7ff',
border: '1px solid #1890ff',
borderRadius: '4px',
cursor: 'pointer',
textAlign: 'left',
fontSize: '14px',
}}
>
📥 输入节点
</button>
<button
onClick={() => onAddNode('ai', 'AI 分析')}
style={{
padding: '8px',
backgroundColor: '#f6ffed',
border: '1px solid #52c41a',
borderRadius: '4px',
cursor: 'pointer',
textAlign: 'left',
fontSize: '14px',
}}
>
🤖 AI 节点
</button>
<button
onClick={() => onAddNode('output', '结果输出')}
style={{
padding: '8px',
backgroundColor: '#fff2e8',
border: '1px solid #fa8c16',
borderRadius: '4px',
cursor: 'pointer',
textAlign: 'left',
fontSize: '14px',
}}
>
📤 输出节点
</button>
<div style={{ marginTop: '20px' }}>
<h4 style={{ margin: '12px 0 8px 0', fontSize: '14px' }}>🛠️ 操作</h4>
<button
onClick={() => {
const workflow = {
nodes: window.__rf?.getNodes?.() || [],
edges: window.__rf?.getEdges?.() || [],
};
localStorage.setItem('workflow', JSON.stringify(workflow));
alert('✅ 工作流已保存到本地!');
}}
style={{
padding: '8px',
backgroundColor: '#52c41a',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
width: '100%',
fontSize: '14px',
}}
>
💾 保存工作流
</button>
<button
onClick={() => {
const saved = localStorage.getItem('workflow');
if (saved) {
const { nodes, edges } = JSON.parse(saved);
window.__rf?.setNodes?.(nodes);
window.__rf?.setEdges?.(edges);
alert('✅ 工作流已加载!');
} else {
alert('⚠️ 无已保存的工作流');
}
}}
style={{
padding: '8px',
backgroundColor: '#1890ff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
width: '100%',
fontSize: '14px',
marginTop: '8px',
}}
>
📂 加载工作流
</button>
</div>
</div>
);
}
💡 临时全局访问:在
WorkflowCanvas.jsx中添加:// 用于 ControlsPanel 临时访问(生产环境应使用 Context) useEffect(() => { window.__rf = { getNodes: () => nodes, getEdges: () => edges, setNodes, setEdges }; return () => { delete window.__rf; }; }, [nodes, edges, setNodes, setEdges]);
步骤 5:在 App.jsx 中集成
// src/App.jsx
import React from 'react';
import WorkflowCanvas from './components/WorkflowCanvas';
import ControlsPanel from './components/ControlsPanel';
function App() {
return (
<div style={{
fontFamily: 'Inter, -apple-system, sans-serif',
width: '100vw',
height: '100vh',
display: 'flex'
}}>
<ControlsPanel />
<WorkflowCanvas />
</div>
);
}
export default App;
✅ 效果验证
- ✅ 画布显示默认工作流(输入 → AI → 输出)
- ✅ 从左侧“节点库”拖拽新节点到画布
- ✅ 拖拽连线(从输出句柄到输入句柄)
- ✅ 点击“保存工作流” → 存入 localStorage
- ✅ 刷新页面 → 点击“加载工作流” → 恢复状态
- ✅ 支持缩放、平移、小地图(MiniMap)
🤔 思考与延伸
-
节点配置:如何为 AI 节点添加模型选择/提示词配置?
→ 点击节点弹出配置面板(使用useReactFlow的setNodes更新) -
执行引擎:如何运行工作流?
→ 遍历 DAG,按拓扑排序执行节点(Day 13 实现) -
模板市场:如何分享工作流?
→ 将 JSON 转为短链接(如workflow.to/abc123)
💡 为 Day 13 做准备:今日的
nodes/edges结构可直接用于工作流执行
📅 明日预告
Day 13:工作流执行监控
- 实现工作流执行引擎(DAG 遍历)
- 实时显示节点状态(运行中/成功/失败)
- 日志面板 + 进度条
✍️ 小结
今天,我们迈出了构建 AI 自动化工作流 的第一步!通过可视化编排,用户可像搭积木一样组合 AI 能力,无需写代码。低代码 + AI,是普惠智能的关键路径。
💬 实践提示:React Flow 支持自定义边、背景、快捷键等,可进一步优化体验。欢迎分享你的工作流设计!

浙公网安备 33010602011771号