From 2ead56f59df75e447e86354a7bce7f9bbb2aeac2 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Thu, 16 Apr 2026 13:21:29 +0800 Subject: [PATCH] Simplify detail panel loading state --- frontend/components/dashboard/DetailPanel.tsx | 123 ++---------------- frontend/hooks/useDashboardStore.tsx | 22 ++-- 2 files changed, 20 insertions(+), 125 deletions(-) diff --git a/frontend/components/dashboard/DetailPanel.tsx b/frontend/components/dashboard/DetailPanel.tsx index a17620be..b39296b1 100644 --- a/frontend/components/dashboard/DetailPanel.tsx +++ b/frontend/components/dashboard/DetailPanel.tsx @@ -16,7 +16,6 @@ import { getCityProfileStats, getRiskBadgeLabel, getTemperatureChartData, - getWeatherSummary, } from "@/lib/dashboard-utils"; function DetailMiniTemperatureChart({ detail }: { detail: CityDetail }) { @@ -151,7 +150,6 @@ export function DetailPanel() { ); const isPro = store.proAccess.subscriptionActive; const isAuthenticated = store.proAccess.authenticated; - const isProStateLoading = store.proAccess.loading; const panelRef = useRef(null); const [heavyContentReady, setHeavyContentReady] = useState(false); const isOverlayOpen = Boolean(store.futureModalDate) || store.historyState.isOpen; @@ -180,12 +178,6 @@ export function DetailPanel() { () => getTodayPolymarketUrl(detail, locale), [detail, locale], ); - const weatherSummary = detail - ? getWeatherSummary(detail, locale) - : { weatherIcon: "", weatherText: "" }; - 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 || @@ -195,34 +187,9 @@ export function DetailPanel() { selectedCityItem?.airport || selectedSummary?.icao || (locale === "en-US" ? "Airport pending" : "机场待确认"); - const activeTempSymbol = detail?.temp_symbol || selectedSummary?.temp_symbol || "°C"; - const heroCurrentTemp = detail?.current?.temp ?? basicCurrentTemp; - const heroCurrentTempText = - heroCurrentTemp != null ? `${heroCurrentTemp}${activeTempSymbol}` : "--"; - const heroObsTimeLabel = - detail?.current?.obs_time || - basicObsTime || - (locale === "en-US" ? "Observation pending" : "观测时间待更新"); - const heroDebValue = detail?.deb?.prediction ?? basicDeb; - const heroDebText = - heroDebValue != null - ? `${heroDebValue}${activeTempSymbol}` - : locale === "en-US" - ? "Pending" - : "待更新"; const heroSettlementLabel = detail?.current?.settlement_source_label || basicSettlementLabel; const heroAirportLabel = detail?.risk?.airport || basicAirportLabel; - const heroWeatherText = detail - ? weatherSummary.weatherText - : locale === "en-US" - ? "City snapshot" - : "城市快照"; - const heroWeatherIcon = detail ? weatherSummary.weatherIcon : ""; - const isBasicSummaryLoading = !detail && !selectedSummary && store.loadingState.cityDetail; - const shouldShowSyncCard = - !detail && - (store.loadingState.cityDetail || isProStateLoading || isAuthenticated); const blurActiveElement = () => { if (typeof document === "undefined") return; @@ -423,87 +390,15 @@ export function DetailPanel() { ) : !detail ? ( - <> -
-
-
-
- {locale === "en-US" ? "Quick read" : "基础快照"} -
-

{locale === "en-US" ? "Summary before deep sync." : "先看基础结论,再等深度详情。"}

-
-
- {isBasicSummaryLoading ? ( -
- {locale === "en-US" ? "Syncing public city snapshot..." : "正在同步城市基础信息..."} -
- ) : null} -
-
- {locale === "en-US" ? "Current posture" : "当前态势"} - {heroCurrentTempText} - @{heroObsTimeLabel} - {heroWeatherText} -
-
-
- DEB - {heroDebText} -
-
- {locale === "en-US" ? "Settlement" : "结算口径"} - {heroSettlementLabel} -
-
- {locale === "en-US" ? "Airport" : "结算机场"} - {heroAirportLabel} -
-
- {locale === "en-US" ? "Sync status" : "同步状态"} - - {locale === "en-US" ? "Deep detail pending" : "深度详情补齐中"} - -
-
-
-
- -
-
-
-
- {shouldShowSyncCard - ? locale === "en-US" - ? "Background sync" - : "后台同步" - : locale === "en-US" - ? "Pro workflow" - : "Pro 工作流"} -
-

- {shouldShowSyncCard - ? locale === "en-US" - ? "Deep evidence will appear automatically." - : "更深层的结算证据会自动补齐。" - : locale === "en-US" - ? "Intraday and history live behind the analysis flow." - : "今日日内分析和历史对账会在分析流中继续展开。"} -

-
-
-
- - {shouldShowSyncCard - ? locale === "en-US" - ? "Full city detail is still syncing. Nearby stations, source links, and mini trend will land here once ready." - : "完整城市详情仍在同步中。周边站点、官方参考和温度微趋势会在完成后自动出现在这里。" - : locale === "en-US" - ? "Intraday analysis, history reconciliation, and deeper structure signals stay available from the action bar." - : "今日日内分析、历史对账和更深层结构信号会从上方操作区继续展开。"} - -
-
- +
+ {store.loadingState.cityDetail + ? locale === "en-US" + ? "Loading city cards..." + : "正在加载城市卡片..." + : locale === "en-US" + ? "City cards will appear here." + : "城市卡片会显示在这里。"} +
) : ( <>
diff --git a/frontend/hooks/useDashboardStore.tsx b/frontend/hooks/useDashboardStore.tsx index bfe65d7f..ca49c106 100644 --- a/frontend/hooks/useDashboardStore.tsx +++ b/frontend/hooks/useDashboardStore.tsx @@ -715,11 +715,13 @@ export function DashboardStoreProvider({ if (proAccessRef.current.loading) { setLoadingState((current) => ({ ...current, cityDetail: true })); + const detailPromise = ensureCityDetail(cityName, false, "panel"); try { - await summaryPromise; - const detail = await ensureCityDetail(cityName, false, "panel"); + const [, detail] = await Promise.allSettled([summaryPromise, detailPromise]); if (selectedCityRef.current === cityName) { - setSelectedForecastDate(detail.local_date); + if (detail.status === "fulfilled") { + setSelectedForecastDate(detail.value.local_date); + } } } catch { } finally { @@ -734,15 +736,13 @@ export function DashboardStoreProvider({ cachedDetail?.local_date, ); setLoadingState((current) => ({ ...current, cityDetail: true })); - try { - await summaryPromise; - } catch { - } - - void ensureCityDetail(cityName, needsDetailRefresh, "panel") - .then((detail) => { + const detailPromise = ensureCityDetail(cityName, needsDetailRefresh, "panel"); + void Promise.allSettled([summaryPromise, detailPromise]) + .then(([, detail]) => { if (selectedCityRef.current !== cityName) return; - setSelectedForecastDate(detail.local_date); + if (detail.status === "fulfilled") { + setSelectedForecastDate(detail.value.local_date); + } }) .finally(() => { if (selectedCityRef.current !== cityName) return;