fix: analysis 500s, caching, alert page perf

P0: Fix KeyError in 3 analysis endpoints. geojson.py stores 1d risk
as "risk_value" but analysis.py accessed "risk_1d" — always crashed.

Backend: Add lru_cache to GeoJSON/CSV/Parquet loaders, date helpers,
and district loader. Add try/except and FileNotFoundError guards.

Frontend: Debounce riskRange, merge counts into useMemo, stabilize
handleGridClick with ref, memoize nearest-grid scan, wrap AlertMap
in React.memo, switch useLodGrid from fetch to cachedGet.
This commit is contained in:
2026-06-05 02:27:10 +08:00
parent fc468464b2
commit e64ca3b4f5
9 changed files with 154 additions and 114 deletions

View File

@@ -1,10 +1,10 @@
import { useEffect, useRef, useState, useCallback } from 'react';
import { useEffect, useRef, useState, useCallback, memo } from 'react';
import L from 'leaflet';
import { useRiskStore } from '@/stores';
import { LodGridLayer } from '@/components/LodGridLayer';
import { GridStatsOverlay } from '@/components/GridStatsOverlay';
import { useLodGrid } from '@/hooks/useLodGrid';
import type { Alert } from '@/types';
import type { Alert, GridRisk } from '@/types';
export interface CellInfo {
lat: number;
@@ -44,6 +44,8 @@ function getRiskLabel(value: number): string {
return '低风险';
}
const EMPTY_GRIDS: GridRisk[] = [];
function AlertMapComponent({
selectedGridId,
onGridClick,
@@ -62,7 +64,7 @@ function AlertMapComponent({
const clickHandlerRef = useRef(onGridClick);
const [currentZoom, setCurrentZoom] = useState(10);
const grids = useRiskStore((s) => s.grids ?? []);
const grids = useRiskStore((s) => s.grids ?? EMPTY_GRIDS);
// LOD grid data for stats overlay
const { count, avgRisk, maxRisk, loading } = useLodGrid(currentZoom, forecastDay);
@@ -299,4 +301,4 @@ function AlertMapComponent({
);
}
export const AlertMap = AlertMapComponent;
export const AlertMap = memo(AlertMapComponent);