106 lines
3.7 KiB
JavaScript
106 lines
3.7 KiB
JavaScript
import React, { useEffect, useState } from 'react'
|
||
import { api } from '../services/api'
|
||
import { UserAccountGroup, CreateUserForm } from './AdminShared'
|
||
import './AdminDashboard.css'
|
||
|
||
export default function AdminUserManagement() {
|
||
const [data, setData] = useState(null)
|
||
const [loading, setLoading] = useState(true)
|
||
const [error, setError] = useState(null)
|
||
|
||
const loadData = async () => {
|
||
try {
|
||
if (!data) setLoading(true)
|
||
const [usersRes, dashboardRes, servicesRes, accountsRes] = await Promise.all([
|
||
api.get('/admin/users/detailed').catch(() => ({ data: [] })),
|
||
api.getAdminDashboard(),
|
||
api.get('/system/trading/services').catch(() => ({ data: { services: [] } })),
|
||
api.get('/accounts').catch(() => ({ data: [] }))
|
||
])
|
||
const users = usersRes.data || []
|
||
const globalStats = dashboardRes
|
||
const services = servicesRes.data?.services || []
|
||
const allAccounts = accountsRes.data || []
|
||
const statsMap = {}
|
||
globalStats.accounts?.forEach(a => { statsMap[a.id] = a })
|
||
const serviceMap = {}
|
||
services.forEach(s => {
|
||
const match = s.program?.match(/auto_sys_acc(\d+)/)
|
||
if (match) serviceMap[match[1]] = s
|
||
})
|
||
const enrichedUsers = users.map(u => ({
|
||
...u,
|
||
accounts: (u.accounts || []).map(acc => ({
|
||
...acc,
|
||
total_balance: statsMap[acc.id]?.total_balance ?? 0,
|
||
total_pnl: statsMap[acc.id]?.total_pnl ?? 0,
|
||
open_positions: statsMap[acc.id]?.open_positions ?? 0,
|
||
serviceStatus: serviceMap[acc.id]
|
||
}))
|
||
}))
|
||
setData({ users: enrichedUsers, allAccounts })
|
||
setError(null)
|
||
} catch (err) {
|
||
setError(err?.message)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
const handleServiceAction = async (accountId, action) => {
|
||
if (action === 'refresh') { loadData(); return }
|
||
if (!window.confirm(`确定要${action === 'start' ? '启动' : '停止'}账号 #${accountId} 的交易服务吗?`)) return
|
||
try {
|
||
await api.post(`/accounts/${accountId}/service/${action}`)
|
||
setTimeout(loadData, 1000)
|
||
} catch (e) {
|
||
alert(`操作失败: ${e?.message || '未知错误'}`)
|
||
}
|
||
}
|
||
|
||
useEffect(() => {
|
||
loadData()
|
||
const t = setInterval(loadData, 30000)
|
||
return () => clearInterval(t)
|
||
}, [])
|
||
useEffect(() => {
|
||
const onUpdated = () => loadData()
|
||
window.addEventListener('ats:accounts:updated', onUpdated)
|
||
return () => window.removeEventListener('ats:accounts:updated', onUpdated)
|
||
}, [])
|
||
|
||
if (loading && !data) return <div className="loading">加载中...</div>
|
||
if (error) return <div className="error">加载失败: {error}</div>
|
||
if (!data) return null
|
||
|
||
const { users, allAccounts } = data
|
||
return (
|
||
<div className="admin-dashboard">
|
||
<div className="dashboard-header">
|
||
<h2>用户管理</h2>
|
||
<button className="refresh-btn" onClick={loadData}>刷新</button>
|
||
</div>
|
||
<div className="users-section">
|
||
<h3>用户管理 ({users.length})</h3>
|
||
<div className="users-section-grid">
|
||
<div className="create-user-block">
|
||
<h4 className="create-user-title">➕ 添加用户</h4>
|
||
<p className="create-user-desc">创建新用户后,可在下方为其关联交易账号。</p>
|
||
<CreateUserForm onSuccess={loadData} />
|
||
</div>
|
||
<div className="users-list">
|
||
{users.map(user => (
|
||
<UserAccountGroup
|
||
key={user.id}
|
||
user={user}
|
||
allAccounts={allAccounts}
|
||
onServiceAction={handleServiceAction}
|
||
/>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
}
|