From bef3c610b7511c836fdb0e8465d837343f514ee5 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Wed, 27 May 2026 08:53:36 +0800 Subject: [PATCH] feat: implement Telegram push utility and temperature threshold visualization components --- .../LiveTemperatureThresholdChart.tsx | 21 ++- .../scan-terminal/TemperatureChartCanvas.tsx | 9 +- .../__tests__/refreshCadencePolicy.test.ts | 4 +- .../__tests__/ssePatchArchitecture.test.ts | 12 ++ .../scan-terminal/temperature-chart-logic.ts | 18 +++ src/utils/telegram_push.py | 138 +++++++----------- 6 files changed, 106 insertions(+), 96 deletions(-) diff --git a/frontend/components/dashboard/scan-terminal/LiveTemperatureThresholdChart.tsx b/frontend/components/dashboard/scan-terminal/LiveTemperatureThresholdChart.tsx index 2b1576cf..12d8f285 100644 --- a/frontend/components/dashboard/scan-terminal/LiveTemperatureThresholdChart.tsx +++ b/frontend/components/dashboard/scan-terminal/LiveTemperatureThresholdChart.tsx @@ -28,6 +28,7 @@ import { isTemperatureSeriesVisibleByDefault, mergePatchIntoHourly, normObs, + prefersHighFrequencyRunwayResolution, readSessionCache, seedHourlyForecastFromRow, shouldPollLiveChart, @@ -130,7 +131,9 @@ export function LiveTemperatureThresholdChart({ const [refAreaLeft, setRefAreaLeft] = useState(null); const [refAreaRight, setRefAreaRight] = useState(null); const [zoomRange, setZoomRange] = useState<[number, number] | null>(null); - const [targetResolution, setTargetResolution] = useState("10m"); + const [targetResolution, setTargetResolution] = useState(() => + prefersHighFrequencyRunwayResolution(row, null) ? "1m" : "10m", + ); const [currentCityLocalDate, setCurrentCityLocalDate] = useState(() => formatCityLocalDate(row?.tz_offset_seconds), ); @@ -138,8 +141,9 @@ export function LiveTemperatureThresholdChart({ useEffect(() => { setUserToggledKeys({}); setZoomRange(null); - setViewMode("auto"); + setViewMode("full"); setShowRunwayDetails(true); + setTargetResolution(prefersHighFrequencyRunwayResolution(row, null) ? "1m" : "10m"); setHourly(seedHourlyForecastFromRow(row)); setLiveTemp(null); setIsHourlyLoading(Boolean(city)); @@ -246,7 +250,7 @@ export function LiveTemperatureThresholdChart({ const refreshFullDetail = () => { lastPatchAtRef.current = Date.now(); - fetchHourlyForecastForCity(city, { ignoreCache: true }) + fetchHourlyForecastForCity(city, { ignoreCache: true, resolution: targetResolution }) .then((data) => { if (cancelled || !data) return; hasLoadedHourlyDetailRef.current = true; @@ -279,7 +283,7 @@ export function LiveTemperatureThresholdChart({ cancelled = true; clearInterval(id); }; - }, [city, compact, isActive, isMaximized]); + }, [city, compact, isActive, isMaximized, targetResolution]); useEffect(() => { if (!city || !currentCityLocalDate) return; @@ -323,6 +327,10 @@ export function LiveTemperatureThresholdChart({ ); const visibleRange = zoomRange ?? autoWindowRange; const visibleRangeKey = visibleRange ? `${visibleRange[0]}:${visibleRange[1]}` : "full"; + const shouldUseRunwayResolution = useMemo( + () => prefersHighFrequencyRunwayResolution(row, chartHourly), + [row, chartHourly], + ); const zoomedData = useMemo(() => { if (!visibleRange || data.length === 0) return data; @@ -331,6 +339,9 @@ export function LiveTemperatureThresholdChart({ }, [data, visibleRangeKey]); const nextTargetResolution = useMemo(() => { + if (shouldUseRunwayResolution) { + return "1m"; + } if (visibleRange && data.length > 0) { const zoomedData = data.slice(visibleRange[0], visibleRange[1] + 1); if (zoomedData.length > 0) { @@ -342,7 +353,7 @@ export function LiveTemperatureThresholdChart({ } } return "10m"; - }, [data, visibleRangeKey]); + }, [data, visibleRangeKey, shouldUseRunwayResolution]); useEffect(() => { if (targetResolution !== nextTargetResolution) { diff --git a/frontend/components/dashboard/scan-terminal/TemperatureChartCanvas.tsx b/frontend/components/dashboard/scan-terminal/TemperatureChartCanvas.tsx index b8742ac9..e880ebe1 100644 --- a/frontend/components/dashboard/scan-terminal/TemperatureChartCanvas.tsx +++ b/frontend/components/dashboard/scan-terminal/TemperatureChartCanvas.tsx @@ -114,6 +114,13 @@ export function TemperatureChartCanvas({ const canRenderChart = chartSize.width > 0 && chartSize.height > 0; const chartWidth = Math.max(1, chartSize.width); const chartHeight = Math.max(220, chartSize.height); + const individualRunwaySeriesCount = chartSeries.filter( + (series) => series.key.startsWith("runway_") && series.key !== "runway_max", + ).length; + const canToggleRunwayDetails = + hasRunwayData && + individualRunwaySeriesCount > 1 && + chartSeries.some((series) => series.key === "runway_max"); return (
@@ -142,7 +149,7 @@ export function TemperatureChartCanvas({ ))} - {hasRunwayData && ( + {canToggleRunwayDetails && (