修复城市决策卡切换时地图白屏和第二城市加载失败
- MapCanvas 改为始终挂载,视图切换用 display:none 隐藏而非卸载, 避免 Leaflet 重初始化时容器尺寸为 0 导致白屏 - handleMapCitySelect 在 matchedRow 为空时主动调用 ensureCityDetail 预加载城市详情,不再依赖 hydration 队列异步补拉
This commit is contained in:
@@ -289,8 +289,15 @@ function ScanTerminalScreen() {
|
||||
setMapSelectedCityName(cityName);
|
||||
lastMapSelectedCityRef.current = normalizeCityKey(cityName);
|
||||
const matchedRow = findRowForCity(timeSortedRows, cityName);
|
||||
if (matchedRow) store.preloadCityFromRow(matchedRow);
|
||||
setSelectedRowId(matchedRow?.id || null);
|
||||
if (matchedRow) {
|
||||
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);
|
||||
setActiveView("analysis");
|
||||
}, [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) {
|
||||
return (
|
||||
<div className="scan-table-shell empty">
|
||||
@@ -392,7 +375,35 @@ function ScanTerminalScreen() {
|
||||
</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) {
|
||||
|
||||
@@ -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",
|
||||
);
|
||||
assert(
|
||||
ankaraChartData?.datasets.debSeries.length >= 4,
|
||||
(ankaraChartData?.datasets.debSeries.length ?? 0) >= 4,
|
||||
"Ankara chart should build the DEB original path from MGM hourly data",
|
||||
);
|
||||
assert(
|
||||
|
||||
Reference in New Issue
Block a user