From 00eed525455f05ea76b8d0dfc8a5b711f3e61d31 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Wed, 22 Apr 2026 02:30:49 +0800 Subject: [PATCH] feat: implement FutureForecastModal and PanelSections for advanced weather visualization and dashboard data display --- .../dashboard/FutureForecastModal.tsx | 45 ++++++++++++------- .../components/dashboard/PanelSections.tsx | 18 ++++++-- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/frontend/components/dashboard/FutureForecastModal.tsx b/frontend/components/dashboard/FutureForecastModal.tsx index 391dad36..d453825f 100644 --- a/frontend/components/dashboard/FutureForecastModal.tsx +++ b/frontend/components/dashboard/FutureForecastModal.tsx @@ -736,24 +736,39 @@ export function FutureForecastModal() { if (!cityName || !dateStr) return; let cancelled = false; - dashboardClient - .getCityMarketScan(cityName, { - force: false, - marketSlug: detail.market_scan?.primary_market?.slug || null, - targetDate: dateStr, - }) - .then((payload) => { - if (cancelled) return; - setFreshMarketScan(payload.market_scan || null); - }) - .catch(() => { - if (!cancelled) { - setFreshMarketScan(null); - } - }); + let intervalId: ReturnType | null = null; + + const refreshMarketScan = () => { + dashboardClient + .getCityMarketScan(cityName, { + force: false, + marketSlug: detail.market_scan?.primary_market?.slug || null, + targetDate: dateStr, + }) + .then((payload) => { + if (cancelled) return; + setFreshMarketScan(payload.market_scan || null); + }) + .catch(() => { + if (!cancelled) { + setFreshMarketScan(null); + } + }); + }; + + refreshMarketScan(); + intervalId = setInterval(() => { + if (typeof document !== "undefined" && document.visibilityState === "hidden") { + return; + } + refreshMarketScan(); + }, 3000); return () => { cancelled = true; + if (intervalId != null) { + clearInterval(intervalId); + } }; }, [ dateStr, diff --git a/frontend/components/dashboard/PanelSections.tsx b/frontend/components/dashboard/PanelSections.tsx index f50a13ba..baa7911c 100644 --- a/frontend/components/dashboard/PanelSections.tsx +++ b/frontend/components/dashboard/PanelSections.tsx @@ -924,6 +924,14 @@ export function ProbabilityDistribution({ row.probability > best.probability ? row : best, ) : null; + const displayTopLabel = topContractRow?.label || topProbabilityLabel || null; + const displayTopProbability = + topContractRow?.probability ?? + (topProbability?.probability != null + ? Number(topProbability.probability) + : null); + const displayTopProbabilityText = toPercent(displayTopProbability); + const displayUsesMarketBuckets = marketContractRows.length > 0; const linkedMarketBucket = useMemo(() => { if (topContractRow?.marketBucket) return topContractRow.marketBucket; if (topProbabilityTemp == null) return null; @@ -1092,10 +1100,14 @@ export function ProbabilityDistribution({
{probabilityEngineLabel} - {topProbability && topProbabilityText + {displayTopLabel && displayTopProbabilityText ? locale === "en-US" - ? `${topProbabilityLabel} is the top single bucket at ${topProbabilityText}` - : `${topProbabilityLabel} 单点最高,${topProbabilityText}` + ? displayUsesMarketBuckets + ? `${displayTopLabel} is the top displayed contract bucket at ${displayTopProbabilityText}` + : `${displayTopLabel} is the top single bucket at ${displayTopProbabilityText}` + : displayUsesMarketBuckets + ? `${displayTopLabel} 为当前显示分布最高,${displayTopProbabilityText}` + : `${displayTopLabel} 单点最高,${displayTopProbabilityText}` : locale === "en-US" ? "Awaiting calibrated buckets" : "等待校准概率桶"}