feat: 支持查询指定日期里程+删除搜索关键词和车牌号筛选

- 后端支持 date 参数,指定日期时实时查询数据库(不用缓存)
- 同时查询前一天数据计算环比
- 高级筛选添加"查询日期"日期选择器
- 删除高级筛选中的"搜索关键词"和"车牌号"(已有快捷筛选)
- 筛选标签支持显示日期条件

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-01 23:41:03 +08:00
parent cbf0e18634
commit 0b8bbbb063
3 changed files with 92 additions and 38 deletions

View File

@@ -152,11 +152,43 @@ async function refreshMonitoringCache() {
refreshMonitoringCache();
setInterval(refreshMonitoringCache, 2 * 60 * 1000);
// GET /monitoring — 从缓存取数据,支持筛选/排序/分页
app.get('/monitoring', (c) => {
if (!monitoringCache) {
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() });
// 查询指定日期的里程数据(非缓存)
async function queryDateMileage(dateStr: string): Promise<{ vehicles: CachedVehicle[]; yesterdayTotal: number }> {
const [mileageRows] = await mileagePool.execute(
`SELECT plate, vin, daily_km, total_km, source FROM v_vehicle_daily_stats WHERE stat_date = ?`,
[dateStr]
) as any;
const [yesterdayRows] = await mileagePool.execute(
`SELECT SUM(daily_km) as total FROM v_vehicle_daily_stats WHERE stat_date = DATE_SUB(?, INTERVAL 1 DAY)`,
[dateStr]
) as any;
const [infoRows] = await pool.execute(VEHICLE_INFO_SQL) as any;
const infoMap = new Map<string, any>();
for (const row of infoRows) infoMap.set(row.plate, row);
const mileageMap = new Map<string, any>();
for (const row of mileageRows) {
const existing = mileageMap.get(row.plate);
if (!existing || Number(row.daily_km) > Number(existing.daily_km)) mileageMap.set(row.plate, row);
}
const vehicles: CachedVehicle[] = Array.from(mileageMap.values()).map((m: any) => {
const info = infoMap.get(m.plate);
const dailyKm = Number(m.daily_km) || 0;
const source = m.source || 'NONE';
return {
plate: m.plate, vin: m.vin, dailyKm,
totalKm: m.total_km !== null ? Number(m.total_km) : null,
source, isOnline: source !== 'NONE' && dailyKm > 0, isDataSynced: source !== 'NONE',
customer: info?.customer || null, department: info?.department || null,
manager: info?.manager || null, rentStatus: info?.rent_status || null,
entity: info?.entity || null, project: info?.project || null,
};
});
return { vehicles, yesterdayTotal: Number(yesterdayRows[0]?.total) || 0 };
}
// GET /monitoring — 从缓存取数据(或指定日期实时查询),支持筛选/排序/分页
app.get('/monitoring', async (c) => {
const emptyResponse = { 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';
const sortOrder = c.req.query('sortOrder') || 'desc';
@@ -170,8 +202,43 @@ app.get('/monitoring', (c) => {
const mileageMin = c.req.query('mileageMin') || '';
const mileageMax = c.req.query('mileageMax') || '';
const plate = c.req.query('plate') || '';
const date = c.req.query('date') || '';
let vehicles = monitoringCache.vehicles;
let allVehicles: CachedVehicle[];
let yesterdayTotal: number;
let filters: MonitoringCache['filters'];
if (date) {
// 指定日期:实时查询
try {
const result = await queryDateMileage(date);
allVehicles = result.vehicles;
yesterdayTotal = result.yesterdayTotal;
// 从查询结果提取筛选选项
const deptOrder = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十'];
filters = {
departments: (Array.from(new Set(allVehicles.map(v => v.department).filter(Boolean))) as string[]).sort((a, b) => {
const ai = deptOrder.findIndex(d => a.includes(d)); const bi = deptOrder.findIndex(d => b.includes(d));
return (ai === -1 ? 99 : ai) - (bi === -1 ? 99 : bi);
}),
customers: Array.from(new Set(allVehicles.map(v => v.customer).filter(Boolean))) as string[],
plates: allVehicles.map(v => v.plate),
projects: Array.from(new Set(allVehicles.map(v => v.project).filter(Boolean))) as string[],
entities: Array.from(new Set(allVehicles.map(v => v.entity).filter(Boolean))) as string[],
};
} catch (e) {
console.error('monitoring date query error:', e);
return c.json(emptyResponse, 500);
}
} else {
// 默认:从缓存取
if (!monitoringCache) return c.json(emptyResponse);
allVehicles = monitoringCache.vehicles;
yesterdayTotal = monitoringCache.stats.yesterdayTotal;
filters = monitoringCache.filters;
}
let vehicles = allVehicles;
// 筛选
if (search) {
@@ -197,7 +264,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,
yesterdayTotal,
};
// 排序
@@ -214,11 +281,11 @@ app.get('/monitoring', (c) => {
return c.json({
vehicles: paged,
stats: filteredStats,
filters: monitoringCache.filters,
filters,
total,
page,
totalPages: Math.ceil(total / limit),
updatedAt: monitoringCache.updatedAt,
updatedAt: date || monitoringCache?.updatedAt || new Date().toISOString(),
});
});