feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
import { useEffect, useState, useMemo } from 'react';
|
2026-06-21 20:24:26 +08:00
|
|
|
|
import { Activity } from 'lucide-react';
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
import { caseApi, riskApi, alertApi, envApi } from '@/services/api';
|
|
|
|
|
|
import { ErrorBanner } from '@/components/ErrorBanner';
|
2026-06-21 20:24:26 +08:00
|
|
|
|
import { LoadingState, Segmented } from '@/components/ui';
|
|
|
|
|
|
import { TESTIDS } from '@/utils/testids';
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
import type {
|
|
|
|
|
|
CaseTrendPoint,
|
|
|
|
|
|
DistrictCaseData,
|
|
|
|
|
|
PollutantPoint,
|
|
|
|
|
|
DiagnosisBreakdown,
|
|
|
|
|
|
Alert,
|
|
|
|
|
|
} from '@/types';
|
2026-06-21 20:24:26 +08:00
|
|
|
|
import { KpiRow, type KpiData } from '@/components/overview/KpiRow';
|
|
|
|
|
|
import { CaseAqiTrend, type MergedTrendItem } from '@/components/overview/CaseAqiTrend';
|
|
|
|
|
|
import { DistrictChoropleth } from '@/components/overview/DistrictChoropleth';
|
|
|
|
|
|
import { TopDistrictsBar } from '@/components/overview/TopDistrictsBar';
|
|
|
|
|
|
import { TopDiagnosesBar } from '@/components/overview/TopDiagnosesBar';
|
|
|
|
|
|
import { AlertSeverityDonut, type AlertSlice } from '@/components/overview/AlertSeverityDonut';
|
|
|
|
|
|
import { CHART_COLORS } from '@/components/overview/chartColors';
|
|
|
|
|
|
import {
|
|
|
|
|
|
joinDistrictCases,
|
|
|
|
|
|
buildMetricLookup,
|
|
|
|
|
|
type MetricKey,
|
|
|
|
|
|
} from '@/components/overview/districtNormalize';
|
|
|
|
|
|
|
|
|
|
|
|
const METRIC_OPTIONS: { value: MetricKey; label: string }[] = [
|
|
|
|
|
|
{ value: 'all', label: '全部' },
|
|
|
|
|
|
{ value: 'outpatient', label: '门诊' },
|
|
|
|
|
|
{ value: 'inpatient', label: '住院' },
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
const METRIC_LABEL: Record<MetricKey, string> = {
|
|
|
|
|
|
all: '病例',
|
|
|
|
|
|
outpatient: '门诊',
|
|
|
|
|
|
inpatient: '住院',
|
|
|
|
|
|
};
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
|
|
|
|
|
|
function computeChangeRatio(trend: CaseTrendPoint[]): number | null {
|
|
|
|
|
|
if (trend.length < 8) return null;
|
|
|
|
|
|
const recent7 = trend.slice(-7).reduce((s, p) => s + p.total, 0);
|
|
|
|
|
|
const prior7 = trend.slice(-14, -7).reduce((s, p) => s + p.total, 0);
|
|
|
|
|
|
if (prior7 === 0) return null;
|
|
|
|
|
|
return ((recent7 - prior7) / prior7) * 100;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export function OverviewDashboard() {
|
|
|
|
|
|
const [kpi, setKpi] = useState<KpiData | null>(null);
|
|
|
|
|
|
const [mergedTrend, setMergedTrend] = useState<MergedTrendItem[]>([]);
|
2026-06-21 20:24:26 +08:00
|
|
|
|
const [districts, setDistricts] = useState<DistrictCaseData[]>([]);
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
const [topDiagnoses, setTopDiagnoses] = useState<DiagnosisBreakdown[]>([]);
|
2026-06-21 20:24:26 +08:00
|
|
|
|
const [alertPie, setAlertPie] = useState<AlertSlice[]>([]);
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
|
|
const [errors, setErrors] = useState<string[]>([]);
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
// 门诊/住院/全部 — 同时驱动 choropleth 与 Top5 区县条形图。
|
|
|
|
|
|
const [metric, setMetric] = useState<MetricKey>('all');
|
|
|
|
|
|
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
let cancelled = false;
|
|
|
|
|
|
|
|
|
|
|
|
const fetchAll = async () => {
|
|
|
|
|
|
setIsLoading(true);
|
|
|
|
|
|
setErrors([]);
|
|
|
|
|
|
|
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
const endStr = now.toISOString().split('T')[0];
|
|
|
|
|
|
const start14 = new Date(now);
|
|
|
|
|
|
start14.setDate(start14.getDate() - 14);
|
|
|
|
|
|
const start14Str = start14.toISOString().split('T')[0];
|
|
|
|
|
|
const start30 = new Date(now);
|
|
|
|
|
|
start30.setDate(start30.getDate() - 30);
|
|
|
|
|
|
const start30Str = start30.toISOString().split('T')[0];
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
// KPI sources — Promise.allSettled to survive individual failures.
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
const [statsR, trend14R, alertsR, riskStatsR, pollutantsR] = await Promise.allSettled([
|
|
|
|
|
|
caseApi.getStats(),
|
|
|
|
|
|
caseApi.getTrend({ start_date: start14Str, end_date: endStr, group_by: 'day' }),
|
|
|
|
|
|
alertApi.getAlerts(),
|
|
|
|
|
|
riskApi.getStats(),
|
|
|
|
|
|
envApi.getPollutants(7),
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
// Trend + district sources.
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
const [trend30R, districtsR, diagStatsR] = await Promise.allSettled([
|
|
|
|
|
|
caseApi.getTrend({ start_date: start30Str, end_date: endStr, group_by: 'day' }),
|
|
|
|
|
|
caseApi.getDistricts(),
|
|
|
|
|
|
caseApi.getStats(), // reuse for top_diagnoses
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
if (cancelled) return;
|
|
|
|
|
|
|
|
|
|
|
|
const newErrors: string[] = [];
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
// --- KPI ---
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
let totalCases = 0;
|
|
|
|
|
|
if (statsR.status === 'fulfilled') {
|
|
|
|
|
|
const s = statsR.value;
|
|
|
|
|
|
totalCases = (s.total_outpatient || 0) + (s.total_inpatient || 0);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newErrors.push('累计病例数据加载失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let todayCases = 0;
|
|
|
|
|
|
let changeRatio: number | null = null;
|
|
|
|
|
|
if (trend14R.status === 'fulfilled') {
|
|
|
|
|
|
const trend = trend14R.value.trend || [];
|
2026-06-21 20:24:26 +08:00
|
|
|
|
if (trend.length > 0) todayCases = trend[trend.length - 1].total;
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
changeRatio = computeChangeRatio(trend);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newErrors.push('今日病例数据加载失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let activeAlerts = 0;
|
|
|
|
|
|
let alertList: Alert[] = [];
|
|
|
|
|
|
if (alertsR.status === 'fulfilled') {
|
|
|
|
|
|
alertList = alertsR.value.alerts || [];
|
|
|
|
|
|
activeAlerts = alertList.length;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newErrors.push('预警数据加载失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let highRiskGrids = 0;
|
|
|
|
|
|
if (riskStatsR.status === 'fulfilled') {
|
|
|
|
|
|
highRiskGrids = riskStatsR.value.high_risk_count || 0;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newErrors.push('风险网格数据加载失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let avgAQI = 0;
|
|
|
|
|
|
let pollutantData: PollutantPoint[] = [];
|
|
|
|
|
|
if (pollutantsR.status === 'fulfilled') {
|
|
|
|
|
|
pollutantData = pollutantsR.value.data || [];
|
|
|
|
|
|
if (pollutantData.length > 0) {
|
|
|
|
|
|
const sumAQI = pollutantData.reduce((s, p) => s + (p.AQI || 0), 0);
|
|
|
|
|
|
avgAQI = Math.round(sumAQI / pollutantData.length);
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newErrors.push('AQI数据加载失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setKpi({ totalCases, todayCases, changeRatio, activeAlerts, highRiskGrids, avgAQI });
|
|
|
|
|
|
|
|
|
|
|
|
// --- Merge case trend + AQI ---
|
|
|
|
|
|
if (trend30R.status === 'fulfilled') {
|
|
|
|
|
|
const trend30 = trend30R.value.trend || [];
|
|
|
|
|
|
const aqiMap: Record<string, number> = {};
|
2026-06-21 20:24:26 +08:00
|
|
|
|
for (const p of pollutantData) aqiMap[p.date] = p.AQI || 0;
|
|
|
|
|
|
setMergedTrend(
|
|
|
|
|
|
trend30.map((t) => ({ date: t.date, cases: t.total, aqi: aqiMap[t.date] || 0 }))
|
|
|
|
|
|
);
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
} else if (!newErrors.includes('今日病例数据加载失败')) {
|
|
|
|
|
|
newErrors.push('趋势数据加载失败');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
// --- Districts (feeds choropleth + Top5 via normalize/join) ---
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
if (districtsR.status === 'fulfilled') {
|
2026-06-21 20:24:26 +08:00
|
|
|
|
setDistricts(districtsR.value.districts || []);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
newErrors.push('区县数据加载失败');
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Top 5 Diagnoses ---
|
|
|
|
|
|
if (diagStatsR.status === 'fulfilled') {
|
|
|
|
|
|
const topDiag = diagStatsR.value.top_diagnoses || [];
|
|
|
|
|
|
setTopDiagnoses(
|
|
|
|
|
|
topDiag.slice(0, 5).map((d) => ({
|
|
|
|
|
|
diagnosis: d.diagnosis,
|
|
|
|
|
|
outpatient: d.outpatient,
|
|
|
|
|
|
inpatient: d.inpatient,
|
|
|
|
|
|
total: d.outpatient + d.inpatient,
|
|
|
|
|
|
}))
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// --- Alert severity donut ---
|
|
|
|
|
|
const p1 = alertList.filter((a) => a.priority === 'P1').length;
|
|
|
|
|
|
const p2 = alertList.filter((a) => a.priority === 'P2').length;
|
|
|
|
|
|
setAlertPie([
|
2026-06-21 20:24:26 +08:00
|
|
|
|
{ name: 'P1 紧急', value: p1, color: CHART_COLORS.alertP1 },
|
|
|
|
|
|
{ name: 'P2 关注', value: p2, color: CHART_COLORS.alertP2 },
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
]);
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
setErrors(newErrors);
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
setIsLoading(false);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
fetchAll();
|
|
|
|
|
|
return () => {
|
|
|
|
|
|
cancelled = true;
|
|
|
|
|
|
};
|
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
// 归一并聚合到 13 区一次,供 choropleth 与 Top5 共享。
|
|
|
|
|
|
const joinedDistricts = useMemo(() => joinDistrictCases(districts), [districts]);
|
|
|
|
|
|
const metricLookup = useMemo(
|
|
|
|
|
|
() => buildMetricLookup(joinedDistricts, metric),
|
|
|
|
|
|
[joinedDistricts, metric]
|
|
|
|
|
|
);
|
|
|
|
|
|
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
if (isLoading) {
|
2026-06-21 20:24:26 +08:00
|
|
|
|
return <LoadingState label="加载概览数据…" testid={TESTIDS.pageLoading} />;
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
2026-06-21 20:24:26 +08:00
|
|
|
|
<div data-testid={TESTIDS.pageOverview} className="flex flex-col h-full overflow-auto">
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
{errors.length > 0 && (
|
|
|
|
|
|
<div className="px-6 pt-4">
|
|
|
|
|
|
<ErrorBanner
|
|
|
|
|
|
error={errors.join(';')}
|
|
|
|
|
|
onRetry={() => window.location.reload()}
|
|
|
|
|
|
onDismiss={() => setErrors([])}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
<div className="p-6 space-y-6">
|
2026-06-21 20:24:26 +08:00
|
|
|
|
{/* Page header + honesty badge + metric toggle */}
|
|
|
|
|
|
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<h1 className="font-display text-[18px] font-semibold mb-1 flex items-center gap-2">
|
|
|
|
|
|
<Activity className="w-5 h-5 text-primary" />
|
|
|
|
|
|
综合概览
|
|
|
|
|
|
<span
|
|
|
|
|
|
data-testid={TESTIDS.asofBadge}
|
|
|
|
|
|
className="ml-1 inline-flex items-center rounded-full bg-bg-hover px-2 py-0.5 text-[11px] font-medium text-text-secondary border border-border"
|
|
|
|
|
|
>
|
|
|
|
|
|
数据截至2023-12
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</h1>
|
|
|
|
|
|
<p className="text-[12px] text-text-secondary">病例、环境与预警关键指标总览</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<Segmented
|
|
|
|
|
|
options={METRIC_OPTIONS}
|
|
|
|
|
|
value={metric}
|
|
|
|
|
|
onChange={setMetric}
|
|
|
|
|
|
testid={TESTIDS.outinpatientToggle}
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
{/* KPI Row */}
|
|
|
|
|
|
<KpiRow kpi={kpi} />
|
|
|
|
|
|
|
|
|
|
|
|
{/* Headline: Wuhan 13-district choropleth */}
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
<div className="card p-4">
|
2026-06-21 20:24:26 +08:00
|
|
|
|
<div className="text-[11px] font-medium text-text-secondary uppercase tracking-wide mb-3">
|
|
|
|
|
|
武汉市13区{METRIC_LABEL[metric]}分布(高风险高亮)
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
</div>
|
2026-06-21 20:24:26 +08:00
|
|
|
|
<DistrictChoropleth
|
|
|
|
|
|
metricLookup={metricLookup}
|
|
|
|
|
|
metricLabel={`${METRIC_LABEL[metric]}数`}
|
|
|
|
|
|
/>
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
{/* Case + AQI trend */}
|
|
|
|
|
|
<CaseAqiTrend data={mergedTrend} />
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
{/* Top districts (metric-driven) + Top diagnoses */}
|
|
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
|
|
|
|
|
<TopDistrictsBar
|
|
|
|
|
|
districts={joinedDistricts}
|
|
|
|
|
|
metric={metric}
|
|
|
|
|
|
metricLabel={METRIC_LABEL[metric]}
|
|
|
|
|
|
/>
|
|
|
|
|
|
<TopDiagnosesBar diagnoses={topDiagnoses} />
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-06-21 20:24:26 +08:00
|
|
|
|
{/* Alert severity donut */}
|
|
|
|
|
|
<AlertSeverityDonut data={alertPie} />
|
feat: add analysis pages and raster risk map
Ship a new app version with broader analytics, restructured
dashboards, and a server-rendered risk map.
Frontend:
- Add Overview, Demographic, Disease, and Environmental Health
analysis pages
- Add AnomalyMarkers, CalendarHeatmap, and MetricHeatmapTable
components
- Rebuild Alerts map onto server-rendered raster risk tiles;
expand Monitoring, Trend, and District Comparison views
- Extend API client, stores, and TypeScript types
Backend:
- Add environment router (pollutants, lag correlations)
- Add risk_raster util serving XYZ 100m risk tiles
- Expand cases endpoints (demographics, seasonality, diagnoses)
and insights; harden auth and file-based loaders
Data & tooling:
- Add processed outpatient/inpatient/combined case parquet (LFS)
- Add nested CLAUDE.md guides, pyrightconfig, and test updates
2026-06-21 17:35:03 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|