From 1c1580b344d7897dc4423a2d7802d10ac74d1d2d 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 21:49:42 +0800 Subject: [PATCH] a --- frontend/src/components/AccountSelector.jsx | 72 ++++++++++++++++++--- frontend/src/components/GlobalConfig.jsx | 66 ++++++++++++++----- frontend/src/store/appSlice.js | 18 +++++- 3 files changed, 128 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/AccountSelector.jsx b/frontend/src/components/AccountSelector.jsx index f4c295e..1d0ca9d 100644 --- a/frontend/src/components/AccountSelector.jsx +++ b/frontend/src/components/AccountSelector.jsx @@ -107,11 +107,37 @@ const AccountSelector = ({ onChanged }) => { const optionsKey = options.map((x) => x.id).join(',') useEffect(() => { - if (!options.length) return - if (options.some((a) => a.id === accountId)) return - const firstActive = options.find((a) => String(a?.status || 'active') === 'active') || options[0] + if (!options.length) { + // 如果没有账号,清空 accountId + if (accountId) { + dispatch(setAccountId(null)) + } + return + } + + // 检查当前选中的账号是否在新列表中且是 active 的 + const currentAccount = options.find((a) => a.id === accountId) + if (currentAccount) { + // 如果当前账号是 disabled,需要切换到 active 账号 + if (String(currentAccount?.status || 'active') === 'disabled') { + const firstActive = options.find((a) => String(a?.status || 'active') === 'active') + if (firstActive) { + dispatch(setAccountId(parseInt(String(firstActive.id || ''), 10))) + } else { + // 如果没有 active 账号,清空 accountId + dispatch(setAccountId(null)) + } + } + return + } + + // 如果当前账号不在新列表中,选择第一个 active 账号 + const firstActive = options.find((a) => String(a?.status || 'active') === 'active') if (firstActive) { dispatch(setAccountId(parseInt(String(firstActive.id || ''), 10))) + } else { + // 如果没有 active 账号,清空 accountId + dispatch(setAccountId(null)) } }, [optionsKey, accountId, dispatch]) @@ -123,20 +149,46 @@ const AccountSelector = ({ onChanged }) => { value={accountId || ''} onChange={(e) => { const v = parseInt(e.target.value, 10) - dispatch(setAccountId(Number.isFinite(v) && v > 0 ? v : 1)) + if (Number.isFinite(v) && v > 0) { + // 检查选中的账号是否是 disabled + const selectedAccount = options.find((a) => a.id === v) + if (selectedAccount && String(selectedAccount?.status || 'active') === 'disabled') { + // 如果选中的是 disabled 账号,不允许选择,保持当前值 + return + } + dispatch(setAccountId(v)) + } else { + dispatch(setAccountId(null)) + } }} title="切换账号后:配置/持仓/交易记录/统计会按账号隔离;推荐仍是全局" disabled={isAdmin && !effectiveUserId} > {options.length === 0 ? ( + ) : accountId === null ? ( + <> + + {options.map((a) => { + const isDisabled = String(a?.status || 'active') === 'disabled' + return ( + + ) + })} + ) : ( - options.map((a) => ( - - )) + options.map((a) => { + const isDisabled = String(a?.status || 'active') === 'disabled' + return ( + + ) + }) )} diff --git a/frontend/src/components/GlobalConfig.jsx b/frontend/src/components/GlobalConfig.jsx index dcb24da..9d33657 100644 --- a/frontend/src/components/GlobalConfig.jsx +++ b/frontend/src/components/GlobalConfig.jsx @@ -361,18 +361,30 @@ const GlobalConfig = () => { const loadConfigs = async () => { try { - // 管理员全局配置:使用全局策略账号的配置,不依赖当前 account - if (isAdmin && configMeta?.global_strategy_account_id) { - const globalAccountId = parseInt(String(configMeta?.global_strategy_account_id || '1'), 10) || 1 + // 管理员全局配置:始终使用全局策略账号的配置,不依赖当前 account + // 即使 configMeta 还没加载完成,也使用默认值 1 + if (isAdmin) { + const globalAccountId = configMeta?.global_strategy_account_id + ? parseInt(String(configMeta.global_strategy_account_id || '1'), 10) || 1 + : 1 // 如果 configMeta 还没加载,使用默认值 1 const data = await api.getGlobalConfigs(globalAccountId) setConfigs(data) } else { - // 非管理员或未加载 configMeta 时,使用默认方式 + // 非管理员:使用默认方式(会受当前 account 影响,但非管理员不应该访问这个页面) const data = await api.getConfigs() setConfigs(data) } } catch (error) { console.error('Failed to load configs:', error) + // 如果加载失败,尝试使用默认值 1 重试一次 + if (isAdmin) { + try { + const data = await api.getGlobalConfigs(1) + setConfigs(data) + } catch (retryError) { + console.error('Retry load configs with accountId=1 failed:', retryError) + } + } } } @@ -440,11 +452,20 @@ const GlobalConfig = () => { loadAccounts() // 只有管理员才加载配置和系统状态 if (isAdmin) { - // 先加载 configMeta,再加载 configs(因为 loadConfigs 需要 global_strategy_account_id) + // 立即加载 configs(不等待 configMeta,使用默认值 1) + // 同时加载 configMeta,加载完成后会触发重新加载 configs(如果 global_strategy_account_id 不是 1) + loadConfigs().catch(() => {}) loadConfigMeta() .then(() => { - // configMeta 加载完成后,再加载 configs - loadConfigs().catch(() => {}) + // configMeta 加载完成后,如果 global_strategy_account_id 不是 1,重新加载 configs + // 这样可以确保使用正确的全局策略账号ID + const globalAccountId = configMeta?.global_strategy_account_id + ? parseInt(String(configMeta.global_strategy_account_id || '1'), 10) || 1 + : 1 + // 如果 globalAccountId 不是 1,说明之前加载的是默认值,需要重新加载 + if (globalAccountId !== 1) { + loadConfigs().catch(() => {}) + } }) .catch(() => {}) // 静默失败 loadSystemStatus().catch(() => {}) // 静默失败 @@ -608,12 +629,15 @@ const GlobalConfig = () => { } }).filter(Boolean) - // 管理员全局配置:应用到全局策略账号 + // 管理员全局配置:始终使用全局策略账号,即使 configMeta 还没加载也使用默认值 1 let response - if (isAdmin && configMeta?.global_strategy_account_id) { - const globalAccountId = parseInt(String(configMeta?.global_strategy_account_id || '1'), 10) || 1 + if (isAdmin) { + const globalAccountId = configMeta?.global_strategy_account_id + ? parseInt(String(configMeta.global_strategy_account_id || '1'), 10) || 1 + : 1 response = await api.updateGlobalConfigsBatch(configItems, globalAccountId) } else { + // 非管理员不应该访问这个页面,但为了安全还是处理一下 response = await api.updateConfigsBatch(configItems) } setMessage(response.message || `已应用${preset.name}`) @@ -654,10 +678,12 @@ const GlobalConfig = () => { } const buildConfigSnapshot = async (includeSecrets) => { - // 管理员全局配置:使用全局策略账号的配置 + // 管理员全局配置:始终使用全局策略账号的配置,即使 configMeta 还没加载也使用默认值 1 let data - if (isAdmin && configMeta?.global_strategy_account_id) { - const globalAccountId = parseInt(String(configMeta?.global_strategy_account_id || '1'), 10) || 1 + if (isAdmin) { + const globalAccountId = configMeta?.global_strategy_account_id + ? parseInt(String(configMeta.global_strategy_account_id || '1'), 10) || 1 + : 1 data = await api.getGlobalConfigs(globalAccountId) } else { data = await api.getConfigs() @@ -1169,10 +1195,16 @@ const GlobalConfig = () => { try { setSaving(true) setMessage('') - // 检查 configMeta 是否存在,如果不存在则使用默认值 1 - const globalAccountId = configMeta?.global_strategy_account_id - ? parseInt(String(configMeta?.global_strategy_account_id || '1'), 10) || 1 - : 1 + // 管理员始终使用全局策略账号,即使 configMeta 还没加载也使用默认值 1 + const globalAccountId = isAdmin + ? (configMeta?.global_strategy_account_id + ? parseInt(String(configMeta.global_strategy_account_id || '1'), 10) || 1 + : 1) + : null + if (!isAdmin || !globalAccountId) { + setMessage('只有管理员可以修改全局配置') + return + } await api.updateGlobalConfigsBatch([{ key, value, diff --git a/frontend/src/store/appSlice.js b/frontend/src/store/appSlice.js index da14209..0a9a483 100644 --- a/frontend/src/store/appSlice.js +++ b/frontend/src/store/appSlice.js @@ -74,6 +74,13 @@ const appSlice = createSlice({ } catch (e) { // ignore } + } else { + // 如果 accountId 为 null,清空 localStorage + try { + localStorage.removeItem(ACCOUNT_ID_STORAGE_KEY) + } catch (e) { + // ignore + } } }, setAccounts: (state, action) => { @@ -97,8 +104,9 @@ const appSlice = createSlice({ // 等待账号列表加载完成后再切换 }, // 切换用户后,账号列表加载完成,自动选择第一个active账号 + // 如果没有 active 账号,不改变当前 accountId(保持为 null 或之前的值) selectFirstActiveAccount: (state) => { - const firstActive = state.accounts.find((a) => String(a?.status || 'active') === 'active') || state.accounts[0] + const firstActive = state.accounts.find((a) => String(a?.status || 'active') === 'active') if (firstActive) { const nextAccountId = parseInt(String(firstActive.id || ''), 10) if (Number.isFinite(nextAccountId) && nextAccountId > 0) { @@ -115,6 +123,14 @@ const appSlice = createSlice({ // ignore } } + } else { + // 如果没有 active 账号,清空 accountId + state.accountId = null + try { + localStorage.removeItem(ACCOUNT_ID_STORAGE_KEY) + } catch (e) { + // ignore + } } }, },