From a0ea4740b931b4c7cbbaa401d09135b2b39eef8b Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Thu, 23 Apr 2026 01:48:08 +0800 Subject: [PATCH] Optimize homepage dashboard render paths --- .../dashboard/PolyWeatherDashboard.tsx | 340 +++++++++++------- 1 file changed, 211 insertions(+), 129 deletions(-) diff --git a/frontend/components/dashboard/PolyWeatherDashboard.tsx b/frontend/components/dashboard/PolyWeatherDashboard.tsx index 1fd8570a..bfa801f5 100644 --- a/frontend/components/dashboard/PolyWeatherDashboard.tsx +++ b/frontend/components/dashboard/PolyWeatherDashboard.tsx @@ -476,130 +476,206 @@ function HomeIntelligencePanel({ snapshots }: { snapshots: CitySnapshot[] }) { label: string; temperatureText: string; } | null>(null); - const selectedSnapshot = store.selectedCity - ? snapshots.find((snapshot) => snapshot.city.name === store.selectedCity) - : null; - const spotlight = selectedSnapshot || null; + const spotlight = useMemo( + () => + store.selectedCity + ? snapshots.find((snapshot) => snapshot.city.name === store.selectedCity) || null + : null, + [snapshots, store.selectedCity], + ); + const spotlightView = useMemo(() => { + if (!spotlight) return null; - if (!spotlight) return null; - - const { city, detail, summary } = spotlight; - const symbol = getTempSymbol(city, summary, detail); - const currentTemp = summary?.current?.temp ?? detail?.current?.temp; - const debPrediction = summary?.deb?.prediction ?? detail?.deb?.prediction; - const maxSoFar = detail?.current?.max_so_far ?? detail?.airport_current?.max_so_far; - const maxTime = detail?.current?.max_temp_time || detail?.airport_current?.max_temp_time || "--"; - const localTime = summary?.local_time || detail?.local_time || "--"; - const riskLevel = - city.deb_recent_tier || - city.risk_level || - summary?.risk?.level || - detail?.risk?.level; - const deviation = summary?.deviation_monitor || detail?.deviation_monitor; - const observationSource = - normalizeObservationSourceLabel( + const { city, detail, summary } = spotlight; + const symbol = getTempSymbol(city, summary, detail); + const currentTemp = summary?.current?.temp ?? detail?.current?.temp; + const debPrediction = summary?.deb?.prediction ?? detail?.deb?.prediction; + const maxSoFar = detail?.current?.max_so_far ?? detail?.airport_current?.max_so_far; + const maxTime = + detail?.current?.max_temp_time || detail?.airport_current?.max_temp_time || "--"; + const localTime = summary?.local_time || detail?.local_time || "--"; + const riskLevel = + city.deb_recent_tier || + city.risk_level || + summary?.risk?.level || + detail?.risk?.level; + const deviation = summary?.deviation_monitor || detail?.deviation_monitor; + const observationSource = normalizeObservationSourceLabel( summary?.current?.settlement_source_label || detail?.current?.settlement_source_label || city.settlement_source_label, "METAR", ); - const probabilityBuckets = - detail?.probabilities?.distribution || - (detail?.local_date - ? detail?.multi_model_daily?.[detail.local_date]?.probabilities - : undefined) || - []; - const displayedProbabilities = probabilityBuckets.slice(0, 5); - const modelLabels = getModelLabels(detail); - const marketScan = detail?.market_scan; - const hasMarketScan = Boolean(marketScan); - const showOpportunityLabel = !hasMarketScan || spotlight.tradableOpportunity; - const marketBucket = marketScan?.temperature_bucket || marketScan?.top_buckets?.[0] || null; - const yesPrice = - marketScan?.yes_buy ?? - readNumericField(marketBucket, "yes_buy") ?? - marketScan?.yes_token?.buy_price ?? - marketScan?.yes_token?.midpoint ?? - marketScan?.price_analysis?.yes?.ask; - const noPrice = - marketScan?.no_buy ?? - readNumericField(marketBucket, "no_buy") ?? - marketScan?.no_token?.buy_price ?? - marketScan?.no_token?.midpoint ?? - marketScan?.price_analysis?.no?.ask; - const marketEdge = - marketScan?.edge_percent ?? - marketScan?.price_analysis?.yes?.edge_percent ?? - marketScan?.price_analysis?.yes?.edge ?? - marketScan?.price_analysis?.no?.edge_percent ?? - marketScan?.price_analysis?.no?.edge; - const marketLabel = marketBucket - ? getProbabilityLabel(marketBucket, symbol) - : debPrediction != null - ? `> ${formatTemperature(debPrediction, symbol)}` - : "--"; - const marketProbability = - marketScan?.market_price ?? - readNumericField(marketBucket, "market_price") ?? - readNumericField(marketBucket, "yes_buy") ?? - yesPrice ?? - marketScan?.model_probability; - const marketModelProbability = marketScan?.model_probability ?? marketBucket?.probability; - const sparklinePoints = buildSparklinePoints(marketScan?.sparkline); - const isLoading = store.loadingState.cityDetail && store.selectedCity === city.name; - const isPro = store.proAccess.subscriptionActive; - const cityCode = city.icao || detail?.risk?.icao || city.airport; - const localizedCityName = getLocalizedCityDisplay(city, locale, summary, detail); - const localizedAirportName = getLocalizedAirportDisplay(city, locale, detail); - const subtitle = `${cityCode} · ${localizedAirportName}`; - const highRiskLabel = - riskLevel === "high" - ? locale === "en-US" - ? "High risk" - : "高风险" - : getRiskCopy(riskLevel, locale); - const weatherIconKind = getHomeWeatherIconKind(detail, locale); - const trendChart = buildHomeTrendChart(detail, locale); - const debLabel = locale === "en-US" ? "DEB forecast" : "DEB 预测"; - const dayMaxLabel = locale === "en-US" ? "24h max" : "24 小时最高"; - const probabilityTitle = locale === "en-US" ? "EMOS probability" : "EMOS 概率"; - const marketTitle = locale === "en-US" ? "Market edge" : "市场优势"; - const marketEdgeLabel = locale === "en-US" ? "Edge" : "优势"; - const marketImpliedLabel = locale === "en-US" ? "Implied" : "市场隐含"; - const marketModelLabel = locale === "en-US" ? "Model prob" : "模型概率"; - const proLabel = isPro - ? locale === "en-US" - ? "Pro signal" - : "PRO 信号" - : locale === "en-US" - ? "Pro locked" - : "PRO 锁定"; - const forecastDays = buildHomeForecastDays(detail, locale); - const keySignals = [ - { - active: Number(marketEdge) > 0, - label: - locale === "en-US" - ? "DEB > Market implied" - : "DEB 高于市场隐含", - tone: "green", - }, - { - active: deviation?.trend === "expanding" || deviation?.direction === "hot", - label: locale === "en-US" ? "Rising temps trend" : "升温趋势", - tone: "green", - }, - { - active: Boolean(detail?.peak?.hours?.length), - label: - detail?.peak?.hours?.length - ? `${locale === "en-US" ? "High impact window" : "高影响窗口"} ${detail.peak.hours[0]}-${detail.peak.hours[detail.peak.hours.length - 1]}` + const probabilityBuckets = + detail?.probabilities?.distribution || + (detail?.local_date + ? detail?.multi_model_daily?.[detail.local_date]?.probabilities + : undefined) || + []; + const displayedProbabilities = probabilityBuckets.slice(0, 5); + const modelLabels = getModelLabels(detail); + const marketScan = detail?.market_scan; + const marketBucket = + marketScan?.temperature_bucket || marketScan?.top_buckets?.[0] || null; + const yesPrice = + marketScan?.yes_buy ?? + readNumericField(marketBucket, "yes_buy") ?? + marketScan?.yes_token?.buy_price ?? + marketScan?.yes_token?.midpoint ?? + marketScan?.price_analysis?.yes?.ask; + const noPrice = + marketScan?.no_buy ?? + readNumericField(marketBucket, "no_buy") ?? + marketScan?.no_token?.buy_price ?? + marketScan?.no_token?.midpoint ?? + marketScan?.price_analysis?.no?.ask; + const marketEdge = + marketScan?.edge_percent ?? + marketScan?.price_analysis?.yes?.edge_percent ?? + marketScan?.price_analysis?.yes?.edge ?? + marketScan?.price_analysis?.no?.edge_percent ?? + marketScan?.price_analysis?.no?.edge; + + return { + city, + detail, + tradableOpportunity: spotlight.tradableOpportunity, + symbol, + currentTemp, + debPrediction, + maxSoFar, + maxTime, + localTime, + riskLevel, + observationSource, + displayedProbabilities, + modelLabels, + marketScan, + showOpportunityLabel: !marketScan || spotlight.tradableOpportunity, + marketLabel: marketBucket + ? getProbabilityLabel(marketBucket, symbol) + : debPrediction != null + ? `> ${formatTemperature(debPrediction, symbol)}` + : "--", + yesPrice, + noPrice, + marketEdge, + marketProbability: + marketScan?.market_price ?? + readNumericField(marketBucket, "market_price") ?? + readNumericField(marketBucket, "yes_buy") ?? + yesPrice ?? + marketScan?.model_probability, + marketModelProbability: marketScan?.model_probability ?? marketBucket?.probability, + sparklinePoints: buildSparklinePoints(marketScan?.sparkline), + isLoading: store.loadingState.cityDetail && store.selectedCity === city.name, + isPro: store.proAccess.subscriptionActive, + cityCode: city.icao || detail?.risk?.icao || city.airport, + localizedCityName: getLocalizedCityDisplay(city, locale, summary, detail), + localizedAirportName: getLocalizedAirportDisplay(city, locale, detail), + highRiskLabel: + riskLevel === "high" + ? locale === "en-US" + ? "High risk" + : "高风险" + : getRiskCopy(riskLevel, locale), + weatherIconKind: getHomeWeatherIconKind(detail, locale), + trendChart: buildHomeTrendChart(detail, locale), + debLabel: locale === "en-US" ? "DEB forecast" : "DEB 预测", + dayMaxLabel: locale === "en-US" ? "24h max" : "24 小时最高", + probabilityTitle: locale === "en-US" ? "EMOS probability" : "EMOS 概率", + marketTitle: locale === "en-US" ? "Market edge" : "市场优势", + marketEdgeLabel: locale === "en-US" ? "Edge" : "优势", + marketImpliedLabel: locale === "en-US" ? "Implied" : "市场隐含", + marketModelLabel: locale === "en-US" ? "Model prob" : "模型概率", + proLabel: + store.proAccess.subscriptionActive + ? locale === "en-US" + ? "Pro signal" + : "PRO 信号" : locale === "en-US" - ? "High impact window pending" - : "高影响窗口待确认", - tone: "amber", - }, - ]; + ? "Pro locked" + : "PRO 锁定", + forecastDays: buildHomeForecastDays(detail, locale), + keySignals: [ + { + active: Number(marketEdge) > 0, + label: + locale === "en-US" + ? "DEB > Market implied" + : "DEB 高于市场隐含", + tone: "green", + }, + { + active: deviation?.trend === "expanding" || deviation?.direction === "hot", + label: locale === "en-US" ? "Rising temps trend" : "升温趋势", + tone: "green", + }, + { + active: Boolean(detail?.peak?.hours?.length), + label: + detail?.peak?.hours?.length + ? `${locale === "en-US" ? "High impact window" : "高影响窗口"} ${detail.peak.hours[0]}-${detail.peak.hours[detail.peak.hours.length - 1]}` + : locale === "en-US" + ? "High impact window pending" + : "高影响窗口待确认", + tone: "amber", + }, + ], + }; + }, [ + locale, + spotlight, + store.loadingState.cityDetail, + store.proAccess.subscriptionActive, + store.selectedCity, + ]); + + if (!spotlightView) return null; + + const { + city, + detail, + symbol, + currentTemp, + debPrediction, + maxSoFar, + maxTime, + localTime, + riskLevel, + observationSource, + displayedProbabilities, + modelLabels, + marketScan, + tradableOpportunity, + showOpportunityLabel, + marketLabel, + yesPrice, + noPrice, + marketEdge, + marketProbability, + marketModelProbability, + sparklinePoints, + isLoading, + isPro, + cityCode, + localizedCityName, + localizedAirportName, + highRiskLabel, + weatherIconKind, + trendChart, + debLabel, + dayMaxLabel, + probabilityTitle, + marketTitle, + marketEdgeLabel, + marketImpliedLabel, + marketModelLabel, + proLabel, + forecastDays, + keySignals, + } = spotlightView; + const subtitle = `${cityCode} · ${localizedAirportName}`; return (