From 83e19e9a3d7c3cc56b7c2e887ae033a37b5b606f Mon Sep 17 00:00:00 2001 From: meusinfirmary Date: Thu, 26 Jun 2025 04:40:21 +0700 Subject: [PATCH] update --- app/Http/Controllers/VehiclesController.php | 2 + app/Models/Tracks.php | 195 ++++++++++++-------- app/Models/Tracks_copy.php | 125 +++++++++---- resources/views/menu_v1/vehicles.blade.php | 53 ++++-- 4 files changed, 254 insertions(+), 121 deletions(-) diff --git a/app/Http/Controllers/VehiclesController.php b/app/Http/Controllers/VehiclesController.php index 467ff2c..16183fb 100755 --- a/app/Http/Controllers/VehiclesController.php +++ b/app/Http/Controllers/VehiclesController.php @@ -234,6 +234,7 @@ class VehiclesController extends Controller "nopol1" => strtoupper($req->nopol1), // "nopol2" => strtoupper($req->nopol2), // "nopol3" => strtoupper($req->nopol3), + "sum_milleage" => $req->sum_milleage ?? 0, "c_did" => $req->d_current ?? 0, "a_did" => $req->d_assign ?? 0, "is_track_holiday" => Vehicles::DEFAULT_TRACK_HOLIDAY, @@ -489,6 +490,7 @@ class VehiclesController extends Controller "nopol3" => strtoupper($req->nopol3), "c_did" => $req->d_current ?? 0, "a_did" => $req->d_assign ?? 0, + "sum_milleage" => $req->sum_milleage ?? 0, "is_track_holiday" => Vehicles::DEFAULT_TRACK_HOLIDAY, "track_sch_d" => Vehicles::DEFAULT_TRACK_SCH_D, "track_sch_h" => Vehicles::DEFAULT_TRACK_SCH_H, diff --git a/app/Models/Tracks.php b/app/Models/Tracks.php index 3cdec4b..6d63415 100755 --- a/app/Models/Tracks.php +++ b/app/Models/Tracks.php @@ -305,11 +305,85 @@ class Tracks extends Model return $list; } + // public static function lastMoveTracks($vid, $filter = []) + // { + // $now = time(); + // $params = []; + // $query = "SELECT"; + // $query .= " v.id as vid,v.device_id,v.nopol1,v.nopol2,v.nopol3"; + // $query .= " ,tr.id as master_id,tr.latitude,tr.longitude,tr.speed,tr.orientation"; + // $query .= " ,tr.crt AS lst_loc_crt,tr.crt_d AS lst_loc_crt_d,tr.crt_s AS lst_loc_crt_s"; + // $query .= " ,tr.ignition,tr.stts_engine"; + // $query .= " ,tr.pre_milleage,tr.sum_milleage,tr.vhc_milleage,v.sum_milleage AS vhc_sum_milleage_1"; + // $query .= " ,addr.master_id AS addr_master_id,addr.crt AS addr_loc_crt"; + // $query .= + // " ,addr.country_text,addr.state_text,addr.city_text,addr.district_text,addr.village_text,addr.postcode,addr.streets,addr.postcode,addr.fulladdress"; + // $query .= " FROM t_vehicles AS v"; + // // $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.device_id = tr.device_id"; // cara lama berlaku utk gps tracker saja + // $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.id = tr.vhc_id"; // support gps tracker dan smartphone / apapun yang mempunyai device_id(IMEI) + // $query .= " LEFT JOIN " . self::T_TRACKS_ADDR . " AS addr ON tr.id = addr.master_id"; + // $query .= " WHERE v.dlt is null"; + // $query .= " AND v.id = ?"; + // array_push($params, $vid); + // $query .= " AND tr.latitude is not null"; + // $query .= " AND tr.longitude is not null"; + + // // last move based on date + // // $query .= " AND tr.crt BETWEEN ? AND ?"; + // // array_push($params, strtotime('-24 hours', $now), $now); + + // if (isset($filter["start_date"]) && isset($filter["end_date"])) { + // $query .= " AND tr.crt_d BETWEEN ? AND ?"; + // array_push($params, $filter["start_date"], $filter["end_date"]); + // } + + // if (isset($filter["start_at"])) { + // $query .= " AND tr.crt > ?"; + // $params[] = $filter["start_at"]; + // } + + // // last move based on last count data + // $query .= " GROUP BY tr.crt_d"; + // $query .= " ORDER BY tr.crt_d DESC"; + // // array_push($params, strtotime('-24 hours', $now), $now); + + // // if (isset($filter["limit"])) { + // // $query .= " LIMIT ?"; + // // $params[] = $filter["limit"] ?? 500; + // // } + + // $query .= " ;"; + + // // return DB::select($query, $params); + // $rawTracks = DB::select($query, $params); + // $cleanTracks = self::filterJumps($rawTracks); + + // if (isset($filter["limit"])) { + // return array_slice($cleanTracks, 0, $filter["limit"]); + // } + // return $cleanTracks; + // } + public static function lastMoveTracks($vid, $filter = []) { $now = time(); $params = []; + /** + * bikin lemot 30s timeout karena ada 2 join di rows yang banyak + * solution: indexing column + * show index from t_gps_tracks_address; + * create index addr_device_id on t_gps_tracks_address (device_id); + * create index addr_master_id on t_gps_tracks_address (master_id); + * show index from t_gps_tracks; + * create index tracks_device_id on t_gps_tracks (device_id); + * show index from t_vehicles; + * create index vhc_device_id on t_vehicles (device_id); + * + * solution not working. Don't reinvent the wheel + * create view. not working + */ + $query = "SELECT"; $query .= " v.id as vid,v.device_id,v.nopol1,v.nopol2,v.nopol3"; $query .= " ,tr.id as master_id,tr.latitude,tr.longitude,tr.speed,tr.orientation"; @@ -320,17 +394,22 @@ class Tracks extends Model $query .= " ,addr.country_text,addr.state_text,addr.city_text,addr.district_text,addr.village_text,addr.postcode,addr.streets,addr.postcode,addr.fulladdress"; $query .= " FROM t_vehicles AS v"; - $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.id = tr.vhc_id"; + // $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.device_id = tr.device_id"; // cara lama berlaku utk gps tracker saja + $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.id = tr.vhc_id"; // support gps tracker dan smartphone / apapun yang mempunyai device_id(IMEI) $query .= " LEFT JOIN " . self::T_TRACKS_ADDR . " AS addr ON tr.id = addr.master_id"; - $query .= " WHERE v.dlt is null AND v.id = ?"; - $params[] = $vid; + $query .= " WHERE v.dlt is null"; + $query .= " AND v.id = ?"; + array_push($params, $vid); + $query .= " AND tr.latitude is not null"; + $query .= " AND tr.longitude is not null"; - $query .= " AND tr.latitude is not null AND tr.longitude is not null"; + // last move based on date + // $query .= " AND tr.crt BETWEEN ? AND ?"; + // array_push($params, strtotime('-24 hours', $now), $now); if (isset($filter["start_date"]) && isset($filter["end_date"])) { $query .= " AND tr.crt_d BETWEEN ? AND ?"; - $params[] = $filter["start_date"]; - $params[] = $filter["end_date"]; + array_push($params, $filter["start_date"], $filter["end_date"]); } if (isset($filter["start_at"])) { @@ -338,8 +417,10 @@ class Tracks extends Model $params[] = $filter["start_at"]; } - // ASC supaya filter berurutan waktu - $query .= " ORDER BY tr.crt DESC"; + // last move based on last count data + $query .= " GROUP BY tr.crt_d"; + $query .= " ORDER BY tr.crt_d DESC"; + // array_push($params, strtotime('-24 hours', $now), $now); if (isset($filter["limit"])) { $query .= " LIMIT ?"; @@ -348,74 +429,7 @@ class Tracks extends Model $query .= " ;"; - // Ambil data - $rawTracks = DB::select($query, $params); - - // Sort manual jika perlu - usort($rawTracks, fn($a, $b) => $a->lst_loc_crt <=> $b->lst_loc_crt); - - // Filter loncatan - $filtered = self::filterJumps($rawTracks, 3000, 5, 300); - - return $filtered; - // return array_reverse($filtered); - } - - public static function filterJumps($points, $maxDistance = 3000, $maxTimeGap = 5, $maxSpeed = 150) - { - $filtered = []; - $last = null; - - // Sort dari terbaru ke terlama (pastikan sesuai kebutuhan) - usort($points, fn($a, $b) => $b->lst_loc_crt <=> $a->lst_loc_crt); - - foreach ($points as $p) { - // 1. Validasi koordinat - if (!is_numeric($p->latitude) || !is_numeric($p->longitude)) { - continue; - } - - if ( - strlen(explode(".", $p->latitude)[1] ?? "") < 6 || - strlen(explode(".", $p->longitude)[1] ?? "") < 6 - ) { - continue; - } - - if (!$last) { - $filtered[] = $p; - $last = $p; - continue; - } - - // 2. Jarak & waktu - $distance = self::haversineDistance( - $last->latitude, - $last->longitude, - $p->latitude, - $p->longitude - ); - $timeGap = $last->lst_loc_crt - $p->lst_loc_crt; - - if ($timeGap <= 0) { - continue; - } - - $speed = ($distance / $timeGap) * 3.6; // m/s to km/h - - // 3. Filter logis - if ($speed <= $maxSpeed || $distance <= $maxDistance) { - $filtered[] = $p; - $last = $p; - } - } - - // 4. Pastikan hasil minimal N - if (count($filtered) < 500 && count($points) > 500) { - return array_slice($points, 0, 500); // fallback ke raw jika terlalu sedikit - } - - return $filtered; + return DB::select($query, $params); } public static function haversineDistance($lat1, $lon1, $lat2, $lon2) @@ -436,6 +450,35 @@ class Tracks extends Model return $earthRadius * $c; } + public static function filterJumps($points, $maxDistance = 50, $maxTimeGap = 10) + { + $filtered = []; + $last = null; + + foreach ($points as $p) { + if (!$last) { + $filtered[] = $p; + $last = $p; + continue; + } + + $distance = self::haversineDistance( + $last->latitude, + $last->longitude, + $p->latitude, + $p->longitude + ); + $timeGap = $p->lst_loc_crt - $last->lst_loc_crt; + + if ($distance <= $maxDistance || $timeGap > $maxTimeGap) { + $filtered[] = $p; + $last = $p; + } + } + + return $filtered; + } + public static function nearestInCircle($lat, $lng, $rad, $filter = []) { $earth_rad = Helper::EARTH_RADIUS_M; diff --git a/app/Models/Tracks_copy.php b/app/Models/Tracks_copy.php index e84bdb7..0a16a32 100755 --- a/app/Models/Tracks_copy.php +++ b/app/Models/Tracks_copy.php @@ -310,21 +310,6 @@ class Tracks_copy extends Model $now = time(); $params = []; - /** - * bikin lemot 30s timeout karena ada 2 join di rows yang banyak - * solution: indexing column - * show index from t_gps_tracks_address; - * create index addr_device_id on t_gps_tracks_address (device_id); - * create index addr_master_id on t_gps_tracks_address (master_id); - * show index from t_gps_tracks; - * create index tracks_device_id on t_gps_tracks (device_id); - * show index from t_vehicles; - * create index vhc_device_id on t_vehicles (device_id); - * - * solution not working. Don't reinvent the wheel - * create view. not working - */ - $query = "SELECT"; $query .= " v.id as vid,v.device_id,v.nopol1,v.nopol2,v.nopol3"; $query .= " ,tr.id as master_id,tr.latitude,tr.longitude,tr.speed,tr.orientation"; @@ -335,22 +320,17 @@ class Tracks_copy extends Model $query .= " ,addr.country_text,addr.state_text,addr.city_text,addr.district_text,addr.village_text,addr.postcode,addr.streets,addr.postcode,addr.fulladdress"; $query .= " FROM t_vehicles AS v"; - // $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.device_id = tr.device_id"; // cara lama berlaku utk gps tracker saja - $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.id = tr.vhc_id"; // support gps tracker dan smartphone / apapun yang mempunyai device_id(IMEI) + $query .= " INNER JOIN " . self::T_TRACKS . " AS tr ON v.id = tr.vhc_id"; $query .= " LEFT JOIN " . self::T_TRACKS_ADDR . " AS addr ON tr.id = addr.master_id"; - $query .= " WHERE v.dlt is null"; - $query .= " AND v.id = ?"; - array_push($params, $vid); - $query .= " AND tr.latitude is not null"; - $query .= " AND tr.longitude is not null"; + $query .= " WHERE v.dlt is null AND v.id = ?"; + $params[] = $vid; - // last move based on date - // $query .= " AND tr.crt BETWEEN ? AND ?"; - // array_push($params, strtotime('-24 hours', $now), $now); + $query .= " AND tr.latitude is not null AND tr.longitude is not null"; if (isset($filter["start_date"]) && isset($filter["end_date"])) { $query .= " AND tr.crt_d BETWEEN ? AND ?"; - array_push($params, $filter["start_date"], $filter["end_date"]); + $params[] = $filter["start_date"]; + $params[] = $filter["end_date"]; } if (isset($filter["start_at"])) { @@ -358,10 +338,8 @@ class Tracks_copy extends Model $params[] = $filter["start_at"]; } - // last move based on last count data - $query .= " GROUP BY tr.crt_d"; - $query .= " ORDER BY tr.crt_d DESC"; - // array_push($params, strtotime('-24 hours', $now), $now); + // ASC supaya filter berurutan waktu + $query .= " ORDER BY tr.crt DESC"; if (isset($filter["limit"])) { $query .= " LIMIT ?"; @@ -370,7 +348,92 @@ class Tracks_copy extends Model $query .= " ;"; - return DB::select($query, $params); + // Ambil data + $rawTracks = DB::select($query, $params); + + // Sort manual jika perlu + usort($rawTracks, fn($a, $b) => $a->lst_loc_crt <=> $b->lst_loc_crt); + + // Filter loncatan + $filtered = self::filterJumps($rawTracks, 3000, 5, 300); + + return $filtered; + // return array_reverse($filtered); + } + + public static function filterJumps($points, $maxDistance = 3000, $maxTimeGap = 5, $maxSpeed = 150) + { + $filtered = []; + $last = null; + + // Sort dari terbaru ke terlama (pastikan sesuai kebutuhan) + usort($points, fn($a, $b) => $b->lst_loc_crt <=> $a->lst_loc_crt); + + foreach ($points as $p) { + // 1. Validasi koordinat + if (!is_numeric($p->latitude) || !is_numeric($p->longitude)) { + continue; + } + + if ( + strlen(explode(".", $p->latitude)[1] ?? "") < 6 || + strlen(explode(".", $p->longitude)[1] ?? "") < 6 + ) { + continue; + } + + if (!$last) { + $filtered[] = $p; + $last = $p; + continue; + } + + // 2. Jarak & waktu + $distance = self::haversineDistance( + $last->latitude, + $last->longitude, + $p->latitude, + $p->longitude + ); + $timeGap = $last->lst_loc_crt - $p->lst_loc_crt; + + if ($timeGap <= 0) { + continue; + } + + $speed = ($distance / $timeGap) * 3.6; // m/s to km/h + + // 3. Filter logis + if ($speed <= $maxSpeed || $distance <= $maxDistance) { + $filtered[] = $p; + $last = $p; + } + } + + // 4. Pastikan hasil minimal N + if (count($filtered) < 500 && count($points) > 500) { + return array_slice($points, 0, 500); // fallback ke raw jika terlalu sedikit + } + + return $filtered; + } + + public static function haversineDistance($lat1, $lon1, $lat2, $lon2) + { + $earthRadius = 6371000; // meters + + $lat1 = deg2rad($lat1); + $lon1 = deg2rad($lon1); + $lat2 = deg2rad($lat2); + $lon2 = deg2rad($lon2); + + $dlat = $lat2 - $lat1; + $dlon = $lon2 - $lon1; + + $a = sin($dlat / 2) ** 2 + cos($lat1) * cos($lat2) * sin($dlon / 2) ** 2; + $c = 2 * atan2(sqrt($a), sqrt(1 - $a)); + + return $earthRadius * $c; } public static function nearestInCircle($lat, $lng, $rad, $filter = []) diff --git a/resources/views/menu_v1/vehicles.blade.php b/resources/views/menu_v1/vehicles.blade.php index 6716327..bd787cf 100755 --- a/resources/views/menu_v1/vehicles.blade.php +++ b/resources/views/menu_v1/vehicles.blade.php @@ -11,18 +11,18 @@ @section('customcss') @endsection @@ -146,10 +146,22 @@ @endforeach -
- - +
+
+
+ + +
+
+
+
+ + +
+
+ +
@@ -351,9 +363,19 @@ @endforeach -
- - +
+
+
+ + +
+
+
+
+ + +
+
@@ -1002,6 +1024,7 @@ data.append('type_id', safeVal('#add-type')); data.append('model_id', safeVal('#add-model') ?? 0); data.append('speed_limit', safeVal('#add-speedlimit')); + data.append('sum_milleage', safeVal('#add-sum_milleage')); data.append('fuel_capacity', safeVal('#add-fuelcapacity') ?? 0); data.append('fuel_drop_treshold', safeVal('#add-fueldroptreshold') ?? 0); data.append('max_pressure', safeVal('#add-maxpressure') ?? 0); @@ -1217,6 +1240,7 @@ $('#edt-model').val(data?.model_id).trigger('change'); $('#edt-speedlimit').val(data?.speed_limit); + $('#edt-sum_milleage').val(data?.sum_milleage); $('#edt-fuelcapacity').val(data?.fuel_capacity); $('#edt-fueldroptreshold').val(data?.fuel_drop_treshold); $('#edt-maxpressure').val(data?.max_pressure); @@ -1272,6 +1296,7 @@ data.model_id = $('#edt-model').val(); data.speed_limit = $('#edt-speedlimit').val(); + data.sum_milleage = $('#edt-sum_milleage').val(); data.fuel_capacity = $('#edt-fuelcapacity').val(); data.fuel_drop_treshold = $('#edt-fueldroptreshold').val(); data.max_pressure = $('#edt-maxpressure').val();