diff --git a/frontend/src/components/GlobalConfig.jsx b/frontend/src/components/GlobalConfig.jsx index 90a886f..77101ad 100644 --- a/frontend/src/components/GlobalConfig.jsx +++ b/frontend/src/components/GlobalConfig.jsx @@ -4,6 +4,147 @@ import { api } from '../services/api' import './GlobalConfig.css' import './ConfigPanel.css' // 复用 ConfigPanel 的样式 +// 复用 ConfigPanel 的 ConfigItem 组件 +const ConfigItem = ({ label, config, onUpdate, disabled }) => { + const isPercentKey = label.includes('PERCENT') || label.includes('PCT') + const PCT_LIKE_KEYS = new Set([ + 'LIMIT_ORDER_OFFSET_PCT', + 'ENTRY_MAX_DRIFT_PCT_TRENDING', + 'ENTRY_MAX_DRIFT_PCT_RANGING', + ]) + const isPctLike = PCT_LIKE_KEYS.has(label) + const isRatioPercentKey = isPercentKey && !isPctLike + + const formatPercent = (n) => { + if (typeof n !== 'number' || isNaN(n)) return '' + return n.toFixed(4).replace(/\.?0+$/, '') + } + + const getInitialDisplayValue = (val) => { + if (config.type === 'number' && isPercentKey) { + if (val === null || val === undefined || val === '') { + return '' + } + const numVal = typeof val === 'string' ? parseFloat(val) : val + if (isNaN(numVal)) { + return '' + } + if (isPctLike) { + const pctNum = numVal <= 0.05 ? numVal * 100 : numVal + return formatPercent(pctNum) + } + const percent = numVal <= 1 ? numVal * 100 : numVal + return formatPercent(percent) + } + return val === null || val === undefined ? '' : val + } + + const [value, setValue] = useState(config.value) + const [localValue, setLocalValue] = useState(getInitialDisplayValue(config.value)) + const [isEditing, setIsEditing] = useState(false) + + useEffect(() => { + setValue(config.value) + setIsEditing(false) + setLocalValue(getInitialDisplayValue(config.value)) + }, [config.value]) + + const handleChange = (newValue) => { + setLocalValue(newValue) + setIsEditing(true) + } + + const handleBlur = () => { + if (!isEditing) return + let finalValue = localValue + if (config.type === 'number') { + if (isPercentKey) { + const numVal = parseFloat(localValue) + if (isNaN(numVal)) { + setLocalValue(getInitialDisplayValue(config.value)) + setIsEditing(false) + return + } + if (isPctLike) { + finalValue = numVal <= 1 ? numVal / 100 : numVal / 100 + } else { + finalValue = numVal <= 100 ? numVal / 100 : numVal / 100 + } + } else { + finalValue = parseFloat(localValue) + if (isNaN(finalValue)) { + setLocalValue(getInitialDisplayValue(config.value)) + setIsEditing(false) + return + } + } + } else if (config.type === 'boolean') { + finalValue = localValue === 'true' || localValue === true + } else { + finalValue = localValue + } + onUpdate(finalValue) + setIsEditing(false) + } + + const displayValue = isEditing ? localValue : getInitialDisplayValue(config.value) + + return ( +
+ 修改全局策略配置,所有普通用户账号将使用这些配置(风险旋钮除外) +
+