@@ -314,6 +314,20 @@
// Timestamp 'start' TIDAK diubah karena itu waktu kejadian sebenarnya —
// yang disamakan hanya titik lokasi & odometer supaya laporan terlihat
// kontinu (finish trip N == start trip N+1).
+ //
+ // PENTING: perbandingan koordinat dilakukan secara NUMERIK (parseFloat +
+ // hitung jarak meter via getDistanceMeters), BUKAN string mentah.
+ // Ini supaya kasus seperti berikut tetap terdeteksi & diperbaiki:
+ // - km/odometer sudah nyambung (finish trip N == start trip N+1)
+ // TAPI titik GPS-nya beda beberapa meter (drift GPS), sehingga
+ // salah satu titik "masuk" radius site tertentu (mis. "Bank BNU")
+ // dan yang lain tidak -> teks lokasi jadi kelihatan "loncat"
+ // walau kendaraan sebenarnya di tempat yang sama.
+ // Toleransi 0 meter berarti: kalau titiknya tidak PERSIS sama,
+ // selalu disamakan dengan finish sebelumnya. Ini paling aman untuk
+ // laporan (finish trip N akan selalu == start trip N+1).
+ const TRIP_CONTINUITY_TOLERANCE_METERS = 0; // >>> ADDED
+
function normalizeTripContinuity(rows) { // >>> ADDED
if (!Array.isArray(rows) || rows.length === 0) return rows;
@@ -333,14 +347,54 @@
const prev = groupRows[i - 1];
const curr = groupRows[i];
- const locMismatch = (prev.finish_lat_long || '').trim() !== (curr.start_lat_long || '')
- .trim();
+ // 1) Cek mismatch km/odometer
const kmMismatch = Number(prev.finishMileage) !== Number(curr.startMileage);
- if (locMismatch || kmMismatch) {
+ // 2) Cek mismatch koordinat GPS -- HANYA kalau datanya tersedia,
+ // karena banyak data (seperti contoh Anda) punya
+ // start_lat_long/finish_lat_long = null untuk semua baris.
+ const prevCoord = parseLatLong(prev.finish_lat_long);
+ const currCoord = parseLatLong(curr.start_lat_long);
+ let coordMismatch = false;
+ if (prevCoord.lat !== null && currCoord.lat !== null) {
+ const distMeters = getDistanceMeters(
+ prevCoord.lat, prevCoord.lng,
+ currCoord.lat, currCoord.lng
+ );
+ coordMismatch = distMeters > TRIP_CONTINUITY_TOLERANCE_METERS;
+ }
+
+ // 3) Cek mismatch TEKS lokasi (startLoc vs finishLoc). Ini penting
+ // karena saat lat_long null, satu-satunya sumber lokasi yang
+ // dipakai untuk render adalah field teks ini (lihat kolom
+ // Start/Finish -> prioritas 2: row.startLoc / row.finishLoc).
+ // Tanpa cek ini, kasus seperti "Estrada Suai - Maliana, Cendana"
+ // vs "Bank BNU, Estrada Suai - Maliana, Cendana" tidak akan
+ // terdeteksi sebagai mismatch walau km-nya sudah nyambung.
+ const prevFinishText = (prev.finishLoc || '').trim();
+ const currStartText = (curr.startLoc || '').trim();
+ const textMismatch = prevFinishText !== currStartText;
+
+ if (kmMismatch || coordMismatch || textMismatch) {
curr.start_lat_long = prev.finish_lat_long;
curr.startLoc = prev.finishLoc;
curr.startMileage = prev.finishMileage;
+
+ // Hitung ulang Distance (kolom 'mileage') dari selisih odometer
+ // yang baru (finishMileage - startMileage yang sudah disinkronkan),
+ // supaya kolom Distance tetap konsisten dengan kolom Start(km)/Finish(km)
+ // yang tampil di tabel. Sebelumnya 'mileage' berasal dari GPS track
+ // mentah, yang bisa beda dengan selisih odometer setelah normalisasi ini.
+ //
+ // - Kalau hasilnya minus (finishMileage < startMileage, misal odometer
+ // sempat reset/kebalik), jadikan positif (absolute value).
+ // - Lalu bulatkan ke bilangan bulat terdekat: desimal >= 0.5 dibulatkan
+ // ke atas, desimal < 0.5 dibulatkan ke bawah (standard round-half-up;
+ // Math.round sudah berlaku demikian untuk angka positif).
+ const rawDiff = Number(curr.finishMileage) - Number(curr.startMileage);
+ if (!isNaN(rawDiff)) {
+ curr.mileage = Math.round(Math.abs(rawDiff));
+ }
}
}
});
@@ -600,7 +654,8 @@
locationLabel = formatSiteLabel(nearestSite);
} else if (row.startLoc) {
// Prioritas 2: startLoc sudah ada dari API
- locationLabel = Helper.shortenText(decodeURIComponent(row.startLoc), 255);
+ locationLabel = Helper.shortenText(decodeURIComponent(row
+ .startLoc), 255);
} else if (type === 'export') {
// Export bersifat sinkron, tidak bisa menunggu hasil geocode background
locationLabel = '-';
@@ -630,7 +685,8 @@
if (nearestSite) {
locationLabel = formatSiteLabel(nearestSite);
} else if (row.finishLoc) {
- locationLabel = Helper.shortenText(decodeURIComponent(row.finishLoc), 255);
+ locationLabel = Helper.shortenText(decodeURIComponent(row
+ .finishLoc), 255);
} else if (type === 'export') {
locationLabel = '-';
} else {