diff --git a/frontend/src/components/ConfigPanel.css b/frontend/src/components/ConfigPanel.css index 87faae8..f1cafee 100644 --- a/frontend/src/components/ConfigPanel.css +++ b/frontend/src/components/ConfigPanel.css @@ -315,6 +315,9 @@ } .config-input-wrapper { + display: flex; + align-items: center; + gap: 0.5rem; display: flex; gap: 0.5rem; align-items: center; @@ -324,6 +327,13 @@ flex: 1; } +.percent-suffix { + color: #666; + font-size: 0.9rem; + font-weight: 500; + white-space: nowrap; +} + .save-btn { padding: 0.5rem 1rem; background: #4CAF50; diff --git a/frontend/src/components/ConfigPanel.jsx b/frontend/src/components/ConfigPanel.jsx index eb4855b..b4ef66a 100644 --- a/frontend/src/components/ConfigPanel.jsx +++ b/frontend/src/components/ConfigPanel.jsx @@ -10,17 +10,18 @@ const ConfigPanel = () => { const [message, setMessage] = useState('') // 预设方案配置 + // 注意:百分比配置使用整数形式(如2.0表示2%),在应用时会转换为小数(0.02) const presets = { conservative: { name: '保守配置', desc: '适合新手,风险较低,交易频率适中', configs: { SCAN_INTERVAL: 3600, - MIN_CHANGE_PERCENT: 2.0, + MIN_CHANGE_PERCENT: 2.0, // 2% MIN_SIGNAL_STRENGTH: 5, TOP_N_SYMBOLS: 10, MAX_SCAN_SYMBOLS: 150, - MIN_VOLATILITY: 0.02 + MIN_VOLATILITY: 0.02 // 保持小数形式(波动率) } }, balanced: { @@ -28,11 +29,11 @@ const ConfigPanel = () => { desc: '推荐使用,平衡频率和质量', configs: { SCAN_INTERVAL: 600, - MIN_CHANGE_PERCENT: 1.5, + MIN_CHANGE_PERCENT: 1.5, // 1.5% MIN_SIGNAL_STRENGTH: 4, TOP_N_SYMBOLS: 12, MAX_SCAN_SYMBOLS: 250, - MIN_VOLATILITY: 0.018 + MIN_VOLATILITY: 0.018 // 保持小数形式(波动率) } }, aggressive: { @@ -40,11 +41,11 @@ const ConfigPanel = () => { desc: '晚间波动大时使用,交易频率高', configs: { SCAN_INTERVAL: 300, - MIN_CHANGE_PERCENT: 1.0, + MIN_CHANGE_PERCENT: 1.0, // 1% MIN_SIGNAL_STRENGTH: 3, TOP_N_SYMBOLS: 18, MAX_SCAN_SYMBOLS: 350, - MIN_VOLATILITY: 0.015 + MIN_VOLATILITY: 0.015 // 保持小数形式(波动率) } } } @@ -267,10 +268,15 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => { // 值发生变化,保存 let finalValue = localValue if (config.type === 'number') { - finalValue = parseFloat(localValue) || 0 - // 百分比配置需要转换 + const numValue = parseFloat(localValue) + if (isNaN(numValue)) { + // 如果输入为空或无效,不保存 + return + } + finalValue = numValue + // 百分比配置需要转换:用户输入的是整数(如5),需要转换为小数(0.05) if (label.includes('PERCENT')) { - finalValue = finalValue + finalValue = finalValue / 100 } } else if (config.type === 'boolean') { finalValue = localValue === 'true' || localValue === true @@ -292,8 +298,9 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => { } } + // 显示值:百分比配置显示为整数(如5),其他保持原样 const displayValue = config.type === 'number' && label.includes('PERCENT') - ? (localValue * 100).toFixed(2) + ? (localValue === '' || isNaN(localValue) ? '' : Math.round(localValue * 100)) : localValue if (config.type === 'boolean') { @@ -402,19 +409,31 @@ const ConfigItem = ({ label, config, onUpdate, disabled }) => {
{ - const newValue = config.type === 'number' && label.includes('PERCENT') - ? parseFloat(e.target.value) / 100 - : e.target.value + // 百分比配置:用户直接输入整数(如5),不转换,保存时再转换 + // 其他数字配置:直接使用输入值 + let newValue + if (config.type === 'number' && label.includes('PERCENT')) { + // 百分比配置:保持整数形式,允许空值 + const numValue = parseFloat(e.target.value) + newValue = isNaN(numValue) ? '' : numValue + } else if (config.type === 'number') { + // 其他数字配置:允许空值 + const numValue = parseFloat(e.target.value) + newValue = isNaN(numValue) ? '' : numValue + } else { + newValue = e.target.value + } handleChange(newValue) }} onBlur={handleBlur} onKeyPress={handleKeyPress} disabled={disabled} - step={config.type === 'number' ? '0.01' : undefined} + step={config.type === 'number' && label.includes('PERCENT') ? '1' : (config.type === 'number' ? '0.01' : undefined)} className={isEditing ? 'editing' : ''} /> + {label.includes('PERCENT') && %} {isEditing && (