From 16f5ef874185740918079b393d2aa424b507398a Mon Sep 17 00:00:00 2001 From: kkfluous Date: Sun, 29 Mar 2026 00:42:59 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8C=BA=E5=9F=9F=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AD=9B=E9=80=89=E7=94=9F=E6=95=88=EF=BC=8C?= =?UTF-8?q?=E5=90=8E=E7=AB=AFregion-stats=E6=94=AF=E6=8C=81=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 后端/region-stats新增customer/city/region查询参数 - 前端regionFilters变化时重新请求后端数据 - 移除前端冗余过滤逻辑,由后端统一处理 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/App.tsx | 18 +++++++++++++++--- src/api.ts | 9 +++++++-- src/server/routes/vehicles.ts | 6 +++++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index f5960d9..53c41b1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -236,6 +236,18 @@ export default function App() { return () => clearInterval(interval); }, [loadData]); + // Re-fetch region data when filters change + useEffect(() => { + const hasFilter = regionFilters.customer || regionFilters.city || regionFilters.region; + if (hasFilter) { + fetchRegionStats({ customer: regionFilters.customer || undefined, city: regionFilters.city || undefined, region: regionFilters.region || undefined }) + .then(setRegionData).catch(() => {}); + } else { + // No filters: use data from the main loadData cycle + fetchRegionStats().then(setRegionData).catch(() => {}); + } + }, [regionFilters]); + // Fetch region chart data when view changes useEffect(() => { fetchRegionChart(regionChartView, regionChartView === 'city' ? 5 : 8).then(setRegionChartData).catch(() => setRegionChartData([])); @@ -477,7 +489,7 @@ export default function App() { const uniqueModalLocations = useMemo(() => Array.from(new Set(modalVehicles.map(v => v.location).filter(Boolean))), [modalVehicles]); // Derived data for region section - const filteredRegionData = useMemo(() => regionData.filter((r) => !regionFilters.region || r.region === regionFilters.region), [regionData, regionFilters.region]); + // regionData is already filtered by backend based on regionFilters // Filtered modal vehicles based on modal filters const filteredModalVehicles = useMemo(() => modalVehicles.filter((v) => { @@ -2063,7 +2075,7 @@ export default function App() { - {regionData.filter(r => !regionFilters.region || r.region === regionFilters.region).map((r) => { + {regionData.map((r) => { const isExpanded = expandedRegions.has(r.region); return ( @@ -2124,7 +2136,7 @@ export default function App() { {/* Mobile View (Region) */}
- {regionData.filter(r => !regionFilters.region || r.region === regionFilters.region).map((r) => { + {regionData.map((r) => { const isExpanded = expandedRegions.has(r.region); return (
diff --git a/src/api.ts b/src/api.ts index e6e51b6..52a1fda 100644 --- a/src/api.ts +++ b/src/api.ts @@ -66,8 +66,13 @@ export async function fetchDeptStats(): Promise { return fetchJson(`${BASE}/dept-stats`); } -export async function fetchRegionStats(): Promise { - return fetchJson(`${BASE}/region-stats`); +export async function fetchRegionStats(params?: { customer?: string; city?: string; region?: string }): Promise { + const query = new URLSearchParams(); + if (params?.customer) query.set('customer', params.customer); + if (params?.city) query.set('city', params.city); + if (params?.region) query.set('region', params.region); + const qs = query.toString(); + return fetchJson(`${BASE}/region-stats${qs ? `?${qs}` : ''}`); } export async function fetchCustomerStats(): Promise { diff --git a/src/server/routes/vehicles.ts b/src/server/routes/vehicles.ts index 61ac0fd..c99a004 100644 --- a/src/server/routes/vehicles.ts +++ b/src/server/routes/vehicles.ts @@ -724,7 +724,11 @@ app.get('/dept-stats', async (c) => { // GET /api/vehicles/region-stats — macro-region with city drill-down app.get('/region-stats', async (c) => { const vehicles = await getVehicles(); - const operating = vehicles.filter((v) => v.status === 'Operating' || v.status === 'Pending'); + const { customer, city: filterCity, region: filterRegion } = c.req.query(); + let operating = vehicles.filter((v) => v.status === 'Operating' || v.status === 'Pending'); + if (customer) operating = operating.filter((v) => v.customerName === customer); + if (filterCity) operating = operating.filter((v) => resolveCity(v.city, v.province) === filterCity); + if (filterRegion) operating = operating.filter((v) => mapMacroRegion(v.province, v.city) === filterRegion); const regionCityMap = new Map>(); for (const v of operating) {