feat: 支持查询指定日期里程+删除搜索关键词和车牌号筛选
- 后端支持 date 参数,指定日期时实时查询数据库(不用缓存) - 同时查询前一天数据计算环比 - 高级筛选添加"查询日期"日期选择器 - 删除高级筛选中的"搜索关键词"和"车牌号"(已有快捷筛选) - 筛选标签支持显示日期条件 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -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(),
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user