feat(web): improve trader config UX for initial balance and prompt templates (#629 #630) (#673)

- Add onBlur validation for initial_balance input to enforce minimum of 100
- Add detailed prompt template descriptions with i18n support
- Fix Traditional Chinese to Simplified Chinese
- Extract hardcoded Chinese text to i18n translation system
- Add translation keys for all prompt templates and descriptions
Fixes #629, Fixes #630
This commit is contained in:
0xYYBB | ZYY | Bobo
2025-11-10 11:55:40 +08:00
committed by GitHub
parent f7498ef346
commit a1f015d45c
2 changed files with 126 additions and 11 deletions

View File

@@ -417,6 +417,13 @@ export function TraderConfigModal({
Number(e.target.value)
)
}
onBlur={(e) => {
// Force minimum value on blur
const value = Number(e.target.value)
if (value < 100) {
handleInputChange('initial_balance', 100)
}
}}
className="w-full px-3 py-2 bg-[#0B0E11] border border-[#2B3139] rounded text-[#EAECEF] focus:border-[#F0B90B] focus:outline-none"
min="100"
step="0.01"
@@ -617,7 +624,7 @@ export function TraderConfigModal({
{/* 系统提示词模板选择 */}
<div>
<label className="text-sm text-[#EAECEF] block mb-2">
{t('systemPromptTemplate', language)}
</label>
<select
value={formData.system_prompt_template}
@@ -626,17 +633,75 @@ export function TraderConfigModal({
}
className="w-full px-3 py-2 bg-[#0B0E11] border border-[#2B3139] rounded text-[#EAECEF] focus:border-[#F0B90B] focus:outline-none"
>
{promptTemplates.map((template) => (
<option key={template.name} value={template.name}>
{template.name === 'default'
? 'Default (默认稳健)'
: template.name === 'aggressive'
? 'Aggressive (激进)'
: template.name.charAt(0).toUpperCase() +
template.name.slice(1)}
</option>
))}
{promptTemplates.map((template) => {
// Template name mapping with i18n
const getTemplateName = (name: string) => {
const keyMap: Record<string, string> = {
default: 'promptTemplateDefault',
adaptive: 'promptTemplateAdaptive',
adaptive_relaxed: 'promptTemplateAdaptiveRelaxed',
Hansen: 'promptTemplateHansen',
nof1: 'promptTemplateNof1',
taro_long_prompts: 'promptTemplateTaroLong',
}
const key = keyMap[name]
return key
? t(key, language)
: name.charAt(0).toUpperCase() + name.slice(1)
}
return (
<option key={template.name} value={template.name}>
{getTemplateName(template.name)}
</option>
)
})}
</select>
{/* 動態描述區域 */}
<div
className="mt-2 p-3 rounded"
style={{
background: 'rgba(240, 185, 11, 0.05)',
border: '1px solid rgba(240, 185, 11, 0.15)',
}}
>
<div
className="text-xs font-semibold mb-1"
style={{ color: '#F0B90B' }}
>
{(() => {
const titleKeyMap: Record<string, string> = {
default: 'promptDescDefault',
adaptive: 'promptDescAdaptive',
adaptive_relaxed: 'promptDescAdaptiveRelaxed',
Hansen: 'promptDescHansen',
nof1: 'promptDescNof1',
taro_long_prompts: 'promptDescTaroLong',
}
const key = titleKeyMap[formData.system_prompt_template]
return key
? t(key, language)
: t('promptDescDefault', language)
})()}
</div>
<div className="text-xs" style={{ color: '#848E9C' }}>
{(() => {
const contentKeyMap: Record<string, string> = {
default: 'promptDescDefaultContent',
adaptive: 'promptDescAdaptiveContent',
adaptive_relaxed: 'promptDescAdaptiveRelaxedContent',
Hansen: 'promptDescHansenContent',
nof1: 'promptDescNof1Content',
taro_long_prompts: 'promptDescTaroLongContent',
}
const key = contentKeyMap[formData.system_prompt_template]
return key
? t(key, language)
: t('promptDescDefaultContent', language)
})()}
</div>
</div>
<p className="text-xs text-[#848E9C] mt-1">
</p>