Restore guest city summaries and refetch missing Pro details

This commit is contained in:
2569718930@qq.com
2026-04-08 18:25:25 +08:00
parent 951eb2f261
commit f108c9f7df
2 changed files with 138 additions and 2 deletions
+92 -2
View File
@@ -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<HTMLElement | null>(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() {
</div>
<div className="panel-body">
{!detail ? (
{!hasBasicPanelContent ? (
<section>
<div style={{ color: "var(--text-muted)", fontSize: "13px" }}>
{store.loadingState.cityDetail
@@ -348,6 +375,69 @@ export function DetailPanel() {
: t("detail.emptyHint")}
</div>
</section>
) : !detail ? (
<>
<section className="detail-section">
<h3>{locale === "en-US" ? "City Snapshot" : "城市概览"}</h3>
<div className="detail-grid">
<div className="detail-card">
<span className="detail-label">
{locale === "en-US" ? "Current temp" : "当前温度"}
</span>
<span className="detail-value">
{basicCurrentTemp != null
? `${basicCurrentTemp}${selectedSummary?.temp_symbol || ""}`
: locale === "en-US"
? "--"
: "--"}
</span>
</div>
<div className="detail-card">
<span className="detail-label">
{locale === "en-US" ? "Observed" : "观测时间"}
</span>
<span className="detail-value">
{basicObsTime || (locale === "en-US" ? "Pending" : "待更新")}
</span>
</div>
<div className="detail-card">
<span className="detail-label">DEB</span>
<span className="detail-value">
{basicDeb != null
? `${basicDeb}${selectedSummary?.temp_symbol || ""}`
: locale === "en-US"
? "Pending"
: "待更新"}
</span>
</div>
<div className="detail-card">
<span className="detail-label">
{locale === "en-US" ? "Settlement" : "结算口径"}
</span>
<span className="detail-value">{basicSettlementLabel}</span>
</div>
<div className="detail-card">
<span className="detail-label">
{locale === "en-US" ? "Airport" : "结算机场"}
</span>
<span className="detail-value">{basicAirportLabel}</span>
</div>
</div>
</section>
<section className="detail-section">
<div className="detail-card">
<span className="detail-label">
{locale === "en-US" ? "Pro features" : "Pro 功能"}
</span>
<span className="detail-value" style={{ fontSize: "15px" }}>
{locale === "en-US"
? "Intraday analysis, history reconciliation, and deeper structure signals require Pro."
: "今日日内分析、历史对账和更深入的结构信号需要 Pro。"}
</span>
</div>
</section>
</>
) : (
<>
<section className="detail-scenery-card">
+46
View File
@@ -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,