From 1d07cdc907793db13d1ed5dc64f40df0f3b32915 Mon Sep 17 00:00:00 2001
From: WangLeo <690854599@qq.com>
Date: Wed, 17 Jun 2026 18:22:30 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E8=BE=93=E5=85=A5=E6=A1=86=E5=AE=BD?=
=?UTF-8?q?=E5=BA=A662%=E3=80=81=E5=8F=91=E9=80=81=E6=8C=89=E9=92=AE?=
=?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=9C=86=E5=BD=A2=E7=81=B0=E5=BA=A6=E5=88=87?=
=?UTF-8?q?=E6=8D=A2=E3=80=81=E7=BB=98=E7=94=BB=E5=B9=B3=E5=8F=B0=E9=BB=98?=
=?UTF-8?q?=E8=AE=A4=E9=80=89=E6=96=87=E7=94=9F=E5=9B=BE=E9=A6=96=E4=B8=AA?=
=?UTF-8?q?=E6=A8=A1=E5=9E=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 输入框从75%缩至62%
- 发送按钮去掉文字改为44px正圆形,无提示词时浅灰底+深色箭头,有提示词时稍深灰底+白色箭头
- 绘画平台 getDefaultModel() 返回空字符串,modelSelector 加载后优先选 text tag 模型
- CLAUDE.md 新增 Display Store/Canvas/视图层架构章节,移除已删除的 model-configs 目录,修正环境变量表
---
CLAUDE.md | 62 +++++++++++++++++++++---
src/components/dialogBox/index.vue | 28 ++++-------
src/platforms/painting/index.js | 2 +-
src/platforms/painting/modelSelector.vue | 11 +++--
4 files changed, 73 insertions(+), 30 deletions(-)
diff --git a/CLAUDE.md b/CLAUDE.md
index 9471e5d..c63fb11 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -34,7 +34,6 @@ AI 绘画/视频/音乐生成前端操作平台,通过 HTTP 接口对接算力
### 关键目录
```
-├── model-configs/ # 运维参考:模型参数配置 JSON 文件(hailuo, ltx, vidu 等,位于项目根目录)
├── config/
│ └── plugins.js # Vite 插件配置(unplugin-auto-import + unplugin-vue-components resolver)
├── vite.config.js # 构建配置:alias(@→src, ~→根目录)、envPrefix: ['VITE','FILE']、optimizeDeps
@@ -74,7 +73,7 @@ src/
│ └── timeControl.vue # 时长滑块(常用模式)
├── stores/ # Pinia 状态管理
│ ├── user.js # 用户认证、信息(含 sessionId),pinia persist 持久化 token
-│ ├── display.js # 生成历史列表、UI 状态(滚动、画布等)
+│ ├── display.js # 中央调度器:历史列表、画布状态、重新编辑/再次生成、输入框收缩
│ └── param.js # 参数 store(当前为空)
├── apis/ # HTTP API 层:纯请求封装,不含业务逻辑
│ ├── auth/ # 认证相关(登录、token 校验、用户信息、验证码)
@@ -171,6 +170,39 @@ props: (config) => ({
4. `taskPolling.js` 直接读取 `data.body` → `getModelId(type, modelName)` 查找 UUID → POST `/suanli/v1/tasks`(请求体含 `sessionId`)
5. 20s 间隔轮询直至完成/失败
+### Display Store — 中央调度器
+
+`src/stores/display.js`(`useDisplayStore`)被 6 个文件引用,是展示层跨组件通信的中央枢纽:
+
+- **历史列表生命周期**:`initHistoryList`(首次加载)→ `appendHistoryList`(滚动加载更多)→ `deleteHistoryItem`
+- **生成状态追踪**:`addGeneratingItem`(生成中占位)→ `updateItemToSuccess`(完成时替换为结果 URL),`isSubGerenate` 控制发送按钮 loading 态
+- **重新编辑/再次生成**:`setResultData()` 存储当前操作的历史数据 → `fillParamsForEdit()` 仅回填参数到 dialogBox → `triggerGenerateWithResult()` 回填后立即发起生成。二者通过 `dialogBoxRef` 跨组件调用 `dialogBox` 的 `fillParamsFromResult()` + `handleStart()`
+- **Canvas 状态**:`openCanvas(data)` 统一入口,接收来自 Set 卡片或 ImageUploader 的数据,设置 `canvasVisible/canvasImage/canvasReferenceImages/canvasSource` 四个响应式状态
+- **滚动 → 输入框收缩**:`scrollToBottom()` 调用虚拟滚动 API;`Sender_variant` ref 在 `display/index.vue` 的 `handleScroll` 中被修改,在 `dialogBox` 的 `autoSizeConfig` 中被消费
+
+### Canvas 画布编辑架构
+
+`src/components/canvas/index.vue` 是一个完整的图片编辑器(~600 行),用于局部重绘场景:
+
+- **选区绘制**:圆形/矩形选区,5 色(红/橙/绿/蓝/紫)自动轮换,按住拖拽绘制到 canvas 上
+- **undo/redo**:`history` 数组 + `historyIndex` 指针,每次操作(添加选区/删除/修改描述)保存快照并推进指针
+- **参考图选择**:从 props 的 `referenceImages` 中多选参考图,选区描述自动拼接为「将图1{颜色}{框/圈}内的【XXX】替换为【图{X}中的{描述}】」
+- **提示词组合**:选区描述 + 笔刷 textarea 内容组合为完整 prompt,通过 `generate()` 提交任务(`modelType: 'edit'`)
+- **编辑模式限制**:画笔生成的任务标记 `modelType === 'edit'`,在 Set 卡片中禁止"重新编辑"和"再次生成"
+- **触发入口**:Set 卡片的画笔按钮、ImageUploader 的已上传图片点击
+
+### 视图层
+
+`src/views/home/index.vue` 是 thin shell,同时挂载 `dialogBox`(输入编排)和 `display`(结果展示),通过 `useDisplay.setDialogBoxRef()` 建立两者之间的通信桥梁。
+
+`src/views/home/display/index.vue` 负责结果展示区:
+
+- **首次加载**:`onMounted` → `fetchHistory()` 拉取第 1 页 → 转换后 `initHistoryList` → 多次重试 `scrollToBottom`
+- **无限滚动**:`handleScroll` 监听 `isAtPageTop` → `fetchHistory(true)`(加载更早的历史),3 秒防抖锁 `isLoadingMoreLocked` 防重复请求
+- **数据转换**:`conversion()` 将 API 响应适配为 UI 格式 — status 映射(`queued/processing`→`generate`,`failed/cancelled`→`error`)、`outputs` 扁平化为 `files` URL 数组
+- **筛选控件**:时间段选择(全部/一周/一月/三月)+ 收藏筛选,通过 `requestTaskHistory` 的 `user_id`/`platform_code`/`status` 参数过滤
+- **退出按钮**:如果在 iframe 内通过 `postMessage` 通知父页面导航,否则 `router.go(-1)`
+
### 模型标识与查找
API 返回的模型对象包含三个标识字段:
@@ -181,6 +213,14 @@ API 返回的模型对象包含三个标识字段:
| `name` | `vidu-text-to-video-q3-turbo` | 内部标识名,通常也唯一 |
| `display_name` | `Vidu q3-turbo` | 用户可见的显示名,**可能重复**(不同 pattern 下的同名模型) |
+各平台 `model.value` 使用的标识类型不同:
+
+| 平台 | `model.value` 类型 | 原因 |
+|------|-------------------|------|
+| Painting | `display_name` | 历史兼容,`getDefaultModel()` 返回 `''` 后由 modelSelector watcher 自动选第一个 text tag 模型 |
+| Video | `id`(UUID) | 避免 `display_name` 在不同 pattern 下重复导致查找歧义 |
+| Music | `id`(UUID) | 与 Video 一致,避免冲突 |
+
**Video 平台使用 `id`(UUID)作为 `model.value`**,避免 `display_name` 冲突导致的模型查找错误。`modelSelector.vue` 中 `modelGroups` 的 `value` 设为 `m.id`,`label` 仍用 `display_name` 显示。
`getModelId(type, modelName)` 查找优先级:`m.id === modelName` → `m.name === modelName` → `m.display_name === modelName`,向下兼容旧的 name/display_name 调用。
@@ -384,20 +424,30 @@ Music 平台与 Painting/Video 的关键差异:
### 环境变量速查
+`.env.development`(测试环境)和 `.env.production`(生产环境)中实际配置的变量:
+
```bash
-# .env.development
+# 地址前缀
VITE_BASE = '/' # 应用基础路径
+
+# 主服务
VITE_API_PREFIX = '/api' # 主服务前缀
VITE_API_BASE_URL = 'http://...' # 主服务(默认目标)
-VITE_API_PAY_PREFIX = '/pay' # 支付服务前缀
-VITE_API_PAY_TARGET = 'http://...' # 支付服务目标
+
+# 任务服务
VITE_API_TASK_PREFIX = '/suanli' # 任务服务前缀
VITE_API_TASK_TARGET = 'http://...' # 任务服务目标
+
+# 图片上传
VITE_API_WORKFLOW_UPLOAD = 'http://...' # 图片上传地址(imageUploader 组件 action)
-VITE_OPEN_DEVTOOLS = false # 是否开启开发者工具
+
+# 其他
+VITE_OPEN_DEVTOOLS = false # 是否开启开发者工具(仅 .env.development)
FILE_OPEN_PREVIEW = true # 是否开启 KKFileView 预览
```
+`request.js` 还引用了 `VITE_API_PAY_PREFIX`/`VITE_API_PAY_TARGET` 和 `VITE_API_AIGC_PREFIX`/`VITE_API_AIGC_TARGET`,作为**可选**前缀路由扩展点——未配置时走默认 target,当前两个 .env 文件中均未设置。
+
`vite.config.js` 中 `envPrefix: ['VITE', 'FILE']`,因此只有以 `VITE_` 和 `FILE_` 开头的变量会被暴露给客户端代码。
### 平台编码映射
diff --git a/src/components/dialogBox/index.vue b/src/components/dialogBox/index.vue
index 29f1fa8..14f12c2 100644
--- a/src/components/dialogBox/index.vue
+++ b/src/components/dialogBox/index.vue
@@ -60,10 +60,9 @@