"use client"; import { useEffect, useState, useCallback } from "react"; import { authFetch } from "@/lib/auth"; import { useAuth } from "@/lib/auth"; import Link from "next/link"; import { TrendingUp, TrendingDown, Minus, Clock, Activity, AlertCircle, CheckCircle, PauseCircle, } from "lucide-react"; interface StrategyCard { id: string; display_name: string; status: "running" | "paused" | "error"; started_at: number; initial_balance: number; current_balance: number; net_usdt: number; net_r: number; trade_count: number; win_rate: number; avg_win_r: number; avg_loss_r: number; open_positions: number; pnl_usdt_24h: number; pnl_r_24h: number; std_r: number; last_trade_at: number | null; } function formatDuration(ms: number): string { const totalSec = Math.floor((Date.now() - ms) / 1000); const d = Math.floor(totalSec / 86400); const h = Math.floor((totalSec % 86400) / 3600); const m = Math.floor((totalSec % 3600) / 60); if (d > 0) return `${d}天 ${h}小时`; if (h > 0) return `${h}小时 ${m}分`; return `${m}分钟`; } function formatTime(ms: number | null): string { if (!ms) return "—"; const d = new Date(ms); return d.toLocaleString("zh-CN", { timeZone: "Asia/Shanghai", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hour12: false, }); } function StatusBadge({ status }: { status: string }) { if (status === "running") { return ( 运行中 ); } if (status === "paused") { return ( 已暂停 ); } return ( 异常 ); } function StrategyCardComponent({ s }: { s: StrategyCard }) { const isProfit = s.net_usdt >= 0; const is24hProfit = s.pnl_usdt_24h >= 0; const balancePct = ((s.current_balance / s.initial_balance) * 100).toFixed(1); return (
{/* Header */}

{s.display_name}

已运行 {formatDuration(s.started_at)}
{isProfit ? "+" : ""}{s.net_usdt.toLocaleString()} U
{balancePct}% 余额
{/* Balance Bar */}
当前余额 {s.current_balance.toLocaleString()} / {s.initial_balance.toLocaleString()} USDT
= s.initial_balance ? "bg-emerald-500" : "bg-red-500"}`} style={{ width: `${Math.min(100, Math.max(0, (s.current_balance / s.initial_balance) * 100))}%` }} />
{/* Stats Grid */}
胜率
= 50 ? "text-emerald-400" : s.win_rate >= 45 ? "text-yellow-400" : "text-red-400"}`}> {s.win_rate}%
净R
= 0 ? "text-emerald-400" : "text-red-400"}`}> {s.net_r >= 0 ? "+" : ""}{s.net_r}R
交易数
{s.trade_count}
{/* P&L Ratio */}
平均赢
+{s.avg_win_r}R
平均亏
{s.avg_loss_r}R
{/* 24h & Last Trade */}
{is24hProfit ? ( ) : ( )} 24h {is24hProfit ? "+" : ""}{s.pnl_usdt_24h.toLocaleString()} U ({is24hProfit ? "+" : ""}{s.pnl_r_24h}R)
{s.open_positions > 0 ? ( {s.open_positions}仓持仓中 ) : ( 上次: {formatTime(s.last_trade_at)} )}
); } export default function StrategyPlazaPage() { const { token } = useAuth(); const [strategies, setStrategies] = useState([]); const [loading, setLoading] = useState(true); const [lastUpdated, setLastUpdated] = useState(null); const fetchData = useCallback(async () => { try { const res = await authFetch("/api/strategy-plaza"); const data = await res.json(); setStrategies(data.strategies || []); setLastUpdated(new Date()); } catch (e) { console.error(e); } finally { setLoading(false); } }, []); useEffect(() => { fetchData(); const interval = setInterval(fetchData, 30000); return () => clearInterval(interval); }, [fetchData]); if (loading) { return (
加载中...
); } return (
{/* Header */}

策略广场

点击策略卡片查看信号引擎和模拟盘详情

{lastUpdated ? ( <> {lastUpdated.toLocaleTimeString("zh-CN", { timeZone: "Asia/Shanghai", hour12: false })} 更新 ) : null}
{/* Strategy Cards */}
{strategies.map((s) => ( ))}
{strategies.length === 0 && (
暂无策略数据
)}
); }