diff --git a/frontend/app/strategy-plaza/page.tsx b/frontend/app/strategy-plaza/page.tsx index 27038b5..bf67953 100644 --- a/frontend/app/strategy-plaza/page.tsx +++ b/frontend/app/strategy-plaza/page.tsx @@ -317,6 +317,16 @@ export default function StrategyPlazaPage() { const [lastUpdated, setLastUpdated] = useState(null); const [addBalanceTarget, setAddBalanceTarget] = useState(null); + type SymbolFilter = "ALL" | "BTCUSDT" | "ETHUSDT" | "XRPUSDT" | "SOLUSDT"; + type StatusFilter = "all" | "running" | "paused" | "error"; + type PnlFilter = "all" | "positive" | "negative"; + type SortKey = "recent" | "net_usdt_desc" | "net_usdt_asc" | "pnl24h_desc" | "pnl24h_asc"; + + const [symbolFilter, setSymbolFilter] = useState("ALL"); + const [statusFilter, setStatusFilter] = useState("all"); + const [pnlFilter, setPnlFilter] = useState("all"); + const [sortKey, setSortKey] = useState("net_usdt_desc"); + const fetchData = useCallback(async () => { try { const res = await authFetch("/api/strategies"); @@ -350,6 +360,33 @@ export default function StrategyPlazaPage() { } }; + const filteredStrategies = strategies + .filter((s) => { + if (symbolFilter !== "ALL" && s.symbol !== symbolFilter) return false; + if (statusFilter !== "all" && s.status !== statusFilter) return false; + if (pnlFilter === "positive" && s.net_usdt <= 0) return false; + if (pnlFilter === "negative" && s.net_usdt >= 0) return false; + return true; + }) + .sort((a, b) => { + switch (sortKey) { + case "net_usdt_desc": + return b.net_usdt - a.net_usdt; + case "net_usdt_asc": + return a.net_usdt - b.net_usdt; + case "pnl24h_desc": + return b.pnl_usdt_24h - a.pnl_usdt_24h; + case "pnl24h_asc": + return a.pnl_usdt_24h - b.pnl_usdt_24h; + case "recent": + default: { + const aTs = a.last_trade_at ?? a.started_at ?? 0; + const bTs = b.last_trade_at ?? b.started_at ?? 0; + return bTs - aTs; + } + } + }); + if (loading) { return (
@@ -383,9 +420,101 @@ export default function StrategyPlazaPage() {
+ {/* Filters & Sorting */} +
+ {/* 左侧:币种 + 盈亏过滤 */} +
+
+ 币种: + {(["ALL", "BTCUSDT", "ETHUSDT", "XRPUSDT", "SOLUSDT"] as SymbolFilter[]).map((sym) => { + const label = sym === "ALL" ? "全部" : sym.replace("USDT", ""); + const active = symbolFilter === sym; + return ( + + ); + })} +
+
+ 盈亏: + {[ + { key: "all" as PnlFilter, label: "全部" }, + { key: "positive" as PnlFilter, label: "仅盈利" }, + { key: "negative" as PnlFilter, label: "仅亏损" }, + ].map((opt) => { + const active = pnlFilter === opt.key; + return ( + + ); + })} +
+
+ + {/* 右侧:状态 + 排序 */} +
+
+ 状态: + {[ + { key: "all" as StatusFilter, label: "全部" }, + { key: "running" as StatusFilter, label: "运行中" }, + { key: "paused" as StatusFilter, label: "已暂停" }, + { key: "error" as StatusFilter, label: "异常" }, + ].map((opt) => { + const active = statusFilter === opt.key; + return ( + + ); + })} +
+
+ 排序: + +
+
+
+ {/* Strategy Cards */}
- {strategies.map((s) => ( + {filteredStrategies.map((s) => ( - {strategies.length === 0 && ( + {filteredStrategies.length === 0 && (

暂无运行中的策略