feat: add frontend types and API client for dept/region/customer stats

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-03-27 18:15:07 +08:00
parent 73d5afde5c
commit 01a64431dc
2 changed files with 70 additions and 0 deletions

View File

@@ -2,6 +2,9 @@ import type {
SummaryData, SummaryData,
TypeSummary, TypeSummary,
VehicleListItem, VehicleListItem,
DeptGroup,
RegionGroup,
CustomerStats,
} from './types'; } from './types';
const BASE = '/api/vehicles'; const BASE = '/api/vehicles';
@@ -26,6 +29,11 @@ export async function fetchVehicleList(params: {
location?: string; location?: string;
status?: string; status?: string;
category?: string; category?: string;
vehicleType?: string;
manager?: string;
customer?: string;
isColdChain?: string;
isTrailer?: string;
}): Promise<VehicleListItem[]> { }): Promise<VehicleListItem[]> {
const query = new URLSearchParams(); const query = new URLSearchParams();
if (params.batch) query.set('batch', params.batch); if (params.batch) query.set('batch', params.batch);
@@ -33,6 +41,11 @@ export async function fetchVehicleList(params: {
if (params.location) query.set('location', params.location); if (params.location) query.set('location', params.location);
if (params.status) query.set('status', params.status); if (params.status) query.set('status', params.status);
if (params.category) query.set('category', params.category); if (params.category) query.set('category', params.category);
if (params.vehicleType) query.set('vehicleType', params.vehicleType);
if (params.manager) query.set('manager', params.manager);
if (params.customer) query.set('customer', params.customer);
if (params.isColdChain) query.set('isColdChain', params.isColdChain);
if (params.isTrailer) query.set('isTrailer', params.isTrailer);
return fetchJson<VehicleListItem[]>(`${BASE}/list?${query.toString()}`); return fetchJson<VehicleListItem[]>(`${BASE}/list?${query.toString()}`);
} }
@@ -44,6 +57,18 @@ export interface WeeklyDetailItem {
customer_name: string | null; customer_name: string | null;
} }
export async function fetchDeptStats(): Promise<DeptGroup[]> {
return fetchJson<DeptGroup[]>(`${BASE}/dept-stats`);
}
export async function fetchRegionStats(): Promise<RegionGroup[]> {
return fetchJson<RegionGroup[]>(`${BASE}/region-stats`);
}
export async function fetchCustomerStats(): Promise<CustomerStats[]> {
return fetchJson<CustomerStats[]>(`${BASE}/customer-stats`);
}
export async function fetchWeeklyDetail(type: string): Promise<WeeklyDetailItem[]> { export async function fetchWeeklyDetail(type: string): Promise<WeeklyDetailItem[]> {
return fetchJson<WeeklyDetailItem[]>(`${BASE}/weekly-detail?type=${type}`); return fetchJson<WeeklyDetailItem[]>(`${BASE}/weekly-detail?type=${type}`);
} }

View File

@@ -109,3 +109,48 @@ export interface VehicleListItem {
customerName: string | null; customerName: string | null;
subjectOrg: string | null; subjectOrg: string | null;
} }
export interface ManagerStats {
manager: string;
department: string;
t4_5: number;
t4_5c: number;
t18: number;
t49: number;
trailer: number;
other: number;
total: number;
}
export interface DeptGroup {
department: string;
totalAssets: number;
operatingCount: number;
idleCount: number;
managers: ManagerStats[];
}
export interface RegionGroup {
region: string;
totalAssets: number;
operatingCount: number;
inventoryCount: number;
customers: string[];
typeBreakdown: { type: string; total: number; operating: number; inventory: number; customers: string[] }[];
}
export interface CustomerStats {
customer: string;
manager: string;
brand: string;
department: string;
region: string;
city: string;
t4_5: number;
t4_5c: number;
t18: number;
t49: number;
trailer: number;
other: number;
total: number;
}