docs: 更新 CLAUDE.md 反映后端化改造

- 删除 models/、createTask.js、modelConfig.js 引用
- 新增 modelConfigHelper.js 共享工具说明
- 更新数据流描述为 API 驱动
- 新增 number ui 类型和 showWhen 机制
- 新增模型配置缓存(60s TTL)
- 删除过时的 displayNameMap 节
- 接口速查新增 config 相关 API
This commit is contained in:
王佑琳 2026-06-09 18:16:35 +08:00
parent 18e7dbc6ed
commit b964c826ce

View File

@ -33,8 +33,6 @@ src/
│ │ ├── index.js # definePaintingPlatform()controls、state、loadConfig、buildTaskBody 等
│ │ ├── modelSelector.vue # 模型选择器(按 API tags 分组)
│ │ ├── imageUploader.vue # 图片上传组件
│ │ ├── models/ # 模型参数 schema本地 JS待后端化
│ │ │ └── index.js # getModelConfig(modelName) → 查找 config
│ │ └── controls/ # 平台专用控件
│ │ ├── proportion.vue
│ │ ├── dimension.vue
@ -67,9 +65,8 @@ src/
└── utils/
├── request.js # Axios 实例 + 拦截器:统一 Auth不带 Bearer+ 按前缀路由 baseURL
├── taskPolling.js # 任务生成入口:组装参数 → POST 创建任务 → 20s HTTP 轮询直至完成/失败
├── modelApi.js # 模型业务层localStorage 30s 缓存 + pendingRequests 并发去重 + 平台编码映射
├── createTask.js # 透传层return data.body各平台 buildTaskBody() 已返回扁平 modelParams
├── modelConfig.js # Video 专用:从远程 JSON 加载 workflow 配置(含 localStorage 每日缓存)
├── modelApi.js # 模型业务层localStorage 缓存 + 并发去重。平台模型列表(30s TTL) + 模型参数配置(60s TTL)
├── modelConfigHelper.js # 模型配置共享工具syncDefaults / syncParamValues / getDimConfig / checkShowWhen
├── downloadImage.js # 图片/视频下载fetch → Blob → 自动文件名下载
├── uploadImage.js # 图片上传工具
├── tokenError.js # 认证失败处理:提示后 5 秒刷新页面
@ -128,47 +125,54 @@ props: (config) => ({
- **平台切换**`const platform = computed(() => createPlatform(props.type))`,切换时重置默认模型并加载模型列表
- **控件渲染**`visibleControls = platform.controls.filter(c => c.show(getCurrentConfig()))`,用 `<component :is>` + `v-bind="ctrl.props(...)"` 渲染
- **配置获取**`getCurrentConfig()` 返回 `platform.modelConfig?.value ?? platform.modelDisplayConfig?.value`,兼容两种配置来源
- **配置获取**`getCurrentConfig()` 返回 `platform.modelConfig?.value`
- **模型切换**`watch([model, modelType])` → `platform.loadConfig()``syncDefaults()` 将 schema 写入响应式 state → controls 的 `show()`/`props()` 读取 state → `visibleControls` 自动更新 → UI 重渲染
- **任务发起**`handleStart()` 调用 `platform.validateBeforeSubmit()``platform.buildTaskBody()``generate()`
- **参数回填**`fillParamsFromResult()` 委托给 `platform.fillFromResult()`
### 统一数据流Painting + Video
两个平台现已统一,`createTask.js` 是纯透传
两个平台现已统一,通过后端 API 获取模型参数配置
1. 用户选择模型 → `platform.loadConfig(modelName, modelType)` 加载参数 schema
1. 用户选择模型 → `platform.loadConfig(modelName, modelType)` → 调用 `GET /suanli/v1/models/:id/config`(优先 60s 缓存)加载参数 schema
2. 参数 schema 驱动 `controls` 渲染 UI用户填写参数
3. 用户点击发送 → `handleStart()``platform.buildTaskBody({ prompt, referenceImages })` 返回扁平 `modelParams`
4. `createTask(data)` 透传 `data.body`(不再做任何转换)
5. `getModelId(type, modelName)` 查找 UUID → POST `/suanli/v1/tasks``X-Session-Id` header
6. 20s 间隔轮询直至完成/失败
4. `taskPolling.js` 直接读取 `data.body``getModelId(type, modelName)` 查找 UUID → POST `/suanli/v1/tasks``X-Session-Id` header
5. 20s 间隔轮询直至完成/失败
### 模型参数配置
Painting 模型参数 schema 在 `src/platforms/painting/models/*.js` 中,参数通过 `ui` 字段映射到 UI 控件:
模型参数配置通过后端 API `GET /suanli/v1/models/:id/config` 获取60s localStorage 缓存),替代了旧的本地硬编码。参数通过 `ui` 字段映射到前端控件:
| `ui` 值 | 控件 | 说明 |
|---------|------|------|
| `textarea` | Sender 内置 textarea | prompt 输入框 |
| `proportion` | `PaintingProportion` / `VideoProportion` | 比例选择 Popover`options` 含 `custom` 时可自定义宽高) |
| `resolution` | proportion 控件内部 | 分辨率子选项,与 proportion 共用 Popover |
| `dimension` | `DimensionInput` | **组合模式**:单字段 `"W*H"` 格式,通过 `dimension.parse/format` 序列化 |
| `dimensionWidth` + `dimensionHeight` | `DimensionInput` | **拆分模式**:两个独立字段,共享同一 Popover 和比例锁 |
| `dimension` | `DimensionInput` | **组合模式**:单字段 `"W*H"` 格式,后端传 `dimension.separator`,前端生成 parse/format |
| `dimensionWidth` + `dimensionHeight` | `DimensionInput` | **拆分模式**:两个独立字段(含 `min`/`max`),共享比例锁 |
| `number` | proportion 控件内部 | 自定义宽高(如 Flux 的 customWidth/customHight配合 `showWhen` 条件显示 |
| `select` | `Select` | 通用下拉(如 quality |
| `quantity` | `Quantity` | 生成数量,上限由 `options` 最大值派生 |
| `quantity` | `Quantity` | 生成数量,`options` 必须为数字数组,上限由 `Math.max()` 派生 |
| `imageUpload` | `ImageUploader` | 参考图上传,`maxCount` 控制上限 |
| `hidden` | 无 | 静默写入默认值 |
**dimension 模式区分**通过 `getDimConfig()` 自动检测 `ui: 'dimension'`(组合)或 `ui: 'dimensionWidth'`(拆分),两种模式共用 `DimensionInput` 组件。
**dimension 模式区分**`getDimConfig()`(来自 `modelConfigHelper.js`自动检测 `ui: 'dimension'`(组合)或 `ui: 'dimensionWidth'`(拆分),两种模式共用 `DimensionInput` 组件。
**条件显示**`showWhen: { aspectRatio: 'custom' }` 使参数仅在 proportion 选 `custom` 时显示。
**条件显示**`showWhen: { aspectRatio: 'custom' }` 使参数仅在 proportion 选 `custom` 时显示。`checkShowWhen()` 在 controls 的 `show()` 回调中调用,因直接读取 reactive 的 `paramValues[key]`computed 自动追踪依赖。
### `displayNameMap` 机制
### modelConfigHelper 共享工具
`src/platforms/painting/models/index.js` 中 `displayNameMap` 负责将 API 返回的 `display_name` 映射到 config key。同一模型在不同 tag 下可能共用一个 `display_name`(如 `GPT-Image-2``GPT-image-2`config key 采用内部中文名区分。
`src/utils/modelConfigHelper.js` 提供 Painting/Video 双平台共用的 4 个纯函数:
**已知 bug**`displayNameMap` 存在重复 key `'GPT-Image-2'`,第二条会覆盖第一条,导致文字生图版 GPT-Image-2 查找走 `displayNameMap` 时映射到 I2I 版。当前因 `model.value` 已是中文 config key 直达 `configs[]`,暂不触发。若后续改为按 `display_name` 查找,需修复此重复 key。
| 函数 | 说明 |
|------|------|
| `syncDefaults(config, state)` | 将 API 返回的 config 同步到响应式 state。增强项`dimension.separator` → parse/format 生成、`promptPlaceholder` 同步 |
| `syncParamValues(config, state)` | 在 `buildTaskBody` 前将专用 ref 回写到 `paramValues` |
| `getDimConfig(config)` | 检测 combined/split 模式 |
| `checkShowWhen(param, paramValues)` | 检查 `showWhen` 条件 |
`state` 参数对象需包含 `modelConfig, paramValues, proportion, resolution, quantity, quality, customWidth, customHight, dimWidth, dimHeight, promptPlaceholder`。各平台通过包装函数(如 `syncDefaults(config) { _syncDefaults(config, paintingState) }`)适配。
### `$attrs` 穿透注意
@ -184,6 +188,7 @@ Painting 模型参数 schema 在 `src/platforms/painting/models/*.js` 中,参
- **`sessionId`** 来自登录接口返回的 `userInfo.sessionId`,存储在 `useUserStore().userInfo` 中。`taskPolling.js` 必须使用该值,禁止随机生成。
- **`X-Session-Id`** 自定义 header 需要 nginx 在 `/suanli/` location 的 `Access-Control-Allow-Headers` 中加入,否则 POST 请求会触发 CORS 预检失败。
- **模型列表缓存**`modelApi.js` 中 `fetchPlatformModels` 使用 localStorage 30 秒 TTL + `pendingRequests` Map 并发去重。
- **模型配置缓存**`modelApi.js` 中 `getModelConfig` 使用 localStorage 60 秒 TTL + `pendingConfigRequests` Map 并发去重。`loadModels()` 会在获取模型列表后调用 `preloadModelConfigs` 批量预加载。
- **平台包预加载**dialogBox 顶层 `import` Painting 和 Video 平台包,触发自注册,确保首次使用时 registry 已就绪。
- **VirtualScroller 反旋转**:组件用外层 `transform: rotate(180deg)` 实现 reverse 底部锚定。所有作为 slot 插入的内容必须在根元素加 `transform: rotate(180deg)` 反旋转,否则文字/图片会颠倒显示。参考 `src/views/home/display/components/set.vue:2`
- **VirtualScroller 存在独立测试页**`src/components/virtual-scroller/test.html` + `test-data.js`,可用于验证虚拟滚动行为。
@ -225,6 +230,8 @@ Painting 模型参数 schema 在 `src/platforms/painting/models/*.js` 中,参
| `requestTaskStatus` | GET `/suanli/v1/tasks/:id` | 查询单个任务状态 |
| `requestTaskHistory` | GET `/suanli/v1/tasks/history` | 历史任务列表(支持 `user_id`/`platform_code`/`page`/`pageSize` |
| `fetchPlatformModels` | GET `/suanli/v1/platforms/:code/models` | 获取平台模型列表(返回 `{id, display_name, tags, disabled?}` |
| `requestModelConfigsBatch` | POST `/suanli/v1/models/configs` | 批量获取模型配置body: `{ modelIds: [...] }` |
| `requestModelConfig` | GET `/suanli/v1/models/:id/config` | 单条模型配置60s 缓存优先) |
| `cancelOrCollect` | POST `/collect/toggle` | 收藏/取消收藏 |
| `deleteGenerateHistory` | DELETE `/taskRecordHistory/delete` | 删除历史记录 |