修复城市决策卡切换时地图白屏和第二城市加载失败
- MapCanvas 改为始终挂载,视图切换用 display:none 隐藏而非卸载, 避免 Leaflet 重初始化时容器尺寸为 0 导致白屏 - handleMapCitySelect 在 matchedRow 为空时主动调用 ensureCityDetail 预加载城市详情,不再依赖 hydration 队列异步补拉
This commit is contained in:
@@ -289,8 +289,15 @@ function ScanTerminalScreen() {
|
|||||||
setMapSelectedCityName(cityName);
|
setMapSelectedCityName(cityName);
|
||||||
lastMapSelectedCityRef.current = normalizeCityKey(cityName);
|
lastMapSelectedCityRef.current = normalizeCityKey(cityName);
|
||||||
const matchedRow = findRowForCity(timeSortedRows, cityName);
|
const matchedRow = findRowForCity(timeSortedRows, cityName);
|
||||||
if (matchedRow) store.preloadCityFromRow(matchedRow);
|
if (matchedRow) {
|
||||||
setSelectedRowId(matchedRow?.id || null);
|
store.preloadCityFromRow(matchedRow);
|
||||||
|
setSelectedRowId(matchedRow.id);
|
||||||
|
} else {
|
||||||
|
// City not in scan rows — still preload its detail so the decision
|
||||||
|
// card can render immediately instead of showing a loading spinner.
|
||||||
|
void store.ensureCityDetail(cityName, false, "panel").catch(() => {});
|
||||||
|
setSelectedRowId(null);
|
||||||
|
}
|
||||||
addAiPinnedCity(cityName);
|
addAiPinnedCity(cityName);
|
||||||
setActiveView("analysis");
|
setActiveView("analysis");
|
||||||
}, [addAiPinnedCity, store, timeSortedRows]);
|
}, [addAiPinnedCity, store, timeSortedRows]);
|
||||||
@@ -352,30 +359,6 @@ function ScanTerminalScreen() {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (resolvedView === "map") {
|
|
||||||
return (
|
|
||||||
<div className="scan-map-view">
|
|
||||||
<div className="scan-map-shell">
|
|
||||||
<MapCanvas
|
|
||||||
onCitySelect={handleMapCitySelect}
|
|
||||||
selectionMode="select"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (resolvedView === "analysis") {
|
|
||||||
return (
|
|
||||||
<AiPinnedForecastView
|
|
||||||
items={aiPinnedCities}
|
|
||||||
rows={timeSortedRows}
|
|
||||||
detailsByName={store.cityDetailsByName}
|
|
||||||
locale={locale}
|
|
||||||
onRefreshCityDetail={refreshAiPinnedCityDetail}
|
|
||||||
onRemoveCity={removeAiPinnedCity}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!isPro) {
|
if (!isPro) {
|
||||||
return (
|
return (
|
||||||
<div className="scan-table-shell empty">
|
<div className="scan-table-shell empty">
|
||||||
@@ -392,7 +375,35 @@ function ScanTerminalScreen() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
// Keep MapCanvas always mounted — hiding with CSS avoids Leaflet
|
||||||
|
// reinitialization that causes a white background on tab switches.
|
||||||
|
// The analysis view overlays on top when active.
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="scan-map-view"
|
||||||
|
style={{ display: resolvedView === "map" ? undefined : "none" }}
|
||||||
|
>
|
||||||
|
<div className="scan-map-shell">
|
||||||
|
<MapCanvas
|
||||||
|
onCitySelect={handleMapCitySelect}
|
||||||
|
selectionMode="select"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{resolvedView === "analysis" ? (
|
||||||
|
<AiPinnedForecastView
|
||||||
|
items={aiPinnedCities}
|
||||||
|
rows={timeSortedRows}
|
||||||
|
detailsByName={store.cityDetailsByName}
|
||||||
|
locale={locale}
|
||||||
|
onRefreshCityDetail={refreshAiPinnedCityDetail}
|
||||||
|
onRemoveCity={removeAiPinnedCity}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (proAccess.loading) {
|
if (proAccess.loading) {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export function runTests() {
|
|||||||
"Ankara chart should build the DEB original path from MGM hourly data when Open-Meteo hourly is unavailable",
|
"Ankara chart should build the DEB original path from MGM hourly data when Open-Meteo hourly is unavailable",
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
ankaraChartData?.datasets.debSeries.length >= 4,
|
(ankaraChartData?.datasets.debSeries.length ?? 0) >= 4,
|
||||||
"Ankara chart should build the DEB original path from MGM hourly data",
|
"Ankara chart should build the DEB original path from MGM hourly data",
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
|
|||||||
Reference in New Issue
Block a user