Appearance
Feature: 节点多选批量连线
Goal
用户多选节点后,选区框出现 group handle,拖拽可一次性将所有选中节点批量连接到目标节点(或从外部节点批量连接到所有选中节点),避免逐条手动拖线。
Behavior Constraints
约束 1:选区 Group Handle 显示
Pre: 画布中有 2+ 个节点被选中 Behavior: 选区框左侧出现 group target handle,右侧出现 group source handle Post: Group handle 仅在多选状态下可见,取消选择后消失
约束 2:批量连出(多→一)
Pre: 多个节点被选中,选区框显示 group source handle Behavior: 用户从 group source handle 拖拽到目标节点的 target handle(或节点体),系统为每个选中节点逐一创建到目标节点的连线 Post: 通过验证的连线全部创建,未通过的跳过
约束 3:批量连入(一→多)
Pre: 多个节点被选中,选区框显示 group target handle Behavior: 用户从外部节点的 source handle 拖拽到 group target handle,系统为每个选中节点逐一创建从源节点到该选中节点的连线 Post: 通过验证的连线全部创建,未通过的跳过
约束 4:逐条验证,部分成功
Pre: 批量连线触发(约束 2 或 3) Behavior: 对每条待创建的连线独立执行现有验证规则(自连接、循环、重复、handle 方向、uploaded target 限制)。验证通过的创建,不通过的静默跳过。 Post: 仅创建合法连线,无失败反馈
约束 5:拖拽到空白区域
Pre: 用户从 group source handle 拖拽到画布空白区域 Behavior: 弹出浮动菜单,用户选择类型后创建新节点,并为每个选中节点创建到新节点的连线(逐条验证) Post: 新节点创建,通过验证的连线全部建立
约束 6:选中节点包含目标节点
Pre: 批量连线的目标节点本身也在选中集合中 Behavior: 不做特殊处理,该边由现有自连接校验自然拦截 Post: 无自连接边产生,无额外提示
Acceptance Criteria
显示
- [x] AC-01:选中 2+ 个节点时,选区框右侧出现 group source handle,左侧出现 group target handle
- [x] AC-02:取消多选后(点击空白区域 / 只剩 1 个选中),group handle 消失
批量连出(多→一)
- [x] AC-03:从 group source handle 拖拽到目标节点 target handle,为每个选中节点创建到目标节点的连线
- [x] AC-04:从 group source handle 拖拽到目标节点体(非 handle),同样批量创建连线
- [x] AC-05:从 group source handle 拖拽到空白区域,弹出浮动菜单,选择类型后创建新节点并批量连线
批量连入(一→多)
- [x] AC-06:从外部节点 source handle 拖拽到 group target handle,为每个选中节点创建从源节点到该选中节点的连线
验证
- [x] AC-07:批量创建时,不通过验证的连线(自连接、循环、重复、handle 方向、uploaded target)被静默跳过,通过的正常创建
- [x] AC-08:目标节点在选中集合中时,自连接边被现有规则拦截,其余连线正常创建
BDD Scenarios
gherkin
Feature: 节点多选批量连线
# AC-01, AC-02
Scenario: 多选时显示 group handle
Given 画布中有节点 A、B、C
When 用户框选 A 和 B
Then 选区框右侧出现 group source handle
And 选区框左侧出现 group target handle
When 用户点击画布空白区域取消选择
Then group handle 消失
# AC-03
Scenario: 批量连出到目标节点 handle
Given 画布中有节点 A、B、C
And 用户已选中 A 和 B
When 用户从 group source handle 拖拽到 C 的 target handle
Then 创建 A → C 连线
And 创建 B → C 连线
# AC-04
Scenario: 批量连出到目标节点体
Given 画布中有节点 A、B、C
And 用户已选中 A 和 B
When 用户从 group source handle 拖拽到 C 的节点体
Then 创建 A → C 连线
And 创建 B → C 连线
# AC-05
Scenario: 批量连出到空白区域创建新节点
Given 画布中有节点 A 和 B
And 用户已选中 A 和 B
When 用户从 group source handle 拖拽到画布空白区域
Then 弹出浮动菜单
When 选择 "图片" 节点类型
Then 创建图片节点 C
And 创建 A → C 连线
And 创建 B → C 连线
# AC-06
Scenario: 批量连入从外部节点
Given 画布中有节点 A、B、C
And 用户已选中 B 和 C
When 用户从 A 的 source handle 拖拽到 group target handle
Then 创建 A → B 连线
And 创建 A → C 连线
# AC-07
Scenario: 验证失败的连线被静默跳过
Given 画布中有节点 A、B、C
And 已存在 A → C 连线
And 用户已选中 A 和 B
When 用户从 group source handle 拖拽到 C 的 target handle
Then A → C 重复边被跳过
And 仅创建 B → C 连线
# AC-07 uploaded 限制
Scenario: uploaded 节点作为 target 被跳过
Given 画布中有文本节点 A 和图片节点 B(origin 为 uploaded)和图片节点 C(origin 为 empty)
And 用户已选中 B 和 C
And 外部有文本节点 D
When 用户从 D 的 source handle 拖拽到 group target handle
Then D → B 被跳过(uploaded 不可作 target)
And 仅创建 D → C 连线
# AC-08
Scenario: 目标节点在选中集合中
Given 画布中有节点 A、B、C
And 用户已选中 A、B、C
When 用户从 group source handle 拖拽到 C 的 target handle
Then A → C 连线创建成功
And B → C 连线创建成功
And C → C 自连接被跳过TDD Pointers
批量连线创建逻辑(flowStore.addBatchEdges):
- [x] Test: 传入 N 个 source 节点 + 1 个 target 节点,返回 N 条边(AC-03) →
flowStore.test.ts - [x] Test: 传入 1 个 source 节点 + N 个 target 节点,返回 N 条边(AC-06) →
flowStore.test.ts - [x] Test: 其中一条边已存在(重复),结果中排除该边(AC-07) →
flowStore.test.ts - [x] Test: 其中一个 target 为 uploaded 图片节点,结果中排除该边(AC-07) →
flowStore.test.ts - [x] Test: target 节点在 source 集合中,自连接边被排除(AC-08) →
flowStore.test.ts - [x] Test: 所有边都不通过验证时,返回空数组(AC-07 边界) →
flowStore.test.ts - [x] Test: 传入空选中集合,返回空数组(边界) →
flowStore.test.ts
flowValidation 扩展:
未新增 validateBatchEdges 函数 — addBatchEdges 直接在循环中逐条调用 validateEdge,无需独立批量验证函数。
Out of Scope
- Group handle 的视觉样式(颜色、大小、动画)— 属于 design-system 职责
- 多选框选的交互本身(框选、Shift+点击)— Vue Flow 内置能力,不需要自定义
- 批量删除、批量移动等其他多选操作 — 不在本功能范围
- 连线兼容性警告态(edge-system AC-11/12)— 依赖 model-capabilities
- 批量连线的撤销/重做 — 属于 canvas-system 撤销重做功能
连线动画或拖拽过程中的视觉预览(如同时显示多条虚线)— ✅ 已实现(connection-lineslot 多线预览)