175 lines
5.5 KiB
TypeScript
175 lines
5.5 KiB
TypeScript
import type {
|
|
SummaryData,
|
|
TypeSummary,
|
|
VehicleListItem,
|
|
DeptGroup,
|
|
RegionGroup,
|
|
CustomerStats,
|
|
RegionalInventoryStats,
|
|
} from './types';
|
|
import { fetchJson } from '../../auth/api-client';
|
|
|
|
const BASE = '/api/vehicles';
|
|
|
|
export interface SubjectOption {
|
|
name: string;
|
|
total: number;
|
|
inventory: number;
|
|
operating: number;
|
|
}
|
|
|
|
function withSubject(path: string, subject?: string | null): string {
|
|
if (!subject) return path;
|
|
const sep = path.includes('?') ? '&' : '?';
|
|
return `${path}${sep}subject=${encodeURIComponent(subject)}`;
|
|
}
|
|
|
|
export async function fetchSubjects(): Promise<SubjectOption[]> {
|
|
return fetchJson<SubjectOption[]>(`${BASE}/subjects`);
|
|
}
|
|
|
|
export async function fetchSummary(subject?: string | null): Promise<SummaryData> {
|
|
return fetchJson<SummaryData>(withSubject(`${BASE}/summary`, subject));
|
|
}
|
|
|
|
export async function fetchByType(subject?: string | null): Promise<TypeSummary[]> {
|
|
return fetchJson<TypeSummary[]>(withSubject(`${BASE}/by-type`, subject));
|
|
}
|
|
|
|
export async function fetchVehicleList(params: {
|
|
batch?: string;
|
|
model?: string;
|
|
location?: string;
|
|
status?: string;
|
|
category?: string;
|
|
vehicleType?: string;
|
|
manager?: string;
|
|
customer?: string;
|
|
isColdChain?: string;
|
|
isTrailer?: string;
|
|
department?: string;
|
|
attendance?: string;
|
|
subject?: string | null;
|
|
source?: string;
|
|
}): Promise<VehicleListItem[]> {
|
|
const query = new URLSearchParams();
|
|
if (params.batch) query.set('batch', params.batch);
|
|
if (params.model) query.set('model', params.model);
|
|
if (params.location) query.set('location', params.location);
|
|
if (params.status) query.set('status', params.status);
|
|
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);
|
|
if (params.department) query.set('department', params.department);
|
|
if (params.attendance) query.set('attendance', params.attendance);
|
|
if (params.subject) query.set('subject', params.subject);
|
|
if (params.source) query.set('source', params.source);
|
|
return fetchJson<VehicleListItem[]>(`${BASE}/list?${query.toString()}`);
|
|
}
|
|
|
|
export interface WeeklyDetailItem {
|
|
truck_id: number;
|
|
plate_number: string;
|
|
handover_date: string | null;
|
|
contract_type: string | null;
|
|
customer_name: string | null;
|
|
}
|
|
|
|
export type FlowType = 'delivered' | 'returned' | 'replaced';
|
|
|
|
export interface FlowDailyPoint {
|
|
date: string;
|
|
delivered: number;
|
|
returned: number;
|
|
replaced: number;
|
|
total: number;
|
|
}
|
|
|
|
export interface FlowDetailItem {
|
|
id: string;
|
|
type: FlowType;
|
|
typeLabel: string;
|
|
date: string;
|
|
truckId: string;
|
|
plateNumber: string;
|
|
eventTime: string | null;
|
|
submitTime: string | null;
|
|
department: string;
|
|
manager: string;
|
|
customerName: string | null;
|
|
}
|
|
|
|
export interface FlowStatsResponse {
|
|
start: string;
|
|
end: string;
|
|
daily: FlowDailyPoint[];
|
|
totals: {
|
|
delivered: number;
|
|
returned: number;
|
|
replaced: number;
|
|
total: number;
|
|
};
|
|
details: FlowDetailItem[];
|
|
}
|
|
|
|
export async function fetchDeptStats(subject?: string | null): Promise<DeptGroup[]> {
|
|
return fetchJson<DeptGroup[]>(withSubject(`${BASE}/dept-stats`, subject));
|
|
}
|
|
|
|
export async function fetchRegionStats(
|
|
params?: { customer?: string; city?: string; region?: string },
|
|
subject?: string | null,
|
|
): Promise<RegionGroup[]> {
|
|
const query = new URLSearchParams();
|
|
if (params?.customer) query.set('customer', params.customer);
|
|
if (params?.city) query.set('city', params.city);
|
|
if (params?.region) query.set('region', params.region);
|
|
if (subject) query.set('subject', subject);
|
|
const qs = query.toString();
|
|
return fetchJson<RegionGroup[]>(`${BASE}/region-stats${qs ? `?${qs}` : ''}`);
|
|
}
|
|
|
|
export async function fetchCustomerStats(subject?: string | null): Promise<CustomerStats[]> {
|
|
return fetchJson<CustomerStats[]>(withSubject(`${BASE}/customer-stats`, subject));
|
|
}
|
|
|
|
export async function fetchInventoryStats(subject?: string | null): Promise<RegionalInventoryStats[]> {
|
|
return fetchJson<RegionalInventoryStats[]>(withSubject(`${BASE}/inventory-stats`, subject));
|
|
}
|
|
|
|
export async function fetchRegionChart(
|
|
groupBy: string,
|
|
top = 8,
|
|
source = 'realtime',
|
|
subject?: string | null,
|
|
): Promise<{ name: string; value: number }[]> {
|
|
return fetchJson<{ name: string; value: number }[]>(
|
|
withSubject(`${BASE}/region-chart?groupBy=${groupBy}&top=${top}&source=${source}`, subject),
|
|
);
|
|
}
|
|
|
|
export async function fetchWeeklyDetail(
|
|
type: string,
|
|
filters?: { model?: string; batch?: string; location?: string; source?: string },
|
|
): Promise<WeeklyDetailItem[]> {
|
|
const params = new URLSearchParams({ type });
|
|
if (filters?.model && filters.model !== 'All') params.set('model', filters.model);
|
|
if (filters?.batch && filters.batch !== 'All') params.set('batch', filters.batch);
|
|
if (filters?.location && filters.location !== 'All') params.set('location', filters.location);
|
|
if (filters?.source) params.set('source', filters.source);
|
|
return fetchJson<WeeklyDetailItem[]>(`${BASE}/weekly-detail?${params.toString()}`);
|
|
}
|
|
|
|
export async function fetchFlowStats(params: {
|
|
start: string;
|
|
end: string;
|
|
subject?: string | null;
|
|
}): Promise<FlowStatsResponse> {
|
|
const query = new URLSearchParams({ start: params.start, end: params.end });
|
|
if (params.subject) query.set('subject', params.subject);
|
|
return fetchJson<FlowStatsResponse>(`${BASE}/flow-stats?${query.toString()}`);
|
|
}
|