Thêm tính năng trong mục 4.1 của ARCHITECTURE.md

This commit is contained in:
2026-06-13 20:14:52 +07:00
parent b54707823c
commit c51ddc34c7
13 changed files with 343 additions and 60 deletions
+66 -1
View File
@@ -157,6 +157,71 @@ TourController = __decorate([
Controller('v1/tours'),
__metadata("design:paramtypes", [PrismaService])
], TourController);
function calculateDistance(lat1, lon1, lat2, lon2) {
const p = 0.017453292519943295;
const c = Math.cos;
const a = 0.5 - c((lat2 - lat1) * p) / 2 +
c(lat1 * p) * c(lat2 * p) *
(1 - c((lon2 - lon1) * p)) / 2;
return 12742 * Math.asin(Math.sqrt(a));
}
let RoutingController = class RoutingController {
constructor(prisma) {
this.prisma = prisma;
}
async optimize(legId) {
const locations = await this.prisma.location.findMany({
where: { legId },
});
if (locations.length <= 2)
return locations;
const optimized = [];
const unvisited = [...locations];
let current = unvisited.sort((a, b) => (a.plannedStart?.getTime() || 0) - (b.plannedStart?.getTime() || 0)).shift();
optimized.push(current);
while (unvisited.length > 0) {
let nearestIdx = 0;
let minDist = Infinity;
for (let i = 0; i < unvisited.length; i++) {
const d = calculateDistance(current.latitude, current.longitude, unvisited[i].latitude, unvisited[i].longitude);
if (d < minDist) {
minDist = d;
nearestIdx = i;
}
}
current = unvisited.splice(nearestIdx, 1)[0];
optimized.push(current);
}
let totalDistance = 0;
for (let i = 0; i < optimized.length - 1; i++) {
totalDistance += calculateDistance(optimized[i].latitude, optimized[i].longitude, optimized[i + 1].latitude, optimized[i + 1].longitude);
}
const baseTime = optimized[0].plannedStart || new Date();
await Promise.all(optimized.map((loc, index) => this.prisma.location.update({
where: { id: loc.id },
data: { plannedStart: new Date(baseTime.getTime() + index * 3600000) },
})));
const updatedLocations = await this.prisma.location.findMany({
where: { legId },
orderBy: { plannedStart: 'asc' }
});
return {
locations: updatedLocations,
totalDistance: parseFloat(totalDistance.toFixed(2))
};
}
};
__decorate([
Post('optimize/:legId'),
__param(0, Param('legId', ParseUUIDPipe)),
__metadata("design:type", Function),
__metadata("design:paramtypes", [String]),
__metadata("design:returntype", Promise)
], RoutingController.prototype, "optimize", null);
RoutingController = __decorate([
Controller('v1/routing'),
__metadata("design:paramtypes", [PrismaService])
], RoutingController);
let UserController = class UserController {
constructor(prisma) {
this.prisma = prisma;
@@ -240,7 +305,7 @@ AppModule = __decorate([
signOptions: { expiresIn: '1d' },
}),
],
controllers: [AppController, AuthController, TourController, UserController],
controllers: [AppController, AuthController, TourController, UserController, RoutingController],
providers: [PrismaService, JwtStrategy],
exports: [PrismaService]
})