diff --git a/docs/superpowers/plans/2026-06-04-extended-visual-ratio-settings.md b/docs/superpowers/plans/2026-06-04-extended-visual-ratio-settings.md new file mode 100644 index 0000000..eed561e --- /dev/null +++ b/docs/superpowers/plans/2026-06-04-extended-visual-ratio-settings.md @@ -0,0 +1,932 @@ +# 扩展可视化倍率设置实施计划 + +> **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. + +**目标:** 在 ModelSettingsVisualEditor 组件中添加 5 个高级倍率字段支持(缓存、图片、音频倍率) + +**架构:** 扩展现有 React 组件的状态管理和表单逻辑,增加高级倍率字段的数据初始化、编辑、保存和验证功能 + +**技术栈:** React, Semi UI, i18n, JavaScript + +--- + +## 文件结构 + +### 修改文件 +- `web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx` - 主要功能实现(500+ 行) +- `web/src/i18n/locales/zh-CN.json` - 中文翻译 +- `web/src/i18n/locales/en.json` - 英文翻译 + +### 参考文件(只读,用于理解实现模式) +- `feat/channel-pricing-extended:web/src/pages/Setting/Ratio/ChannelPricingView.jsx` - 渠道价格设置的参考实现 + +### 数据流向 +``` +props.options (API 数据) + ↓ +useEffect 解析 JSON → models 状态(包含 5 个新字段) + ↓ +用户编辑表单 → currentModel 状态 + ↓ +addOrUpdateModel → 更新 models 状态 + ↓ +SubmitData → 序列化 JSON → API.put('/api/option/') +``` + +--- + +## Task 1: 添加国际化文本 + +**文件:** +- Modify: `web/src/i18n/locales/zh-CN.json` +- Modify: `web/src/i18n/locales/en.json` + +### 步骤 1.1: 添加中文翻译 + +在 `web/src/i18n/locales/zh-CN.json` 中添加以下键值对。找到文件末尾,在最后一个键值对后添加逗号,然后添加: + +```json +"高级比例(留空使用默认值)": "高级比例(留空使用默认值)", +"缓存读取倍率": "缓存读取倍率", +"缓存创建倍率(5分钟)": "缓存创建倍率(5分钟)", +"图片倍率": "图片倍率", +"音频输入倍率": "音频输入倍率", +"音频输出倍率": "音频输出倍率", +"默认值:1.0": "默认值:1.0", +"默认值:1.25": "默认值:1.25" +``` + +### 步骤 1.2: 添加英文翻译 + +在 `web/src/i18n/locales/en.json` 中添加对应的英文翻译: + +```json +"高级比例(留空使用默认值)": "Advanced Ratios (Leave empty for defaults)", +"缓存读取倍率": "Cache Read Ratio", +"缓存创建倍率(5分钟)": "Cache Creation Ratio (5min)", +"图片倍率": "Image Ratio", +"音频输入倍率": "Audio Input Ratio", +"音频输出倍率": "Audio Output Ratio", +"默认值:1.0": "Default: 1.0", +"默认值:1.25": "Default: 1.25" +``` + +### 步骤 1.3: 验证 JSON 格式 + +确保添加的 JSON 格式正确,没有语法错误: + +```bash +cd web/src/i18n/locales +node -e "console.log('zh-CN:', JSON.parse(require('fs').readFileSync('zh-CN.json', 'utf8'))); console.log('en:', JSON.parse(require('fs').readFileSync('en.json', 'utf8')))" +``` + +预期输出:无错误,输出两个对象的内容 + +### 步骤 1.4: 提交国际化更改 + +```bash +git add web/src/i18n/locales/zh-CN.json web/src/i18n/locales/en.json +git commit -m "feat(i18n): add advanced ratio translations + +- Add Chinese translations for 5 advanced ratio fields +- Add English translations for 5 advanced ratio fields + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 2: 扩展数据初始化逻辑 + +**文件:** +- Modify: `web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:59-91` + +### 步骤 2.1: 在 useEffect 中解析高级倍率 JSON + +找到 `useEffect` 开始(约第 59 行),在 `try` 块中,在现有的 `const completionRatio = JSON.parse(props.options.CompletionRatio || '{}');` 之后添加: + +```javascript +// 新增:解析高级倍率字段 +const cacheRatio = JSON.parse(props.options.CacheRatio || '{}'); +const createCacheRatio = JSON.parse(props.options.CreateCacheRatio || '{}'); +const imageRatio = JSON.parse(props.options.ImageRatio || '{}'); +const audioRatio = JSON.parse(props.options.AudioRatio || '{}'); +const audioCompletionRatio = JSON.parse(props.options.AudioCompletionRatio || '{}'); +``` + +### 步骤 2.2: 扩展模型名称合并逻辑 + +在同一个 `useEffect` 中,找到 `const modelNames = new Set([...])`(约第 66 行),将数组扩展为: + +```javascript +const modelNames = new Set([ + ...Object.keys(modelPrice), + ...Object.keys(modelRatio), + ...Object.keys(completionRatio), + ...Object.keys(cacheRatio), + ...Object.keys(createCacheRatio), + ...Object.keys(imageRatio), + ...Object.keys(audioRatio), + ...Object.keys(audioCompletionRatio), +]); +``` + +### 步骤 2.3: 扩展模型数据对象 + +在同一个 `useEffect` 中,找到 `const modelData = Array.from(modelNames).map((name) => {`(约第 72 行),在返回对象中添加新字段。找到现有的: + +```javascript +const comp = completionRatio[name] === undefined ? '' : completionRatio[name]; +``` + +在这一行后添加: + +```javascript +const cacheR = cacheRatio[name] === undefined ? '' : cacheRatio[name]; +const cacheCreationR = createCacheRatio[name] === undefined ? '' : createCacheRatio[name]; +const imageR = imageRatio[name] === undefined ? '' : imageRatio[name]; +const audioR = audioRatio[name] === undefined ? '' : audioRatio[name]; +const audioCompR = audioCompletionRatio[name] === undefined ? '' : audioCompletionRatio[name]; +``` + +### 步骤 2.4: 更新返回对象结构 + +继续在同一个 `map` 函数中,找到返回对象(约第 78 行),更新为: + +```javascript +return { + name, + price, + ratio, + completionRatio: comp, + cacheRatio: cacheR, + cacheCreationRatio: cacheCreationR, + imageRatio: imageR, + audioRatio: audioR, + audioCompletionRatio: audioCompR, + hasConflict: price !== '' && (ratio !== '' || comp !== ''), +}; +``` + +### 步骤 2.5: 启动开发服务器验证数据加载 + +```bash +cd web +bun run dev +``` + +访问:http://localhost:5173/setting/ratio → 切换到"可视化倍率设置"标签 + +打开浏览器控制台,输入: + +```javascript +// 检查 models 状态是否包含新字段 +const tableRows = document.querySelectorAll('.semi-table-row'); +console.log('Table rows count:', tableRows.length); +``` + +预期:表格正常显示,无 JavaScript 错误 + +### 步骤 2.6: 提交数据初始化更改 + +```bash +git add web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx +git commit -m "feat(ratio): parse advanced ratio fields in data initialization + +- Parse 5 new JSON fields from props.options +- Extend modelNames Set to include keys from all ratio fields +- Add 5 new fields to model data objects + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 3: 添加高级比例表单区域 + +**文件:** +- Modify: `web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:616-737` + +### 步骤 3.1: 找到插入位置 + +在文件中找到 `{pricingSubMode === 'token-price' && (` 块的闭合位置(约第 736 行),应该在 `)}$ 之前,`{pricingMode === 'per-request' && (` 之前。 + +### 步骤 3.2: 插入高级比例表单区域 + +在 `{pricingSubMode === 'token-price' && (` 块的闭合 `)}` 之后,`{pricingMode === 'per-request' && (` 之前,添加: + +```jsx + + + + + + + +``` + +**注意缩进**:保持与周围代码一致的缩进(约 14-16 个空格) + +### 步骤 3.2: 验证表单渲染 + +确保开发服务器仍在运行(`bun run dev`),访问:http://localhost:5173/setting/ratio + +1. 点击任意模型的"编辑"按钮 +2. 确认定价模式为"按量计费" +3. 向下滚动,应该能看到"高级比例(留空使用默认值)"区域 +4. 确认 5 个输入框都有正确的标签和 placeholder + +预期: +- 新区域显示在"价格设置方式"和"固定价格"之间 +- 所有 5 个字段可见且可交互 +- placeholder 显示正确的默认值 + +### 步骤 3.3: 测试输入验证 + +在高级比例区域的任意输入框中: +1. 输入负数(如 `-1`),预期:无法输入或显示验证错误 +2. 输入文字(如 `abc`),预期:无法输入(InputNumber 组件自动限制) +3. 输入小数(如 `1.23`),预期:正常接受 +4. 输入多位小数(如 `1.23456`),预期:step=0.01 限制 + +### 步骤 3.4: 提交表单 UI 更改 + +```bash +git add web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx +git commit -m "feat(ui): add advanced ratios form section + +- Add Form.Section with 5 advanced ratio input fields +- Configure min={0}, step={0.01} for all fields +- Add placeholders showing default values +- Only show when pricingMode === 'per-token' + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 4: 更新编辑模型逻辑 + +**文件:** +- Modify: `web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:395-454` + +### 步骤 4.1: 在 editModel 中设置表单值 + +找到 `editModel` 函数中的 `setTimeout` 块(约第 435 行),在 `formRef.current.setValues({` 调用中添加新字段。 + +找到现有的: +```javascript +completionTokenPrice: modelCopy.completionTokenPrice +``` + +在这一行后添加(注意在 `})` 之前添加逗号): +```javascript +, +// 新增:高级倍率字段 +cacheRatio: modelCopy.cacheRatio, +cacheCreationRatio: modelCopy.cacheCreationRatio, +imageRatio: modelCopy.imageRatio, +audioRatio: modelCopy.audioRatio, +audioCompletionRatio: modelCopy.audioCompletionRatio +``` + +### 步骤 4.2: 验证编辑回显 + +1. 点击已有数据的模型(如 gpt-4)的"编辑"按钮 +2. 在浏览器控制台中执行: + +```javascript +// 检查表单值是否正确设置 +const formApi = document.querySelector('[data-form-id]')?.__semi_form__; +if (formApi) { + console.log('Form values:', formApi.getValues()); +} +``` + +或者更简单:直接观察高级比例区域的输入框,如果有数据应该显示对应的值 + +预期: +- 如果模型有高级倍率数据,输入框应显示对应值 +- 如果没有数据,输入框应为空 + +### 步骤 4.3: 提交编辑逻辑更改 + +```bash +git add web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx +git commit -m "feat(edit): populate advanced ratios in edit modal + +- Add 5 advanced ratio fields to formRef.current.setValues +- Ensure existing ratio data displays correctly in edit modal + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 5: 更新添加/更新模型逻辑 + +**文件:** +- Modify: `web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:334-382` + +### 步骤 5.1: 在 addOrUpdateModel 中处理高级倍率字段 + +找到 `addOrUpdateModel` 函数(约第 334 行),在 `const updatedModel = {` 对象中添加新字段。 + +找到现有的: +```javascript +completionRatio: values.completionRatio || '', +``` + +在这一行后添加: +```javascript +// 新增:高级倍率字段 +cacheRatio: values.cacheRatio || '', +cacheCreationRatio: values.cacheCreationRatio || '', +imageRatio: values.imageRatio || '', +audioRatio: values.audioRatio || '', +audioCompletionRatio: values.audioCompletionRatio || '', +``` + +### 步骤 5.2: 测试添加新模型 + +1. 点击"添加模型"按钮 +2. 输入模型名称:`test-model-advanced` +3. 在高级比例区域输入测试值: + - 缓存读取倍率:`0.5` + - 缓存创建倍率:`1.5` + - 图片倍率:`2.0` + - 音频输入倍率:`1.2` + - 音频输出倍率:`0.8` +4. 点击"确定" + +预期: +- 模型成功添加到表格 +- 浏览器控制台无错误 + +### 步骤 5.3: 验证数据保存到状态 + +在浏览器控制台中检查: + +```javascript +// 检查是否能在表格中看到新模型 +const rows = document.querySelectorAll('.semi-table-row'); +console.log('Total rows:', rows.length); +// 应该比之前多 1 行 +``` + +### 步骤 5.4: 提交添加/更新逻辑更改 + +```bash +git add web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx +git commit -m "feat(add): handle advanced ratios in addOrUpdateModel + +- Add 5 advanced ratio fields to updatedModel object +- Use empty string fallback for undefined values + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 6: 更新保存逻辑 + +**文件:** +- Modify: `web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:110-177` + +### 步骤 6.1: 扩展 output 对象 + +找到 `SubmitData` 函数中的 `const output = {`(约第 112 行),在对象中添加新字段。 + +找到现有的: +```javascript +CompletionRatio: {}, +``` + +在这一行后添加: +```javascript +// 新增:高级倍率字段 +CacheRatio: {}, +CreateCacheRatio: {}, +ImageRatio: {}, +AudioRatio: {}, +AudioCompletionRatio: {} +``` + +### 步骤 6.2: 添加数据转换逻辑 + +在同一个 `SubmitData` 函数中,找到 `models.forEach((model) => {` 块(约第 119 行),在现有的转换逻辑后添加。 + +找到: +```javascript +if (model.completionRatio !== '') + output.CompletionRatio[model.name] = parseFloat(model.completionRatio); +``` + +在这一行后添加: +```javascript + +// 新增:处理高级倍率字段 +if (model.cacheRatio !== '') + output.CacheRatio[model.name] = parseFloat(model.cacheRatio); +if (model.cacheCreationRatio !== '') + output.CreateCacheRatio[model.name] = parseFloat(model.cacheCreationRatio); +if (model.imageRatio !== '') + output.ImageRatio[model.name] = parseFloat(model.imageRatio); +if (model.audioRatio !== '') + output.AudioRatio[model.name] = parseFloat(model.audioRatio); +if (model.audioCompletionRatio !== '') + output.AudioCompletionRatio[model.name] = parseFloat(model.audioCompletionRatio); +``` + +### 步骤 6.3: 扩展 finalOutput 对象 + +找到 `const finalOutput = {`(约第 137 行),在对象中添加新字段。 + +找到现有的: +```javascript +CompletionRatio: JSON.stringify(output.CompletionRatio, null, 2), +``` + +在这一行后添加: +```javascript +CacheRatio: JSON.stringify(output.CacheRatio, null, 2), +CreateCacheRatio: JSON.stringify(output.CreateCacheRatio, null, 2), +ImageRatio: JSON.stringify(output.ImageRatio, null, 2), +AudioRatio: JSON.stringify(output.AudioRatio, null, 2), +AudioCompletionRatio: JSON.stringify(output.AudioCompletionRatio, null, 2), +``` + +### 步骤 6.4: 测试保存功能 + +1. 确保 Task 5.2 中添加的 `test-model-advanced` 还在表格中 +2. 修改它的一些高级倍率值(如将缓存读取倍率改为 `0.8`) +3. 点击"应用更改"按钮 +4. 打开浏览器网络标签,筛选 `/api/option/` 请求 + +预期: +- 看到多个 `PUT /api/option/` 请求 +- 其中包含 `CacheRatio`、`CreateCacheRatio` 等新增字段 +- 请求体包含 JSON 数据,键为 `test-model-advanced` + +### 步骤 6.5: 验证 API 请求体 + +在网络标签中点击任意一个 `/api/option/` 请求,查看"Payload"或"请求体": + +```json +{ + "key": "CacheRatio", + "value": "{\n \"test-model-advanced\": 0.8\n}" +} +``` + +预期: +- `value` 是格式化的 JSON 字符串(有缩进) +- 包含正确的模型名和倍率值 + +### 步骤 6.6: 提交保存逻辑更改 + +```bash +git add web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx +git commit -m "feat(save): serialize and save advanced ratio fields + +- Add 5 new fields to output object +- Convert model data to float and populate output fields +- Serialize all fields to JSON in finalOutput +- Submit 7 total option fields (2 existing + 5 new) + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 7: 更新输入验证逻辑 + +**文件:** +- Modify: `web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:255-270` + +### 步骤 7.1: 确认 updateModel 函数 + +找到 `updateModel` 函数(约第 255 行),确认现有的验证逻辑: + +```javascript +const updateModel = (name, field, value) => { + if (isNaN(value) && value !== '') { + showError(t('请输入数字')); + return; + } + // ... 更新逻辑 +}; +``` + +**说明**:由于我们使用 `Form.InputNumber` 组件,它已经内置了数字验证,所以 `updateModel` 函数不需要修改。`isNaN` 检查已经足够处理高级倍率字段。 + +### 步骤 7.2: 测试验证逻辑 + +在开发服务器运行的情况下: + +1. 尝试在表格中直接点击模型倍率或补全倍率输入框 +2. 输入文字(如 `abc`) +3. 观察是否显示错误提示"请输入数字" + +**注意**:由于我们现在使用 `Form.InputNumber` 而非 `Input`,高级比例字段在弹窗中,`updateModel` 函数不会被它们调用。`Form.InputNumber` 会自动限制只能输入数字。 + +### 步骤 7.3: 验证空值处理 + +测试空值是否正确处理: + +1. 编辑一个模型 +2. 在高级比例区域,将所有输入框留空 +3. 点击"确定" +4. 点击"应用更改" + +预期: +- 保存成功,无错误 +- 空值保存为空字符串,后端使用默认值 + +### 步骤 7.4: 提交验证相关更改 + +如果本任务没有代码修改,跳过提交。否则: + +```bash +git add web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx +git commit -m "feat(validation): enhance input validation for advanced ratios + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 8: 完整功能测试 + +**文件:** +- Test: `web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx` + +### 步骤 8.1: 测试数据初始化 + +1. 清空浏览器缓存或使用隐私模式 +2. 访问:http://localhost:5173/setting/ratio +3. 切换到"可视化倍率设置"标签 + +预期: +- 表格正常显示 +- 无 JavaScript 错误 +- 表格包含所有现有模型 + +### 步骤 8.2: 测试添加带高级倍率的模型 + +1. 点击"添加模型" +2. 输入: + - 模型名称:`claude-3-5-sonnet-20241022` + - 定价模式:按量计费 + - 价格设置方式:按倍率设置 + - 模型倍率:`1.5` + - 补全倍率:`1.2` + - 缓存读取倍率:`0.1` + - 缓存创建倍率:`1.25` + - 图片倍率:留空 + - 音频输入倍率:留空 + - 音频输出倍率:留空 +3. 点击"确定" + +预期: +- 模型成功添加 +- 表格中显示新模型 +- 无错误提示 + +### 步骤 8.3: 测试编辑高级倍率 + +1. 点击刚才添加的模型的"编辑"按钮 +2. 修改高级倍率值: + - 缓存读取倍率:`0.15` + - 缓存创建倍率:`1.3` + - 图片倍率:`2.5` + - 音频输入倍率:`10.0` + - 音频输出倍率:`20.0` +3. 点击"确定" +4. 点击"应用更改" + +预期: +- 编辑成功 +- 显示"保存成功"提示 + +### 步骤 8.4: 验证数据持久化 + +刷新浏览器页面,重新访问可视化倍率设置: + +1. 点击刚才编辑的模型的"编辑"按钮 +2. 检查高级比例区域的值是否与步骤 8.3 中设置的一致 + +预期: +- 缓存读取倍率:显示 `0.15` +- 缓存创建倍率:显示 `1.3` +- 图片倍率:显示 `2.5` +- 音频输入倍率:显示 `10.0` +- 音频输出倍率:显示 `20.0` + +### 步骤 8.5: 测试删除模型 + +1. 选择测试模型 +2. 点击"删除"按钮 +3. 确认删除 + +预期: +- 模型从表格中移除 +- 删除的高级倍率数据在保存时被清除(后续保存不会包含该模型) + +### 步骤 8.6: 测试边界情况 + +**测试负数输入**: +1. 尝试在高级比例输入框输入 `-1` +2. 预期:`min={0}` 限制,无法输入负数 + +**测试小数精度**: +1. 输入 `0.123456` +2. 预期:`step={0.01}` 限制,可以输入但会保留多位小数(Semi UI InputNumber 行为) + +**测试空值保存**: +1. 编辑模型,清空所有高级比例输入框 +2. 点击"确定",然后"应用更改" +3. 预期:保存成功,后端使用默认值 + +### 步骤 8.7: 测试国际化切换 + +1. 在系统设置中切换到英文(如果支持) +2. 重新访问可视化倍率设置 +3. 检查高级比例区域的标签是否显示为英文 + +预期: +- "高级比例(留空使用默认值)" → "Advanced Ratios (Leave empty for defaults)" +- "缓存读取倍率" → "Cache Read Ratio" +- 其他字段类似 + +### 步骤 8.8: 创建测试提交 + +如果所有测试通过,创建一个测试提交标记: + +```bash +git add web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx +git commit -m "test: verify advanced ratios functionality + +- Test data initialization with empty options +- Test adding model with advanced ratios +- Test editing advanced ratios +- Test data persistence after page refresh +- Test model deletion +- Test edge cases (negative numbers, decimal precision, empty values) +- Test internationalization (English/Chinese) + +All tests passed successfully. + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## Task 9: 代码清理和优化 + +**文件:** +- Modify: `web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx` + +### 步骤 9.1: 检查代码格式化 + +运行代码格式化工具(如果项目配置了): + +```bash +cd web +bun run lint --fix +``` + +预期: +- 无 lint 错误 +- 代码格式符合项目规范 + +### 步骤 9.2: 检查 console.log + +搜索并移除任何调试用的 `console.log`: + +```bash +cd web/src/pages/Setting/Ratio +grep -n "console.log" ModelSettingsVisualEditor.jsx +``` + +如果找到任何 `console.log`,删除它们。 + +### 步骤 9.3: 验证组件性能 + +检查是否有不必要的重渲染: + +1. 打开浏览器 React DevTools(如果可用) +2. 选择 "Profiler" 标签 +3. 记录编辑模型时的性能 +4. 检查是否有异常的重渲染 + +预期: +- 组件重渲染次数合理 +- 无明显的性能问题 + +### 步骤 9.4: 提交清理更改 + +如果有任何清理更改: + +```bash +git add web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx +git commit -m "refactor: code cleanup and optimization + +- Remove debug console.log statements +- Format code with linter +- Verify component performance + +Co-Authored-By: Claude Sonnet 4.6 " +``` + +--- + +## 验证清单 + +在实施完成后,验证以下所有项目: + +### 功能验证 +- [ ] 可以添加带有高级倍率的模型 +- [ ] 可以编辑模型的高级倍率字段 +- [ ] 可以删除模型 +- [ ] 数据正确保存到后端 +- [ ] 刷新页面后数据正确加载 +- [ ] 空值字段使用默认值 + +### UI/UX 验证 +- [ ] 高级比例区域正确显示 +- [ ] 所有 5 个字段都有正确的标签 +- [ ] Placeholder 显示正确的默认值 +- [ ] 输入验证正常工作(负数、非数字) +- [ ] 中英文切换正常 + +### 代码质量 +- [ ] 无 TypeScript/JavaScript 错误 +- [ ] 无 lint 错误 +- [ ] 无调试 console.log +- [ ] 代码格式符合项目规范 +- [ ] 所有提交都有清晰的 commit message + +### 数据完整性 +- [ ] 前端字段名与后端 Option Key 一致 +- [ ] JSON 序列化/反序列化正确 +- [ ] 空值处理正确(空字符串,非 null) +- [ ] 数值转换正确(parseFloat) + +--- + +## 实施完成后的最终检查 + +### 步骤 1: 查看所有提交 + +```bash +git log --oneline --no-merges | head -20 +``` + +预期:看到一系列清晰的、原子性的提交,每个提交对应一个任务或功能点 + +### 步骤 2: 验证文件更改 + +```bash +git diff HEAD~10 HEAD --stat +``` + +预期: +- `ModelSettingsVisualEditor.jsx` 有显著更改 +- `zh-CN.json` 和 `en.json` 有新增翻译 +- 无其他意外更改 + +### 步骤 3: 最终功能测试 + +重复 Task 8 中的所有测试步骤,确保一切正常。 + +### 步骤 4: 合并到主分支(如果需要) + +```bash +git checkout master +git merge +git push +``` + +--- + +## 故障排查 + +### 问题:表格不显示 + +**症状**:访问可视化倍率设置页面,表格为空 + +**排查**: +1. 打开浏览器控制台,检查是否有 JavaScript 错误 +2. 检查 `useEffect` 中的 JSON 解析是否成功 +3. 验证 `props.options` 是否包含所有必需的字段 + +**解决**: +- 确保后端 API 返回所有 7 个字段(ModelPrice, ModelRatio, CompletionRatio, CacheRatio, CreateCacheRatio, ImageRatio, AudioRatio, AudioCompletionRatio) + +### 问题:高级比例区域不显示 + +**症状**:编辑模型时看不到高级比例输入框 + +**排查**: +1. 检查定价模式是否为"按量计费"(`pricingMode === 'per-token'`) +2. 检查 Form.Section 的条件渲染 +3. 验证国际化文本是否加载 + +**解决**: +- 确保在"按量计费"模式下编辑 +- 检查 `t()` 函数是否返回正确的翻译文本 + +### 问题:数据保存失败 + +**症状**:点击"应用更改"后显示错误 + +**排查**: +1. 打开浏览器网络标签,检查 `/api/option/` 请求 +2. 查看请求响应状态码和消息 +3. 验证请求数据格式是否正确 + +**解决**: +- 确保所有 7 个字段都包含在 `finalOutput` 中 +- 检查 JSON 序列化是否正确 +- 验证后端 API 是否支持所有 7 个 Option Key + +### 问题:翻译文本显示为键名 + +**症状**:界面显示 `"高级比例(留空使用默认值)"` 而非翻译后的文本 + +**排查**: +1. 检查 i18n 配置文件是否正确加载 +2. 验证 JSON 格式是否正确 +3. 检查是否有语法错误导致整个文件无法解析 + +**解决**: +- 修复 JSON 语法错误 +- 重新加载页面 +- 清除浏览器缓存 + +--- + +## 预计时间 + +- Task 1 (国际化): 15 分钟 +- Task 2 (数据初始化): 20 分钟 +- Task 3 (表单 UI): 15 分钟 +- Task 4 (编辑逻辑): 10 分钟 +- Task 5 (添加/更新): 10 分钟 +- Task 6 (保存逻辑): 15 分钟 +- Task 7 (验证逻辑): 5 分钟 +- Task 8 (完整测试): 30 分钟 +- Task 9 (代码清理): 10 分钟 + +**总计**: 约 2.5 小时 + +--- + +## 参考资源 + +### 内部文档 +- 设计规范: `docs/superpowers/specs/2026-06-04-extended-visual-ratio-settings-design.md` +- 渠道价格设置实现: `feat/channel-pricing-extended:web/src/pages/Setting/Ratio/ChannelPricingView.jsx` + +### API 文档 +- Semi UI Form: https://douyinfe.github.io/semi-ui/form/form-inputnumber +- React hooks: https://react.dev/reference/react + +### 后端接口 +- GET `/api/option/` - 获取所有选项 +- PUT `/api/option/` - 更新单个选项(请求体: `{ key, value }`) + +--- + +**实施计划完成**