- 删除 src/platforms/painting/models/(9 个硬编码 JS) - 删除 src/utils/modelConfig.js(Video 旧远程 JSON 加载) 配置已全部迁移至后端 API。
736 lines
20 KiB
Markdown
736 lines
20 KiB
Markdown
# 模型参数后端化 — 前端适配实现计划
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
||
**Goal:** 将 Painting/Video 平台的模型参数配置从硬编码迁移至后端 API 获取
|
||
|
||
**Architecture:** 新建 modelConfigHelper.js 共享工具函数,在 modelApi.js 加缓存层,Painting/Video 双平台统一走 API + params 驱动。方案 A 最小改动。
|
||
|
||
**Tech Stack:** Vue 3 Composition API + Vite 7 + Pinia + Axios
|
||
|
||
---
|
||
|
||
### Task 1: 新建 `src/utils/modelConfigHelper.js`
|
||
|
||
**Files:**
|
||
- Create: `src/utils/modelConfigHelper.js`
|
||
|
||
- [ ] **Step 1: 写入完整文件**
|
||
|
||
```js
|
||
// 模型配置共享工具函数
|
||
// 供 Painting / Video descriptor 使用
|
||
|
||
/**
|
||
* 检测 dimension 配置模式
|
||
* @param {Object|null} config - 模型配置对象
|
||
* @returns {Object|null}
|
||
* - combined: { type: 'combined', config: dimension子对象, paramName: string }
|
||
* - split: { type: 'split', wParam: 宽度参数, hParam: 高度参数 }
|
||
* - null: 无 dimension 参数
|
||
*/
|
||
export function getDimConfig(config) {
|
||
if (!config) return null
|
||
const dimParam = config.params.find(p => p.ui === 'dimension')
|
||
if (dimParam) return { type: 'combined', config: dimParam.dimension, paramName: dimParam.name }
|
||
const wParam = config.params.find(p => p.ui === 'dimensionWidth')
|
||
const hParam = config.params.find(p => p.ui === 'dimensionHeight')
|
||
if (wParam && hParam) return { type: 'split', wParam, hParam }
|
||
return null
|
||
}
|
||
|
||
/**
|
||
* 检查 showWhen 条件是否满足
|
||
* @param {Object} param - 参数定义(可能含 showWhen)
|
||
* @param {Object} paramValues - 当前所有参数值
|
||
* @returns {boolean}
|
||
*/
|
||
export function checkShowWhen(param, paramValues) {
|
||
if (!param.showWhen) return true
|
||
return Object.entries(param.showWhen).every(([key, expected]) => {
|
||
return paramValues[key] === expected
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 将 API 返回的 config 同步到响应式 state
|
||
*
|
||
* state 对象需包含以下属性(均为 ref 或 reactive):
|
||
* modelConfig, paramValues, proportion, resolution, quantity, quality,
|
||
* customWidth, customHight, dimWidth, dimHeight, promptPlaceholder
|
||
*/
|
||
export function syncDefaults(config, state) {
|
||
const {
|
||
modelConfig, paramValues, proportion, resolution, quantity, quality,
|
||
customWidth, customHight, dimWidth, dimHeight, promptPlaceholder,
|
||
} = state
|
||
|
||
modelConfig.value = config
|
||
if (!config) return
|
||
|
||
// 1. dimension.separator → 生成 parse/format(在遍历 params 之前完成)
|
||
config.params.forEach(p => {
|
||
if (p.ui === 'dimension' && p.dimension?.separator && !p.dimension.parse) {
|
||
const sep = p.dimension.separator
|
||
p.dimension.parse = (val) => {
|
||
const parts = (val || '').split(sep)
|
||
return { width: parseInt(parts[0]) || 0, height: parseInt(parts[1]) || 0 }
|
||
}
|
||
p.dimension.format = (w, h) => `${w}${sep}${h}`
|
||
}
|
||
})
|
||
|
||
// 2. 初始化 paramValues(已存在的 key 保留,避免切换模型时丢失值)
|
||
config.params.forEach(p => {
|
||
if (!(p.name in paramValues)) {
|
||
paramValues[p.name] = p.default ?? (p.name === 'outputFormat' ? 'png' : '')
|
||
}
|
||
})
|
||
|
||
// 3. 同步专用 ref
|
||
const ratioParam = config.params.find(p => p.ui === 'proportion')
|
||
if (ratioParam) proportion.value = ratioParam.default || '1:1'
|
||
|
||
const resParam = config.params.find(p => p.ui === 'resolution')
|
||
if (resParam) resolution.value = resParam.default || '2k'
|
||
|
||
const qtyParam = config.params.find(p => p.ui === 'quantity')
|
||
if (qtyParam) quantity.value = qtyParam.default || 1
|
||
|
||
const cwParam = config.params.find(p => p.name === 'customWidth')
|
||
if (cwParam) customWidth.value = cwParam.default || 1024
|
||
|
||
const chParam = config.params.find(p => p.name === 'customHight')
|
||
if (chParam) customHight.value = chParam.default || 1024
|
||
|
||
const qualityParam = config.params.find(p => p.name === 'quality')
|
||
if (qualityParam) quality.value = qualityParam.default || 'medium'
|
||
|
||
// 4. dimension 初始化
|
||
const dc = getDimConfig(config)
|
||
if (dc?.type === 'split') {
|
||
dimWidth.value = dc.wParam.default || 1024
|
||
dimHeight.value = dc.hParam.default || 1024
|
||
} else if (dc?.type === 'combined') {
|
||
const dimParam = config.params.find(p => p.name === dc.paramName)
|
||
const raw = dimParam?.default || ''
|
||
const parsed = dc.config.parse(raw)
|
||
dimWidth.value = parsed.width
|
||
dimHeight.value = parsed.height
|
||
}
|
||
|
||
// 5. promptPlaceholder 同步
|
||
if (config.promptPlaceholder) {
|
||
promptPlaceholder.value = config.promptPlaceholder
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 将专用 ref 的当前值回写到 paramValues
|
||
* (在 buildTaskBody 之前调用)
|
||
*/
|
||
export function syncParamValues(config, state) {
|
||
const {
|
||
paramValues, proportion, resolution, quantity,
|
||
customWidth, customHight, dimWidth, dimHeight, quality,
|
||
} = state
|
||
|
||
const ratioParam = config?.params?.find(p => p.ui === 'proportion')
|
||
if (ratioParam) paramValues[ratioParam.name] = proportion.value
|
||
|
||
const resParam = config?.params?.find(p => p.ui === 'resolution')
|
||
if (resParam) paramValues[resParam.name] = resolution.value
|
||
|
||
const qtyParam = config?.params?.find(p => p.ui === 'quantity')
|
||
if (qtyParam) paramValues[qtyParam.name] = quantity.value
|
||
|
||
if (config?.params?.find(p => p.name === 'customWidth')) {
|
||
paramValues.customWidth = customWidth.value
|
||
}
|
||
if (config?.params?.find(p => p.name === 'customHight')) {
|
||
paramValues.customHight = customHight.value
|
||
}
|
||
if (config?.params?.find(p => p.name === 'quality')) {
|
||
paramValues.quality = quality.value
|
||
}
|
||
|
||
const dc = getDimConfig(config)
|
||
if (dc?.type === 'split') {
|
||
paramValues[dc.wParam.name] = dimWidth.value
|
||
paramValues[dc.hParam.name] = dimHeight.value
|
||
} else if (dc?.type === 'combined') {
|
||
paramValues[dc.paramName] = dc.config.format(dimWidth.value, dimHeight.value)
|
||
}
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 验证语法**
|
||
|
||
Run: `npx eslint src/utils/modelConfigHelper.js --fix`
|
||
Expected: 无错误
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add src/utils/modelConfigHelper.js
|
||
git commit -m "feat: 新增 modelConfigHelper 共享工具函数
|
||
|
||
提取 getDimConfig / checkShowWhen / syncDefaults / syncParamValues,
|
||
供 Painting 和 Video 平台共用。syncDefaults 新增 dimension.separator
|
||
解析和 promptPlaceholder 同步能力。"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 2: 新增 API 函数
|
||
|
||
**Files:**
|
||
- Modify: `src/apis/display/index.js`
|
||
|
||
- [ ] **Step 1: 在文件末尾追加两个 API 函数**
|
||
|
||
```js
|
||
// 批量获取模型配置(POST /suanli/v1/models/configs)
|
||
export function requestModelConfigsBatch(modelIds) {
|
||
return service.post('/suanli/v1/models/configs', { modelIds })
|
||
}
|
||
|
||
// 单条查询模型配置(GET /suanli/v1/models/:modelId/config)
|
||
export function requestModelConfig(modelId) {
|
||
return service.get(`/suanli/v1/models/${modelId}/config`)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 验证语法**
|
||
|
||
Run: `npx eslint src/apis/display/index.js --fix`
|
||
Expected: 无错误
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add src/apis/display/index.js
|
||
git commit -m "feat: 新增模型配置 API(批量 + 单条)"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 3: 添加缓存层
|
||
|
||
**Files:**
|
||
- Modify: `src/utils/modelApi.js`
|
||
|
||
- [ ] **Step 1: 在文件末尾追加缓存相关函数**
|
||
|
||
在 `clearPlatformModelCache` 函数之前插入以下代码:
|
||
|
||
```js
|
||
// ==================== 模型配置缓存 ====================
|
||
|
||
const CONFIG_CACHE_PREFIX = 'model_config_'
|
||
const CONFIG_CACHE_TTL = 60 * 1000 // 60 秒
|
||
const pendingConfigRequests = new Map()
|
||
|
||
// 导入 API 函数(在文件顶部添加)
|
||
// import { requestModelConfigsBatch, requestModelConfig } from '@/apis/display/index.js'
|
||
|
||
/**
|
||
* 批量预加载模型配置到缓存
|
||
* @param {string[]} modelIds - 模型 UUID 列表
|
||
*/
|
||
export async function preloadModelConfigs(modelIds) {
|
||
if (!modelIds.length) return
|
||
const result = await requestModelConfigsBatch(modelIds)
|
||
const data = result?.data || {}
|
||
const now = Date.now()
|
||
modelIds.forEach(id => {
|
||
const config = data[id]
|
||
if (config) {
|
||
const cacheEntry = { config, timestamp: now }
|
||
try {
|
||
localStorage.setItem(CONFIG_CACHE_PREFIX + id, JSON.stringify(cacheEntry))
|
||
} catch { /* localStorage 满时静默失败 */ }
|
||
}
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 获取单个模型配置(优先读缓存,未命中调 API)
|
||
* @param {string} modelId - 模型 UUID
|
||
* @returns {Promise<Object|null>} 模型配置对象
|
||
*/
|
||
export async function getModelConfig(modelId) {
|
||
if (!modelId) return null
|
||
|
||
// 1. 读缓存
|
||
try {
|
||
const cached = localStorage.getItem(CONFIG_CACHE_PREFIX + modelId)
|
||
if (cached) {
|
||
const { config, timestamp } = JSON.parse(cached)
|
||
if (Date.now() - timestamp < CONFIG_CACHE_TTL) {
|
||
return config
|
||
}
|
||
}
|
||
} catch { /* 缓存解析失败,走 API */ }
|
||
|
||
// 2. 并发去重
|
||
if (pendingConfigRequests.has(modelId)) {
|
||
return pendingConfigRequests.get(modelId)
|
||
}
|
||
|
||
// 3. 调单条 API
|
||
const promise = (async () => {
|
||
try {
|
||
const result = await requestModelConfig(modelId)
|
||
const config = result?.data
|
||
if (config) {
|
||
const cacheEntry = { config, timestamp: Date.now() }
|
||
try {
|
||
localStorage.setItem(CONFIG_CACHE_PREFIX + modelId, JSON.stringify(cacheEntry))
|
||
} catch { /* 静默 */ }
|
||
}
|
||
return config || null
|
||
} catch {
|
||
return null
|
||
} finally {
|
||
pendingConfigRequests.delete(modelId)
|
||
}
|
||
})()
|
||
|
||
pendingConfigRequests.set(modelId, promise)
|
||
return promise
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: 在文件顶部追加 import**
|
||
|
||
在 `import { fetchPlatformModels as _fetchPlatformModels } from '@/apis/display/index.js'` 所在行(或其附近),改为同时导入新 API 函数。如果是按需导入,在已有 import 语句中加入 `requestModelConfigsBatch, requestModelConfig`:
|
||
|
||
```js
|
||
import { fetchPlatformModels as _fetchPlatformModels, requestModelConfigsBatch, requestModelConfig } from '@/apis/display/index.js'
|
||
```
|
||
|
||
- [ ] **Step 3: 验证语法**
|
||
|
||
Run: `npx eslint src/utils/modelApi.js --fix`
|
||
Expected: 无错误
|
||
|
||
- [ ] **Step 4: Commit**
|
||
|
||
```bash
|
||
git add src/utils/modelApi.js
|
||
git commit -m "feat: 新增模型配置缓存层(60s TTL + 并发去重)"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 4: Painting 平台接入 API
|
||
|
||
**Files:**
|
||
- Modify: `src/platforms/painting/index.js`
|
||
|
||
- [ ] **Step 1: 替换 import**
|
||
|
||
将:
|
||
```js
|
||
import { fetchPlatformModels, getPlatformCode } from '@/utils/modelApi'
|
||
import { getModelConfig } from './models/index.js'
|
||
```
|
||
|
||
替换为:
|
||
```js
|
||
import { fetchPlatformModels, getPlatformCode, getModelId, getModelConfig, preloadModelConfigs } from '@/utils/modelApi'
|
||
import { getDimConfig, checkShowWhen, syncDefaults as _syncDefaults, syncParamValues as _syncParamValues } from '@/utils/modelConfigHelper.js'
|
||
```
|
||
|
||
- [ ] **Step 2: 新增 paintingState + 删除 getDimConfig**
|
||
|
||
删除 painting/index.js 中第 12-20 行的 `getDimConfig` 函数(已在 helper 中)。
|
||
|
||
- [ ] **Step 3: 替换 `syncDefaults` 函数**
|
||
|
||
将第 46-77 行的 `syncDefaults` 函数替换为对 helper 的调用:
|
||
|
||
```js
|
||
function syncDefaults(config) {
|
||
syncDefaults_internal(config, paintingState)
|
||
}
|
||
```
|
||
|
||
实际上,直接用 helper 版本替换原来的内部函数。由于 helper 的 `syncDefaults` 接受 `(config, state)`,在 descriptor 内部创建一个包装:
|
||
|
||
删除原 `syncDefaults` 函数(第 46-77 行),改为:
|
||
|
||
```js
|
||
// state 对象供 helper 函数使用
|
||
const paintingState = {
|
||
modelConfig, paramValues, proportion, resolution, quantity, quality,
|
||
customWidth, customHight, dimWidth, dimHeight, promptPlaceholder,
|
||
}
|
||
|
||
function syncDefaults(config) {
|
||
_syncDefaults(config, paintingState)
|
||
}
|
||
```
|
||
|
||
同时将 helper 的 `syncDefaults` 以别名导入(避免与本地函数重名):
|
||
|
||
```js
|
||
import { getDimConfig, checkShowWhen, syncDefaults as _syncDefaults, syncParamValues as _syncParamValues } from '@/utils/modelConfigHelper.js'
|
||
```
|
||
|
||
- [ ] **Step 4: 替换 `syncParamValues` 函数**
|
||
|
||
将第 79-102 行的 `syncParamValues` 函数替换为:
|
||
|
||
```js
|
||
function syncParamValues() {
|
||
_syncParamValues(modelConfig.value, paintingState)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 5: 替换 `loadConfig` 函数**
|
||
|
||
将第 194-198 行的:
|
||
```js
|
||
async loadConfig(modelName, _modelType) {
|
||
const config = getModelConfig(modelName)
|
||
syncDefaults(config)
|
||
return config
|
||
},
|
||
```
|
||
|
||
替换为:
|
||
```js
|
||
async loadConfig(modelName, _modelType) {
|
||
const modelId = await getModelId('Painting', modelName)
|
||
if (!modelId) return null
|
||
const config = await getModelConfig(modelId)
|
||
syncDefaults(config)
|
||
return config
|
||
},
|
||
```
|
||
|
||
- [ ] **Step 6: 替换 `loadModels` 函数,加入批量预加载**
|
||
|
||
将第 189-192 行的:
|
||
```js
|
||
async loadModels() {
|
||
const code = getPlatformCode('Painting')
|
||
return fetchPlatformModels(code)
|
||
},
|
||
```
|
||
|
||
替换为:
|
||
```js
|
||
async loadModels() {
|
||
const code = getPlatformCode('Painting')
|
||
const models = await fetchPlatformModels(code)
|
||
if (models?.length) {
|
||
const modelIds = models.map(m => m.id)
|
||
await preloadModelConfigs(modelIds)
|
||
}
|
||
return models
|
||
},
|
||
```
|
||
|
||
- [ ] **Step 7: 在 controls 的 `show()` 中加入 showWhen 判断**
|
||
|
||
dimension control 的 `show`(第 133 行)改为:
|
||
|
||
```js
|
||
show: (config) => {
|
||
const hasDim = config?.params?.find(p =>
|
||
(p.ui === 'dimension' || p.ui === 'dimensionWidth') && checkShowWhen(p, paramValues)
|
||
)
|
||
return !!hasDim
|
||
},
|
||
```
|
||
|
||
- [ ] **Step 8: 验证语法**
|
||
|
||
Run: `npx eslint src/platforms/painting/index.js --fix`
|
||
Expected: 无错误
|
||
|
||
- [ ] **Step 9: Commit**
|
||
|
||
```bash
|
||
git add src/platforms/painting/index.js
|
||
git commit -m "feat: Painting 平台接入模型配置 API
|
||
|
||
- loadModels 增加批量预加载模型配置
|
||
- loadConfig 改为 API 获取(替代硬编码 getModelConfig)
|
||
- syncDefaults/syncParamValues/getDimConfig 迁移至 helper
|
||
- controls show() 加入 showWhen 条件判断"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 5: Video 平台接入 API
|
||
|
||
**Files:**
|
||
- Modify: `src/platforms/video/index.js`
|
||
|
||
- [ ] **Step 1: 替换 import**
|
||
|
||
将:
|
||
```js
|
||
import { fetchModelConfig } from '@/utils/modelConfig'
|
||
import { fetchPlatformModels, getPlatformCode } from '@/utils/modelApi'
|
||
```
|
||
|
||
替换为:
|
||
```js
|
||
import { fetchPlatformModels, getPlatformCode, getModelId, getModelConfig, preloadModelConfigs } from '@/utils/modelApi'
|
||
import { getDimConfig, checkShowWhen, syncDefaults as _syncDefaults, syncParamValues as _syncParamValues } from '@/utils/modelConfigHelper.js'
|
||
```
|
||
|
||
- [ ] **Step 2: 增加 params 驱动的 state**
|
||
|
||
在 `defineVideoPlatform` 函数内部,原有 state ref 定义之后(第 33-35 行之后),追加:
|
||
|
||
```js
|
||
// params 驱动(与 Painting 统一)
|
||
const paramValues = reactive({})
|
||
const modelConfig = ref(null)
|
||
const quality = ref('medium')
|
||
const customWidth = ref(1024)
|
||
const customHight = ref(1024)
|
||
const dimWidth = ref(1024)
|
||
const dimHeight = ref(1024)
|
||
const quantity = ref(1)
|
||
|
||
const paintingCompatState = {
|
||
modelConfig, paramValues, proportion, resolution, quantity, quality,
|
||
customWidth, customHight, dimWidth, dimHeight, promptPlaceholder,
|
||
}
|
||
|
||
function syncDefaults(config) {
|
||
_syncDefaults(config, paintingCompatState)
|
||
}
|
||
|
||
function syncParamValues() {
|
||
_syncParamValues(modelConfig.value, paintingCompatState)
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 3: 替换 `loadInternalConfig` 和 `loadConfig`**
|
||
|
||
删除 `loadInternalConfig` 函数(第 45-67 行)。
|
||
|
||
将 `loadConfig`(第 122-124 行)替换为:
|
||
|
||
```js
|
||
async loadConfig(modelName, modelTypeVal) {
|
||
const modelId = await getModelId('Video', modelName)
|
||
if (!modelId) return null
|
||
const config = await getModelConfig(modelId)
|
||
syncDefaults(config)
|
||
return config
|
||
},
|
||
```
|
||
|
||
- [ ] **Step 4: 替换 `loadModels` 加入批量预加载**
|
||
|
||
将第 117-120 行替换为:
|
||
|
||
```js
|
||
async loadModels() {
|
||
const code = getPlatformCode('Video')
|
||
const models = await fetchPlatformModels(code)
|
||
if (models?.length) {
|
||
const modelIds = models.map(m => m.id)
|
||
await preloadModelConfigs(modelIds)
|
||
}
|
||
return models
|
||
},
|
||
```
|
||
|
||
- [ ] **Step 5: 替换 `showImageUploader` 和 `isImageRequired`**
|
||
|
||
将第 141-143 行的:
|
||
```js
|
||
showImageUploader() {
|
||
return modelType.value !== 'text'
|
||
},
|
||
```
|
||
|
||
替换为:
|
||
```js
|
||
showImageUploader() {
|
||
return modelConfig.value?.inputType === 'image' || modelConfig.value?.inputType === 'both'
|
||
},
|
||
```
|
||
|
||
将第 149-151 行的:
|
||
```js
|
||
isImageRequired() {
|
||
return modelType.value !== 'text'
|
||
},
|
||
```
|
||
|
||
替换为:
|
||
```js
|
||
isImageRequired() {
|
||
return !!(modelConfig.value?.params?.find(p => p.ui === 'imageUpload'))
|
||
},
|
||
```
|
||
|
||
- [ ] **Step 6: 替换 `imageUploadLimit`**
|
||
|
||
将第 145-147 行替换为:
|
||
|
||
```js
|
||
imageUploadLimit() {
|
||
if (!modelConfig.value) return 4
|
||
const imageParam = modelConfig.value.params.find(p => p.ui === 'imageUpload')
|
||
return imageParam?.maxCount || modelConfig.value.maxImages || 4
|
||
},
|
||
```
|
||
|
||
- [ ] **Step 7: 替换 `buildTaskBody`**
|
||
|
||
将第 153-162 行替换为:
|
||
|
||
```js
|
||
buildTaskBody(shared) {
|
||
syncParamValues()
|
||
const modelParams = { ...paramValues }
|
||
if (shared.prompt.value) modelParams.prompt = shared.prompt.value
|
||
return modelParams
|
||
},
|
||
```
|
||
|
||
- [ ] **Step 8: 替换 `modelDisplayConfig` → `modelConfig`**
|
||
|
||
在 platform 对象中,将 `modelDisplayConfig` 替换为 `modelConfig`(第 114 行附近)。
|
||
|
||
在 `fillFromResult` 中保持不变(不涉及 config 字段)。
|
||
|
||
- [ ] **Step 9: 验证语法**
|
||
|
||
Run: `npx eslint src/platforms/video/index.js --fix`
|
||
Expected: 无错误
|
||
|
||
- [ ] **Step 10: Commit**
|
||
|
||
```bash
|
||
git add src/platforms/video/index.js
|
||
git commit -m "feat: Video 平台接入模型配置 API
|
||
|
||
- loadModels 增加批量预加载
|
||
- loadConfig 改为 API 获取(替代 modelConfig.js)
|
||
- buildTaskBody 改为 params 驱动
|
||
- showImageUploader/isImageRequired 改为 inputType 驱动
|
||
- modelDisplayConfig 统一为 modelConfig"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 6: 移除 createTask 依赖
|
||
|
||
**Files:**
|
||
- Modify: `src/utils/taskPolling.js`
|
||
- Delete: `src/utils/createTask.js`
|
||
|
||
- [ ] **Step 1: 确认 createTask 的引用点**
|
||
|
||
`taskPolling.js:4` import + `taskPolling.js:93-94` 调用。`createTask(data)` 只返回 `data.body`(纯透传)。
|
||
|
||
- [ ] **Step 2: 修改 taskPolling.js**
|
||
|
||
删除第 4 行的 import:
|
||
```js
|
||
import { createTask } from '@/utils/createTask'
|
||
```
|
||
|
||
将第 93-94 行的:
|
||
```js
|
||
// 通过 createTask 获取 body 内容(RunningHub workflow payload)
|
||
const body = await createTask(data)
|
||
```
|
||
|
||
替换为:
|
||
```js
|
||
const body = data.body
|
||
```
|
||
|
||
- [ ] **Step 3: 删除 createTask.js**
|
||
|
||
```bash
|
||
rm src/utils/createTask.js
|
||
```
|
||
|
||
- [ ] **Step 4: 验证语法**
|
||
|
||
Run: `npx eslint src/utils/taskPolling.js --fix`
|
||
Expected: 无错误
|
||
|
||
- [ ] **Step 5: Commit**
|
||
|
||
```bash
|
||
git add src/utils/taskPolling.js
|
||
git rm src/utils/createTask.js
|
||
git commit -m "refactor: 移除 createTask 透传层,taskPolling 直接读 data.body"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 7: 删除旧配置文件
|
||
|
||
**Files:**
|
||
- Delete: `src/platforms/painting/models/`(整个目录,9 个文件)
|
||
- Delete: `src/utils/modelConfig.js`
|
||
|
||
- [ ] **Step 1: 确认无其他引用**
|
||
|
||
`src/platforms/painting/models/index.js` — 仅被 painting/index.js 引用(已在 Task 4 移除 import)
|
||
`src/utils/modelConfig.js` — 仅被 video/index.js 引用(已在 Task 5 移除 import)
|
||
|
||
- [ ] **Step 2: 删除文件**
|
||
|
||
```bash
|
||
rm -rf src/platforms/painting/models/
|
||
rm src/utils/modelConfig.js
|
||
```
|
||
|
||
- [ ] **Step 3: Commit**
|
||
|
||
```bash
|
||
git add -A
|
||
git commit -m "refactor: 删除 Painting 硬编码模型配置和 Video 旧 config 加载
|
||
|
||
- 删除 src/platforms/painting/models/(9 个硬编码 JS)
|
||
- 删除 src/utils/modelConfig.js(Video 旧远程 JSON 加载)
|
||
配置已全部迁移至后端 API。"
|
||
```
|
||
|
||
---
|
||
|
||
### Task 8: 验证
|
||
|
||
- [ ] **Step 1: ESLint 全量检查**
|
||
|
||
Run: `npx eslint src/ --fix`
|
||
Expected: 无错误
|
||
|
||
- [ ] **Step 2: 启动开发服务器**
|
||
|
||
Run: `pnpm dev`
|
||
Expected: Vite 启动成功,无编译错误
|
||
|
||
- [ ] **Step 3: 功能冒烟**
|
||
|
||
在浏览器中验证:
|
||
- Painting 平台模型列表正常加载
|
||
- 切换模型后控件正常渲染(参数来自 API)
|
||
- 生成任务提交正常
|
||
- Video 平台(暂无模型)不报错
|
||
|
||
- [ ] **Step 4: Commit(如有 lint 修复)**
|
||
|
||
```bash
|
||
git add -A
|
||
git commit -m "chore: ESLint 修复"
|
||
```
|