From 156acc92e01ae4d4cf963db107d027b6aed77d42 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 09:06:10 +0800 Subject: [PATCH] a --- frontend/src/App.jsx | 2 +- frontend/src/components/AccountSelector.jsx | 107 ++++++++++++++++---- frontend/src/components/ConfigPanel.jsx | 6 +- frontend/src/components/StatsDashboard.jsx | 13 ++- frontend/src/components/TradeList.jsx | 15 +-- frontend/src/services/api.js | 20 ++++ 6 files changed, 136 insertions(+), 27 deletions(-) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 57e358a..a37d68a 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -81,7 +81,7 @@ function App() {

自动交易系统

- +
仪表板 diff --git a/frontend/src/components/AccountSelector.jsx b/frontend/src/components/AccountSelector.jsx index 27e5e89..749f1df 100644 --- a/frontend/src/components/AccountSelector.jsx +++ b/frontend/src/components/AccountSelector.jsx @@ -1,23 +1,67 @@ import React, { useEffect, useState } from 'react' import { api, getCurrentAccountId, setCurrentAccountId } from '../services/api' -const AccountSelector = ({ onChanged }) => { +const AccountSelector = ({ onChanged, currentUser }) => { const [accounts, setAccounts] = useState([]) const [accountId, setAccountId] = useState(getCurrentAccountId()) + const [users, setUsers] = useState([]) + const [selectedUserId, setSelectedUserId] = useState(null) + const isAdmin = (currentUser?.role || '') === 'admin' + // 管理员:加载用户列表 useEffect(() => { - const load = () => { - api.getAccounts() - .then((list) => setAccounts(Array.isArray(list) ? list : [])) + if (isAdmin) { + api.getUsers() + .then((list) => { + setUsers(Array.isArray(list) ? list : []) + // 默认选择当前登录用户 + const currentUserId = parseInt(String(currentUser?.id || ''), 10) + if (currentUserId && list.some((u) => parseInt(String(u?.id || ''), 10) === currentUserId)) { + setSelectedUserId(currentUserId) + } else if (list.length > 0) { + setSelectedUserId(parseInt(String(list[0]?.id || ''), 10)) + } + }) + .catch(() => setUsers([])) + } + }, [isAdmin, currentUser?.id]) + + // 管理员:根据选择的用户加载账号列表 + useEffect(() => { + if (isAdmin && selectedUserId) { + api.getUserAccounts(selectedUserId) + .then((list) => { + const accountsList = Array.isArray(list) ? list : [] + setAccounts(accountsList) + // 自动选择第一个active账号 + const firstActive = accountsList.find((a) => String(a?.status || 'active') === 'active') || accountsList[0] + if (firstActive) { + const nextAccountId = parseInt(String(firstActive.id || ''), 10) + if (Number.isFinite(nextAccountId) && nextAccountId > 0) { + setAccountId(nextAccountId) + } + } + }) .catch(() => setAccounts([])) } - load() + }, [isAdmin, selectedUserId]) - // 配置页创建/更新账号后会触发该事件,用于即时刷新下拉列表 - const onUpdated = () => load() - window.addEventListener('ats:accounts:updated', onUpdated) - return () => window.removeEventListener('ats:accounts:updated', onUpdated) - }, []) + // 普通用户:直接加载自己的账号列表 + useEffect(() => { + if (!isAdmin) { + const load = () => { + api.getAccounts() + .then((list) => setAccounts(Array.isArray(list) ? list : [])) + .catch(() => setAccounts([])) + } + load() + + // 配置页创建/更新账号后会触发该事件,用于即时刷新下拉列表 + const onUpdated = () => load() + window.addEventListener('ats:accounts:updated', onUpdated) + return () => window.removeEventListener('ats:accounts:updated', onUpdated) + } + }, [isAdmin]) useEffect(() => { setCurrentAccountId(accountId) @@ -50,22 +94,49 @@ const AccountSelector = ({ onChanged }) => { return (
+ {isAdmin ? ( + <> + 用户 + + + ) : null} 账号
) diff --git a/frontend/src/components/ConfigPanel.jsx b/frontend/src/components/ConfigPanel.jsx index 11054b3..b452308 100644 --- a/frontend/src/components/ConfigPanel.jsx +++ b/frontend/src/components/ConfigPanel.jsx @@ -900,6 +900,7 @@ const ConfigPanel = ({ currentUser }) => {
{/* 我的交易进程(按账号;owner/admin 可启停) */} + {currentAccountMeta && String(currentAccountMeta?.status || 'active') === 'active' ? (

我的交易进程(当前账号 #{accountId})

@@ -967,8 +968,10 @@ const ConfigPanel = ({ currentUser }) => { ) : null}
+ ) : null} {/* 账号密钥(当前账号;owner/admin 可改) */} + {currentAccountMeta && String(currentAccountMeta?.status || 'active') === 'active' ? (

账号密钥(当前账号)

@@ -1037,6 +1040,7 @@ const ConfigPanel = ({ currentUser }) => {
+ ) : null} {/* 系统控制:清缓存 / 启停 / 重启(supervisor) */} {isAdmin ? ( @@ -1495,7 +1499,7 @@ const ConfigPanel = ({ currentUser }) => {
{/* 配置可行性检查提示 */} - {feasibilityCheck && ( + {currentAccountMeta && String(currentAccountMeta?.status || 'active') === 'active' && feasibilityCheck && (

diff --git a/frontend/src/components/StatsDashboard.jsx b/frontend/src/components/StatsDashboard.jsx index 68f5624..f19a979 100644 --- a/frontend/src/components/StatsDashboard.jsx +++ b/frontend/src/components/StatsDashboard.jsx @@ -46,7 +46,18 @@ const StatsDashboard = () => { loadDashboard() loadTradingConfig() // 同时刷新配置 }, 30000) // 每30秒刷新 - return () => clearInterval(interval) + + // 监听账号切换事件,自动重新加载数据 + const handleAccountChange = () => { + loadDashboard() + loadTradingConfig() + } + window.addEventListener('ats:account:changed', handleAccountChange) + + return () => { + clearInterval(interval) + window.removeEventListener('ats:account:changed', handleAccountChange) + } }, []) const loadTradingConfig = async () => { diff --git a/frontend/src/components/TradeList.jsx b/frontend/src/components/TradeList.jsx index 378fb67..d1db965 100644 --- a/frontend/src/components/TradeList.jsx +++ b/frontend/src/components/TradeList.jsx @@ -19,13 +19,16 @@ const TradeList = () => { useEffect(() => { loadData() - // 每30秒自动刷新一次,确保订单状态及时更新 - // const interval = setInterval(() => { - // loadData() - // }, 30000) // 30秒刷新一次 - // return () => clearInterval(interval) - loadData() + // 监听账号切换事件,自动重新加载数据 + const handleAccountChange = () => { + loadData() + } + window.addEventListener('ats:account:changed', handleAccountChange) + + return () => { + window.removeEventListener('ats:account:changed', handleAccountChange) + } }, []) const loadData = async () => { diff --git a/frontend/src/services/api.js b/frontend/src/services/api.js index c3a1348..ee2e662 100644 --- a/frontend/src/services/api.js +++ b/frontend/src/services/api.js @@ -610,4 +610,24 @@ export const api = { } return response.json(); }, + + // 管理员:获取用户列表 + getUsers: async () => { + const response = await fetch(buildUrl('/api/admin/users'), { headers: withAuthHeaders() }); + if (!response.ok) { + const error = await response.json().catch(() => ({ detail: '获取用户列表失败' })); + throw new Error(error.detail || '获取用户列表失败'); + } + return response.json(); + }, + + // 管理员:获取用户关联的账号列表 + getUserAccounts: async (userId) => { + const response = await fetch(buildUrl(`/api/admin/users/${userId}/accounts`), { headers: withAuthHeaders() }); + if (!response.ok) { + const error = await response.json().catch(() => ({ detail: '获取用户账号列表失败' })); + throw new Error(error.detail || '获取用户账号列表失败'); + } + return response.json(); + }, };