diff --git a/src/modules/mileage/MonitoringView.tsx b/src/modules/mileage/MonitoringView.tsx index 87d2ca4..74a89e7 100644 --- a/src/modules/mileage/MonitoringView.tsx +++ b/src/modules/mileage/MonitoringView.tsx @@ -106,7 +106,7 @@ export default function MonitoringView() { const [appliedMileageRange, setAppliedMileageRange] = useState({ min: '', max: '' }); const [vehicles, setVehicles] = useState([]); - const [stats, setStats] = useState({ totalToday: 0, totalAll: 0, vehicleCount: 0 }); + const [stats, setStats] = useState({ totalToday: 0, totalAll: 0, vehicleCount: 0, yesterdayTotal: 0 }); const [filterOptions, setFilterOptions] = useState({ departments: [], customers: [], plates: [], projects: [], entities: [] }); const [total, setTotal] = useState(0); const [page, setPage] = useState(1); @@ -713,7 +713,11 @@ export default function MonitoringView() {
{Math.round(sortBy === 'today' ? stats.totalToday : stats.totalAll).toLocaleString()} - {sortBy === 'today' && {'\u2191'}12%} + {sortBy === 'today' && stats.yesterdayTotal > 0 && (() => { + const change = ((stats.totalToday - stats.yesterdayTotal) / stats.yesterdayTotal) * 100; + const isUp = change >= 0; + return {isUp ? '\u2191' : '\u2193'}{Math.abs(change).toFixed(1)}%; + })()}
diff --git a/src/modules/mileage/types.ts b/src/modules/mileage/types.ts index 3f82294..b7f44f5 100644 --- a/src/modules/mileage/types.ts +++ b/src/modules/mileage/types.ts @@ -18,6 +18,7 @@ export interface MonitoringStats { totalToday: number; totalAll: number; vehicleCount: number; + yesterdayTotal: number; } export interface MonitoringFilters { diff --git a/src/server/routes/mileage.ts b/src/server/routes/mileage.ts index 2d72dc1..b56fee8 100644 --- a/src/server/routes/mileage.ts +++ b/src/server/routes/mileage.ts @@ -43,7 +43,7 @@ interface CachedVehicle { interface MonitoringCache { vehicles: CachedVehicle[]; - stats: { totalToday: number; totalAll: number; vehicleCount: number }; + stats: { totalToday: number; totalAll: number; vehicleCount: number; yesterdayTotal: number }; filters: { departments: string[]; customers: string[]; plates: string[]; projects: string[]; entities: string[] }; updatedAt: string; } @@ -56,7 +56,7 @@ async function refreshMonitoringCache() { const start = Date.now(); // 并行查询两个数据库 - const [mileageResult, infoRows] = await Promise.all([ + const [mileageResult, yesterdayResult, infoRows] = await Promise.all([ (async () => { const [dateRows] = await mileagePool.execute( 'SELECT MAX(stat_date) as latest FROM v_vehicle_daily_stats' @@ -70,6 +70,13 @@ async function refreshMonitoringCache() { ) as any; return rows; })(), + (async () => { + const [rows] = await mileagePool.execute( + `SELECT SUM(daily_km) as total FROM v_vehicle_daily_stats + WHERE stat_date = DATE_SUB((SELECT MAX(stat_date) FROM v_vehicle_daily_stats), INTERVAL 1 DAY)` + ) as any; + return Number(rows[0]?.total) || 0; + })(), pool.execute(VEHICLE_INFO_SQL).then(([rows]) => rows as any[]), ]); @@ -130,7 +137,7 @@ async function refreshMonitoringCache() { monitoringCache = { vehicles, - stats: { totalToday, totalAll, vehicleCount: vehicles.length }, + stats: { totalToday, totalAll, vehicleCount: vehicles.length, yesterdayTotal: yesterdayResult }, filters: { departments, customers, plates, projects, entities }, updatedAt: new Date().toISOString(), }; @@ -148,7 +155,7 @@ setInterval(refreshMonitoringCache, 2 * 60 * 1000); // GET /monitoring — 从缓存取数据,支持筛选/排序/分页 app.get('/monitoring', (c) => { if (!monitoringCache) { - return c.json({ vehicles: [], stats: { totalToday: 0, totalAll: 0, vehicleCount: 0 }, filters: { departments: [], customers: [], plates: [], projects: [], entities: [] }, total: 0, page: 1, totalPages: 1, updatedAt: new Date().toISOString() }); + return c.json({ vehicles: [], stats: { totalToday: 0, totalAll: 0, vehicleCount: 0, yesterdayTotal: 0 }, filters: { departments: [], customers: [], plates: [], projects: [], entities: [] }, total: 0, page: 1, totalPages: 1, updatedAt: new Date().toISOString() }); } const sortBy = c.req.query('sortBy') || 'today'; @@ -190,6 +197,7 @@ app.get('/monitoring', (c) => { totalToday: vehicles.reduce((sum, v) => sum + v.dailyKm, 0), totalAll: vehicles.reduce((sum, v) => sum + (v.totalKm || 0), 0), vehicleCount: vehicles.length, + yesterdayTotal: monitoringCache.stats.yesterdayTotal, }; // 排序