# 工作流画布交互设计调研报告 > **版本:V2.0 | 最后更新:2026-08-17** > **目标产品:eai_agentplatform-app · 数字员工平台 · 工坊(Studio)** --- ## 目录 1. [调研范围与背景](#1-调研范围与背景) 2. [行业产品全景对比](#2-行业产品全景对比) 3. [节点体系设计](#3-节点体系设计) - 3.1 三节点 vs 五节点体系 - 3.2 子类型(SubType)架构 - 3.3 连接器作为被引用资源 4. [画布交互模型](#4-画布交互模型) - 4.1 拖入创建(Drag & Drop) - 4.2 右键菜单体系 - 4.3 键盘快捷键体系 - 4.4 选中与视觉反馈 - 4.5 Edge 交互(连线) 5. [布局与导航](#5-布局与导航) 6. [技术实现(VueFlow)](#6-技术实现vueflow) - 6.1 核心事件 - 6.2 自定义节点 - 6.3 自定义边 - 6.4 CSS 主题与样式 7. [当前实现状态](#7-当前实现状态) 8. [待完成项](#8-待完成项) 9. [参考资料](#9-参考资料) --- ## 1. 调研范围与背景 ### 1.1 调研目标 为数字员工平台的 **工坊(Studio)** 模块设计一套符合行业标准、贴近业务用户心智的工作流画布交互模型。核心需求: - 业务用户能通过 **拖拽 + 配置** 的方式定义数字员工的工作流程 - 画布交互对标 Dify / n8n / Make / Zapier / Coze 等主流产品 - 节点体系从 SY18(信源/动作/结果/权限)简化为 3 节点体系(开始/动作/结束) ### 1.2 调研的产品 | 产品 | 定位 | 节点体系 | 画布引擎 | 参考版本 | |------|------|----------|----------|----------| | **Dify** | AI 工作流编排 | 开始/LLM/工具/结束等 | React Flow | v1.14.0 | | **n8n** | 自动化工作流 | 触发器/动作 | 自研 | latest | | **Make** | 可视化自动化 | 触发器/动作/模块 | 自研 | latest | | **Zapier** | 轻量自动化 | Trigger/Action/Search | 自研 | latest | | **Coze** | AI Bot 构建 | 开始/LLM/插件/知识库/结束 | 自研 | latest | | **Langflow** | LLM 流程编排 | Input/LLM/Output | React Flow | latest | | **VueFlow** | 画布引擎库 | N/A | Vue Flow | v1.44+ | --- ## 2. 行业产品全景对比 ### 2.1 产品定位对比 | 维度 | Dify | n8n | Make | Zapier | Coze | 本产品 | |------|------|-----|------|--------|------|--------| | 目标用户 | 开发者/AI 工程师 | 技术运营 | 业务用户 | 业务用户 | 业务用户+开发者 | HR/销售/业务用户 | | 复杂度 | 中高 | 高 | 中 | 低 | 中 | 中 | | 拖入创建 | ✅ | ✅ | ✅ | ❌(点击添加) | ✅ | ✅ | | 右侧检查器 | ✅ | ✅ | ✅ | ✅(弹窗) | ✅ | ✅ | | 节点右键菜单 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | | Edge 右键菜单 | ✅(PR#33391) | ✅ | ✅ | ❌ | ❌ | ✅ | | Delete 键删除 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | | Ctrl+D 复制 | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | | Ctrl+Z 撤销 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | | 连线 "+" 按钮 | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ### 2.2 画布布局对比 | 产品 | 左侧面板 | 右侧面板 | 工具栏 | 布局风格 | |------|----------|----------|--------|----------| | Dify | 节点选择(可折叠) | 检查器(选中后出现) | 顶部薄栏 | 左-中-右 | | n8n | 节点库 | 编辑面板 | 顶部 | 左-中-右 | | Make | 模块库(浮层) | 配置面板 | 顶部 | 中-右(浮层) | | Zapier | 无(步骤式) | 弹窗配置 | 顶部 | 步骤向导 | | Coze | 节点/插件/知识库 | 配置区(底部弹出) | 顶部 | 左-中-右 | | **本产品** | **节点库+工具区** | **检查器面板** | **顶部 48px** | **左-中-右** | --- ## 3. 节点体系设计 ### 3.1 三节点 vs 五节点体系 **行业共识:主流产品均采用 3~4 种核心节点类型。** Dify: Start → LLM/Tool → End n8n: Trigger → Action → No explicit end Make: Trigger → Module → No explicit end Zapier: Trigger → Action/Search → No explicit end Coze: Start → LLM/Plugin/Knowledge → End **本产品的演进:** - **旧(SY18 模型)**:5 种节点(input / connector / action / result / permission) - **新(Zapier/Dify 对齐)**:3 种节点(start / action / end) - start(开始节点):取代旧的 input + connector - action(动作节点):保留旧的 action - end(结束节点):取代旧的 result + permission ### 3.2 子类型(SubType)架构 三节点通过 **子类型(SubType)** 实现具体的行为分化,避免了节点类型爆炸: ``` start (开始节点) ├── schedule (⏰ 定时触发) ├── file (📎 文件触发) ├── connector (🔌 连接器触发) └── manual (✍️ 手动触发) action (动作节点) ├── ai (🤖 AI 处理) ├── code (💻 代码处理) ├── condition (🔀 条件分支) └── connector (🔌 连接器操作) end (结束节点) ├── data (📊 返回数据) ├── file (📁 文件输出) └── connector (🔌 连接器输出) ``` **核心设计原则:** - 每种节点只有一个 **子类型下拉选择**,用户在检查器中切换 - subType 改变时自动清除不兼容的配置(如从 `connector` 切到 `ai` 时清除 `connectorKey`) - 子类型的标签包含 emoji 前缀,便于视觉识别(参考 Dify 的节点 icon + label) ### 3.3 连接器作为被引用资源 **关键架构决策:连接器不是画布上的独立节点类型。** 在旧的 SY18 模型中,"信源"被理解为连接器。经过对 Zapier/Make.com/Coze/Dify 的调研发现: | 产品 | 连接器(Connector)的角色 | |------|------------------------| | Zapier | Trigger 和 Action 通过下拉选择 APP + 事件/操作,APP 就是连接器 | | Make | Module 可以选择不同的 Service,Service 就是连接器 | | Dify | 工具(Tools)是独立节点,但连接器/数据源是 LLM 或知识库的属性 | | Coze | 插件(Plugin)是独立节点,连接器是 Bot 的配置属性 | **本产品的方案:** - 连接器不是画布节点,而是 **start/action/end 节点通过 subType='connector' 引用的资源** - 连接器列表在 **工具区** 中管理,由工具栏 `☑ 🔌 连接器` 按钮控制显示/隐藏 - 用户可以从工具区 **点击添加** 一个 start 节点并自动绑定到选中的连接器 - 在检查器中,当 subType='connector' 时,显示连接器绑定下拉 --- ## 4. 画布交互模型 ### 4.1 拖入创建(Drag & Drop) **Dify 标准流程:** 1. 从左侧节点列表拖出一个节点类型 2. 拖到画布上释放 3. 节点出现在释放位置,自动选中并打开右侧配置面板 **本产品实现:** ```vue
...
...
``` **拖放数据流:** ```javascript dragstart → setData('application/dw-node-kind', kind) dragover → 显示 drop 提示(drag-over class) drop → screenToFlowCoordinate → createCanvasNode dragend → 清理状态 ``` ### 4.2 右键菜单体系 **Dify 标准(PR #34138 + PR #33391):** - **节点右键菜单**:编辑节点 / 复制节点 / 删除节点 / 断开所有连线 - 新版本还支持多选节点时的对齐操作 - **Edge 右键菜单**:删除连线(PR #33391, 2026-03 合并) - 右键点击连线弹出删除选项 - 菜单互斥:同一时间只有一个菜单可见 - **画布空白右键菜单**:粘贴 / 适配视图 / 重置 **本产品实现:** **节点右键菜单:** ```vue
✏️ 编辑节点
📋 复制节点
🗑️ 删除节点
🔗 断开所有连线
🗑️ 删除连线
``` **菜单互斥逻辑:** ```javascript function handleEdgeContextMenu({ edge, event }) { event.preventDefault() closeNodeContextMenu() // 关闭节点菜单 closeEdgeContextMenu() // 关闭已有边菜单 edgeContextMenu.edgeId = edge.id edgeContextMenu.x = event.clientX edgeContextMenu.y = event.clientY edgeContextMenu.visible = true } function handlePaneClick() { selectedNodeId.value = '' closeNodeContextMenu() closeEdgeContextMenu() } ``` ### 4.3 键盘快捷键体系 **Dify 快捷键标准:** | 快捷键 | 功能 | |--------|------| | Delete | 删除选中的节点或边 | | Backspace | 删除选中节点或边(有争议,用户易误触) | | Ctrl+D | 复制选中节点 | | Ctrl+Z | 撤销 | | Ctrl+Shift+Z / Ctrl+Y | 重做 | | Shift + 点击 | 多选节点 | | Arrow keys | 移动选中节点 | | Ctrl+A | 全选 | **本产品实现:** ```javascript function handleKeyDown(event) { const tag = event.target.tagName // 输入框中不触发 if (tag === 'INPUT' || tag === 'TEXTAREA' || event.target.isContentEditable) return if (event.key === 'Delete' || event.key === 'Backspace') { // 1. 先关菜单(如果有) if (contextMenu.visible || edgeContextMenu.visible) { closeNodeContextMenu() closeEdgeContextMenu() event.preventDefault() return } // 2. 删选中的边 const selectedEdges = edges.value.filter(e => e.selected) if (selectedEdges.length > 0) { edges.value = edges.value.filter(e => !e.selected) event.preventDefault() return } // 3. 删选中的节点 const selectedNodes = nodes.value.filter(n => n.selected) if (selectedNodes.length > 0) { const selectedIds = new Set(selectedNodes.map(n => n.id)) nodes.value = nodes.value.filter(n => !selectedIds.has(n.id)) edges.value = edges.value.filter(e => !selectedIds.has(e.source) && !selectedIds.has(e.target)) event.preventDefault() } } } ``` ### 4.4 选中与视觉反馈 **节点选中状态:** - VueFlow 原生支持 `node.selected` 属性 - 点击节点 → 节点获得 `.selected` class → 边框变色 + 阴影增强 - 点击画布空白 → 取消全部选中 **本产品的颜色体系:** | 节点类型 | 边框色 | 选中色 | |----------|--------|--------| | start | `#409eff` (蓝) | 实线蓝色 + 蓝光阴影 | | action | `#e6a23c` (橙) | 实线橙色 + 橙光阴影 | | end | `#67c23a` (绿) | 实线绿色 + 绿光阴影 | ### 4.5 Edge 交互(连线) **Dify 标准:** 1. **连接操作**:从一个节点的右侧 handle 拖到另一个节点的左侧 handle 2. **选中**:点击连线 → 连线高亮(变蓝变粗) 3. **右键菜单**:右键点击连线 → 弹出删除选项 4. **Delete 键删除**:选中连线后按 Delete 键 5. **Hover "+" 按钮**:鼠标悬停在连线上 → 中点出现 "+" 按钮 → 点击后插入一个新节点(串行) 6. **断开连接**:从 handle 拖出新连线覆盖已有连线,自动替换 **本产品实现:** **Edge 视觉反馈(CSS):** ```css /* 点击区域加宽 */ :deep(.vue-flow__edge-path) { stroke-linecap: round; transition: stroke 0.15s, stroke-width 0.15s; } /* hover 高亮 */ :deep(.vue-flow__edge:hover .vue-flow__edge-path) { stroke: #409eff; stroke-width: 2.5; } /* 选中高亮 */ :deep(.vue-flow__edge.selected .vue-flow__edge-path) { stroke: #409eff; stroke-width: 3; } ``` **Handle hover:** ```css :deep(.vue-flow__handle) { transition: transform 0.12s, background 0.12s; } :deep(.vue-flow__handle:hover) { transform: scale(1.3); background: #409eff; } ``` --- ## 5. 布局与导航 ### 5.1 整体布局结构 ``` ┌─────────────────────────────────────────────────────────────┐ │ [头部 Header · 48px] │ ├────────┬────────────────────────────────────┬───────────────┤ │ 左侧 │ 画布区域 │ 右侧检查器 │ │ 节点库 │ Canvas (VueFlow) │ Inspector │ │ +工具区 │ │ (选中后出现) │ │ │ ┌────┐ ┌────┐ ┌────┐ │ │ │ │ │ S │──→│ A │──→│ E │ │ │ │ │ └────┘ └────┘ └────┘ │ │ │ │ │ │ ├────────┴────────────────────────────────────┴───────────────┤ │ [工具栏] ← ☑ 🔌 连接器 | ⚙ 设置 | [保存] │ └─────────────────────────────────────────────────────────────┘ ``` ### 5.2 左侧节点库(Toolbox) | 区域 | 内容 | 可折叠 | |------|------|--------| | 头部 | "节点库" + ◀ 折叠按钮 | ✅ | | 节点列表 | 开始节点/动作节点/结束节点(可拖拽) | 跟随折叠 | | 分隔线 | - | - | | 工具区标题 | "工具区" | - | | 连接器工具 | 连接器列表(由工具栏按钮控制可见性) | ✅(点击文字折叠) | **展开状态宽度:200px** **折叠状态宽度:52px(只显示图标)** ### 5.3 右侧检查器(Inspector) | 区域 | 内容 | |------|------| | 头部 | "节点检查器" | | 当前节点 | 显示节点标题(只读) | | 节点类型 | 显示类型标签(只读) | | 子类型选择 | el-select 下拉(start: 定时/文件/连接器/手动; action: AI/代码/条件/连接器; end: 数据/文件/连接器) | | 连接器绑定 | 仅 subType='connector' 时显示,el-select 选择连接器 | | 节点标题 | el-input 可编辑 | | 节点说明 | el-input textarea 可编辑 | | 节点位置 | X/Y 坐标(只读) | | 上下游 | 上游节点 / 下游节点(只读) | --- ## 6. 技术实现(VueFlow) ### 6.1 核心事件 | VueFlow 事件 | 用途 | 当前状态 | |-------------|------|----------| | `@node-click` | 点击节点 → 选中 + 显示检查器 | ✅ | | `@node-context-menu` | 右键节点 → 弹出菜单 | ✅ | | `@edge-click` | 点击连线 → 选中高亮 | ✅ | | `@edge-context-menu` | 右键连线 → 删除菜单 | ✅ | | `@connect` | 建立连线 | ✅ | | `@pane-click` | 点击画布空白 → 取消选中 + 关菜单 | ✅ | | `@pane-ready` | 画布初始化 → 绑定键盘事件 | ✅ | | `@nodes-change` | 节点变化 | ❌(未用) | | `@edges-change` | 边变化 | ❌(未用) | | `@node-drag-stop` | 拖拽停止 | ❌(未用) | ### 6.2 自定义节点 ```javascript // 节点定义 const newNode = { id: `${kind}-${nodeCounter}`, type: 'dw', // 自定义节点类型,对应