Appearance
Feature: 连线系统
Goal
用户通过连线构建节点间的数据流向,系统提供方向约束、角色校验、拓扑验证和兼容性即时反馈,确保工作流拓扑合理且可执行。
前置条件
ImageNodeData / VideoNodeData 已包含✅ 已实现origin: ContentOrigin字段('empty' | 'uploaded' | 'generated')
Behavior Constraints
约束 1:Handle 方向规则
Pre: 用户拖拽创建连线 Behavior: 连线只能从 source handle 连到 target handle;同类型 handle 之间不可相连 Post: 非法方向的连线不会被创建
约束 2:连线创建 — 拖拽到 Handle
Pre: 画布中有两个以上节点 Behavior: 用户从节点 A 的 source handle 拖拽到节点 B 的 target handle,创建 A → B 连线 Post: 连线通过验证后创建并持久化
约束 3:连线创建 — 拖拽到节点体
Pre: 用户从节点 A 的 source handle 拖拽连线到节点 B 的节点体(非 handle 区域) Behavior: 系统自动建立 A(source) → B(target) 的连线,不弹出节点创建菜单 Post: 连线通过验证后创建并持久化
约束 4:连线创建 — 拖拽到空白区域
Pre: 用户从节点 A 的 source handle 拖拽连线到画布空白区域 Behavior: 在释放位置弹出浮动菜单,用户选择类型后创建新节点并自动建立连线 Post: 新节点创建,A → 新节点的连线创建并持久化
约束 5:拓扑验证
Pre: 用户尝试创建连线 Behavior: 系统验证三种非法拓扑:自连接(source === target)、循环(会形成有向环)、重复边(相同 source/target/handles) Post: 非法连线不被创建
约束 6:节点连接角色规则
Pre: 用户尝试创建连线,目标节点为 Image/Video 类型 Behavior: origin 为 uploaded 的 Image/Video 节点不可作为 target;empty 和 generated 可作为 target;文本节点不受 origin 限制 Post: 违反角色规则的连线不被创建
角色矩阵:
| 节点类型 | origin | 可作为 source | 可作为 target |
|---|---|---|---|
| 文本 | 任意 | ✓ | ✓ |
| 图片 | empty | ✓ | ✓ |
| 图片 | uploaded | ✓ | ✗ |
| 图片 | generated | ✓ | ✓ |
| 视频 | empty | ✓ | ✓ |
| 视频 | uploaded | ✓ | ✗ |
| 视频 | generated | ✓ | ✓ |
约束 7:连线兼容性软提示
Pre: 连线已创建 Behavior: 系统从 AI Service 层读取下游节点当前模型的输入兼容性。若上游输出类型与下游模型不兼容,连线渲染为警告态。用户切换模型后重新评估。 Post: 不兼容连线有视觉提示但不被删除
详见 ADR-008。兼容性规则由 AI Service 层提供,画布只负责渲染提示。
约束 8:连线随节点删除
Pre: 画布中有节点及其关联连线 Behavior: 用户删除节点时,所有关联连线同时被移除 Post: 节点和关联连线均被删除并持久化
Acceptance Criteria
已完成
- [x] AC-01:自连接(source === target)被阻止
- [x] AC-02:循环连线被阻止
- [x] AC-03:重复边被阻止
- [x] AC-04:删除节点同时移除关联连线
- [x] AC-05:连线拖到空白区域弹出浮动菜单创建节点
本次实现
- [x] AC-06:连线只能从 source handle 连到 target handle
- [x] AC-07:同类型 handle(source→source 或 target→target)不可相连
- [x] AC-08:从 source handle 拖拽到目标节点 handle 可创建连线
- [x] AC-09:从 source handle 拖拽到目标节点体(非 handle)自动建立 source→target 连线,不弹出创建菜单
- [x] AC-10:origin 为
uploaded的 Image/Video 节点不可作为 target
待实现(依赖后端 API)
- [ ] AC-11:不兼容的连线渲染为警告态,不阻止创建
- [ ] AC-12:切换下游节点模型后,连线兼容性状态重新评估
BDD Scenarios
gherkin
Feature: 连线系统
# AC-01
Scenario: 阻止自连接
Given 画布中有节点 A
When 用户从 A 的 source handle 拖拽到 A 的 target handle
Then 连线不被创建
# AC-02
Scenario: 阻止循环连线
Given 画布中有 A → B 的连线
When 用户尝试从 B 连到 A
Then 连线不被创建
# AC-05
Scenario: 拖拽到空白区域创建节点和连线
Given 画布中有节点 A
When 用户从 A 的 source handle 拖拽到画布空白区域
Then 在释放位置弹出浮动菜单
When 选择 "图片" 节点类型
Then 创建图片节点并自动建立 A → 新节点连线
# AC-06, AC-07
Scenario: Handle 方向规则校验
Given 画布中有节点 A 和节点 B
When 用户从 A 的 source handle 拖拽到 B 的 target handle
Then 连线创建成功
When 用户从 A 的 source handle 拖拽到 B 的 source handle
Then 连线不被创建
# AC-08
Scenario: 拖拽到目标节点 handle 创建连线
Given 画布中有节点 A 和节点 B
When 用户从 A 的 source handle 拖拽到 B 的 target handle
Then A → B 连线创建成功并持久化
# AC-09
Scenario: 拖拽到目标节点体创建连线
Given 画布中有节点 A 和节点 B
When 用户从 A 的 source handle 拖拽到 B 的节点体
Then 自动建立 A(source) → B(target) 连线
And 不弹出节点创建菜单
# AC-10
Scenario: Uploaded 节点不可作为 target
Given 画布中有文本节点 A 和图片节点 B
And B 的 origin 为 "uploaded"
When 用户从 A 连线到 B
Then 连线不被创建
Scenario: Empty 节点可作为 target
Given 画布中有文本节点 A 和图片节点 B
And B 的 origin 为 "empty"
When 用户从 A 连线到 B
Then 连线创建成功
# AC-11
Scenario: 不兼容连线显示警告态
Given 画布中有文本节点 A 和视频节点 B
And B 当前模型不支持文本输入
When 用户从 A 连线到 B
Then 连线创建成功
And 连线渲染为警告态
# AC-12
Scenario: 切换模型后兼容性重新评估
Given 画布中有 A → B 的警告态连线
When 用户将 B 的模型切换为支持文本输入的模型
Then 连线恢复为正常态TDD Pointers
flowValidation(拓扑验证 + 角色校验):
- [x] Test: 自连接返回
{ valid: false, reason: 'self-connection' }(AC-01) - [x] Test: 存在 A→B 边时,B→A 检测为 cycle(AC-02)
- [x] Test: 完全相同的 source/target/handles 检测为 duplicate(AC-03)
- [x] Test: 合法边返回
{ valid: true } - [x] Test: 同类型 handle 相连返回非法(AC-07)
- [x] Test: uploaded 图片节点作为 target 返回非法(AC-10)
- [x] Test: uploaded 视频节点作为 target 返回非法(AC-10)
- [x] Test: empty / generated 节点作为 target 返回合法(AC-10)
- [x] Test: 文本节点无论 origin 均可作为 target(AC-10)
- [x] Test: 旧数据(无 origin 字段)图片节点可作为 target — 向后兼容(AC-10)
边兼容性评估逻辑:
- [ ] Test: 上游类型与下游模型不兼容时返回 warning 状态(AC-11)
- [ ] Test: 上游类型与下游模型兼容时返回 normal 状态(AC-11)
- [ ] Test: 下游模型切换后重新评估返回正确状态(AC-12)
Out of Scope
- ContentOrigin 字段的实现细节(何时设为 uploaded/generated 等)— 属于节点数据模型职责
- 连线的视觉样式定义(颜色、虚线参数)— 见 design-system
- 自定义边组件的具体实现方案 — 属于 feature-dev 阶段
- 生成时如何处理不兼容上游输入 — 见 data-flow
- 撤销/重做对连线的影响 — 见 canvas-system AC-06