diff --git a/frontend/src/components/AdminDashboard.jsx b/frontend/src/components/AdminDashboard.jsx index 23ed7a8..fc8ba03 100644 --- a/frontend/src/components/AdminDashboard.jsx +++ b/frontend/src/components/AdminDashboard.jsx @@ -126,49 +126,259 @@ const UserAccountGroup = ({ user, allAccounts, onServiceAction }) => { {acc.serviceStatus ? ( - - {acc.serviceStatus.state} - + + {acc.serviceStatus.running ? '运行中' : '停止'} + ) : ( - UNKNOWN + 未启动 )} - {Number(acc.total_balance).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} - = 0 ? 'profit' : 'loss'}> - {Number(acc.total_pnl) > 0 ? '+' : ''}{Number(acc.total_pnl).toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} + {acc.total_balance?.toFixed(2) || '-'} + = 0 ? 'profit' : 'loss'}> + {acc.total_pnl?.toFixed(2) || '-'} - {acc.open_positions} + {acc.open_positions || 0} -
- + + + + ))} + + + )} + +
+

新增关联

+
+ + + +
+
+
+ )} + + ) +} + +const AccountManager = ({ accounts, onRefresh }) => { + const [newAccount, setNewAccount] = useState({ name: '', api_key: '', api_secret: '', use_testnet: false, status: 'active' }) + const [credEditId, setCredEditId] = useState(null) + const [credForm, setCredForm] = useState({ api_key: '', api_secret: '', use_testnet: false }) + const [busy, setBusy] = useState(false) + const [message, setMessage] = useState('') + + const notifyAccountsUpdated = () => { + try { + window.dispatchEvent(new Event('ats:accounts:updated')) + } catch (e) { + // ignore + } + } + + const handleCreate = async () => { + if (!newAccount.name.trim()) return + setBusy(true) + setMessage('') + try { + await api.createAccount(newAccount) + setMessage('账号已创建') + setNewAccount({ name: '', api_key: '', api_secret: '', use_testnet: false, status: 'active' }) + if (onRefresh) onRefresh() + notifyAccountsUpdated() + } catch (e) { + setMessage('创建账号失败: ' + (e?.message || '未知错误')) + } finally { + setBusy(false) + } + } + + const handleUpdateStatus = async (account) => { + setBusy(true) + setMessage('') + try { + const next = account.status === 'active' ? 'disabled' : 'active' + await api.updateAccount(account.id, { status: next }) + setMessage(`账号 #${account.id} 已${next === 'active' ? '启用' : '禁用'}`) + if (onRefresh) onRefresh() + notifyAccountsUpdated() + } catch (e) { + setMessage('更新账号失败: ' + (e?.message || '未知错误')) + } finally { + setBusy(false) + } + } + + const handleUpdateCreds = async () => { + if (!credEditId) return + setBusy(true) + setMessage('') + try { + const payload = {} + if (credForm.api_key) payload.api_key = credForm.api_key + if (credForm.api_secret) payload.api_secret = credForm.api_secret + payload.use_testnet = !!credForm.use_testnet + await api.updateAccountCredentials(credEditId, payload) + setMessage(`账号 #${credEditId} 密钥已更新`) + setCredEditId(null) + if (onRefresh) onRefresh() + notifyAccountsUpdated() + } catch (e) { + setMessage('更新密钥失败: ' + (e?.message || '未知错误')) + } finally { + setBusy(false) + } + } + + return ( +
+

系统账号池管理

+ {message &&
{message}
} + +
+ {/* Create Account Card */} +
+

新增账号

+
+ + setNewAccount({ ...newAccount, name: e.target.value })} + placeholder="例如:user_a" + /> +
+
+ + setNewAccount({ ...newAccount, api_key: e.target.value })} + /> +
+
+ + setNewAccount({ ...newAccount, api_secret: e.target.value })} + /> +
+
+ +
+
+ + +
+ +
+ + {/* Account List Card */} +
+

账号列表 ({accounts?.length || 0})

