From c331c892898ce29f1ad367b3c7cbfbb2a6a4fc43 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Tue, 26 May 2026 07:59:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20fallback=20fetch=20?= =?UTF-8?q?=E4=BE=9D=E8=B5=96=EF=BC=9Arows.length=20=E6=94=B9=E4=B8=BA=20u?= =?UTF-8?q?seRef=20=E6=A0=87=E8=AE=B0=EF=BC=8C=E9=81=BF=E5=85=8D=20termina?= =?UTF-8?q?lData=20=E5=88=B7=E6=96=B0=E6=97=B6=E6=97=A0=E6=84=8F=E4=B9=89?= =?UTF-8?q?=20re-run?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dashboard/ScanTerminalDashboard.tsx | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/frontend/components/dashboard/ScanTerminalDashboard.tsx b/frontend/components/dashboard/ScanTerminalDashboard.tsx index 2bc43569..875d1e2f 100644 --- a/frontend/components/dashboard/ScanTerminalDashboard.tsx +++ b/frontend/components/dashboard/ScanTerminalDashboard.tsx @@ -43,7 +43,7 @@ import { scanRootClass } from "@/components/dashboard/scan-root-styles"; import { useRelativeTime } from "@/hooks/useRelativeTime"; import { Panel } from "@/components/dashboard/scan-terminal/Panel"; import { TrainingDashboard } from "@/components/dashboard/scan-terminal/TrainingDashboard"; -import { LiveTemperatureThresholdChart } from "@/components/dashboard/scan-terminal/LiveTemperatureThresholdChart"; +import { LiveTemperatureThresholdChart, clearCityDetailCache } from "@/components/dashboard/scan-terminal/LiveTemperatureThresholdChart"; import { KoyfinRowsTable } from "@/components/dashboard/scan-terminal/KoyfinRowsTable"; import { rowName, pct, money, temp, edgeClass } from "@/components/dashboard/scan-terminal/utils"; import { CitySelectorDropdown } from "@/components/dashboard/scan-terminal/CitySelectorDropdown"; @@ -400,26 +400,23 @@ function PolyWeatherTerminal({ const totalSlots = getSlotCount(gridCols, gridRows); const [slots, setSlots] = useState>(() => { - const storedCols = getStoredGridSide("polyweather_terminal_grid_cols"); - const storedRows = getStoredGridSide("polyweather_terminal_grid_rows"); - const initialSlotCount = getSlotCount(storedCols, storedRows); if (typeof window !== "undefined") { try { const stored = localStorage.getItem("polyweather_terminal_slots"); if (stored) { const parsed = JSON.parse(stored); if (Array.isArray(parsed)) { - return normalizeSlotList(parsed, initialSlotCount); + return normalizeSlotList(parsed, MAX_TERMINAL_CHARTS); } } } catch {} } - return Array(initialSlotCount).fill(null); + return Array(MAX_TERMINAL_CHARTS).fill(null); }); const [activeSlotIndex, setActiveSlotIndex] = useState(0); const [maximizedSlotIndex, setMaximizedSlotIndex] = useState(null); const [activeSearchSlotIndex, setActiveSearchSlotIndex] = useState(null); - const visibleSlots = useMemo(() => normalizeSlotList(slots, totalSlots), [slots, totalSlots]); + const visibleSlots = useMemo(() => slots.slice(0, totalSlots), [slots, totalSlots]); const handleSetGridSize = (cols: number, rows: number) => { const safeCols = clampGridSide(cols); @@ -434,13 +431,6 @@ function PolyWeatherTerminal({ localStorage.setItem("polyweather_terminal_grid_rows", String(safeRows)); } catch {} - const nextSlots = normalizeSlotList(visibleSlots, nextTotalSlots); - - setSlots(nextSlots); - try { - localStorage.setItem("polyweather_terminal_slots", JSON.stringify(nextSlots)); - } catch {} - if (activeSlotIndex >= nextTotalSlots) { setActiveSlotIndex(0); } @@ -469,8 +459,8 @@ function PolyWeatherTerminal({ }, [rows, selectedRegionKey]); useEffect(() => { - if (filteredRegionRows.length && visibleSlots.every((s) => s === null)) { - const next = Array(totalSlots) + if (filteredRegionRows.length && slots.every((s) => s === null)) { + const next = Array(MAX_TERMINAL_CHARTS) .fill(null) .map((_, idx) => filteredRegionRows[idx]?.city || null); setSlots(next); @@ -478,11 +468,11 @@ function PolyWeatherTerminal({ localStorage.setItem("polyweather_terminal_slots", JSON.stringify(next)); } catch {} } - }, [filteredRegionRows, visibleSlots, totalSlots]); + }, [filteredRegionRows, slots]); const handleSelectCityForSlot = (index: number, city: string | null) => { - if (index < 0 || index >= totalSlots) return; - const next = [...visibleSlots]; + if (index < 0 || index >= MAX_TERMINAL_CHARTS) return; + const next = [...slots]; next[index] = city; setSlots(next); try { @@ -860,6 +850,8 @@ function PolyWeatherTerminal({ row={rowForSlot} allRows={filteredRegionRows} compact={true} + isActive={isSlotActive} + slotIndex={slotIndex} onSearchClick={() => setActiveSearchSlotIndex(slotIndex)} onMaximize={() => { setMaximizedSlotIndex(slotIndex); @@ -1025,9 +1017,24 @@ function ScanTerminalScreen() { timezoneOffsetSeconds: useLocalTimezoneDefault ? localTimezoneOffsetSeconds : null, tradingRegion: selectedRegionKey, }); + const handleRefresh = useCallback(() => { + clearCityDetailCache(); + refreshScanTerminalManually(); + }, [refreshScanTerminalManually]); + const [cityFallbackRows, setCityFallbackRows] = useState([]); + const rows = useMemo( + () => { + const scanRows = terminalData?.rows || []; + return sortRowsByUserTime(scanRows.length ? scanRows : cityFallbackRows); + }, + [cityFallbackRows, terminalData?.rows], + ); + + const fallbackFetchedRef = useRef(false); useEffect(() => { if (!isPro || typeof fetch !== "function") return; + if (fallbackFetchedRef.current) return; const controller = new AbortController(); fetch("/api/cities", { cache: "no-store", @@ -1040,18 +1047,12 @@ function ScanTerminalScreen() { }) .then((payload) => { if (!payload || !Array.isArray(payload.cities)) return; + fallbackFetchedRef.current = true; setCityFallbackRows(cityListItemsToScanRows(payload.cities)); }) .catch(() => {}); return () => controller.abort(); }, [isPro]); - const rows = useMemo( - () => { - const scanRows = terminalData?.rows || []; - return sortRowsByUserTime(scanRows.length ? scanRows : cityFallbackRows); - }, - [cityFallbackRows, terminalData?.rows], - ); const [searchQuery, setSearchQuery] = useState(""); const searchInputRef = useRef(null); @@ -1115,7 +1116,7 @@ function ScanTerminalScreen() { generatedText={generatedText || ""} isEn={isEn} locale={locale} - onRefresh={refreshScanTerminalManually} + onRefresh={handleRefresh} refreshing={scanLoading} rows={filteredRows} selectedRow={selectedRow}