Cho phép xóa tour và xóa chặng trong Tour Dashboard

This commit is contained in:
2026-06-13 21:48:53 +07:00
parent 578b03d808
commit 5e3f10631f
18 changed files with 580 additions and 42 deletions
+81 -3
View File
@@ -111,8 +111,12 @@ class TourController {
@UseGuards(JwtAuthGuard)
@Post(':tourId/locations')
async addLocation(@Param('tourId', ParseUUIDPipe) tourId: string, @Body() body: any) {
const leg = await this.prisma.leg.findFirst({ where: { tourId } });
if (!leg) throw new NotFoundException('Không tìm thấy chặng nào trong tour');
const legId = body.legId;
const leg = legId
? await this.prisma.leg.findUnique({ where: { id: legId } })
: await this.prisma.leg.findFirst({ where: { tourId } });
if (!leg) throw new NotFoundException('Không tìm thấy chặng phù hợp để thêm địa điểm');
return this.prisma.location.create({
data: {
@@ -128,6 +132,48 @@ class TourController {
});
}
@UseGuards(JwtAuthGuard)
@Post(':tourId/legs')
async addLeg(@Param('tourId', ParseUUIDPipe) tourId: string, @Body() body: any) {
const tour = await this.prisma.tour.findUnique({
where: { id: tourId },
include: { legs: true }
});
if (!tour) throw new NotFoundException('Không tìm thấy tour');
return this.prisma.leg.create({
data: {
tourId,
sequence: tour.legs.length + 1,
note: body.note || `Chặng ${tour.legs.length + 1}`
}
});
}
@UseGuards(JwtAuthGuard)
@Patch(':id')
async updateTour(@Param('id', ParseUUIDPipe) id: string, @Body() body: any) {
// Lưu ý: Trong thực tế nên kiểm tra xem user có phải là OWNER không
return this.prisma.tour.update({
where: { id },
data: {
title: body.title,
startDate: body.startDate ? new Date(body.startDate) : undefined,
endDate: body.endDate ? new Date(body.endDate) : undefined,
},
});
}
@UseGuards(JwtAuthGuard)
@Delete(':id')
async deleteTour(@Param('id', ParseUUIDPipe) id: string) {
// Xóa tour sẽ xóa cascade các Leg, Location, Expense nhờ config onDelete: Cascade trong schema
await this.prisma.tour.delete({
where: { id },
});
return { success: true };
}
@Get('explore')
async getPublicTours() {
// Lấy các tour có ít nhất 1 ảnh và thông tin vị trí từ chặng đầu tiên
@@ -167,6 +213,38 @@ class TourController {
}
}
@Controller('v1/legs')
@UseGuards(JwtAuthGuard)
class LegController {
constructor(private prisma: PrismaService) {}
@Patch(':id')
async updateLeg(@Param('id', ParseUUIDPipe) id: string, @Body() body: any) {
return this.prisma.leg.update({
where: { id },
data: {
note: body.note,
sequence: body.sequence
}
});
}
@Delete(':id')
async deleteLeg(@Param('id', ParseUUIDPipe) id: string) {
const leg = await this.prisma.leg.findUnique({
where: { id },
include: { _count: { select: { locations: true } } }
});
if (leg?._count.locations && leg._count.locations > 0) {
throw new BadRequestException('Không thể xóa chặng đang có địa điểm. Hãy xóa địa điểm trước.');
}
await this.prisma.leg.delete({ where: { id } });
return { success: true };
}
}
/**
* Helper tính khoảng cách giữa 2 tọa độ (Haversine formula)
*/
@@ -302,7 +380,7 @@ class UserController {
signOptions: { expiresIn: '1d' },
}),
],
controllers: [AppController, AuthController, TourController, UserController, RoutingController],
controllers: [AppController, AuthController, TourController, UserController, RoutingController, LegController],
providers: [PrismaService, JwtStrategy],
exports: [PrismaService]
})