From f108c9f7dfb8c4e9c19dc2798aa6a2e2c1204e44 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Wed, 8 Apr 2026 18:25:25 +0800 Subject: [PATCH] Restore guest city summaries and refetch missing Pro details --- frontend/components/dashboard/DetailPanel.tsx | 94 ++++++++++++++++++- frontend/hooks/useDashboardStore.tsx | 46 +++++++++ 2 files changed, 138 insertions(+), 2 deletions(-) diff --git a/frontend/components/dashboard/DetailPanel.tsx b/frontend/components/dashboard/DetailPanel.tsx index 8ee1d796..c207084e 100644 --- a/frontend/components/dashboard/DetailPanel.tsx +++ b/frontend/components/dashboard/DetailPanel.tsx @@ -142,6 +142,13 @@ export function DetailPanel() { : null, [store.cities, store.selectedCity], ); + const selectedSummary = useMemo( + () => + store.selectedCity + ? store.citySummariesByName[store.selectedCity] || null + : null, + [store.citySummariesByName, store.selectedCity], + ); const isPro = store.proAccess.subscriptionActive; const isAuthenticated = store.proAccess.authenticated; const panelRef = useRef(null); @@ -153,12 +160,20 @@ export function DetailPanel() { store.isPanelOpen && Boolean(store.selectedCity) && !isOverlayOpen; + const hasBasicPanelContent = Boolean( + detail || selectedSummary || selectedCityItem, + ); const panelDisplayName = detail?.display_name || + selectedSummary?.display_name || selectedCityItem?.display_name || store.selectedCity || "..."; - const panelRiskLevel = detail?.risk?.level || selectedCityItem?.risk_level || "low"; + const panelRiskLevel = + detail?.risk?.level || + selectedSummary?.risk?.level || + selectedCityItem?.risk_level || + "low"; const profileStats = useMemo( () => (detail ? getCityProfileStats(detail, locale) : []), [detail, locale], @@ -172,6 +187,18 @@ export function DetailPanel() { [detail, locale], ); const scenery = getCityScenery(detail?.name); + const basicCurrentTemp = selectedSummary?.current?.temp; + const basicObsTime = selectedSummary?.current?.obs_time; + const basicDeb = selectedSummary?.deb?.prediction; + const basicSettlementLabel = + selectedSummary?.current?.settlement_source_label || + selectedCityItem?.settlement_source_label || + selectedCityItem?.settlement_source || + (locale === "en-US" ? "Settlement source pending" : "结算口径待确认"); + const basicAirportLabel = + selectedCityItem?.airport || + selectedSummary?.icao || + (locale === "en-US" ? "Airport pending" : "机场待确认"); const blurActiveElement = () => { if (typeof document === "undefined") return; const active = document.activeElement; @@ -340,7 +367,7 @@ export function DetailPanel() {
- {!detail ? ( + {!hasBasicPanelContent ? (
{store.loadingState.cityDetail @@ -348,6 +375,69 @@ export function DetailPanel() { : t("detail.emptyHint")}
+ ) : !detail ? ( + <> +
+

{locale === "en-US" ? "City Snapshot" : "城市概览"}

+
+
+ + {locale === "en-US" ? "Current temp" : "当前温度"} + + + {basicCurrentTemp != null + ? `${basicCurrentTemp}${selectedSummary?.temp_symbol || ""}` + : locale === "en-US" + ? "--" + : "--"} + +
+
+ + {locale === "en-US" ? "Observed" : "观测时间"} + + + {basicObsTime || (locale === "en-US" ? "Pending" : "待更新")} + +
+
+ DEB + + {basicDeb != null + ? `${basicDeb}${selectedSummary?.temp_symbol || ""}` + : locale === "en-US" + ? "Pending" + : "待更新"} + +
+
+ + {locale === "en-US" ? "Settlement" : "结算口径"} + + {basicSettlementLabel} +
+
+ + {locale === "en-US" ? "Airport" : "结算机场"} + + {basicAirportLabel} +
+
+
+ +
+
+ + {locale === "en-US" ? "Pro features" : "Pro 功能"} + + + {locale === "en-US" + ? "Intraday analysis, history reconciliation, and deeper structure signals require Pro." + : "今日日内分析、历史对账和更深入的结构信号需要 Pro。"} + +
+
+ ) : ( <>
diff --git a/frontend/hooks/useDashboardStore.tsx b/frontend/hooks/useDashboardStore.tsx index 959abf7b..311f7e3c 100644 --- a/frontend/hooks/useDashboardStore.tsx +++ b/frontend/hooks/useDashboardStore.tsx @@ -344,6 +344,39 @@ export function DashboardStoreProvider({ return detail; }; + useEffect(() => { + if (proAccess.loading) return; + if (!selectedCity) return; + if (!isPanelOpen) return; + if (!proAccess.authenticated || !proAccess.subscriptionActive) return; + if (cityDetailsByName[selectedCity]) return; + + let cancelled = false; + setLoadingState((current) => ({ ...current, cityDetail: true })); + void ensureCityDetail(selectedCity, false) + .then((detail) => { + if (cancelled) return; + setSelectedForecastDate(detail.local_date); + }) + .catch(() => {}) + .finally(() => { + if (cancelled) return; + setLoadingState((current) => ({ ...current, cityDetail: false })); + }); + + return () => { + cancelled = true; + }; + }, [ + cityDetailsByName, + ensureCityDetail, + isPanelOpen, + proAccess.authenticated, + proAccess.loading, + proAccess.subscriptionActive, + selectedCity, + ]); + const ensureCityMarketScan = async ( cityName: string, force = false, @@ -526,6 +559,19 @@ export function DashboardStoreProvider({ await refreshProAccess(); } const access = proAccessRef.current; + if (!access.authenticated || !access.subscriptionActive) { + if (!citySummariesRef.current[cityName]) { + try { + const summary = await dashboardClient.getCitySummary(cityName); + setCitySummariesByName((current) => ({ + ...current, + [cityName]: summary, + })); + } catch {} + } + return; + } + const cachedDetail = cityDetailsByName[cityName]; const needsDetailRefresh = hasSparseDetailCoverage( cachedDetail,