mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-02 23:13:40 +00:00
Initial commit of edr-passenger-api alpha version
This commit is contained in:
16
apps/edr-passenger-api/src/modules/live/live.controller.ts
Normal file
16
apps/edr-passenger-api/src/modules/live/live.controller.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { Body, Controller, Get, Param, Patch, UseGuards } from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { LiveService } from './live.service';
|
||||
import { UpdateLiveStatusDto } from './live.dto';
|
||||
import { JwtGuard } from '../../common/jwt.guard';
|
||||
|
||||
@ApiTags('Live Tracking')
|
||||
@Controller('live')
|
||||
export class LiveController {
|
||||
constructor(private service: LiveService) {}
|
||||
@Get('trips/:tripId') @ApiOperation({ summary: 'Get live status for a trip' }) getTripLiveStatus(@Param('tripId') id: string) { return this.service.getTripLiveStatus(id); }
|
||||
@Get('trips/:tripId/stops') @ApiOperation({ summary: 'Get stop timeline for a trip' }) getStopTimeline(@Param('tripId') id: string) { return this.service.getStopTimeline(id); }
|
||||
@Patch('trips/:tripId/status')@UseGuards(JwtGuard) @ApiBearerAuth('JWT-auth') @ApiOperation({ summary: 'Update live trip status (staff/system)' }) updateLiveStatus(@Param('tripId') id: string, @Body() dto: UpdateLiveStatusDto) { return this.service.updateLiveStatus(id, dto); }
|
||||
@Get('crowd-signals') @ApiOperation({ summary: 'Get station crowd signals' }) getCrowdSignals() { return this.service.getStationCrowdSignals(); }
|
||||
@Get('weather-alerts') @ApiOperation({ summary: 'Get active weather alerts' }) getWeatherAlerts() { return this.service.getWeatherAlerts(); }
|
||||
}
|
||||
11
apps/edr-passenger-api/src/modules/live/live.dto.ts
Normal file
11
apps/edr-passenger-api/src/modules/live/live.dto.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { IsString, IsOptional, IsInt, Min, Max } from 'class-validator';
|
||||
import { ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class UpdateLiveStatusDto {
|
||||
@ApiPropertyOptional({ example: 'EN_ROUTE' }) @IsOptional() @IsString() state?: string;
|
||||
@ApiPropertyOptional({ example: 'Between Dire Dawa and Dewele' }) @IsOptional() @IsString() currentLocationLabel?: string;
|
||||
@ApiPropertyOptional({ example: 45 }) @IsOptional() @IsInt() @Min(0) @Max(100) progressPercent?: number;
|
||||
@ApiPropertyOptional({ example: 10 }) @IsOptional() @IsInt() @Min(0) delayMinutes?: number;
|
||||
@ApiPropertyOptional({ example: 120 }) @IsOptional() @IsInt() @Min(0) currentSpeedKph?: number;
|
||||
@ApiPropertyOptional({ example: 'Platform 2' }) @IsOptional() @IsString() platformLabel?: string;
|
||||
}
|
||||
6
apps/edr-passenger-api/src/modules/live/live.module.ts
Normal file
6
apps/edr-passenger-api/src/modules/live/live.module.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { LiveController } from './live.controller';
|
||||
import { LiveService } from './live.service';
|
||||
|
||||
@Module({ controllers: [LiveController], providers: [LiveService] })
|
||||
export class LiveModule {}
|
||||
35
apps/edr-passenger-api/src/modules/live/live.service.ts
Normal file
35
apps/edr-passenger-api/src/modules/live/live.service.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { PrismaService } from '../../common/prisma.service';
|
||||
|
||||
@Injectable()
|
||||
export class LiveService {
|
||||
constructor(private prisma: PrismaService) {}
|
||||
|
||||
async getTripLiveStatus(tripId: string) {
|
||||
const trip = await this.prisma.trip.findUnique({
|
||||
where: { id: tripId },
|
||||
include: { service: true, originStation: true, destinationStation: true, liveStatus: true, stopTimes: { include: { station: true }, orderBy: { sequence: 'asc' } } },
|
||||
});
|
||||
if (!trip) throw new NotFoundException('Trip not found');
|
||||
const live = trip.liveStatus;
|
||||
const nextStop = trip.stopTimes.find((s) => s.status === 'UPCOMING' || s.status === 'APPROACHING');
|
||||
return {
|
||||
tripId: trip.id, trainName: trip.service.name,
|
||||
fromStationName: trip.originStation.name, toStationName: trip.destinationStation.name,
|
||||
state: live?.state ?? trip.status, currentLocationLabel: live?.currentLocationLabel,
|
||||
progressPercent: live?.progressPercent ?? 0, delayMinutes: live?.delayMinutes ?? 0,
|
||||
currentSpeedKph: live?.currentSpeedKph, platformLabel: live?.platformLabel,
|
||||
nextStopStationName: nextStop?.station.name, updatedAt: live?.updatedAt ?? trip.departureAt,
|
||||
};
|
||||
}
|
||||
|
||||
updateLiveStatus(tripId: string, data: any) {
|
||||
return this.prisma.tripLiveStatus.upsert({ where: { tripId }, update: data, create: { tripId, state: data.state ?? 'SCHEDULED', ...data } });
|
||||
}
|
||||
|
||||
getStopTimeline(tripId: string) { return this.prisma.tripStopTime.findMany({ where: { tripId }, include: { station: true }, orderBy: { sequence: 'asc' } }); }
|
||||
|
||||
getStationCrowdSignals() { return this.prisma.stationCrowdSignal.findMany({ include: { station: true } }); }
|
||||
|
||||
getWeatherAlerts() { return this.prisma.weatherAlert.findMany({ where: { validUntil: { gte: new Date() } }, orderBy: { createdAt: 'desc' } }); }
|
||||
}
|
||||
Reference in New Issue
Block a user