From 86e9c43cfd54278bb3cb5c0e76dbc948a9add859 Mon Sep 17 00:00:00 2001 From: meusinfirmary Date: Tue, 15 Jul 2025 03:03:27 +0700 Subject: [PATCH] update --- app/Http/Controllers/TrackController.php | 5 +- app/Models/Tracks.php | 165 ++--- app/Models/Tracks_copy_new.php | 640 ++++++++++++++++++++ public/index.php | 38 +- resources/views/menu_v1/dashboard.blade.php | 24 +- 5 files changed, 727 insertions(+), 145 deletions(-) create mode 100755 app/Models/Tracks_copy_new.php diff --git a/app/Http/Controllers/TrackController.php b/app/Http/Controllers/TrackController.php index 73dc265..94357bc 100755 --- a/app/Http/Controllers/TrackController.php +++ b/app/Http/Controllers/TrackController.php @@ -151,6 +151,10 @@ class TrackController extends Controller ) { $filter["start_date"] = $req->start_date; $filter["end_date"] = $req->end_date; + + $filter["start_date"] = strtotime(gmdate("Y-m-d H:i:s", $req->start_date)); + $filter["end_date"] = strtotime(gmdate("Y-m-d H:i:s", $req->end_date)); + $filter["limit"] = 5000; } @@ -164,7 +168,6 @@ class TrackController extends Controller return new Response($apiResp, $apiResp["meta"]["code"]); } } - public function api_conf_list_logs_gps(Request $req) { try { diff --git a/app/Models/Tracks.php b/app/Models/Tracks.php index 7a6731d..06cc63f 100755 --- a/app/Models/Tracks.php +++ b/app/Models/Tracks.php @@ -307,27 +307,40 @@ class Tracks extends Model 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, tr.crt_d_format"; - $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.id as master_id,tr.latitude,tr.longitude,tr.speed,tr.orientation"; + $query .= " + ,(tr.crt + ( 9 * 3600 )) AS lst_loc_crt + ,(tr.crt_d + ( 9 * 3600 )) 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 .= " ,addr.country_text, + addr.state_text,addr.city_text,addr.district_text,addr.village_text,addr.postcode,addr.streets,addr.postcode, + concat(addr.fulladdress,';',tr.id) as 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 .= " AND tr.latitude IS NOT NULL AND tr.longitude IS NOT NULL"; + $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.action in ('location')"; - if (isset($filter["start_date"], $filter["end_date"])) { + // 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"])) { @@ -335,125 +348,29 @@ class Tracks 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"; - $limit = isset($filter["limit"]) && $filter["limit"] > 500 ? $filter["limit"] : 50000; - $query .= " LIMIT ?"; - $params[] = $limit; + // $query .= " ORDER BY tr.id DESC"; + // array_push($params, strtotime('-24 hours', $now), $now); - $raw = DB::select($query, $params); - $rawAscCleaned = self::removeSpeedSandwich($raw); - $filtered = self::filterJumps($rawAscCleaned); - $combined = $filtered; - - // usort($combined, fn($a, $b) => $b->lst_loc_crt_d <=> $a->lst_loc_crt_d); - $final = array_slice($combined, 0, 500); - return $final; - } - - 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; - } - - private static function removeSpeedSandwich($data) - { - $cleaned = []; - - for ($i = 0; $i < count($data); $i++) { - $next = $data[$i + 1] ?? null; // lebih lama - $curr = $data[$i]; - $prev = $data[$i - 1] ?? null; // lebih baru - - // Logika dibalik: prev = lebih baru, next = lebih lama - if ($prev && $next && $prev->speed > 5 && $curr->speed < 5 && $next->speed > 5) { - continue; - } - - $cleaned[] = $curr; + if (isset($filter["limit"])) { + $query .= " LIMIT ?"; + $params[] = $filter["limit"] ?? 500; } - return $cleaned; - } + $query .= " ;"; - public static function filterJumps( - $points, - $maxDistance = 150, - $maxTimeGap = 20, - $maxSpeed = 100, - $maxHardJump = 100, - $maxIdleJump = 100, - $maxRealSpeed = 100 - ) { - $filtered = []; - $last = null; - $start = null; + // return DB::select($query, $params); + $rawTracks = DB::select($query, $params); + // $cleanTracks = self::filterJumps($rawTracks); + $cleanTracks = $rawTracks; + //dd($cleanTracks); - foreach ($points as $p) { - if (!$last) { - $filtered[] = $p; - $last = $p; - $start = $p; - continue; - } - - $distance = self::haversineDistance( - $last->latitude, - $last->longitude, - $p->latitude, - $p->longitude - ); - - $t1 = strtotime($last->lst_loc_crt); - $t2 = strtotime($p->lst_loc_crt); - $timeGap = $t2 - $t1; - $speed = $timeGap > 0 ? $distance / $timeGap : 0; - $realSpeedKmh = $speed * 3.6; - - $jumpFromStart = self::haversineDistance( - $start->latitude, - $start->longitude, - $p->latitude, - $p->longitude - ); - - if ($distance > $maxHardJump) { - continue; - } - - if ($distance > $maxIdleJump && $p->speed < 5 && $last->speed < 5) { - continue; - } - - if ($timeGap <= $maxTimeGap && $speed > $maxSpeed) { - continue; - } - - if ($realSpeedKmh > $maxRealSpeed) { - continue; - } - - if ($jumpFromStart > 500 && $p->speed < 5) { - continue; - } // >10 km dari area awal tapi status idle - - $filtered[] = $p; - $last = $p; - } - - return $filtered; + // if (isset($filter["limit"])) { + // return array_slice($cleanTracks, 0, $filter["limit"]); + // } + return $cleanTracks; } public static function nearestInCircle($lat, $lng, $rad, $filter = []) diff --git a/app/Models/Tracks_copy_new.php b/app/Models/Tracks_copy_new.php new file mode 100755 index 0000000..0950819 --- /dev/null +++ b/app/Models/Tracks_copy_new.php @@ -0,0 +1,640 @@ +no signal, 2=>extremely weak signal 3=>very weak signal, 4=>good signal, 5=>strong signal + const STTS_GSM_DFT = 0; // default + const STTS_GSM_NO_SIGNAL = 1; + const STTS_GSM_BAD_SIGNAL = 2; + const STTS_GSM_WEAK_SIGNAL = 3; + const STTS_GSM_GOOD_SIGNAL = 4; + const STTS_GSM_STRONG_SIGNAL = 5; + + // type source + const SOURCE_GPS_TRACKER = 1; + const SOURCE_SMARTPHONE = 2; + + /** + * perlu tambahin filter untuk melihat tracking yang sesuai dengan vehiclenya aja + * karena ada case: + * device sudah sampai dilokasi pengantaran dan dimatikan, ketika dipakai lagi data tracking yang lama kelihatan dan loncat + * untuk mengatasi itu di service_tracking juga perlu validasi tambahan, entah seperti apa caranya + */ + public static function listCurrentTracks($filter = []) + { + $now = time(); + $params = []; + + $query = "SELECT"; + $query .= + " v.id as vid,v.device_id,v.name as vhc_name,c.name as vhc_cat_name,t.name as vhc_type_name"; + $query .= " ,v.nopol1,v.nopol2,v.nopol3,vd.fvhc_img"; + $query .= " ,v.is_track_holiday,v.track_sch_d,v.track_sch_h,vd.speed_limit,v.crt as vhc_crt"; + $query .= " ,client.id as client_group_id,client.c_name as client_group_name"; + $query .= " ,tr.ignition,tr.stts_engine,tr.stts_gps,tr.stts_gsm"; + $query .= " ,tr.pre_milleage,tr.sum_milleage,tr.vhc_milleage,v.sum_milleage AS vhc_sum_milleage_1"; + + // FRO + // $query .= " ,(SELECT SUM(pre_milleage) FROM " . self::T_TRACKS . " WHERE vhc_id = v.id LIMIT 1) as vhc_sum_milleage"; + + // $query .= " ,(SELECT crt_s FROM " . self::T_TRACKS . " WHERE stts_engine = " . self::STTS_EN_IDLING . " AND vhc_id = v.id AND crt_s >= ( + // SELECT crt_s FROM " . self::T_TRACKS . " WHERE stts_engine IN (" . self::STTS_EN_STOPING . "," . self::STTS_EN_MOVING . ") AND vhc_id = v.id AND crt_s <= tr.crt_s ORDER BY id DESC LIMIT 1 + // ) ORDER BY id ASC LIMIT 1) as lst_idle_at"; + + // $query .= " ,(SELECT crt_s FROM " . self::T_TRACKS . " WHERE stts_engine = " . self::STTS_EN_STOPING . " AND vhc_id = v.id AND crt_s >= ( + // SELECT crt_s FROM " . self::T_TRACKS . " WHERE stts_engine IN (" . self::STTS_EN_IDLING . "," . self::STTS_EN_MOVING . ") AND vhc_id = v.id AND crt_s <= tr.crt_s ORDER BY id DESC LIMIT 1 + // ) ORDER BY id ASC LIMIT 1) as lst_stop_at"; + + $query .= + " ,tr.id AS lst_master_id,tr.latitude AS lst_lat,tr.longitude AS lst_lng,tr.speed AS lst_speed,tr.orientation AS lst_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_addr.master_id AS lst_addr_master_id,tr_addr.country_text AS lst_country_text,tr_addr.state_text AS lst_state_text,tr_addr.city_text AS lst_city_text"; + $query .= + " ,tr_addr.district_text AS lst_district_text,tr_addr.village_text AS lst_village_text,tr_addr.postcode AS lst_postcode"; + $query .= " ,tr_addr.streets AS lst_streets,tr_addr.fulladdress AS lst_fulladdress"; + + // FRO + // $query .= " ,(SELECT COUNT(id) FROM " . self::T_TRACKS . " WHERE vhc_id = v.id AND action = 'heartbeat' AND crt BETWEEN ".($now-(10*60))." AND ".$now." LIMIT 1) as lst_heartbeat"; // heartbeat last data on further 10 minutes + + if (isset($filter["active_rates"])) { + $query .= + ",rate.vdr_id as rate_vdr_id,rate.vhc_type as rate_vhc_type,rate.origin_prov as rate_origin_prov,rate.dest_city as rate_dest_city,rate.dest_district as rate_dest_district"; + $query .= + ",rate.fast_time as rate_fast_time,rate.long_time as rate_long_time,rate.sell_kg as rate_sell_kg,rate.sell_cbm as rate_sell_cbm,rate.sell_ftl as rate_sell_ftl"; + } + if (isset($filter["get_order_data"])) { + $query .= + ",ord.id as ord_id,ord.code as ord_code,ord.status as ord_stts,ord.crt as ord_crt,ord_pck.pck_name as ord_pck_name,ord_pck.pck_addr as ord_pck_addr,ord_drop.drop_name as ord_drop_name,ord_drop.drop_addr as ord_drop_addr"; + $query .= + ",(SELECT nmKotamadyaKel FROM t_region WHERE kodeKab = ord_pck.pck_ktid LIMIT 1) ord_pck_ktname, (SELECT nmKotamadyaKel FROM t_region WHERE kodeKab = ord_drop.drop_ktid LIMIT 1) ord_drop_ktname"; + $query .= + ",ord_drv.drv_name as ord_drv_name,ord_drv.drv_phone_val as ord_drv_phone_val,ord_drv.drv_phone2_val as ord_drv_phone2_val,ord_drv.drv_addr as ord_drv_addr"; + $query .= ",ord_c.c_name as ord_c_name,ord_c.c_pt_name as ord_c_pt_name"; + } + $query .= " FROM t_vehicles AS v"; + $query .= " INNER JOIN t_vehicles_detail AS vd ON v.id = vd.vid"; + $query .= " INNER JOIN t_vehicles_types AS t ON v.type_id = t.id"; + $query .= " INNER JOIN t_vehicles_cats AS c ON v.cat_id = c.id"; + $query .= " LEFT JOIN t_users AS vendor ON v.vendor_id = vendor.id"; + $query .= " LEFT JOIN t_clients AS client ON vendor.client_group_id = client.id"; + // get last updated row from many rows + // $query .= " LEFT JOIN ( SELECT MAX(crt) max_crt, device_id FROM " . self::T_TRACKS . " WHERE latitude is not null AND longitude is not null GROUP BY device_id ORDER BY crt DESC ) AS tr1 ON (v.device_id = tr1.device_id)"; // cara lama berlaku utk gps tracker saja + // // $query .= " LEFT JOIN ( SELECT MAX(crt) max_crt, device_id, vhc_id FROM " . self::T_TRACKS . " WHERE latitude is not null AND longitude is not null GROUP BY vhc_id ORDER BY crt DESC ) AS tr1 ON (v.id = tr1.vhc_id)"; // support gps tracker dan smartphone / apapun yang mempunyai device_id(IMEI) + // $query .= " LEFT JOIN " . self::T_TRACKS . " AS tr ON (tr.crt = tr1.max_crt)"; + // get last updated tracking from updated table realtime + // $query .= " LEFT JOIN db_trucking.t_gps_tracks_rltm AS tr ON tr.vhc_id = v.id"; + $query .= " LEFT JOIN t_gps_tracks_rltm AS tr ON tr.vhc_id = v.id"; + // $query .= " LEFT JOIN " . self::T_TRACKS_ADDR . " AS tr_addr ON tr.id = tr_addr.master_id"; + + //FRO + $query .= + " LEFT JOIN " . + self::T_TRACKS_ADDR . + " AS tr_addr ON tr.latitude = tr_addr.lat and tr.longitude = tr_addr.lng"; + + if (isset($filter["active_rates"])) { + // $query .= " INNER JOIN t_conf_rates as rate ON v.type_id = rate.vhc_type"; + $query .= " INNER JOIN t_conf_rates as rate ON v.vendor_id = rate.vdr_id"; + } + if (isset($filter["get_order_data"])) { + // the old way => only 1 order 1 vehicle + $query .= " LEFT JOIN t_orders as ord ON v.ord_id = ord.id"; + $query .= " LEFT JOIN t_orders_pickups as ord_pck ON v.ord_id = ord_pck.ord_id"; + $query .= " LEFT JOIN t_orders_drops as ord_drop ON v.ord_id = ord_drop.ord_id"; + $query .= " LEFT JOIN t_orders_drivers as ord_drv ON v.ord_id = ord_drv.ord_id"; + $query .= " LEFT JOIN t_orders_clients as ord_c ON v.ord_id = ord_c.ord_id"; + + // the new way => can handle 2 order in 1 vehicle + // $query .= " LEFT JOIN t_orders_vehicles as ord_vhc ON v.id = ord_vhc.vhc_id"; + // $query .= " LEFT JOIN t_orders as ord ON ord_vhc.ord_id = ord.id"; + // $query .= " LEFT JOIN t_orders_pickups as ord_pck ON ord_vhc.ord_id = ord_pck.ord_id"; + // $query .= " LEFT JOIN t_orders_drops as ord_drop ON ord_vhc.ord_id = ord_drop.ord_id"; + // $query .= " LEFT JOIN t_orders_drivers as ord_drv ON ord_vhc.ord_id = ord_drv.ord_id"; + // $query .= " LEFT JOIN t_orders_clients as ord_c ON ord_vhc.ord_id = ord_c.ord_id"; + } + $query .= " WHERE v.dlt is null"; + // $query .= " AND tr.action IN ('location','alarm')"; // kalo gamau ngambil data heartbeat(idling) + // $query .= " AND tr.device_id = v.device_id"; // cara lama berlaku utk gps tracker saja + // $query .= " AND tr.vhc_id = v.id"; // support gps tracker dan smartphone / apapun yang mempunyai device_id(IMEI) // bikin lemot + $query .= " AND tr.latitude != 0 AND tr.latitude is not null"; + if (isset($filter["status"])) { + $query .= " AND v.status = ?"; + $params[] = $filter["status"]; + } + if (isset($filter["is_in_ord"])) { + $query .= " AND v.is_in_ord = ?"; + $params[] = $filter["is_in_ord"]; + } + if (isset($filter["nopol1"]) && isset($filter["nopol2"]) && isset($filter["nopol3"])) { + $query .= " AND v.nopol1 = ? AND v.nopol2 = ? AND v.nopol3 = ?"; + array_push($params, $filter["nopol1"], $filter["nopol2"], $filter["nopol3"]); + } + if (isset($filter["vid"])) { + $query .= " AND v.id = ?"; + $params[] = $filter["vid"]; + } + if (isset($filter["vids"])) { + if ($filter["vids"] && count($filter["vids"]) > 0) { + $binds_vids = ""; + foreach ($filter["vids"] as $k => $v) { + $binds_vids .= "?,"; + $params[] = $v; + } + if (substr($binds_vids, -1) === ",") { + $binds_vids = substr($binds_vids, 0, -1); + } + $query .= " AND v.id IN ($binds_vids)"; + } else { + $query .= " AND v.id = ?"; + $params[] = 0; + } + } + if (isset($filter["own_by_vdr_id"])) { + $query .= " AND v.vendor_id = ?"; + $params[] = $filter["own_by_vdr_id"]; + } + if (isset($filter["active_rates"])) { + // v1 + // $query .= " AND rate.vdr_id != 0 AND rate.dest_city != 0 AND rate.dest_district != 0"; + // $query .= " AND rate.origin_prov = ? AND (rate.dest_city = ? OR rate.dest_district = ?) AND rate.sell_kg = ? AND rate.sell_cbm = ? AND rate.long_time = ?"; + // array_push($params, $filter['active_rates']->origin_prov, $filter['active_rates']->dest_city, $filter['active_rates']->dest_district, $filter['active_rates']->sell_kg, $filter['active_rates']->sell_cbm, $filter['active_rates']->long_time); + // v2 + $query .= + " AND rate.vdr_id != 0 AND rate.dest_city != 0 AND rate.is_active = " . ConfRates::IS_ACTIVE; + $query .= + " AND rate.origin_prov = ? AND (rate.dest_city = ? OR rate.dest_district = ?) AND rate.sell_ftl = ? AND rate.long_time = ?"; + array_push( + $params, + $filter["active_rates"]->origin_prov, + $filter["active_rates"]->dest_city, + $filter["active_rates"]->dest_district, + $filter["active_rates"]->sell_ftl, + $filter["active_rates"]->long_time + ); + } + if (isset($filter["prefer_truck_type"])) { + $query .= " AND v.type_id = ?"; + $params[] = $filter["prefer_truck_type"]; + } + if (isset($filter["get_order_data"])) { + if (isset($filter["client_id"])) { + $query .= " AND ord_c.c_id = ?"; + $params[] = $filter["client_id"]; + } + // $query .= " AND ord.status IN (22,4)"; + } + if (isset($filter["company"])) { + $query .= " AND client.id = ?"; + $params[] = $filter["company"]; + } + + // $query .= " AND v.id = 70"; + + $query .= " GROUP BY v.id"; + $query .= " ORDER BY tr.crt_d DESC"; + $query .= " LIMIT 500;"; + + // dd($query); + + $list = DB::select($query, $params); + foreach ($list as $_list) { + $_query = + " SELECT SUM(pre_milleage) as vhc_sum_milleage FROM " . self::T_TRACKS . " WHERE vhc_id = ?"; + $_query = DB::select($_query, [$_list->vid]); + $_list->vhc_sum_milleage = $_query[0]->vhc_sum_milleage; + + $_query = + " + SELECT + crt_s as lst_idle_at + FROM + " . + self::T_TRACKS . + " + WHERE + stts_engine = " . + self::STTS_EN_IDLING . + " + AND vhc_id = ? + AND crt_s >= ( + SELECT + crt_s + FROM + " . + self::T_TRACKS . + " + WHERE + stts_engine IN ( + " . + self::STTS_EN_STOPING . + ", + " . + self::STTS_EN_MOVING . + ") + AND vhc_id = ? + AND crt_s <= ? + ORDER BY + id DESC + LIMIT 1 + ) + ORDER BY + id ASC + LIMIT 1"; + $_query = DB::select($_query, [$_list->vid, $_list->vid, $_list->lst_loc_crt_s]); + $_list->lst_idle_at = count($_query) == 0 ? "" : $_query[0]->lst_idle_at; + + $_query = + "SELECT crt_s as lst_stop_at FROM " . + self::T_TRACKS . + " WHERE stts_engine = " . + self::STTS_EN_STOPING . + " AND vhc_id = ? AND crt_s >= ( + SELECT crt_s FROM " . + self::T_TRACKS . + " WHERE stts_engine IN (" . + self::STTS_EN_IDLING . + "," . + self::STTS_EN_MOVING . + ") AND vhc_id = ? AND crt_s <= ? ORDER BY id DESC LIMIT 1 + ) ORDER BY id ASC LIMIT 1 "; + $_query = DB::select($_query, [$_list->vid, $_list->vid, $_list->lst_loc_crt_s]); + $_list->lst_stop_at = count($_query) == 0 ? "" : $_query[0]->lst_stop_at; + + $_query = + " SELECT COUNT(id) as lst_heartbeat FROM " . + self::T_TRACKS . + " WHERE vhc_id = ? AND action = 'heartbeat' AND crt BETWEEN " . + ($now - 10 * 60) . + " AND " . + $now . + " LIMIT 1"; + $_query = DB::select($_query, [$_list->vid]); + $_list->lst_heartbeat = count($_query) == 0 ? "" : $_query[0]->lst_heartbeat; + } + // em + return $list; + } + + public static function lastMoveTracks($vid, $filter = []) + { + $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, tr.crt_d_format"; + $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.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 AND v.id = ?"; + $params[] = $vid; + $query .= " AND tr.latitude IS NOT NULL AND tr.longitude IS NOT NULL"; + + if (isset($filter["start_date"], $filter["end_date"])) { + $query .= " AND tr.crt_d BETWEEN ? AND ?"; + $params[] = $filter["start_date"]; + $params[] = $filter["end_date"]; + } + + if (isset($filter["start_at"])) { + $query .= " AND tr.crt > ?"; + $params[] = $filter["start_at"]; + } + + $query .= " ORDER BY tr.crt_d DESC"; + $limit = isset($filter["limit"]) && $filter["limit"] > 500 ? $filter["limit"] : 50000; + $query .= " LIMIT ?"; + $params[] = $limit; + + $raw = DB::select($query, $params); + $rawAscCleaned = self::removeSpeedSandwich($raw); + $filtered = self::filterJumps($rawAscCleaned); + $combined = $filtered; + + // usort($combined, fn($a, $b) => $b->lst_loc_crt_d <=> $a->lst_loc_crt_d); + $final = array_slice($combined, 0, 500); + return $final; + } + + 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; + } + + private static function removeSpeedSandwich($data) + { + $cleaned = []; + + for ($i = 0; $i < count($data); $i++) { + $next = $data[$i + 1] ?? null; // lebih lama + $curr = $data[$i]; + $prev = $data[$i - 1] ?? null; // lebih baru + + // Logika dibalik: prev = lebih baru, next = lebih lama + if ($prev && $next && $prev->speed > 5 && $curr->speed < 5 && $next->speed > 5) { + continue; + } + + $cleaned[] = $curr; + } + + return $cleaned; + } + + public static function filterJumps( + $points, + $maxDistance = 150, + $maxTimeGap = 20, + $maxSpeed = 100, + $maxHardJump = 100, + $maxIdleJump = 100, + $maxRealSpeed = 100 + ) { + $filtered = []; + $last = null; + $start = null; + + foreach ($points as $p) { + if (!$last) { + $filtered[] = $p; + $last = $p; + $start = $p; + continue; + } + + $distance = self::haversineDistance( + $last->latitude, + $last->longitude, + $p->latitude, + $p->longitude + ); + + $t1 = strtotime($last->lst_loc_crt); + $t2 = strtotime($p->lst_loc_crt); + $timeGap = $t2 - $t1; + $speed = $timeGap > 0 ? $distance / $timeGap : 0; + $realSpeedKmh = $speed * 3.6; + + $jumpFromStart = self::haversineDistance( + $start->latitude, + $start->longitude, + $p->latitude, + $p->longitude + ); + + if ($distance > $maxHardJump) { + continue; + } + + if ($distance > $maxIdleJump && $p->speed < 5 && $last->speed < 5) { + continue; + } + + if ($timeGap <= $maxTimeGap && $speed > $maxSpeed) { + continue; + } + + if ($realSpeedKmh > $maxRealSpeed) { + continue; + } + + if ($jumpFromStart > 500 && $p->speed < 5) { + continue; + } // >10 km dari area awal tapi status idle + + $filtered[] = $p; + $last = $p; + } + + return $filtered; + } + + public static function nearestInCircle($lat, $lng, $rad, $filter = []) + { + $earth_rad = Helper::EARTH_RADIUS_M; + $t_gps_tracks = self::T_TRACKS; + + $select_select = ""; + $join_join = ""; + $where_where = ""; + + $params = [ + "lat1" => $lat, + "lat2" => $lat, + "lng" => $lng, + "v_status" => Vehicles::STTS_ACTIVE, + "v_is_in_ord" => Vehicles::IN_ORD_NO, + "rad" => $rad, + ]; + + if (isset($filter["active_rates"])) { + $select_select .= + ",rate.vdr_id as rate_vdr_id,rate.vhc_type as rate_vhc_type,rate.origin_prov as rate_origin_prov,rate.dest_city as rate_dest_city,rate.dest_district as rate_dest_district"; + $select_select .= + ",rate.fast_time as rate_fast_time,rate.long_time as rate_long_time,rate.sell_kg as rate_sell_kg,rate.sell_cbm"; + } + if (isset($filter["active_rates"])) { + // $join_join .= " INNER JOIN t_conf_rates as rate ON v.type_id = rate.vhc_type"; + $join_join .= " INNER JOIN t_conf_rates as rate ON v.vendor_id = rate.vdr_id"; + } + if (isset($filter["active_rates"])) { + // v1 + // $where_where .= " AND rate.vdr_id != 0 AND rate.dest_city != 0 AND rate.dest_district != 0"; + // $where_where .= " AND rate.origin_prov = :origin_prov AND (rate.dest_city = :dest_city OR rate.dest_district = :dest_district) AND rate.sell_kg = :sell_kg AND rate.sell_cbm = :sell_cbm AND rate.long_time = :long_time"; + // v2 + $where_where .= + " AND rate.vdr_id != 0 AND rate.dest_city != 0 AND rate.is_active = " . ConfRates::IS_ACTIVE; + $where_where .= + " AND rate.origin_prov = :origin_prov AND (rate.dest_city = :dest_city OR rate.dest_district = :dest_district) AND rate.sell_ftl = :sell_ftl AND rate.long_time = :long_time"; + $params["origin_prov"] = $filter["active_rates"]->origin_prov; + $params["dest_city"] = $filter["active_rates"]->dest_city; + $params["dest_district"] = $filter["active_rates"]->dest_district; + // v1 + // $params['sell_kg'] = $filter['active_rates']->sell_kg; + // $params['sell_cbm'] = $filter['active_rates']->sell_cbm; + // v2 + $params["sell_ftl"] = $filter["active_rates"]->sell_ftl; + $params["long_time"] = $filter["active_rates"]->long_time; + } + if (isset($filter["prefer_truck_type"])) { + $where_where .= " AND v.type_id = :prefer_truck_type"; + $params["prefer_truck_type"] = $filter["prefer_truck_type"]; + } + + $query = "SELECT v.*,tr.latitude,tr.longitude,tr.id as master_id + ,u.first_name as vendor_name,u.phone as vendor_phone,u.phone_code as vendor_phone_code,u.email as vendor_mail,u.fulladdress as vendor_addr + ,( $earth_rad * acos( cos( radians( :lat1 ) ) * cos( radians( tr.latitude ) ) + * cos( radians( tr.longitude ) - radians( :lng ) ) + sin( radians( :lat2 ) ) * sin(radians( tr.latitude )) ) ) AS distance + $select_select + FROM $t_gps_tracks as tr + INNER JOIN t_vehicles as v ON tr.vhc_id = v.id + INNER JOIN t_users as u ON v.vendor_id = u.id + -- get last updated row from many rows + LEFT JOIN ( SELECT MAX(crt) max_crt, vhc_id FROM $t_gps_tracks WHERE latitude is not null AND longitude is not null GROUP BY vhc_id ORDER BY crt DESC ) AS tr1 ON (v.id = tr1.vhc_id) + $join_join + WHERE v.dlt is null + AND v.status = :v_status + AND v.is_in_ord = :v_is_in_ord + AND tr.latitude is not null + AND tr.longitude != 0 + -- get last updated row from many rows + AND tr.crt = tr1.max_crt + $where_where + GROUP BY tr.vhc_id + HAVING distance <= :rad + -- ORDER BY distance ASC + ORDER BY tr.crt DESC + ;"; + return DB::select($query, $params); + } + + public static function addTracks($data) + { + $id = DB::table(self::T_TRACKS)->insertGetId($data); + return $id; + } + + public static function addTracksAddr($data) + { + $id = DB::table(self::T_TRACKS_ADDR)->insertGetId($data); + return $id; + } + + public static function listLogsGps($filter = []) + { + $params = []; + $where_where = ""; + $limit = ""; + + if (isset($filter["crt_greater_than"])) { + $where_where .= " AND crt > ?"; + $params[] = $filter["crt_greater_than"]; + } + + if (isset($filter["limit"])) { + $limit .= " LIMIT ?"; + $params[] = $filter["limit"]; + } + + return DB::select( + "SELECT + * + FROM " . + self::T_TRACKS . + " as tr + WHERE device_id is not null + AND device_id != 0 + " . + $where_where . + " + ORDER BY tr.crt DESC + " . + $limit . + " + ", + $params + ); + } + + public static function gpsLocsAddr($filter = []) + { + $params = []; + $select = ""; + $join = ""; + $where = ""; + $order_by = ""; + $group_by = ""; + $limit = ""; + + if (isset($filter["source"])) { + $where .= " AND tr.source = ?"; + $params[] = $filter["source"]; + } + + if (isset($filter["vhc_id"])) { + $where .= " AND tr.vhc_id = ?"; + $params[] = $filter["vhc_id"]; + } + + if (isset($filter["drv_id"])) { + $where .= " AND tr.drv_id = ?"; + $params[] = $filter["drv_id"]; + } + + if (isset($filter["group_by"])) { + $group_by .= " GROUP BY " . $filter["group_by"]; + } + if (isset($filter["order_by"])) { + $order_by .= " ORDER BY " . $filter["order_by"]; + } + if (isset($filter["limit"])) { + $limit .= " LIMIT " . $filter["limit"]; + } + + return DB::select( + "SELECT + tr.* + ,tr_addr.country_id,tr_addr.country_text,tr_addr.state_id,tr_addr.state_text,tr_addr.city_id,tr_addr.city_text + ,tr_addr.district_id,tr_addr.district_text,tr_addr.village_id,tr_addr.village_text,tr_addr.postcode,tr_addr.streets,tr_addr.fulladdress + ,tr_addr.stts_reverse_geo + $select + FROM t_gps_tracks as tr + LEFT JOIN t_gps_tracks_address as tr_addr ON tr.id = tr_addr.master_id + $join + WHERE tr.latitude is not null AND tr.longitude != 0 + $where + $group_by + $order_by + $limit + ;", + $params + ); + } +} diff --git a/public/index.php b/public/index.php index 95e5cf2..94012d6 100755 --- a/public/index.php +++ b/public/index.php @@ -1,5 +1,5 @@ */ -define('LARAVEL_START', microtime(true)); -setlocale(LC_TIME, 'id_ID.UTF8', 'id_ID.UTF-8', 'id_ID.8859-1', 'id_ID', 'IND.UTF8', 'IND.UTF-8', 'IND.8859-1', 'IND', 'Indonesian.UTF8', 'Indonesian.UTF-8', 'Indonesian.8859-1', 'Indonesian', 'Indonesia', 'id', 'ID', 'en_US.UTF8', 'en_US.UTF-8', 'en_US.8859-1', 'en_US', 'American', 'ENG', 'English'); +define("LARAVEL_START", microtime(true)); +setlocale( + LC_TIME, + "id_ID.UTF8", + "id_ID.UTF-8", + "id_ID.8859-1", + "id_ID", + "IND.UTF8", + "IND.UTF-8", + "IND.8859-1", + "IND", + "Indonesian.UTF8", + "Indonesian.UTF-8", + "Indonesian.8859-1", + "Indonesian", + "Indonesia", + "id", + "ID", + "en_US.UTF8", + "en_US.UTF-8", + "en_US.8859-1", + "en_US", + "American", + "ENG", + "English" +); /* |-------------------------------------------------------------------------- @@ -22,7 +46,7 @@ setlocale(LC_TIME, 'id_ID.UTF8', 'id_ID.UTF-8', 'id_ID.8859-1', 'id_ID', 'IND.UT | */ -require __DIR__.'/../vendor/autoload.php'; +require __DIR__ . "/../vendor/autoload.php"; /* |-------------------------------------------------------------------------- @@ -36,7 +60,7 @@ require __DIR__.'/../vendor/autoload.php'; | */ -$app = require_once __DIR__.'/../bootstrap/app.php'; +$app = require_once __DIR__ . "/../bootstrap/app.php"; /* |-------------------------------------------------------------------------- @@ -52,9 +76,7 @@ $app = require_once __DIR__.'/../bootstrap/app.php'; $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); -$response = $kernel->handle( - $request = Illuminate\Http\Request::capture() -); +$response = $kernel->handle($request = Illuminate\Http\Request::capture()); $response->send(); diff --git a/resources/views/menu_v1/dashboard.blade.php b/resources/views/menu_v1/dashboard.blade.php index 70d376b..22243f5 100755 --- a/resources/views/menu_v1/dashboard.blade.php +++ b/resources/views/menu_v1/dashboard.blade.php @@ -1337,7 +1337,7 @@
  • ${arrIdx + 1}

    -

    Time: ${moment.unix(obj?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}

    +

    Time: ${moment.unix(obj?.lst_loc_crt_d).format('DD MMM YYYY HH:mm:ss')}

    ${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}

    ${Helper.shortenText(decodeURIComponent(obj?.fulladdress || 'address'), 255)}

    Current speed: ${Number(obj.speed)}km/h

    @@ -1359,8 +1359,8 @@ lat: tr.latitude, lng: tr.longitude, // label: `${tr.key_index}
    ${tr.nopol1} ${tr.nopol2} ${tr.nopol3}
    ${moment.unix(tr?.lst_loc_crt).format('DD MMM YYYY HH:mm')}
    Speed: ${(typeof tr.lst_speed != 'undefined') ? tr.lst_speed : '0'}
    ${tr.latitude},${tr.longitude}
    ${decodeURIComponent(tr?.fulladdress || 'address')}`, - // label: `${tr.nopol1} ${tr.nopol2} ${tr.nopol3}
    ${moment.unix(tr?.lst_loc_crt).format('DD MMM YYYY HH:mm')}
    ${decodeURIComponent(tr?.fulladdress || 'address')}.

    Current speed: ${tr?.speed}km/h`, - label: `${tr.nopol1} ${tr.nopol2} ${tr.nopol3}
    ${moment.unix(tr?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}
    ${decodeURIComponent(tr?.fulladdress || 'address')}.

    Current speed: ${tr?.speed}km/h`, + label: `${tr.nopol1} ${tr.nopol2} ${tr.nopol3}
    ${moment.unix(tr?.lst_loc_crt).format('DD MMM YYYY HH:mm')}
    ${decodeURIComponent(tr?.fulladdress || 'address')}.

    Current speed: ${tr?.speed}km/h`, + //label: `${tr.nopol1} ${tr.nopol2} ${tr.nopol3}
    ${moment.unix(tr?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}
    ${decodeURIComponent(tr?.fulladdress || 'address')}.

    Current speed: ${tr?.speed}km/h`, options: { // icon: Icon.destination() } @@ -2385,8 +2385,8 @@ `${State.storage_lara}${truck?.fvhc_img}`); $('#infoVehicles-platno').text(`${truck?.nopol1} ${truck?.nopol2} ${truck?.nopol3}`); // vehicles - // $('#infoVehicles-crt').text(moment.unix(truck?.lst_loc_crt).format('DD MMM YYYY HH:mm')); - $('#infoVehicles-crt').text(moment.unix(truck?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')); + $('#infoVehicles-crt').text(moment.unix(truck?.lst_loc_crt).format('DD MMM YYYY HH:mm')); + // $('#infoVehicles-crt').text(moment.unix(truck?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')); // ${(truck?.city_text || truck?.state_text || 'address')} - ${(truck?.postcode || 'postcode')} if (truck?.ignition == State.stts_ignition.high) { $('#infoVehicles-ignition').text('ON'); @@ -2425,9 +2425,9 @@ $('#infoVehicles-isTrackHoliday').text(truck?.is_track_holiday_text); $('#infoVehicles-trackSch').text(truck?.track_schedule); $('#infoVehicles-company').text(truck?.client_group_name); - $('#infoVehicles-serviceStart').text(moment.unix(truck?.vhc_crt).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')); + $('#infoVehicles-serviceStart').text(moment.unix(truck?.vhc_crt).format('DD MMM YYYY HH:mm:ss')); // driver - $('#infoDrv-updt').text((truck?.ord_crt) ? moment.unix(truck?.ord_crt).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss') : '-'); + $('#infoDrv-updt').text((truck?.ord_crt) ? moment.unix(truck?.ord_crt).format('DD MMM YYYY HH:mm:ss') : '-'); $('#infoDrv-name').text(truck?.ord_drv_name ?? 'Off Duty'); $('.infoDrv-phone1-text').text((truck?.ord_drv_phone_val) ? Helper.splitEvery4Char('0' + truck?.ord_drv_phone_val) : '-'); $('#infoDrv-phone1-tel').attr('tel:0' + (truck?.ord_drv_phone_val ?? '')); @@ -2585,7 +2585,7 @@ // circle // label: `${obj.key_index}
    ${obj.nopol1} ${obj.nopol2} ${obj.nopol3}
    ${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}
    Speed: ${(typeof obj.speed != 'undefined') ? obj.speed : '0'}
    ${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}
    ${decodeURIComponent(obj?.fulladdress || 'address')}`, // label: `${obj.nopol1} ${obj.nopol2} ${obj.nopol3}
    ${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}
    ${decodeURIComponent(obj?.fulladdress || 'address')}`, - label: `${obj.nopol1} ${obj.nopol2} ${obj.nopol3}
    ${moment.unix(obj?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}
    ${decodeURIComponent(obj?.fulladdress || 'address')}`, + label: `${obj.nopol1} ${obj.nopol2} ${obj.nopol3}
    ${moment.unix(obj?.lst_loc_crt_d).format('DD MMM YYYY HH:mm:ss')}
    ${decodeURIComponent(obj?.fulladdress || 'address')}`, } }); @@ -2609,8 +2609,8 @@ let startMarker = Leaflet.addMarkers({ lat: start.latitude, lng: start.longitude, - // label: `Start Poin
    ${start.nopol1} ${start.nopol2} ${start.nopol3}
    ${moment.unix(start?.lst_loc_crt).format('DD MMM YYYY HH:mm')}
    Speed: ${(typeof start.lst_speed != 'undefined') ? start.lst_speed : '0'}
    ${Number(start.latitude).toFixed(5)},${Number(start.longitude).toFixed(6)}
    ${decodeURIComponent(start.fulladdress || 'address')}`, - label: `Start Poin
    ${start.nopol1} ${start.nopol2} ${start.nopol3}
    ${moment.unix(start?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}
    Speed: ${(typeof start.lst_speed != 'undefined') ? start.lst_speed : '0'}
    ${Number(start.latitude).toFixed(5)},${Number(start.longitude).toFixed(6)}
    ${decodeURIComponent(start.fulladdress || 'address')}`, + label: `Start Poin
    ${start.nopol1} ${start.nopol2} ${start.nopol3}
    ${moment.unix(start?.lst_loc_crt).format('DD MMM YYYY HH:mm')}
    Speed: ${(typeof start.lst_speed != 'undefined') ? start.lst_speed : '0'}
    ${Number(start.latitude).toFixed(5)},${Number(start.longitude).toFixed(6)}
    ${decodeURIComponent(start.fulladdress || 'address')}`, + // label: `Start Poin
    ${start.nopol1} ${start.nopol2} ${start.nopol3}
    ${moment.unix(start?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}
    Speed: ${(typeof start.lst_speed != 'undefined') ? start.lst_speed : '0'}
    ${Number(start.latitude).toFixed(5)},${Number(start.longitude).toFixed(6)}
    ${decodeURIComponent(start.fulladdress || 'address')}`, options: { icon: Icon.titikAwal(), // rotationAngle: 290 @@ -2619,8 +2619,8 @@ let finishMarker = Leaflet.addMarkers({ lat: finish.latitude, lng: finish.longitude, - // label: `End Poin
    ${finish.nopol1} ${finish.nopol2} ${finish.nopol3}
    ${moment.unix(finish?.lst_loc_crt).format('DD MMM YYYY HH:mm')}
    Speed: ${(typeof finish.lst_speed != 'undefined') ? finish.lst_speed : '0'}
    ${Number(finish.latitude).toFixed(5)},${Number(finish.longitude).toFixed(6)}
    ${decodeURIComponent(finish.fulladdress || 'address')}`, - label: `End Poin
    ${finish.nopol1} ${finish.nopol2} ${finish.nopol3}
    ${moment.unix(finish?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}
    Speed: ${(typeof finish.lst_speed != 'undefined') ? finish.lst_speed : '0'}
    ${Number(finish.latitude).toFixed(5)},${Number(finish.longitude).toFixed(6)}
    ${decodeURIComponent(finish.fulladdress || 'address')}`, + label: `End Poin
    ${finish.nopol1} ${finish.nopol2} ${finish.nopol3}
    ${moment.unix(finish?.lst_loc_crt).format('DD MMM YYYY HH:mm')}
    Speed: ${(typeof finish.lst_speed != 'undefined') ? finish.lst_speed : '0'}
    ${Number(finish.latitude).toFixed(5)},${Number(finish.longitude).toFixed(6)}
    ${decodeURIComponent(finish.fulladdress || 'address')}`, + //label: `End Poin
    ${finish.nopol1} ${finish.nopol2} ${finish.nopol3}
    ${moment.unix(finish?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}
    Speed: ${(typeof finish.lst_speed != 'undefined') ? finish.lst_speed : '0'}
    ${Number(finish.latitude).toFixed(5)},${Number(finish.longitude).toFixed(6)}
    ${decodeURIComponent(finish.fulladdress || 'address')}`, options: { icon: Icon.titikAkhir() }