feat: dashbaord overview

This commit is contained in:
Nathnael
2026-08-13 18:13:42 +00:00
parent 89cdc0ad06
commit 147887b7c5
23 changed files with 1795 additions and 94 deletions

View File

@@ -9,8 +9,10 @@ import type { OverviewResponseDto } from './dto/overview-response.dto';
import type {
OverviewBillingTabDto,
OverviewBookingsTabDto,
OverviewClearanceTabDto,
OverviewContractsTabDto,
OverviewCustomersTabDto,
OverviewFleetTabDto,
OverviewOperationsTabDto,
OverviewStaffTabDto,
} from './dto/overview-tab-response.dto';
@@ -237,6 +239,9 @@ export class OverviewService {
wagonStatusBreakdown,
containerStatusBreakdown,
cargoStatusBreakdown,
bookingsByPort,
bookingStatusByPort,
trainLoads,
] = await Promise.all([
this.overviewRepository.getOperationsKpis(),
this.overviewRepository.getDepartureTrend(days),
@@ -249,6 +254,9 @@ export class OverviewService {
this.overviewRepository.getWagonStatusBreakdown(),
this.overviewRepository.getContainerStatusBreakdown(),
this.overviewRepository.getCargoStatusBreakdown(),
this.overviewRepository.getBookingsByPort(days),
this.overviewRepository.getBookingStatusByPort(days),
this.overviewRepository.getTrainLoads(8),
]);
return {
@@ -263,6 +271,76 @@ export class OverviewService {
wagonStatusBreakdown,
containerStatusBreakdown,
cargoStatusBreakdown,
bookingsByPort,
bookingStatusByPort,
trainLoads,
generatedAt: new Date().toISOString(),
};
}
/**
* Rolling stock in depth: wagons and locomotives crossed with type and yard,
* plus how fast each train set turns around. Feeds the operations and control
* centre dashboards.
*/
async getFleetTab(
range: OverviewRangeQuery = '30d',
): Promise<OverviewFleetTabDto> {
const days = OVERVIEW_RANGE_DAYS[range];
const [
wagonStatusBreakdown,
wagonStatusByType,
wagonStatusByYard,
locomotiveStatusBreakdown,
locomotivesByYard,
locomotivesByType,
turnaround,
] = await Promise.all([
this.overviewRepository.getWagonStatusBreakdown(),
this.overviewRepository.getWagonStatusByType(),
this.overviewRepository.getWagonStatusByYard(),
this.overviewRepository.getLocomotiveStatusBreakdown(),
this.overviewRepository.getLocomotivesByYard(),
this.overviewRepository.getLocomotivesByType(),
this.overviewRepository.getTrainTurnaround(days, 8),
]);
return {
wagonStatusBreakdown,
wagonStatusByType,
wagonStatusByYard,
locomotiveStatusBreakdown,
locomotivesByYard,
locomotivesByType,
avgTurnaroundHours: turnaround.avgHours,
turnaroundByTrain: turnaround.rows,
generatedAt: new Date().toISOString(),
};
}
/** Document and invoice queues — the GL desks' and marketing's work in progress. */
async getClearanceTab(): Promise<OverviewClearanceTabDto> {
const [
bookingDocumentsByStatus,
contractDocumentsByStatus,
invoicesByStatus,
invoicesByType,
handoversByMile,
] = await Promise.all([
this.overviewRepository.getBookingDocumentsByStatus(),
this.overviewRepository.getContractDocumentsByStatus(),
this.overviewRepository.getInvoicesByStatus(),
this.overviewRepository.getInvoicesByType(),
this.overviewRepository.getHandoversByMile(),
]);
return {
bookingDocumentsByStatus,
contractDocumentsByStatus,
invoicesByStatus,
invoicesByType,
handoversByMile,
generatedAt: new Date().toISOString(),
};
}
@@ -273,19 +351,26 @@ export class OverviewService {
): Promise<OverviewCustomersTabDto> {
const days = OVERVIEW_RANGE_DAYS[range];
const [kpis, customerGrowthTrend, customersByType, topCustomersByBookings] =
await Promise.all([
this.overviewRepository.getCustomerKpis(),
this.overviewRepository.getCustomerGrowthTrend(days),
this.overviewRepository.getCustomersByType(),
this.overviewRepository.getTopCustomersByBookings(8, dirs),
]);
const [
kpis,
customerGrowthTrend,
customersByType,
topCustomersByBookings,
profilesByTypeStatus,
] = await Promise.all([
this.overviewRepository.getCustomerKpis(),
this.overviewRepository.getCustomerGrowthTrend(days),
this.overviewRepository.getCustomersByType(),
this.overviewRepository.getTopCustomersByBookings(8, dirs),
this.overviewRepository.getProfilesByTypeStatus(),
]);
return {
kpis,
customerGrowthTrend,
customersByType,
topCustomersByBookings,
profilesByTypeStatus,
generatedAt: new Date().toISOString(),
};
}