From 18fdfc6d0a679e70c4f03e3fb5ec2b03ed4018b4 Mon Sep 17 00:00:00 2001 From: dekun Date: Sun, 2 Aug 2026 10:01:52 +0800 Subject: [PATCH] Fullscreen strategy detail with 5-row equity pagination. Co-authored-by: Cursor --- control/frontend/src/pages/Monitor.tsx | 76 ++++++++++++++++++++------ control/frontend/src/styles.css | 41 ++++++++++---- 2 files changed, 88 insertions(+), 29 deletions(-) diff --git a/control/frontend/src/pages/Monitor.tsx b/control/frontend/src/pages/Monitor.tsx index 3a525bd..2ba1f08 100644 --- a/control/frontend/src/pages/Monitor.tsx +++ b/control/frontend/src/pages/Monitor.tsx @@ -204,6 +204,8 @@ export default function MonitorPage() { const [detailStats, setDetailStats] = useState(null); const [detailStatsErr, setDetailStatsErr] = useState(""); const [detailStatsLoading, setDetailStatsLoading] = useState(false); + const [equityPage, setEquityPage] = useState(0); + const EQUITY_PAGE_SIZE = 5; const applyNodes = useCallback((list: NodeCard[]) => { cachedNodes = list; @@ -215,12 +217,14 @@ export default function MonitorPage() { setDetailStats(null); setDetailStatsErr(""); setDetailStatsLoading(false); + setEquityPage(0); return; } let cancelled = false; setDetailStats(null); setDetailStatsErr(""); setDetailStatsLoading(true); + setEquityPage(0); apiFetch(`/api/nodes/${detailId}/stats`) .then((s) => { if (!cancelled) setDetailStats(s); @@ -431,6 +435,18 @@ export default function MonitorPage() { const detailLegs = Array.isArray(detail?.position?.legs) ? (detail!.position.legs as Record[]) : []; + const equityNewestFirst = detailStats?.equity_curve?.length + ? [...detailStats.equity_curve].reverse() + : []; + const equityPageCount = Math.max( + 1, + Math.ceil(equityNewestFirst.length / EQUITY_PAGE_SIZE), + ); + const equityPageSafe = Math.min(equityPage, equityPageCount - 1); + const equityPageRows = equityNewestFirst.slice( + equityPageSafe * EQUITY_PAGE_SIZE, + equityPageSafe * EQUITY_PAGE_SIZE + EQUITY_PAGE_SIZE, + ); return (
@@ -742,7 +758,7 @@ export default function MonitorPage() {
- {detailStats.equity_curve?.length ? ( + {equityNewestFirst.length ? ( <>

按组盈亏

@@ -754,25 +770,51 @@ export default function MonitorPage() { - {[...detailStats.equity_curve] - .reverse() - .slice(0, 30) - .map((x) => ( - - {x.group_id} - - {fmt(x.realized_pnl, 2)} - - - ))} + {equityPageRows.map((x) => ( + + {x.group_id} + + {fmt(x.realized_pnl, 2)} + + + ))}
- {detailStats.equity_curve.length > 30 ? ( -

- 仅显示最近 30 组(共 {detailStats.equity_curve.length}) -

- ) : null} +
+ + 第 {equityPageSafe + 1}/{equityPageCount} 页 · 每页{" "} + {EQUITY_PAGE_SIZE} 行 · 共 {equityNewestFirst.length}{" "} + 组 + +
+ + +
+
) : (

暂无已平仓组

diff --git a/control/frontend/src/styles.css b/control/frontend/src/styles.css index 5dc82b1..38fa86f 100644 --- a/control/frontend/src/styles.css +++ b/control/frontend/src/styles.css @@ -454,29 +454,46 @@ td { .modal-backdrop { position: fixed; inset: 0; - background: rgba(4, 8, 14, 0.72); - display: grid; - place-items: center; - padding: 16px; + background: rgba(4, 8, 14, 0.92); + display: flex; z-index: 50; } .modal-panel { - width: min(720px, 100%); - max-height: min(90vh, 900px); + width: 100%; + height: 100%; + max-height: none; overflow: auto; background: var(--panel); - border: 1px solid var(--line); - border-radius: 12px; - padding: 18px; + border: none; + border-radius: 0; + padding: 20px 24px 28px; display: flex; flex-direction: column; - gap: 14px; + gap: 16px; } .modal-panel.running { - border-color: rgba(60, 179, 113, 0.65); - box-shadow: 0 0 0 1px rgba(60, 179, 113, 0.2); + box-shadow: inset 0 0 0 2px rgba(60, 179, 113, 0.45); +} + +.pager { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-top: 10px; +} + +.pager-meta { + color: var(--muted); + font-size: 0.85rem; + font-variant-numeric: tabular-nums; +} + +.pager-actions { + display: flex; + gap: 8px; } .modal-head {