From 66d68e319fa19ce9ba005a281646bd714ecf6a5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Thu, 22 Jan 2026 11:32:53 +0800 Subject: [PATCH] a --- frontend/src/components/GlobalConfig.jsx | 196 +++++++++++++++++------ 1 file changed, 149 insertions(+), 47 deletions(-) diff --git a/frontend/src/components/GlobalConfig.jsx b/frontend/src/components/GlobalConfig.jsx index 33a900b..bca3526 100644 --- a/frontend/src/components/GlobalConfig.jsx +++ b/frontend/src/components/GlobalConfig.jsx @@ -39,10 +39,8 @@ const GlobalConfig = ({ currentUser }) => { ]) const isAdmin = (currentUser?.role || '') === 'admin' - const globalStrategyAccountId = parseInt(String(configMeta?.global_strategy_account_id || '1'), 10) || 1 - const isGlobalStrategyAccount = isAdmin && currentAccountId === globalStrategyAccountId - - // 预设方案配置 + + // 预设方案配置(必须在函数定义之前) const presets = { swing: { name: '波段回归(推荐)', @@ -184,6 +182,104 @@ const GlobalConfig = ({ currentUser }) => { } } + // 所有函数定义(必须在 useEffect 之前) + const loadUsers = async () => { + try { + const list = await api.getUsers() + setUsers(Array.isArray(list) ? list : []) + } catch (error) { + setMessage('加载用户列表失败: ' + (error.message || '未知错误')) + } finally { + setLoading(false) + } + } + + const loadAccounts = async () => { + try { + const list = await api.getAccounts() + setAccounts(Array.isArray(list) ? list : []) + } catch (error) { + console.error('加载账号列表失败:', error) + } + } + + const loadConfigMeta = async () => { + try { + const m = await api.getConfigMeta() + setConfigMeta(m || null) + } catch (e) { + setConfigMeta(null) + } + } + + const loadConfigs = async () => { + try { + const data = await api.getConfigs() + setConfigs(data) + } catch (error) { + console.error('Failed to load configs:', error) + } + } + + const loadSystemStatus = async () => { + try { + const res = await api.getTradingSystemStatus() + setSystemStatus(res) + } catch (error) { + // 静默失败 + } + } + + const loadBackendStatus = async () => { + try { + const res = await api.getBackendStatus() + setBackendStatus(res) + } catch (error) { + // 静默失败 + } + } + + // 检测当前配置匹配哪个预设方案 + const detectCurrentPreset = () => { + if (!configs || Object.keys(configs).length === 0) return null + + for (const [presetKey, preset] of Object.entries(presets)) { + let match = true + for (const [key, expectedValue] of Object.entries(preset.configs)) { + const currentConfig = configs[key] + if (!currentConfig) { + match = false + break + } + + let currentValue = currentConfig.value + if (key.includes('PERCENT') || key.includes('PCT')) { + if (PCT_LIKE_KEYS.has(key)) { + currentValue = currentValue <= 0.05 ? currentValue * 100 : currentValue + } else { + currentValue = currentValue * 100 + } + } + + if (typeof expectedValue === 'number' && typeof currentValue === 'number') { + if (Math.abs(currentValue - expectedValue) > 0.01) { + match = false + break + } + } else if (currentValue !== expectedValue) { + match = false + break + } + } + + if (match) { + return presetKey + } + } + + return null + } + useEffect(() => { loadUsers() loadAccounts() @@ -199,7 +295,8 @@ const GlobalConfig = ({ currentUser }) => { }, 3000) return () => clearInterval(timer) } - }, []) + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isAdmin]) const loadUsers = async () => { try { @@ -346,46 +443,6 @@ const GlobalConfig = ({ currentUser }) => { } } - // 预设方案函数 - const detectCurrentPreset = () => { - if (!configs || Object.keys(configs).length === 0) return null - - for (const [presetKey, preset] of Object.entries(presets)) { - let match = true - for (const [key, expectedValue] of Object.entries(preset.configs)) { - const currentConfig = configs[key] - if (!currentConfig) { - match = false - break - } - - let currentValue = currentConfig.value - if (key.includes('PERCENT') || key.includes('PCT')) { - if (PCT_LIKE_KEYS.has(key)) { - currentValue = currentValue <= 0.05 ? currentValue * 100 : currentValue - } else { - currentValue = currentValue * 100 - } - } - - if (typeof expectedValue === 'number' && typeof currentValue === 'number') { - if (Math.abs(currentValue - expectedValue) > 0.01) { - match = false - break - } - } else if (currentValue !== expectedValue) { - match = false - break - } - } - - if (match) { - return presetKey - } - } - - return null - } const applyPreset = async (presetKey) => { const preset = presets[presetKey] @@ -518,10 +575,45 @@ const GlobalConfig = ({ currentUser }) => { return a.key.localeCompare(b.key) }) + // 临时获取当前配置以检测预设 + const tempConfigs = data || {} + let detectedPreset = null + for (const [presetKey, preset] of Object.entries(presets)) { + let match = true + for (const [key, expectedValue] of Object.entries(preset.configs)) { + const currentConfig = tempConfigs[key] + if (!currentConfig) { + match = false + break + } + let currentValue = currentConfig.value + if (key.includes('PERCENT') || key.includes('PCT')) { + if (PCT_LIKE_KEYS.has(key)) { + currentValue = currentValue <= 0.05 ? currentValue * 100 : currentValue + } else { + currentValue = currentValue * 100 + } + } + if (typeof expectedValue === 'number' && typeof currentValue === 'number') { + if (Math.abs(currentValue - expectedValue) > 0.01) { + match = false + break + } + } else if (currentValue !== expectedValue) { + match = false + break + } + } + if (match) { + detectedPreset = presetKey + break + } + } + const snapshot = { fetched_at: now.toISOString(), note: 'display_value 对 PERCENT/PCT 做了百分比换算;敏感字段可选择脱敏/明文。', - preset_detected: detectCurrentPreset(), + preset_detected: detectedPreset, system_status: systemStatus ? { running: !!systemStatus.running, pid: systemStatus.pid || null, @@ -577,7 +669,17 @@ const GlobalConfig = ({ currentUser }) => { } } - const currentPreset = detectCurrentPreset() + // 计算全局策略账号ID(依赖 configMeta) + const globalStrategyAccountId = React.useMemo(() => { + return parseInt(String(configMeta?.global_strategy_account_id || '1'), 10) || 1 + }, [configMeta]) + + const isGlobalStrategyAccount = isAdmin && currentAccountId === globalStrategyAccountId + + // 计算当前预设(在 render 时计算,依赖 configs) + const currentPreset = React.useMemo(() => { + return detectCurrentPreset() + }, [configs]) const handleCreateUser = async () => { if (!newUser.username || !newUser.password) {