From 390df86a79220a225f6f3adbaa7699074cad7732 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Mon, 25 May 2026 03:53:46 +0800 Subject: [PATCH] feat: implement ScanTerminalDashboard component for weather market intelligence --- .../dashboard/ScanTerminalDashboard.tsx | 240 ++++++++++++------ 1 file changed, 169 insertions(+), 71 deletions(-) diff --git a/frontend/components/dashboard/ScanTerminalDashboard.tsx b/frontend/components/dashboard/ScanTerminalDashboard.tsx index 8947bcf4..ebd3dcee 100644 --- a/frontend/components/dashboard/ScanTerminalDashboard.tsx +++ b/frontend/components/dashboard/ScanTerminalDashboard.tsx @@ -51,6 +51,7 @@ import { getGapColor, getSignalLabel, getSignalState, + TRADING_REGIONS, } from "@/components/dashboard/scan-terminal/continent-grouping"; import { MobileCityCard } from "@/components/dashboard/scan-terminal/MobileCityCard"; import { MobileRegionTabs } from "@/components/dashboard/scan-terminal/MobileRegionTabs"; @@ -347,16 +348,9 @@ function PolyWeatherTerminal({ window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [searchInputRef, setSearchQuery]); - const approveRows = rows - .filter((row) => ["Approve", "Tradable"].includes(decisionLabel(row))) - .slice(0, 8); - const watchRows = rows - .filter((row) => decisionLabel(row) === "Watch" || !row.tradable) - .slice(0, 8); - const selectedSignal = selectedRow ? getSignalState(selectedRow) : "data" as const; - const selectedLabel = selectedRow ? getSignalLabel(selectedSignal, isEn) : ""; const [navExpanded, setNavExpanded] = useState(false); const [activeNavKey, setActiveNavKey] = useState("contracts"); + const [selectedRegionKey, setSelectedRegionKey] = useState("all"); const NAV_ITEMS = [ { key: "contracts", Icon: Table2, labelEn: "Contracts", labelZh: "天气合约" }, @@ -367,9 +361,40 @@ function PolyWeatherTerminal({ { key: "markets", Icon: Activity, labelEn: "Markets", labelZh: "市场概览" }, ]; + const regionTabs = useMemo(() => { + return [ + { key: "all", labelEn: "ALL", labelZh: "全部" }, + ...TRADING_REGIONS.map((r) => ({ + key: r.key, + labelEn: r.labelEn.toUpperCase(), + labelZh: r.labelZh, + })), + ]; + }, [isEn]); + + const filteredRegionRows = useMemo(() => { + if (selectedRegionKey === "all") return rows; + return rows.filter((row) => String(row.trading_region).toLowerCase() === selectedRegionKey); + }, [rows, selectedRegionKey]); + + const approveRows = useMemo(() => { + return filteredRegionRows + .filter((row) => ["Approve", "Tradable"].includes(decisionLabel(row))) + .slice(0, 8); + }, [filteredRegionRows]); + + const watchRows = useMemo(() => { + return filteredRegionRows + .filter((row) => decisionLabel(row) === "Watch" || !row.tradable) + .slice(0, 8); + }, [filteredRegionRows]); + + const selectedSignal = selectedRow ? getSignalState(selectedRow) : "data" as const; + const selectedLabel = selectedRow ? getSignalLabel(selectedSignal, isEn) : ""; + const continentGroups = useMemo( - () => buildContinentGroups(rows, isEn), - [rows, isEn] + () => buildContinentGroups(filteredRegionRows, isEn), + [filteredRegionRows, isEn] ); const [mobileTab, setMobileTab] = useState("active_signals"); const mobileActiveGroup = useMemo( @@ -381,14 +406,19 @@ function PolyWeatherTerminal({ setMobileTab(continentGroups[0].key); } }, [continentGroups, mobileTab]); - const avgEdge = - rows.reduce((sum, row) => sum + Number(row.edge_percent || 0), 0) / - Math.max(rows.length, 1); - const totalLiquidity = rows.reduce( - (sum, row) => - sum + Number(row.book_liquidity || row.market_liquidity || row.volume || 0), - 0, - ); + + const avgEdge = useMemo(() => { + const list = filteredRegionRows; + return list.reduce((sum, row) => sum + Number(row.edge_percent || 0), 0) / Math.max(list.length, 1); + }, [filteredRegionRows]); + + const totalLiquidity = useMemo(() => { + const list = filteredRegionRows; + return list.reduce( + (sum, row) => sum + Number(row.book_liquidity || row.market_liquidity || row.volume || 0), + 0 + ); + }, [filteredRegionRows]); return (
@@ -566,63 +596,131 @@ function PolyWeatherTerminal({
{/* Column 1 */}
- -
-
-
- {t("rows", isEn)} -
-
{rows.length}
-
-
-
- {t("avgEdge", isEn)} -
-
- {pct(avgEdge)} -
-
-
-
- {t("liquidity", isEn)} -
-
- {money(totalLiquidity)} -
-
-
-
- -
-
- - -
- {(approveRows.length ? approveRows : rows.slice(0, 5)).map((row) => ( + {/* Koyfin-style Region Selector */} +
+ {regionTabs.map((tab) => { + const isActive = selectedRegionKey === tab.key; + return ( - ))} -
- + ); + })} +
+ + {activeNavKey === "signals" ? ( + <> + +
+ {approveRows.map((row) => ( + + ))} + {approveRows.length === 0 && ( +
+ {isEn ? "No approved signals in this timezone" : "该时区暂无已确认信号"} +
+ )} +
+
+ + +
+ +
+
+ + ) : ( + <> + +
+
+
+ {t("rows", isEn)} +
+
{filteredRegionRows.length}
+
+
+
+ {t("avgEdge", isEn)} +
+
+ {pct(avgEdge)} +
+
+
+
+ {t("liquidity", isEn)} +
+
+ {money(totalLiquidity)} +
+
+
+
+ +
+
+ + +
+ {(approveRows.length ? approveRows : rows.slice(0, 5)).map((row) => ( + + ))} +
+
+ + )}
{/* Column 2 */}