feat: add inventory statistics section, adapt to latest prototype

- Add GET /api/vehicles/inventory-stats endpoint that groups inventory vehicles by macro-region, city, brand, type, model, and batch
- Add RegionalInventoryStats type and fetchInventoryStats API function
- Add full inventory statistics section with region/model tabs, filters, desktop table, and mobile views
- Add modal filters (plate number, model, brand, location search) to vehicle detail modal
- Update modal header to support title field for contextual naming

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-03-28 16:24:39 +08:00
parent d6ac1044fe
commit 629451c13d
4 changed files with 660 additions and 10 deletions

View File

@@ -813,6 +813,43 @@ app.get('/list', async (c) => {
);
});
// GET /api/vehicles/inventory-stats — grouped inventory stats for the inventory statistics section
app.get('/inventory-stats', async (c) => {
const vehicles = await getVehicles();
const inventory = vehicles.filter((v) => v.status === 'Inventory');
const TYPE_NAME_MAP: Record<string, string> = {
t4_5: '4.5T普货',
t4_5c: '4.5T冷链',
t18: '18T',
t49: '49T',
trailer: '挂车',
other: '其他',
};
const groups = new Map<string, number>();
for (const v of inventory) {
const typeCategory = classifyVehicleType(v);
const typeName = TYPE_NAME_MAP[typeCategory];
const region = mapMacroRegion(v.province, v.city);
const city = v.city || '其他';
const brand = v.brandLabel || '未知';
const model = v.model;
const batch = v.contractNo || 'N/A';
const key = `${region}|${city}|${brand}|${typeName}|${model}|${batch}`;
groups.set(key, (groups.get(key) || 0) + 1);
}
const result = Array.from(groups.entries())
.map(([key, quantity]) => {
const [region, city, brand, type, model, batch] = key.split('|');
return { region, city, brand, type, model, batch, quantity };
})
.sort((a, b) => b.quantity - a.quantity);
return c.json(result);
});
// GET /api/vehicles/weekly-detail?type=delivered|returned|replaced|pending
app.get('/weekly-detail', async (c) => {
const type = c.req.query('type');