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/')
文件:
web/src/i18n/locales/zh-CN.jsonweb/src/i18n/locales/en.json在 web/src/i18n/locales/zh-CN.json 中添加以下键值对。找到文件末尾,在最后一个键值对后添加逗号,然后添加:
"高级比例(留空使用默认值)": "高级比例(留空使用默认值)",
"缓存读取倍率": "缓存读取倍率",
"缓存创建倍率(5分钟)": "缓存创建倍率(5分钟)",
"图片倍率": "图片倍率",
"音频输入倍率": "音频输入倍率",
"音频输出倍率": "音频输出倍率",
"默认值:1.0": "默认值:1.0",
"默认值:1.25": "默认值:1.25"
在 web/src/i18n/locales/en.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"
确保添加的 JSON 格式正确,没有语法错误:
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')))"
预期输出:无错误,输出两个对象的内容
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 <noreply@anthropic.com>"
文件:
web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:59-91找到 useEffect 开始(约第 59 行),在 try 块中,在现有的 const completionRatio = JSON.parse(props.options.CompletionRatio || '{}'); 之后添加:
// 新增:解析高级倍率字段
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 || '{}');
在同一个 useEffect 中,找到 const modelNames = new Set([...])(约第 66 行),将数组扩展为:
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),
]);
在同一个 useEffect 中,找到 const modelData = Array.from(modelNames).map((name) => {(约第 72 行),在返回对象中添加新字段。找到现有的:
const comp = completionRatio[name] === undefined ? '' : completionRatio[name];
在这一行后添加:
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];
继续在同一个 map 函数中,找到返回对象(约第 78 行),更新为:
return {
name,
price,
ratio,
completionRatio: comp,
cacheRatio: cacheR,
cacheCreationRatio: cacheCreationR,
imageRatio: imageR,
audioRatio: audioR,
audioCompletionRatio: audioCompR,
hasConflict: price !== '' && (ratio !== '' || comp !== ''),
};
cd web
bun run dev
访问:http://localhost:5173/setting/ratio → 切换到"可视化倍率设置"标签
打开浏览器控制台,输入:
// 检查 models 状态是否包含新字段
const tableRows = document.querySelectorAll('.semi-table-row');
console.log('Table rows count:', tableRows.length);
预期:表格正常显示,无 JavaScript 错误
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 <noreply@anthropic.com>"
文件:
web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:616-737在文件中找到 {pricingSubMode === 'token-price' && ( 块的闭合位置(约第 736 行),应该在 )}$ 之前,{pricingMode === ‘per-request’ && (` 之前。
在 {pricingSubMode === 'token-price' && ( 块的闭合 )} 之后,{pricingMode === 'per-request' && ( 之前,添加:
<Form.Section text={t('高级比例(留空使用默认值)')}>
<Form.InputNumber
field='cacheRatio'
label={t('缓存读取倍率')}
min={0}
step={0.01}
placeholder={t('默认值:1.0')}
/>
<Form.InputNumber
field='cacheCreationRatio'
label={t('缓存创建倍率(5分钟)')}
min={0}
step={0.01}
placeholder={t('默认值:1.25')}
/>
<Form.InputNumber
field='imageRatio'
label={t('图片倍率')}
min={0}
step={0.01}
placeholder={t('默认值:1.0')}
/>
<Form.InputNumber
field='audioRatio'
label={t('音频输入倍率')}
min={0}
step={0.01}
placeholder={t('默认值:1.0')}
/>
<Form.InputNumber
field='audioCompletionRatio'
label={t('音频输出倍率')}
min={0}
step={0.01}
placeholder={t('默认值:1.0')}
/>
</Form.Section>
注意缩进:保持与周围代码一致的缩进(约 14-16 个空格)
确保开发服务器仍在运行(bun run dev),访问:http://localhost:5173/setting/ratio
预期:
在高级比例区域的任意输入框中:
-1),预期:无法输入或显示验证错误abc),预期:无法输入(InputNumber 组件自动限制)1.23),预期:正常接受1.23456),预期:step=0.01 限制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 <noreply@anthropic.com>"
文件:
web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:395-454找到 editModel 函数中的 setTimeout 块(约第 435 行),在 formRef.current.setValues({ 调用中添加新字段。
找到现有的:
completionTokenPrice: modelCopy.completionTokenPrice
在这一行后添加(注意在 }) 之前添加逗号):
,
// 新增:高级倍率字段
cacheRatio: modelCopy.cacheRatio,
cacheCreationRatio: modelCopy.cacheCreationRatio,
imageRatio: modelCopy.imageRatio,
audioRatio: modelCopy.audioRatio,
audioCompletionRatio: modelCopy.audioCompletionRatio
// 检查表单值是否正确设置
const formApi = document.querySelector('[data-form-id]')?.__semi_form__;
if (formApi) {
console.log('Form values:', formApi.getValues());
}
或者更简单:直接观察高级比例区域的输入框,如果有数据应该显示对应的值
预期:
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 <noreply@anthropic.com>"
文件:
web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:334-382找到 addOrUpdateModel 函数(约第 334 行),在 const updatedModel = { 对象中添加新字段。
找到现有的:
completionRatio: values.completionRatio || '',
在这一行后添加:
// 新增:高级倍率字段
cacheRatio: values.cacheRatio || '',
cacheCreationRatio: values.cacheCreationRatio || '',
imageRatio: values.imageRatio || '',
audioRatio: values.audioRatio || '',
audioCompletionRatio: values.audioCompletionRatio || '',
test-model-advanced0.51.52.01.20.8预期:
在浏览器控制台中检查:
// 检查是否能在表格中看到新模型
const rows = document.querySelectorAll('.semi-table-row');
console.log('Total rows:', rows.length);
// 应该比之前多 1 行
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 <noreply@anthropic.com>"
文件:
web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:110-177找到 SubmitData 函数中的 const output = {(约第 112 行),在对象中添加新字段。
找到现有的:
CompletionRatio: {},
在这一行后添加:
// 新增:高级倍率字段
CacheRatio: {},
CreateCacheRatio: {},
ImageRatio: {},
AudioRatio: {},
AudioCompletionRatio: {}
在同一个 SubmitData 函数中,找到 models.forEach((model) => { 块(约第 119 行),在现有的转换逻辑后添加。
找到:
if (model.completionRatio !== '')
output.CompletionRatio[model.name] = parseFloat(model.completionRatio);
在这一行后添加:
// 新增:处理高级倍率字段
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);
找到 const finalOutput = {(约第 137 行),在对象中添加新字段。
找到现有的:
CompletionRatio: JSON.stringify(output.CompletionRatio, null, 2),
在这一行后添加:
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),
test-model-advanced 还在表格中0.8)/api/option/ 请求预期:
PUT /api/option/ 请求CacheRatio、CreateCacheRatio 等新增字段test-model-advanced在网络标签中点击任意一个 /api/option/ 请求,查看"Payload"或"请求体”:
{
"key": "CacheRatio",
"value": "{\n \"test-model-advanced\": 0.8\n}"
}
预期:
value 是格式化的 JSON 字符串(有缩进)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 <noreply@anthropic.com>"
文件:
web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx:255-270找到 updateModel 函数(约第 255 行),确认现有的验证逻辑:
const updateModel = (name, field, value) => {
if (isNaN(value) && value !== '') {
showError(t('请输入数字'));
return;
}
// ... 更新逻辑
};
说明:由于我们使用 Form.InputNumber 组件,它已经内置了数字验证,所以 updateModel 函数不需要修改。isNaN 检查已经足够处理高级倍率字段。
在开发服务器运行的情况下:
abc)注意:由于我们现在使用 Form.InputNumber 而非 Input,高级比例字段在弹窗中,updateModel 函数不会被它们调用。Form.InputNumber 会自动限制只能输入数字。
测试空值是否正确处理:
预期:
如果本任务没有代码修改,跳过提交。否则:
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 <noreply@anthropic.com>"
文件:
web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx预期:
claude-3-5-sonnet-202410221.51.20.11.25预期:
0.151.32.510.020.0预期:
刷新浏览器页面,重新访问可视化倍率设置:
预期:
0.151.32.510.020.0预期:
测试负数输入:
-1min={0} 限制,无法输入负数测试小数精度:
0.123456step={0.01} 限制,可以输入但会保留多位小数(Semi UI InputNumber 行为)测试空值保存:
预期:
如果所有测试通过,创建一个测试提交标记:
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 <noreply@anthropic.com>"
文件:
web/src/pages/Setting/Ratio/ModelSettingsVisualEditor.jsx运行代码格式化工具(如果项目配置了):
cd web
bun run lint --fix
预期:
搜索并移除任何调试用的 console.log:
cd web/src/pages/Setting/Ratio
grep -n "console.log" ModelSettingsVisualEditor.jsx
如果找到任何 console.log,删除它们。
检查是否有不必要的重渲染:
预期:
如果有任何清理更改:
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 <noreply@anthropic.com>"
在实施完成后,验证以下所有项目:
git log --oneline --no-merges | head -20
预期:看到一系列清晰的、原子性的提交,每个提交对应一个任务或功能点
git diff HEAD~10 HEAD --stat
预期:
ModelSettingsVisualEditor.jsx 有显著更改zh-CN.json 和 en.json 有新增翻译重复 Task 8 中的所有测试步骤,确保一切正常。
git checkout master
git merge <branch-name>
git push
症状:访问可视化倍率设置页面,表格为空
排查:
useEffect 中的 JSON 解析是否成功props.options 是否包含所有必需的字段解决:
症状:编辑模型时看不到高级比例输入框
排查:
pricingMode === 'per-token')解决:
t() 函数是否返回正确的翻译文本症状:点击"应用更改"后显示错误
排查:
/api/option/ 请求解决:
finalOutput 中症状:界面显示 "高级比例(留空使用默认值)" 而非翻译后的文本
排查:
解决:
总计: 约 2.5 小时
docs/superpowers/specs/2026-06-04-extended-visual-ratio-settings-design.mdfeat/channel-pricing-extended:web/src/pages/Setting/Ratio/ChannelPricingView.jsx/api/option/ - 获取所有选项/api/option/ - 更新单个选项(请求体: { key, value })实施计划完成