diff --git a/src/App.tsx b/src/App.tsx index f231d90..691ac95 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1357,17 +1357,25 @@ export default function App() { 总运营车辆 {deptData.reduce((s, d) => s + d.totalAssets, 0)} -
+
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', attendance: 'active', source: 'department', title: '部门运营统计 - 出勤车辆' })}> 出勤车辆 - - + + {deptData.reduce((acc, d) => acc + d.operatingCount, 0)} +
-
+
setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', attendance: 'idle', source: 'department', title: '部门运营统计 - 闲置车辆' })}> 闲置车辆 - - + + {deptData.reduce((acc, d) => acc + d.idleCount, 0)} +
平均出勤 - - + + {deptData.length > 0 ? (deptData.reduce((acc, d) => acc + d.attendanceRate, 0) / deptData.length).toFixed(1) : 0}% +
@@ -1453,7 +1461,9 @@ export default function App() { {dept.department} - - + + {dept.attendanceRate}% + + + + + {isExpanded ? : } @@ -1651,8 +1665,8 @@ export default function App() { >

{dept.department}

- - 出勤率: - + + 出勤率: {dept.attendanceRate}%
@@ -1661,13 +1675,15 @@ export default function App() {
总运营
{dept.totalAssets}
-
-
出勤
-
-
+
{ e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', department: dept.department, attendance: 'active', source: 'department', title: `部门运营统计 - ${dept.department} - 出勤车辆` }); }}> +
出勤
+
{dept.operatingCount}
-
+
{ e.stopPropagation(); setShowPlateNumbers({ batch: 'All', model: 'All', location: 'All', department: dept.department, attendance: 'idle', source: 'department', title: `部门运营统计 - ${dept.department} - 闲置车辆` }); }}>
闲置
-
-
+
{dept.idleCount}
diff --git a/src/server/routes/vehicles.ts b/src/server/routes/vehicles.ts index 36a3a00..61ac0fd 100644 --- a/src/server/routes/vehicles.ts +++ b/src/server/routes/vehicles.ts @@ -652,35 +652,16 @@ app.get('/dept-stats', async (c) => { const vehicles = await getVehicles(); const withManager = vehicles.filter((v) => v.status === 'Operating'); - // Query mileage data: last 30 days attendance & avg mileage per plate - // + today's mileage for idle detection - const [[mileageRows], [todayRows]] = await Promise.all([ - pool.query(` - SELECT plateNumber, - COUNT(CASE WHEN dayMileage > 0 THEN 1 END) AS activeDays, - COUNT(*) AS totalDays, - AVG(dayMileage) AS avgMileage - FROM ln_vehicle_day_mileage - WHERE dates >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) - GROUP BY plateNumber - `), - pool.query(` - SELECT plateNumber, dayMileage - FROM ln_vehicle_day_mileage - WHERE dates = CURDATE() - `), - ]); - const mileageMap = new Map(); - for (const row of mileageRows as any[]) { - mileageMap.set(row.plateNumber, { - activeDays: Number(row.activeDays), - totalDays: Number(row.totalDays), - avgMileage: Number(row.avgMileage), - }); - } + // Query realtime day_mileage from tab_truck_remote_sync_realtime_info + const [realtimeRows] = await pool.query(` + SELECT plate_number, day_mileage + FROM tab_truck_remote_sync_realtime_info + WHERE is_deleted = 0 AND plate_number IS NOT NULL + `); const todayMileageMap = new Map(); - for (const row of todayRows as any[]) { - todayMileageMap.set(row.plateNumber, Number(row.dayMileage)); + for (const row of realtimeRows as any[]) { + const plate = (row.plate_number || '').trim(); + if (plate) todayMileageMap.set(plate, Number(row.day_mileage) || 0); } const deptMap = new Map>(); @@ -693,15 +674,15 @@ app.get('/dept-stats', async (c) => { mgrMap.get(mgr)!.push(v); } - // Compute attendance (today) & avg mileage (30d) for a set of vehicles + // Compute attendance & avg mileage from realtime data const getMileageStats = (vList: Vehicle[]) => { const todayActive = vList.filter((v) => (todayMileageMap.get(v.plateNumber) || 0) > 0).length; let totalMileage = 0; let count = 0; for (const v of vList) { - const m = mileageMap.get(v.plateNumber); - if (m) { - totalMileage += m.avgMileage; + const m = todayMileageMap.get(v.plateNumber); + if (m !== undefined && m > 0) { + totalMileage += m; count++; } } @@ -859,11 +840,11 @@ app.get('/list', async (c) => { let filtered = vehicles; - // attendance filter: active = today mileage > 0, idle = today mileage = 0 (only for Operating vehicles) + // attendance filter: active = day_mileage > 0, idle = day_mileage = 0 (only for Operating vehicles) if (attendance === 'active' || attendance === 'idle') { - const [todayRows] = await pool.query(`SELECT plateNumber, dayMileage FROM ln_vehicle_day_mileage WHERE dates = CURDATE()`); + const [realtimeRows] = await pool.query(`SELECT plate_number, day_mileage FROM tab_truck_remote_sync_realtime_info WHERE is_deleted = 0 AND plate_number IS NOT NULL`); const todayMap = new Map(); - for (const row of todayRows as any[]) todayMap.set(row.plateNumber, Number(row.dayMileage)); + for (const row of realtimeRows as any[]) todayMap.set((row.plate_number || '').trim(), Number(row.day_mileage) || 0); filtered = filtered.filter((v) => v.status === 'Operating'); if (attendance === 'active') { filtered = filtered.filter((v) => (todayMap.get(v.plateNumber) || 0) > 0);