fix: tạm dừng thuật toán tìm đường đi

This commit is contained in:
2026-06-17 21:16:31 +07:00
parent 69c67a1636
commit ffe3cb6ecd
+60 -6
View File
@@ -640,7 +640,7 @@ export const TourDetailPage = ({
const coordsString = `${p1.longitude},${p1.latitude};${p2.longitude},${p2.latitude}`;
segmentPromises.push(
fetch(`https://router.project-osrm.org/route/v1/${travelMode}/${coordsString}?overview=full&geometries=geojson&alternatives=true`)
fetch(`https://router.project-osrm.org/route/v1/${travelMode}/${coordsString}?overview=full&geometries=geojson&alternatives=3`) // Yêu cầu tối đa 5 phương án thay thế cho mỗi phân đoạn
.then(res => {
if (!res.ok) throw new Error(`OSRM API error: ${res.status}`);
return res.json();
@@ -674,14 +674,24 @@ export const TourDetailPage = ({
const overallAlternativeRoutes: OSRMRoute[] = [];
// Limit overall alternatives based on the number of alternatives for the first segment, up to 3
const maxOverallAlternatives = Math.min(3, allSegmentAlternatives[0]?.length || 1);
const maxOverallAlternativesToGenerate = 3; // Số lượng lộ trình tổng thể muốn tạo
for (let altIdx = 0; altIdx < maxOverallAlternatives; altIdx++) {
const selectedSegmentIndices: number[] = allSegmentAlternatives.map((_, segIdx) =>
segIdx === 0 ? altIdx : 0 // Use altIdx for first segment, 0 for others
// Heuristic để tạo các lộ trình tổng thể đa dạng hơn:
// 1. Lộ trình chính (fastest/default cho tất cả các phân đoạn)
const primarySegmentIndices = allSegmentAlternatives.map(() => 0);
const primaryCombinedRoute = combineSegmentRoutes(allSegmentAlternatives, primarySegmentIndices);
if (primaryCombinedRoute) {
overallAlternativeRoutes.push(primaryCombinedRoute);
}
// 2. Các lộ trình thay thế: Thử kết hợp các phương án thay thế từ các phân đoạn
// Ví dụ: Lấy phương án thứ N của mỗi phân đoạn (nếu có), hoặc phương án 0 nếu không có
for (let altChoice = 1; altChoice < maxOverallAlternativesToGenerate; altChoice++) {
const selectedSegmentIndices: number[] = allSegmentAlternatives.map(segmentAlts =>
Math.min(altChoice, segmentAlts.length - 1) // Chọn phương án thứ 'altChoice', hoặc phương án cuối cùng nếu không đủ
);
const combinedRoute = combineSegmentRoutes(allSegmentAlternatives, selectedSegmentIndices);
if (combinedRoute) {
if (combinedRoute && !overallAlternativeRoutes.some(r => JSON.stringify(r.geometry.coordinates) === JSON.stringify(combinedRoute.geometry.coordinates))) {
overallAlternativeRoutes.push(combinedRoute);
}
}
@@ -711,6 +721,33 @@ export const TourDetailPage = ({
}
}, [selectedRouteIndex, routes]);
// Tính toán thông tin hiển thị cho lộ trình đang chọn để đề xuất cho người dùng
const selectedRouteInfo = useMemo(() => {
if (!routes || routes.length === 0 || !routes[selectedRouteIndex]) return null;
const r = routes[selectedRouteIndex];
// Định dạng thời gian di chuyển
const duration = r.duration;
const hours = Math.floor(duration / 3600);
const minutes = Math.round((duration % 3600) / 60);
const durationStr = hours > 0 ? `${hours}h${minutes}p` : `${minutes}p`;
// Xác định nhãn đề xuất: Index 0 thường là lộ trình tối ưu nhất của OSRM (thông dụng nhất)
// Kiểm tra thêm nếu đây là lộ trình ngắn nhất trong các phương án
const isShortest = routes.length > 1 && r.distance === Math.min(...routes.map(rt => rt.distance));
let label = "Lộ trình";
if (selectedRouteIndex === 0) label = "Đề xuất";
else if (isShortest) label = "Ngắn nhất";
else label = `Lựa chọn ${selectedRouteIndex + 1}`;
return {
distance: (r.distance / 1000).toFixed(1),
duration: durationStr,
label
};
}, [routes, selectedRouteIndex]);
useEffect(() => {
if (initialViewState) {
setMapCenter(initialViewState.center);
@@ -1391,6 +1428,22 @@ export const TourDetailPage = ({
</div>
</div>
)}
{/* Overlay thông tin lộ trình đề xuất (Lộ trình thông dụng nhất) */}
{selectedRouteInfo && drivingRoute.length > 0 && (
<div className="absolute top-3 left-1/2 -translate-x-1/2 z-[1001] bg-white/80 backdrop-blur-md px-4 py-2 rounded-2xl shadow-xl border border-white flex items-center gap-3 animate-in fade-in slide-in-from-top-2 duration-500">
<div className="flex items-center gap-1.5">
<Navigation className="w-3.5 h-3.5 text-blue-600 rotate-45" />
<span className="text-[10px] font-black text-gray-400 uppercase tracking-tighter">{selectedRouteInfo.label}</span>
</div>
<div className="flex items-center gap-2 text-xs font-bold text-blue-700 whitespace-nowrap">
<span>{selectedRouteInfo.distance} km</span>
<span className="text-gray-300"></span>
<span>{selectedRouteInfo.duration}</span>
</div>
</div>
)}
<MapContainer
center={initialViewState?.center || mapCenter}
zoom={mapZoom}
@@ -1647,6 +1700,7 @@ export const TourDetailPage = ({
<button
key={idx}
onClick={() => { setSelectedRouteIndex(idx); setIsMapControlsOpen(false); }}
title={`${(route.distance / 1000).toFixed(1)} km - ${Math.round(route.duration / 60)}p`}
className={`w-8 h-8 flex items-center justify-center rounded-lg transition-all border ${
selectedRouteIndex === idx
? 'bg-blue-600 text-white border-blue-600 shadow-sm'