From ff47f3f9322c44a51cb3840663d626311b3e8b47 Mon Sep 17 00:00:00 2001 From: wayanrivan Date: Sat, 1 Aug 2026 21:22:55 +0700 Subject: [PATCH] update --- .../menu_v1/reports/vehicle_trips.blade.php | 140 ++++++++++++------ 1 file changed, 97 insertions(+), 43 deletions(-) diff --git a/resources/views/menu_v1/reports/vehicle_trips.blade.php b/resources/views/menu_v1/reports/vehicle_trips.blade.php index a32b5aa..abccf6c 100644 --- a/resources/views/menu_v1/reports/vehicle_trips.blade.php +++ b/resources/views/menu_v1/reports/vehicle_trips.blade.php @@ -11,6 +11,12 @@ @section('customcss') + @endsection @section('content') @@ -346,33 +352,59 @@ }); } - // Isi row.startLoc / row.finishLoc yang masih kosong (null/undefined/'') - // menggunakan hasil reverse geocode dari koordinat start_lat_long / finish_lat_long. - // Nilai disimpan dalam bentuk encodeURIComponent supaya konsisten dengan - // field startLoc/finishLoc bawaan API yang memang sudah URL-encoded, - // karena proses render memanggil decodeURIComponent(row.startLoc). - async function fillMissingLocations(rows) { + // Bikin id unik untuk elemen placeholder lokasi per baris+kolom, + // dipakai untuk update teks langsung via DOM setelah geocode selesai di background. + function geoElementId(row, kind) { + // kind: 'start' | 'finish' + return `geo-${kind}-${row.id}-${row.trip_id}`; + } + + // Jalankan reverse geocode di BACKGROUND (tidak menunggu / tidak blocking render tabel). + // Tabel sudah tampil duluan dengan placeholder "Load for location...", lalu begitu + // Nominatim balas untuk satu titik, teks placeholder-nya langsung di-update di tempat + // (tanpa redraw seluruh tabel), row demi row sesuai antrian reverseGeocode. + function scheduleBackgroundGeocode(rows) { if (!Array.isArray(rows)) return; - for (const row of rows) { - if (!row.startLoc) { - const { - lat, - lng - } = parseLatLong(row.start_lat_long); - const address = await reverseGeocode(lat, lng); - row.startLoc = address ? encodeURIComponent(address) : null; + rows.forEach(row => { + const { + lat: startLat, + lng: startLng + } = parseLatLong(row.start_lat_long); + const startNearestSite = findNearestSite(startLat, startLng); + + // hanya perlu geocode kalau bukan site terdaftar & startLoc memang kosong + if (!startNearestSite && !row.startLoc) { + geocodeAndUpdateCell(geoElementId(row, 'start'), startLat, startLng); } - if (!row.finishLoc) { - const { - lat, - lng - } = parseLatLong(row.finish_lat_long); - const address = await reverseGeocode(lat, lng); - row.finishLoc = address ? encodeURIComponent(address) : null; + const { + lat: finishLat, + lng: finishLng + } = parseLatLong(row.finish_lat_long); + const finishNearestSite = findNearestSite(finishLat, finishLng); + + if (!finishNearestSite && !row.finishLoc) { + geocodeAndUpdateCell(geoElementId(row, 'finish'), finishLat, finishLng); } - } + }); + } + + // Panggil reverseGeocode (sudah antri otomatis max 1 request/detik), + // begitu hasilnya datang, cari elemen placeholder di DOM lewat id-nya + // dan replace teksnya. Kalau elemen sudah tidak ada (misal tabel sudah + // di-reload/filter berubah), update di-skip secara aman. + function geocodeAndUpdateCell(elId, lat, lng) { + reverseGeocode(lat, lng).then(address => { + const $el = $('#' + elId); + if (!$el.length) return; // tabel sudah berganti, abaikan hasil basi ini + + if (address) { + $el.text(Helper.shortenText(address, 255)).removeClass('geo-pending'); + } else { + $el.text('-').removeClass('geo-pending'); + } + }); } // ================================ @@ -421,17 +453,22 @@ &poolcode=${$('#poolcode').val() || ''} `, type: 'GET', - success: async function(json) { - // Isi startLoc/finishLoc yang kosong via Nominatim - // SEBELUM tabel dirender, karena render() DataTables bersifat sinkron - // dan tidak bisa menunggu fetch() di dalamnya. - try { - await fillMissingLocations(json && json.data); - } catch (e) { - console.error('Gagal melengkapi lokasi via reverse geocode:', e); - } - + success: function(json) { + // Tampilkan tabel DULUAN dengan semua data apa adanya + // (baris yang startLoc/finishLoc kosong akan muncul + // sebagai placeholder "Load for location..."). callback(json); + + // Reset antrian geocode supaya request dari load sebelumnya + // (misal filter lama) tidak numpuk / membuang kuota Nominatim. + geocodeQueue = Promise.resolve(); + + // Baru SETELAH itu, isi lokasi yang kosong di background. + // setTimeout 0 supaya DOM tabel sudah pasti ter-render dulu + // sebelum kita cari elemen placeholder-nya. + setTimeout(() => { + scheduleBackgroundGeocode(json && json.data); + }, 0); }, error: function(xhr, status, error) { if (status !== 'abort') { @@ -508,12 +545,23 @@ } = parseLatLong(row.start_lat_long); const nearestSite = findNearestSite(startLat, startLng); - // Prioritas: site terdaftar > startLoc (dari API atau hasil reverse geocode) > '-' - const locationLabel = nearestSite ? - formatSiteLabel(nearestSite) : - (row.startLoc ? - Helper.shortenText(decodeURIComponent(row.startLoc), 255) : - '-'); + let locationLabel; + if (nearestSite) { + // Prioritas 1: site terdaftar + locationLabel = formatSiteLabel(nearestSite); + } else if (row.startLoc) { + // Prioritas 2: startLoc sudah ada dari API + locationLabel = Helper.shortenText(decodeURIComponent(row.startLoc), 255); + } else if (type === 'export') { + // Export bersifat sinkron, tidak bisa menunggu hasil geocode background + locationLabel = '-'; + } else { + // Prioritas 3: kosong -> tampilkan placeholder dulu, + // nanti di-update otomatis oleh scheduleBackgroundGeocode() + // begitu hasil dari Nominatim datang. + locationLabel = + `Load for location...`; + } if (type === 'export') return locationLabel; @@ -529,11 +577,17 @@ } = parseLatLong(row.finish_lat_long); const nearestSite = findNearestSite(finishLat, finishLng); - const locationLabel = nearestSite ? - formatSiteLabel(nearestSite) : - (row.finishLoc ? - Helper.shortenText(decodeURIComponent(row.finishLoc), 255) : - '-'); + let locationLabel; + if (nearestSite) { + locationLabel = formatSiteLabel(nearestSite); + } else if (row.finishLoc) { + locationLabel = Helper.shortenText(decodeURIComponent(row.finishLoc), 255); + } else if (type === 'export') { + locationLabel = '-'; + } else { + locationLabel = + `Load for location...`; + } if (type === 'export') return locationLabel;