Appearance
Feature: 图片节点
一句话目标
用户在图片节点中上传参考图或从零开始,通过 AI 生成图片,并从多变体结果中选择。
行为约束
约束 1:图片上传
前置条件: 图片节点已创建,无图片(空状态,显示居中占位图标) 行为: 用户点击上传区域或拖拽图片文件到节点 后置条件: 图片通过验证后(JPG/PNG/WebP,≤ 30MB)显示预览,旧生成结果被清除
约束 2:上传验证
前置条件: 用户选择了文件 行为: 系统校验文件类型和大小 后置条件: 非法文件显示 toast 错误提示,不修改节点状态
约束 2a:下游节点禁止上传
前置条件: 图片节点有 incoming edge(作为其他节点的下游) 行为: 上传区域和工具栏上传按钮不渲染 后置条件: 用户无法通过任何 UI 入口上传图片,只能通过 AI 生成获得内容。删除上游连线后恢复上传能力
约束 3:AI 图片生成(无参考图)
前置条件: 节点无图片,用户已输入 prompt 行为: 点击生成,调用 generateImage API(不携带 images 参数) 后置条件: 生成结果显示为图片预览,多变体结果显示为网格
约束 4:AI 图片生成(有参考图)
前置条件: 节点已有图片(上传或上次生成),用户已输入 prompt 行为: 点击生成,调用 generateImage API(携带当前图片作为 images 参数) 后置条件: 同约束 3
约束 5:多变体结果选择
前置条件: 生成返回多张图片 行为: 用户点击结果网格中的某张图片 后置条件: 该图片成为节点主预览图
状态机
节点生成状态(NodeStatus):
| 状态 | 上传区 | 预览区 | 生成按钮 | Prompt |
|---|---|---|---|---|
| idle(empty) | 居中占位图标 | 隐藏 | 可用 | 可编辑 |
| idle(uploaded) | 隐藏 | 显示上传图片 | 可用 | 可编辑 |
| generating | 隐藏 | 显示 loading | 禁用 | 只读 |
| done | 隐藏 | 显示结果 + 变体网格 | 可用 | 可编辑 |
| error | 保持之前状态 | 保持之前内容 | 可用 | 保持原输入 |
Acceptance Criteria
- [x] AC-01:空状态显示居中占位图标(flex-1 居中,简化自原有虚线上传区域)
- [x] AC-02:点击和拖拽两种方式均可上传图片
- [x] AC-03:非法文件(类型/大小)显示错误 toast
- [~] AC-03a:下游节点(有 incoming edge)不渲染上传区域和工具栏上传按钮
- [~] AC-03b:删除上游连线后上传功能恢复
- [x] AC-04:无参考图时生成纯文生图
- [x] AC-05:有参考图时,图片作为参数随请求发送
- [x] AC-06:多变体结果显示为网格,点击可选择主图
- [x] AC-07:生成失败不丢失已上传的图片和 prompt
- [x] AC-08:组件卸载时释放 Object URL 和 abort 请求
- [~] AC-09:有图片时工具栏显示下载按钮,点击在新标签页打开图片(跨域限制,待后端代理/签名 URL 后改为直接下载)
- [~] AC-10:宽高比/图片尺寸选项根据选中模型的 abilities 动态渲染,无 abilities 的模型不显示参数行
- [~] AC-11:切换模型时自动修正参数到新模型支持的合法值
- [~] AC-12:生成时校验参考图片数量不超过模型的 reference_image 限制,超限时 toast 提示并阻止生成
BDD Scenarios
gherkin
Feature: 图片节点
Scenario: 拖拽上传图片
Given 一个空图片节点
When 用户拖拽一张 JPG 图片到节点
Then 图片预览显示在节点中
And 上传区域消失
Scenario: 拒绝超大文件
Given 一个空图片节点
When 用户上传一张 35MB 的 PNG 图片
Then 显示文件大小超限的错误提示
And 节点保持空状态
Scenario: 下游节点禁止上传
Given 文本节点 A 连线到图片节点 B
Then B 的上传区域不显示
And B 的工具栏中没有上传按钮
Scenario: 删除上游连线后恢复上传
Given 文本节点 A 连线到图片节点 B
When 用户删除 A → B 连线
Then B 的上传区域重新显示
And B 的工具栏中上传按钮恢复
Scenario: 带参考图生成
Given 图片节点已有一张上传的图片
And 用户输入 prompt "添加蓝色背景"
When 用户点击生成按钮
Then 生成请求携带当前图片作为参考
When 生成成功返回 4 张变体
Then 主预览区显示第一张
And 下方显示 4 张缩略图网格
Scenario: 从多变体中选择
Given 图片节点已生成 4 张变体结果
When 用户点击第 3 张缩略图
Then 主预览区切换为第 3 张图片
Scenario: 无参考图纯文生图
Given 一个空图片节点
And 用户输入 prompt "赛博朋克城市"
When 用户点击生成按钮
Then 生成请求不携带 images 参数
When 生成成功返回
Then 图片预览显示在节点中
Scenario: 生成失败保持已上传图片和 prompt
Given 图片节点已有一张上传的图片
And 用户输入 prompt "添加光效"
When 用户点击生成按钮
And API 请求失败
Then 节点状态变为 error
And 上传的图片仍然显示
And prompt 保持 "添加光效"
Scenario: 组件卸载时释放资源
Given 图片节点处于 generating 状态
When 用户导航离开画布
Then 进行中的请求被 abort
And Object URL 被释放TDD 单元测试要点
针对文件验证逻辑:
- [x] JPG/PNG/WebP 通过验证
- [x] 非法类型(如 GIF)返回错误信息
- [x] 超过 30MB 返回错误信息
Out of Scope
- 图片裁剪/旋转
- 图片工具条(抠图/放大/扩展)— 未规划
- 真正的文件下载(需后端代理或 COS 签名 URL,当前为新标签页打开)
宽高比/图片尺寸设置— 已通过 abilities 动态能力系统实现- 批量上传