+
+ + + + + + + + + + + + + {(accounts || []).map(a => ( + + + + + + + @@ -176,37 +386,45 @@ const UserAccountGroup = ({ user, allAccounts, onServiceAction }) => { ))}
ID名称状态测试网API配置操作
#{a.id}{a.name} + + {a.status === 'active' ? '启用' : '禁用'} + + {a.use_testnet ? '是' : '否'} + {a.has_api_key ? '✅' : '❌'} / {a.has_api_secret ? '✅' : '❌'} + +
+ -
- )} +
+
+
- {/* 关联管理区域 */} -
- 新增关联: - - - + {/* Credential Edit Modal/Overlay */} + {credEditId && ( +
+
+

更新密钥 (账号 #{credEditId})

+
+ + setCredForm({ ...credForm, api_key: e.target.value })} + /> +
+
+ + setCredForm({ ...credForm, api_secret: e.target.value })} + /> +
+
+ +
+
+ + +
)} @@ -354,6 +572,11 @@ const AdminDashboard = () => { ))}
+ + ) } diff --git a/frontend/src/components/ConfigPanel.jsx b/frontend/src/components/ConfigPanel.jsx index a25ea34..7705443 100644 --- a/frontend/src/components/ConfigPanel.jsx +++ b/frontend/src/components/ConfigPanel.jsx @@ -42,21 +42,9 @@ const ConfigPanel = () => { } } - // 账号管理(超管) - const [accountsAdmin, setAccountsAdmin] = useState([]) - const [accountsBusy, setAccountsBusy] = useState(false) - const [showAccountsAdmin, setShowAccountsAdmin] = useState(false) - const [newAccount, setNewAccount] = useState({ - name: '', - api_key: '', - api_secret: '', - use_testnet: false, - status: 'active', - }) - const [credEditId, setCredEditId] = useState(null) const [credForm, setCredForm] = useState({ api_key: '', api_secret: '', use_testnet: false }) - // “PCT”类配置里有少数是“百分比数值(<=1表示<=1%)”,而不是“0~1比例” + // 预设方案配置 // 例如 LIMIT_ORDER_OFFSET_PCT=0.5 表示 0.5%(而不是 50%) const PCT_LIKE_KEYS = new Set([ 'LIMIT_ORDER_OFFSET_PCT', @@ -489,23 +477,6 @@ const ConfigPanel = () => { // 当accountId变化时,重新加载相关数据(避免重复调用,已在onChanged和定时器中处理) - const loadAccountsAdmin = async () => { - try { - const list = await api.getAccounts() - setAccountsAdmin(Array.isArray(list) ? list : []) - } catch (e) { - setAccountsAdmin([]) - } - } - - const notifyAccountsUpdated = () => { - try { - window.dispatchEvent(new Event('ats:accounts:updated')) - } catch (e) { - // ignore - } - } - // 注意:accountId 变化时的刷新逻辑已在上面的 useEffect 中处理 const checkFeasibility = async () => { @@ -1041,272 +1012,7 @@ const ConfigPanel = () => { ) : null} - {/* 账号管理(超管) */} - {isAdmin ? ( -
-
-

账号管理(多账号)

-
- - -
-
- {showAccountsAdmin ? ( -
-
-
新增账号
-
- - - - - -
- -
-
-
- -
-
账号列表
-
- {(accountsAdmin || []).length ? ( - - - - - - - - - - - - - - {accountsAdmin.map((a) => ( - - - - - - - - - - ))} - -
ID名称状态测试网API KEYSECRET操作
#{a.id}{a.name || '-'} - - {a.status === 'active' ? '启用' : '禁用'} - - {a.use_testnet ? '是' : '否'}{a.api_key_masked || (a.has_api_key ? '已配置' : '未配置')}{a.has_api_secret ? '已配置' : '未配置'} - - -
- ) : ( -
暂无账号(默认账号 #1 会自动存在)
- )} -
-
- - {credEditId ? ( -
-
更新账号 #{credEditId} 的密钥
-
- - - -
- - -
-
-
- ) : null} -
- ) : null} -
- ) : null} {/* 用户提示 */} {!isAdmin && (