a
This commit is contained in:
parent
ce3a4953f5
commit
0a4bbd3132
|
|
@ -11,14 +11,67 @@ project_root = Path(__file__).parent.parent.parent.parent
|
|||
sys.path.insert(0, str(project_root))
|
||||
sys.path.insert(0, str(project_root / 'backend'))
|
||||
|
||||
from database.models import AccountSnapshot, Trade, MarketScan, TradingSignal
|
||||
from database.models import AccountSnapshot, Trade, MarketScan, TradingSignal, Account
|
||||
from fastapi import HTTPException
|
||||
from api.auth_deps import get_account_id
|
||||
from api.auth_deps import get_account_id, get_admin_user
|
||||
from typing import Dict, Any
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/admin/dashboard")
|
||||
async def get_admin_dashboard_stats(user: Dict[str, Any] = Depends(get_admin_user)):
|
||||
"""获取管理员仪表板数据(所有用户统计)"""
|
||||
try:
|
||||
accounts = Account.list_all()
|
||||
stats = []
|
||||
|
||||
total_assets = 0
|
||||
total_pnl = 0
|
||||
active_accounts = 0
|
||||
|
||||
for acc in accounts:
|
||||
aid = acc['id']
|
||||
# 获取最新快照
|
||||
snapshots = AccountSnapshot.get_recent(1, account_id=aid)
|
||||
acc_stat = {
|
||||
"id": aid,
|
||||
"name": acc['name'],
|
||||
"status": acc['status'],
|
||||
"total_balance": 0,
|
||||
"total_pnl": 0,
|
||||
"open_positions": 0
|
||||
}
|
||||
|
||||
if snapshots:
|
||||
snap = snapshots[0]
|
||||
acc_stat["total_balance"] = snap.get('total_balance', 0)
|
||||
acc_stat["total_pnl"] = snap.get('total_pnl', 0)
|
||||
acc_stat["open_positions"] = snap.get('open_positions', 0)
|
||||
|
||||
total_assets += float(acc_stat["total_balance"])
|
||||
total_pnl += float(acc_stat["total_pnl"])
|
||||
|
||||
if acc['status'] == 'active':
|
||||
active_accounts += 1
|
||||
|
||||
stats.append(acc_stat)
|
||||
|
||||
return {
|
||||
"summary": {
|
||||
"total_accounts": len(accounts),
|
||||
"active_accounts": active_accounts,
|
||||
"total_assets_usdt": total_assets,
|
||||
"total_pnl_usdt": total_pnl
|
||||
},
|
||||
"accounts": stats
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"获取管理员仪表板数据失败: {e}", exc_info=True)
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
|
||||
@router.get("/performance")
|
||||
async def get_performance_stats(
|
||||
days: int = Query(7, ge=1, le=365),
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import ConfigPanel from './components/ConfigPanel'
|
|||
import ConfigGuide from './components/ConfigGuide'
|
||||
import TradeList from './components/TradeList'
|
||||
import StatsDashboard from './components/StatsDashboard'
|
||||
import AdminDashboard from './components/AdminDashboard'
|
||||
import Recommendations from './components/Recommendations'
|
||||
import LogMonitor from './components/LogMonitor'
|
||||
import AccountSelector from './components/AccountSelector'
|
||||
|
|
@ -67,19 +68,23 @@ function App() {
|
|||
<div className="nav-container">
|
||||
<div className="nav-left">
|
||||
<h1 className="nav-title">自动交易系统</h1>
|
||||
<AccountSelector />
|
||||
{!isAdmin && <AccountSelector />}
|
||||
</div>
|
||||
<div className="nav-links">
|
||||
<Link to="/">仪表板</Link>
|
||||
{!isAdmin && (
|
||||
<>
|
||||
<Link to="/recommendations">交易推荐</Link>
|
||||
<Link to="/config">配置</Link>
|
||||
<Link to="/trades">交易记录</Link>
|
||||
{isAdmin ? (
|
||||
</>
|
||||
)}
|
||||
{isAdmin && (
|
||||
<>
|
||||
<Link to="/global-config">全局配置</Link>
|
||||
<Link to="/logs">日志监控</Link>
|
||||
</>
|
||||
) : null}
|
||||
)}
|
||||
</div>
|
||||
<div className="nav-user">
|
||||
<span className="nav-user-name">
|
||||
|
|
@ -104,7 +109,7 @@ function App() {
|
|||
|
||||
<main className="main-content">
|
||||
<Routes>
|
||||
<Route path="/" element={<StatsDashboard />} />
|
||||
<Route path="/" element={isAdmin ? <AdminDashboard /> : <StatsDashboard />} />
|
||||
<Route path="/recommendations" element={<Recommendations />} />
|
||||
<Route path="/config" element={<ConfigPanel />} />
|
||||
<Route path="/config/guide" element={<ConfigGuide />} />
|
||||
|
|
|
|||
|
|
@ -376,6 +376,15 @@ export const api = {
|
|||
return response.json();
|
||||
},
|
||||
|
||||
getAdminDashboard: async () => {
|
||||
const response = await fetch(buildUrl('/api/stats/admin/dashboard'), { headers: withAuthHeaders() });
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ detail: '获取管理员仪表板数据失败' }));
|
||||
throw new Error(error.detail || '获取管理员仪表板数据失败');
|
||||
}
|
||||
return response.json();
|
||||
},
|
||||
|
||||
// 平仓操作
|
||||
closePosition: async (symbol) => {
|
||||
const response = await fetch(buildUrl(`/api/account/positions/${symbol}/close`), {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user