Compare commits
	
		
			42 Commits
		
	
	
		
			ccd7b19ff5
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 8b833e7295 | |||
| 0b79bd665c | |||
| 81efe25ce2 | |||
| fbbcf86509 | |||
| 18897186e0 | |||
| 136db1a158 | |||
| f4202ce146 | |||
| a2c821d4bd | |||
| 1331e4a46e | |||
| 111c3e35a1 | |||
| 4b5cb88e4a | |||
| 0284d25af4 | |||
| a92d0c632f | |||
| 77e5b345b7 | |||
| a3f42315e4 | |||
| 65f7cc1ebf | |||
| e1153c375d | |||
| 0fe1cac8bf | |||
| 0621b14b77 | |||
| 08776e5a1b | |||
| b3a2467629 | |||
| dae0954891 | |||
| d013eb6dd1 | |||
| 8445a18416 | |||
| d1f90af6f6 | |||
| f6d11ce5e9 | |||
| 993b529331 | |||
| 5c687fc24f | |||
| bc92ed5234 | |||
| 5d585a6e26 | |||
| 64235d08f5 | |||
| 85d29d4142 | |||
| 620486de25 | |||
| 48fe5e3ef6 | |||
| e49309f709 | |||
| 36ec099cd9 | |||
| c7e0b57ad6 | |||
| a101b55279 | |||
| c075457053 | |||
| 0217c1c947 | |||
| ff5b411178 | |||
| 14f5246c86 | 
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -13,3 +13,4 @@ npm-debug.log | |||||||
| yarn-error.log | yarn-error.log | ||||||
| .vscode | .vscode | ||||||
| .DS_Store | .DS_Store | ||||||
|  | .sql | ||||||
| @ -9,6 +9,7 @@ class Helper | |||||||
|     const EARTH_RADIUS_M = 6371000; |     const EARTH_RADIUS_M = 6371000; | ||||||
|     const EARTH_RADIUS_KM = 6371; |     const EARTH_RADIUS_KM = 6371; | ||||||
|     const EARTH_RADIUS_MILES = 3959; // 3958.756 || 3959 || 3963 |     const EARTH_RADIUS_MILES = 3959; // 3958.756 || 3959 || 3963 | ||||||
|  | 	const TIMEFIX = 25200; | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Calculates the great-circle distance between two points, with |      * Calculates the great-circle distance between two points, with | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ use App\Models\Users; | |||||||
| use Illuminate\Support\Facades\Auth; | use Illuminate\Support\Facades\Auth; | ||||||
| use Illuminate\Http\JsonResponse; | use Illuminate\Http\JsonResponse; | ||||||
| use Illuminate\Validation\ValidationException; | use Illuminate\Validation\ValidationException; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  |  | ||||||
| class LoginController extends Controller | class LoginController extends Controller | ||||||
| { | { | ||||||
| @ -143,6 +144,12 @@ class LoginController extends Controller | |||||||
|         // return $req->wantsJson() |         // return $req->wantsJson() | ||||||
|         //     ? new JsonResponse([], 204) |         //     ? new JsonResponse([], 204) | ||||||
|         //     : redirect(route('view_dashboard')); |         //     : redirect(route('view_dashboard')); | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Auth", | ||||||
|  | 			"action" => "Login", | ||||||
|  | 			"desc" => "User login", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|         if ($req->wantsJson()) { |         if ($req->wantsJson()) { | ||||||
|             return new JsonResponse([], 204); |             return new JsonResponse([], 204); | ||||||
| @ -173,7 +180,14 @@ class LoginController extends Controller | |||||||
|     public function logout(Request $req) |     public function logout(Request $req) | ||||||
|     { |     { | ||||||
|         $user = Auth::user(); |         $user = Auth::user(); | ||||||
|         if ($user->role == Users::ROLE_ADMIN) { | 		$log = [ | ||||||
|  | 			"module" => "Auth", | ||||||
|  | 			"action" => "Logout", | ||||||
|  | 			"desc" => "User logout", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|  | 		if ($user->role == Users::ROLE_ADMIN) { | ||||||
|             $this->guard()->logout(); |             $this->guard()->logout(); | ||||||
|             $req->session()->invalidate(); |             $req->session()->invalidate(); | ||||||
|             $req->session()->regenerateToken(); |             $req->session()->regenerateToken(); | ||||||
|  | |||||||
| @ -12,6 +12,8 @@ use App\Responses; | |||||||
| use App\Helper; | use App\Helper; | ||||||
| use App\Models\Clients; | use App\Models\Clients; | ||||||
| use App\Models\Users; | use App\Models\Users; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  | use Auth; | ||||||
|  |  | ||||||
| class ClientController extends Controller | class ClientController extends Controller | ||||||
| { | { | ||||||
| @ -25,6 +27,13 @@ class ClientController extends Controller | |||||||
|         $data = [ |         $data = [ | ||||||
|             "disc_types" => Clients::select2DiscountTypes(), |             "disc_types" => Clients::select2DiscountTypes(), | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Company", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Company Menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|         return view("menu_v1.clients", $data); |         return view("menu_v1.clients", $data); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -250,6 +259,13 @@ class ClientController extends Controller | |||||||
|             $apiResp = Responses::created("success add new client"); |             $apiResp = Responses::created("success add new client"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Company", | ||||||
|  | 				"action" => "Create", | ||||||
|  | 				"desc" => "Add new company: ".$req->cname, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             Storage::disk("public")->delete($url_clogo); |             Storage::disk("public")->delete($url_clogo); | ||||||
| @ -481,6 +497,13 @@ class ClientController extends Controller | |||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success update client"); |             $apiResp = Responses::success("success update client"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Company", | ||||||
|  | 				"action" => "Update", | ||||||
|  | 				"desc" => "Update company: ".$req->cname, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             Storage::disk("public")->delete($url_clogo); |             Storage::disk("public")->delete($url_clogo); | ||||||
| @ -541,6 +564,13 @@ class ClientController extends Controller | |||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success delete client"); |             $apiResp = Responses::success("success delete client"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Company", | ||||||
|  | 				"action" => "Delete", | ||||||
|  | 				"desc" => "Delete company: ".$client[0]->c_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
|  | |||||||
							
								
								
									
										232
									
								
								app/Http/Controllers/ConfDistributionController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								app/Http/Controllers/ConfDistributionController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,232 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace App\Http\Controllers; | ||||||
|  |  | ||||||
|  | use App\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Http\Response; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
|  | use Illuminate\Support\Facades\Storage; | ||||||
|  | use Validator; | ||||||
|  | use Hidehalo\Nanoid\Client as Nanoid; | ||||||
|  | use Hidehalo\Nanoid\GeneratorInterface as NanoidInterface; | ||||||
|  | use App\Responses; | ||||||
|  | use App\Helper; | ||||||
|  | use App\Models\ConfRates; | ||||||
|  | use App\Models\ConfTruckTypes; | ||||||
|  | use App\Models\Vehicles; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  | use Auth; | ||||||
|  |  | ||||||
|  | class ConfDistributionController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * View | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     public function view_distribution_category(Request $req) | ||||||
|  |     { | ||||||
|  |         $data = []; | ||||||
|  |  | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Distribution Category", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Distribution Category menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |         return view("menu_v1.configs.distribution_category", $data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * API | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     public function api_add_distribution_category(Request $req) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |             $now = time(); | ||||||
|  | 			// new or edit | ||||||
|  | 			$tipe = $req->tipe ?? "new"; | ||||||
|  |  | ||||||
|  |             $input = [ | ||||||
|  |                 "dc_code" => $req->dc_code, | ||||||
|  |                 "dc_name" => $req->dc_name, | ||||||
|  |             ]; | ||||||
|  |             $rulesInput = [ | ||||||
|  |                 "dc_code" => "required|string|max:10", | ||||||
|  |                 "dc_name" => "required|string|max:100", | ||||||
|  |             ]; | ||||||
|  |  | ||||||
|  |             // validasi input | ||||||
|  |             $isValidInput = Validator::make($input, $rulesInput); | ||||||
|  |             if (!$isValidInput->passes()) { | ||||||
|  |                 $apiResp = Responses::bad_input($isValidInput->messages()->first()); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  | 			if($tipe == "new"){ | ||||||
|  |             	$uniqCode = DB::select("SELECT * FROM t_conf_distribution_category WHERE dc_code = ?", [$req->dc_code]); | ||||||
|  | 			} | ||||||
|  | 			if($tipe == "edit"){ | ||||||
|  | 				$uniqCode = DB::select("SELECT * FROM t_conf_distribution_category WHERE dc_code = ? AND id != ?", [$req->dc_code, $req->id]); | ||||||
|  | 			} | ||||||
|  |             if (count($uniqCode) > 0) { | ||||||
|  |                 $apiResp = Responses::bad_request("type code has been used"); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             DB::beginTransaction(); | ||||||
|  |  | ||||||
|  | 			$insD = [ | ||||||
|  | 				"dc_code" => $req->dc_code, | ||||||
|  | 				"dc_name" => $req->dc_name, | ||||||
|  |                 "crt" => $now, | ||||||
|  |                 "crt_by" => $req->auth->uid, | ||||||
|  |                 "updt" => $now, | ||||||
|  |                 "updt_by" => $req->auth->uid, | ||||||
|  | 			]; | ||||||
|  | 			// $insQ = DB::insert("INSERT | ||||||
|  | 			// 	INTO t_conf_distribution_category (dc_code, dc_name, crt, crt_by, updt, updt_by) | ||||||
|  | 			// 	VALUES (?, ?, ?, ?, ?, ?) | ||||||
|  | 			// ", array_values($insD)); | ||||||
|  | 			$insQ = DB::insert("INSERT into t_conf_distribution_category set | ||||||
|  | 					dc_code = ?, | ||||||
|  | 					dc_name = ?, | ||||||
|  | 					crt = ?, | ||||||
|  | 					crt_by = ?, | ||||||
|  | 					updt = ?, | ||||||
|  | 					updt_by = ? | ||||||
|  | 				on duplicate key update | ||||||
|  | 					dc_code = values(dc_code), | ||||||
|  | 					dc_name = values(dc_name), | ||||||
|  | 					updt = values(updt), | ||||||
|  | 					updt_by = values(updt_by)					 | ||||||
|  | 			", array_values($insD)); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             $apiResp = Responses::created("success " . ($tipe == "new" ? "add new" : "edit") . " distribution category"); | ||||||
|  |  | ||||||
|  |             DB::commit(); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Distribution Category", | ||||||
|  | 				"action" => "".($tipe == "new" ? "Create" : "Update")."", | ||||||
|  | 				"desc" => "".($tipe == "new" ? "Add new" : "Update")." distribution category: ".$req->dc_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             DB::rollBack(); | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 	public function api_list_distribution_category(Request $req) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |             $now = time(); | ||||||
|  |  | ||||||
|  |             $list = DB::select("SELECT * FROM t_conf_distribution_category WHERE dlt IS NULL ORDER BY dc_code ASC"); | ||||||
|  | 			foreach ($list as $key => $row) { | ||||||
|  |                 $list[$key]->DT_RowIndex = $key + 1; | ||||||
|  |                 $list[$key]->action = "-"; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $apiResp = Responses::success("success list distribution category"); | ||||||
|  |             $apiResp["count"] = count($list); | ||||||
|  |             $apiResp["data"] = $list; | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function api_show_distribution_category(Request $req, $id) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |             $input = [ | ||||||
|  |                 "id" => $id, | ||||||
|  |             ]; | ||||||
|  |             $rulesInput = [ | ||||||
|  |                 "id" => "required|integer|not_in:0", | ||||||
|  |             ]; | ||||||
|  |  | ||||||
|  |             // validasi input | ||||||
|  |             $isValidInput = Validator::make($input, $rulesInput); | ||||||
|  |             if (!$isValidInput->passes()) { | ||||||
|  |                 $apiResp = Responses::bad_input($isValidInput->messages()->first()); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  | 			$dtl = DB::select("SELECT * FROM t_conf_distribution_category WHERE id = ? AND dlt IS NULL limit 1", [$id]); | ||||||
|  |             if (count($dtl) < 1) { | ||||||
|  |                 $apiResp = Responses::not_found("truck type not found"); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $apiResp = Responses::success("success get detail vehicle type"); | ||||||
|  |             $apiResp["data"] = $dtl[0]; | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     public function api_del_distribution_category(Request $req, $id) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |             $now = time(); | ||||||
|  |  | ||||||
|  |             $input = [ | ||||||
|  |                 "id" => $id, | ||||||
|  |             ]; | ||||||
|  |             $rulesInput = [ | ||||||
|  |                 "id" => "required|integer|not_in:0", | ||||||
|  |             ]; | ||||||
|  |  | ||||||
|  |             // validasi input | ||||||
|  |             $isValidInput = Validator::make($input, $rulesInput); | ||||||
|  |             if (!$isValidInput->passes()) { | ||||||
|  |                 $apiResp = Responses::bad_input($isValidInput->messages()->first()); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $dtl = DB::select("SELECT * FROM t_conf_distribution_category WHERE id = ? AND dlt IS NULL limit 1", [$id]); | ||||||
|  |             if (count($dtl) < 1) { | ||||||
|  |                 $apiResp = Responses::not_found("vehicle type not found"); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             DB::beginTransaction(); | ||||||
|  |  | ||||||
|  | 			$updtQ = DB::update("UPDATE t_conf_distribution_category | ||||||
|  | 				SET | ||||||
|  | 					dlt = ?, | ||||||
|  | 					dlt_by = ?, | ||||||
|  | 					updt = ?, | ||||||
|  | 					updt_by = ? | ||||||
|  | 				WHERE id = ? AND dlt IS NULL | ||||||
|  | 			", [1, $req->user()->id, $now, $req->user()->id, $id]); | ||||||
|  | 			 | ||||||
|  |             DB::commit(); | ||||||
|  |  | ||||||
|  |             $apiResp = Responses::success("success delete vehicle type"); | ||||||
|  | 			 | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Distribution Category", | ||||||
|  | 				"action" => "Delete", | ||||||
|  | 				"desc" => "Delete distribution category: ".$dtl[0]->dc_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, "Delete distribution category: ".$dtl[0]->dc_name); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             DB::rollBack(); | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										233
									
								
								app/Http/Controllers/ConfPoolController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								app/Http/Controllers/ConfPoolController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,233 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace App\Http\Controllers; | ||||||
|  |  | ||||||
|  | use App\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Http\Response; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
|  | use Illuminate\Support\Facades\Storage; | ||||||
|  | use Validator; | ||||||
|  | use Hidehalo\Nanoid\Client as Nanoid; | ||||||
|  | use Hidehalo\Nanoid\GeneratorInterface as NanoidInterface; | ||||||
|  | use App\Responses; | ||||||
|  | use App\Helper; | ||||||
|  | use App\Models\ConfRates; | ||||||
|  | use App\Models\ConfTruckTypes; | ||||||
|  | use App\Models\Vehicles; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  | use Auth; | ||||||
|  |  | ||||||
|  | class ConfPoolController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * View | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     public function view_pool(Request $req) | ||||||
|  |     { | ||||||
|  |         $data = []; | ||||||
|  |  | ||||||
|  | 		 | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Pool", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Pool menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |         return view("menu_v1.configs.pool", $data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * API | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     public function api_add_pool(Request $req) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |             $now = time(); | ||||||
|  | 			// new or edit | ||||||
|  | 			$tipe = $req->tipe ?? "new"; | ||||||
|  |  | ||||||
|  |             $input = [ | ||||||
|  |                 "pool_code" => $req->pool_code, | ||||||
|  |                 "pool_name" => $req->pool_name, | ||||||
|  |             ]; | ||||||
|  |             $rulesInput = [ | ||||||
|  |                 "pool_code" => "required|string|max:10", | ||||||
|  |                 "pool_name" => "required|string|max:100", | ||||||
|  |             ]; | ||||||
|  |  | ||||||
|  |             // validasi input | ||||||
|  |             $isValidInput = Validator::make($input, $rulesInput); | ||||||
|  |             if (!$isValidInput->passes()) { | ||||||
|  |                 $apiResp = Responses::bad_input($isValidInput->messages()->first()); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  | 			if($tipe == "new"){ | ||||||
|  |             	$uniqCode = DB::select("SELECT * FROM t_conf_pool WHERE pool_code = ?", [$req->pool_code]); | ||||||
|  | 			} | ||||||
|  | 			if($tipe == "edit"){ | ||||||
|  | 				$uniqCode = DB::select("SELECT * FROM t_conf_pool WHERE pool_code = ? AND id != ?", [$req->pool_code, $req->id]); | ||||||
|  | 			} | ||||||
|  |             if (count($uniqCode) > 0) { | ||||||
|  |                 $apiResp = Responses::bad_request("type code has been used"); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             DB::beginTransaction(); | ||||||
|  |  | ||||||
|  | 			$insD = [ | ||||||
|  | 				"pool_code" => $req->pool_code, | ||||||
|  | 				"pool_name" => $req->pool_name, | ||||||
|  |                 "crt" => $now, | ||||||
|  |                 "crt_by" => $req->auth->uid, | ||||||
|  |                 "updt" => $now, | ||||||
|  |                 "updt_by" => $req->auth->uid, | ||||||
|  | 			]; | ||||||
|  | 			// $insQ = DB::insert("INSERT | ||||||
|  | 			// 	INTO t_conf_pool (pool_code, pool_name, crt, crt_by, updt, updt_by) | ||||||
|  | 			// 	VALUES (?, ?, ?, ?, ?, ?) | ||||||
|  | 			// ", array_values($insD)); | ||||||
|  | 			$insQ = DB::insert("INSERT into t_conf_pool set | ||||||
|  | 					pool_code = ?, | ||||||
|  | 					pool_name = ?, | ||||||
|  | 					crt = ?, | ||||||
|  | 					crt_by = ?, | ||||||
|  | 					updt = ?, | ||||||
|  | 					updt_by = ? | ||||||
|  | 				on duplicate key update | ||||||
|  | 					pool_code = values(pool_code), | ||||||
|  | 					pool_name = values(pool_name), | ||||||
|  | 					updt = values(updt), | ||||||
|  | 					updt_by = values(updt_by)					 | ||||||
|  | 			", array_values($insD)); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |             $apiResp = Responses::created("success " . ($tipe == "new" ? "add new" : "edit") . " distribution category"); | ||||||
|  |  | ||||||
|  |             DB::commit(); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Pool", | ||||||
|  | 				"action" => "".($tipe == "new" ? "Create" : "Update")."", | ||||||
|  | 				"desc" => "".($tipe == "new" ? "Add new" : "Update")." pool: ".$req->pool_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             DB::rollBack(); | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | 	public function api_list_pool(Request $req) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |             $now = time(); | ||||||
|  |  | ||||||
|  |             $list = DB::select("SELECT * FROM t_conf_pool WHERE dlt IS NULL ORDER BY pool_code ASC"); | ||||||
|  | 			foreach ($list as $key => $row) { | ||||||
|  |                 $list[$key]->DT_RowIndex = $key + 1; | ||||||
|  |                 $list[$key]->action = "-"; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $apiResp = Responses::success("success list distribution category"); | ||||||
|  |             $apiResp["count"] = count($list); | ||||||
|  |             $apiResp["data"] = $list; | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     public function api_show_pool(Request $req, $id) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |             $input = [ | ||||||
|  |                 "id" => $id, | ||||||
|  |             ]; | ||||||
|  |             $rulesInput = [ | ||||||
|  |                 "id" => "required|integer|not_in:0", | ||||||
|  |             ]; | ||||||
|  |  | ||||||
|  |             // validasi input | ||||||
|  |             $isValidInput = Validator::make($input, $rulesInput); | ||||||
|  |             if (!$isValidInput->passes()) { | ||||||
|  |                 $apiResp = Responses::bad_input($isValidInput->messages()->first()); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  | 			$dtl = DB::select("SELECT * FROM t_conf_pool WHERE id = ? AND dlt IS NULL limit 1", [$id]); | ||||||
|  |             if (count($dtl) < 1) { | ||||||
|  |                 $apiResp = Responses::not_found("truck type not found"); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $apiResp = Responses::success("success get detail vehicle type"); | ||||||
|  |             $apiResp["data"] = $dtl[0]; | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     public function api_del_pool(Request $req, $id) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  |             $now = time(); | ||||||
|  |  | ||||||
|  |             $input = [ | ||||||
|  |                 "id" => $id, | ||||||
|  |             ]; | ||||||
|  |             $rulesInput = [ | ||||||
|  |                 "id" => "required|integer|not_in:0", | ||||||
|  |             ]; | ||||||
|  |  | ||||||
|  |             // validasi input | ||||||
|  |             $isValidInput = Validator::make($input, $rulesInput); | ||||||
|  |             if (!$isValidInput->passes()) { | ||||||
|  |                 $apiResp = Responses::bad_input($isValidInput->messages()->first()); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $dtl = DB::select("SELECT * FROM t_conf_pool WHERE id = ? AND dlt IS NULL limit 1", [$id]); | ||||||
|  |             if (count($dtl) < 1) { | ||||||
|  |                 $apiResp = Responses::not_found("vehicle type not found"); | ||||||
|  |                 return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             DB::beginTransaction(); | ||||||
|  |  | ||||||
|  | 			$updtQ = DB::update("UPDATE t_conf_pool | ||||||
|  | 				SET | ||||||
|  | 					dlt = ?, | ||||||
|  | 					dlt_by = ?, | ||||||
|  | 					updt = ?, | ||||||
|  | 					updt_by = ? | ||||||
|  | 				WHERE id = ? AND dlt IS NULL | ||||||
|  | 			", [1, $req->user()->id, $now, $req->user()->id, $id]); | ||||||
|  | 			 | ||||||
|  |             DB::commit(); | ||||||
|  |  | ||||||
|  |             $apiResp = Responses::success("success delete vehicle type"); | ||||||
|  | 		 | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Pool", | ||||||
|  | 				"action" => "Delete", | ||||||
|  | 				"desc" => "Delete pool: ".$dtl[0]->pool_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } catch (\Exception $e) { | ||||||
|  |             DB::rollBack(); | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -15,6 +15,8 @@ use App\Helper; | |||||||
| use App\Models\ConfRates; | use App\Models\ConfRates; | ||||||
| use App\Models\ConfTruckTypes; | use App\Models\ConfTruckTypes; | ||||||
| use App\Models\Vehicles; | use App\Models\Vehicles; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  | use Auth; | ||||||
|  |  | ||||||
| class ConfTruckTypeController extends Controller | class ConfTruckTypeController extends Controller | ||||||
| { | { | ||||||
| @ -26,6 +28,12 @@ class ConfTruckTypeController extends Controller | |||||||
|     { |     { | ||||||
|         $data = []; |         $data = []; | ||||||
|  |  | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Vehicle Type", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Vehicle Type menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|         return view("menu_v1.configs.truck_types", $data); |         return view("menu_v1.configs.truck_types", $data); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -163,6 +171,14 @@ class ConfTruckTypeController extends Controller | |||||||
|             $apiResp = Responses::created("success add new vehicle type"); |             $apiResp = Responses::created("success add new vehicle type"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Vehicle Type", | ||||||
|  | 				"action" => "Create", | ||||||
|  | 				"desc" => "Add new vehicle type: ".$req->type_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
| @ -256,6 +272,13 @@ class ConfTruckTypeController extends Controller | |||||||
|             $apiResp = Responses::created("success update vehicle type"); |             $apiResp = Responses::created("success update vehicle type"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  | 			 | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Vehicle Type", | ||||||
|  | 				"action" => "Update", | ||||||
|  | 				"desc" => "Update vehicle type: ".$req->type_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
| @ -310,6 +333,13 @@ class ConfTruckTypeController extends Controller | |||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success delete vehicle type"); |             $apiResp = Responses::success("success delete vehicle type"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Vehicle Type", | ||||||
|  | 				"action" => "Delete", | ||||||
|  | 				"desc" => "Delete vehicle type: ".$truckType[0]->name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
|  | |||||||
| @ -11,6 +11,8 @@ use App\Responses; | |||||||
| use App\Helper; | use App\Helper; | ||||||
| use App\Models\Devices; | use App\Models\Devices; | ||||||
| use App\Models\Vehicles; | use App\Models\Vehicles; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  | use Auth; | ||||||
|  |  | ||||||
| class DevicesController extends Controller | class DevicesController extends Controller | ||||||
| { | { | ||||||
| @ -20,6 +22,13 @@ class DevicesController extends Controller | |||||||
|         $data = [ |         $data = [ | ||||||
|             "vhcs" => $vhcs, |             "vhcs" => $vhcs, | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Device", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Device menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|         return view("menu_v1.configs.devices", $data); |         return view("menu_v1.configs.devices", $data); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -202,6 +211,13 @@ class DevicesController extends Controller | |||||||
|             $apiResp = Responses::created("success add new device"); |             $apiResp = Responses::created("success add new device"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Device", | ||||||
|  | 				"action" => "Create", | ||||||
|  | 				"desc" => "Add new device: ".$device_id, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
| @ -354,6 +370,13 @@ class DevicesController extends Controller | |||||||
|             $apiResp = Responses::created("success update device"); |             $apiResp = Responses::created("success update device"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Device", | ||||||
|  | 				"action" => "Update", | ||||||
|  | 				"desc" => "Edit device: ".$device_id, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
| @ -403,6 +426,13 @@ class DevicesController extends Controller | |||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success delete device"); |             $apiResp = Responses::success("success delete device"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Device", | ||||||
|  | 				"action" => "Delete", | ||||||
|  | 				"desc" => "Delete device : ".$device[0]->device_id, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ use App\Models\Drivers; | |||||||
| use App\Models\DriversDetail; | use App\Models\DriversDetail; | ||||||
| use App\Models\Users; | use App\Models\Users; | ||||||
| use App\Models\DrvPhoneDevices; | use App\Models\DrvPhoneDevices; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  |  | ||||||
| class DriversController extends Controller | class DriversController extends Controller | ||||||
| { | { | ||||||
| @ -252,6 +253,13 @@ class DriversController extends Controller | |||||||
|             $apiResp = Responses::created("success add new driver"); |             $apiResp = Responses::created("success add new driver"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Driver", | ||||||
|  | 				"action" => "View", | ||||||
|  | 				"desc" => "Add new driver: ".$req->fullname, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             Storage::disk("public")->delete($url_ktp); |             Storage::disk("public")->delete($url_ktp); | ||||||
| @ -451,6 +459,13 @@ class DriversController extends Controller | |||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success update driver"); |             $apiResp = Responses::success("success update driver"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Driver", | ||||||
|  | 				"action" => "Update", | ||||||
|  | 				"desc" => "Edit driver: ".$req->fullname, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             Storage::disk("public")->delete($url_ktp); |             Storage::disk("public")->delete($url_ktp); | ||||||
| @ -501,6 +516,13 @@ class DriversController extends Controller | |||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success delete driver"); |             $apiResp = Responses::success("success delete driver"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Driver", | ||||||
|  | 				"action" => "Delete", | ||||||
|  | 				"desc" => "Delete driver : ".$driver[0]->fullname, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
|  | |||||||
| @ -30,12 +30,21 @@ use App\Models\Finance; | |||||||
| use App\Models\OrdersCheckpoints; | use App\Models\OrdersCheckpoints; | ||||||
| use App\Models\OrdersInvoices; | use App\Models\OrdersInvoices; | ||||||
| use App\Models\OrdersDriversUploads; | use App\Models\OrdersDriversUploads; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  | use Auth;	 | ||||||
|  |  | ||||||
| class MenuController extends Controller | class MenuController extends Controller | ||||||
| { | { | ||||||
|     public function view_dashboard(Request $req) |     public function view_dashboard(Request $req) | ||||||
|     { |     { | ||||||
|         $data = [ | 		$log = [ | ||||||
|  | 			"module" => "Dashboard", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Dashboard menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert($req->auth->uid, $log); | ||||||
|  |      | ||||||
|  | 		$data = [ | ||||||
|             "client_group" => Clients::getClientById($req->auth->client_group_id), |             "client_group" => Clients::getClientById($req->auth->client_group_id), | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
| @ -45,12 +54,20 @@ class MenuController extends Controller | |||||||
|             $data["client_group"] = null; |             $data["client_group"] = null; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         return view("menu_v1.dashboard", $data); |         return view("menu_v1.dashboard", $data); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public function view_drivers(Request $req) |     public function view_drivers(Request $req) | ||||||
|     { |     { | ||||||
|         $data = [ | 		$log = [ | ||||||
|  | 			"module" => "Driver", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Driver menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert($req->auth->uid, $log); | ||||||
|  |  | ||||||
|  | 		$data = [ | ||||||
|             "bloods" => Helper::listBloods(), |             "bloods" => Helper::listBloods(), | ||||||
|             "relationships" => Drivers::listRelationships(), |             "relationships" => Drivers::listRelationships(), | ||||||
|             "vendors" => Users::listUsersByRole(Users::ROLE_VENDOR), |             "vendors" => Users::listUsersByRole(Users::ROLE_VENDOR), | ||||||
| @ -61,7 +78,17 @@ class MenuController extends Controller | |||||||
|  |  | ||||||
|     public function view_vehicles(Request $req) |     public function view_vehicles(Request $req) | ||||||
|     { |     { | ||||||
|         $data = [ | 		$log = [ | ||||||
|  | 			"module" => "Vehicle", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Vehicle menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert($req->auth->uid, $log); | ||||||
|  |  | ||||||
|  | 		$listPool = DB::select("SELECT * FROM t_conf_pool WHERE dlt IS NULL ORDER BY pool_code ASC"); | ||||||
|  | 		$listDistribution = DB::select("SELECT * FROM t_conf_distribution_category WHERE dlt IS NULL ORDER BY dc_code ASC"); | ||||||
|  |  | ||||||
|  | 		$data = [ | ||||||
|             // 'cats' => Vehicles::listCats(), // default Truck |             // 'cats' => Vehicles::listCats(), // default Truck | ||||||
|             "brands" => Vehicles::listBrands(), |             "brands" => Vehicles::listBrands(), | ||||||
|             "types" => Vehicles::listTypes(), |             "types" => Vehicles::listTypes(), | ||||||
| @ -73,6 +100,8 @@ class MenuController extends Controller | |||||||
|                 "is_idle_yes" => 1, |                 "is_idle_yes" => 1, | ||||||
|                 "is_available" => Devices::IS_AVAIL, |                 "is_available" => Devices::IS_AVAIL, | ||||||
|             ]), |             ]), | ||||||
|  | 			"listPool" => $listPool, | ||||||
|  | 			"listDistribution" => $listDistribution | ||||||
|         ]; |         ]; | ||||||
|         // dd($data); |         // dd($data); | ||||||
|         return view("menu_v1.vehicles", $data); |         return view("menu_v1.vehicles", $data); | ||||||
| @ -84,6 +113,13 @@ class MenuController extends Controller | |||||||
|  |  | ||||||
|     public function view_transactions() |     public function view_transactions() | ||||||
|     { |     { | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Transactions", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Transactions menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|         $data = [ |         $data = [ | ||||||
|             "availOrdToMerge" => Finance::availOrdToMerge(), |             "availOrdToMerge" => Finance::availOrdToMerge(), | ||||||
|         ]; |         ]; | ||||||
| @ -169,6 +205,14 @@ class MenuController extends Controller | |||||||
|     } |     } | ||||||
|     public function view_transactions_view(Request $req) |     public function view_transactions_view(Request $req) | ||||||
|     { |     { | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Transactions", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Transactions menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert($req->auth->uid, $log); | ||||||
|  |  | ||||||
|  |  | ||||||
|         $codes = explode(",", $req->code); |         $codes = explode(",", $req->code); | ||||||
|         $limit = count($codes); |         $limit = count($codes); | ||||||
|         if ($limit > 2) { |         if ($limit > 2) { | ||||||
| @ -330,6 +374,13 @@ class MenuController extends Controller | |||||||
|  |  | ||||||
|     public function view_logs_gps() |     public function view_logs_gps() | ||||||
|     { |     { | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Logs GPS", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Logs GPS menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|         return view("menu_v1.configs.index_logs_gps"); |         return view("menu_v1.configs.index_logs_gps"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -17,23 +17,31 @@ use Maatwebsite\Excel\Concerns\WithHeadings; | |||||||
| use Maatwebsite\Excel\Concerns\WithStyles; | use Maatwebsite\Excel\Concerns\WithStyles; | ||||||
| use Maatwebsite\Excel\Concerns\WithCustomStartCell; | use Maatwebsite\Excel\Concerns\WithCustomStartCell; | ||||||
| use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; | use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; | ||||||
|  | use Carbon\Carbon; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  |  | ||||||
| class ReportsController extends Controller | class ReportsController extends Controller | ||||||
| { | { | ||||||
| 	public function view_report_vehicle_trips(Request $req) | 	public function view_report_vehicle_trips(Request $req) | ||||||
| 	{ | 	{ | ||||||
| 		$q = "select id, nopol1 from t_vehicles WHERE dlt is null order by nopol1"; | 		$q = "SELECT id, nopol1 from t_vehicles WHERE dlt is null order by nopol1"; | ||||||
| 		$listNopol = DB::select($q); | 		$listNopol = DB::select($q); | ||||||
|  |  | ||||||
| 		$data = [ | 		$data = [ | ||||||
| 			'listNopol' => $listNopol, | 			'listNopol' => $listNopol, | ||||||
| 		]; | 		]; | ||||||
|  |  | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Vehicle Trips Report", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Vehicle Trips Report menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
| 		return view('menu_v1.reports.vehicle_trips', $data); | 		return view('menu_v1.reports.vehicle_trips', $data); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public function api_report_vehicle_trips_list(Request $req) | 	public function api_report_vehicle_trips_list(Request $req) | ||||||
| 	{ | 	{ | ||||||
|  | 		// $TIMEFIX = Helper::TIMEFIX; | ||||||
| 		// Validate input | 		// Validate input | ||||||
| 		// date in unix datetime format | 		// date in unix datetime format | ||||||
| 		// dd($req->type); | 		// dd($req->type); | ||||||
| @ -49,58 +57,106 @@ class ReportsController extends Controller | |||||||
| 			return new Response($apiResp, $apiResp["meta"]["code"]); | 			return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$from_date = $req->input('from_date'); | 		// $from_date = $req->input('from_date'); | ||||||
| 		$to_date = $req->input('to_date'); | 		// $to_date = $req->input('to_date'); | ||||||
|  | 		$from_date = $req->input('from_date') - Helper::TIMEFIX; | ||||||
|  | 		$to_date = $req->input('to_date') - Helper::TIMEFIX; | ||||||
| 		$vid = $req->input('vid'); | 		$vid = $req->input('vid'); | ||||||
| 		// $from_date = 1756054800; | 		// $from_date = 1756054800; | ||||||
| 		// $to_date = 1756745940; | 		// $to_date = 1756745940; | ||||||
|  |  | ||||||
| 		try { | 		// get month year | ||||||
| 			$q = " | 		$date = Carbon::createFromTimestamp($from_date); | ||||||
| 				WITH trips AS ( | 		$yymm = $date->format('ym'); | ||||||
| 					SELECT |  | ||||||
| 						t.*, |  | ||||||
| 						-- mark the start of a trip when ignition=4 and previous ignition <> 4 |  | ||||||
| 						CASE |  | ||||||
| 							WHEN ignition = 4  |  | ||||||
| 								AND LAG(ignition, 1, 0) OVER (PARTITION BY vhc_id ORDER BY crt_d) <> 4 |  | ||||||
| 							THEN 1 ELSE 0 |  | ||||||
| 						END AS trip_start |  | ||||||
| 					FROM t_gps_tracks t |  | ||||||
| 					WHERE  |  | ||||||
| 					t.latitude IS NOT NULL |  | ||||||
| 					AND t.longitude IS NOT NULL |  | ||||||
| 					AND t.action = 'location' |  | ||||||
| 					AND t.crt_d BETWEEN ? AND ? |  | ||||||
| 				) |  | ||||||
| 				, numbered AS ( |  | ||||||
| 					SELECT |  | ||||||
| 						*, |  | ||||||
| 						-- assign a trip_id by cumulative sum of trip_start |  | ||||||
| 						SUM(trip_start) OVER (PARTITION BY vhc_id ORDER BY crt_d) AS trip_id |  | ||||||
| 					FROM trips |  | ||||||
| 				) |  | ||||||
| 				select |  | ||||||
| 					v.id, |  | ||||||
| 					-- 	coalesce(max(a.trip_id), 0) numOfTrip, |  | ||||||
| 					-- 	SUM(pre_milleage) AS total_milleage, |  | ||||||
| 					v.name, v.nopol1, |  | ||||||
| 					vhc_id, trip_id, |  | ||||||
| 					sum(pre_milleage) milleage, min(a.crt_d ) start, max(a.crt_d ) finish, |  | ||||||
| 					(select fulladdress from t_gps_tracks_address where master_id = min(a.id) limit 1) startLoc, |  | ||||||
| 					(select fulladdress from t_gps_tracks_address where master_id = max(a.id) limit 1) finishLoc |  | ||||||
| 				FROM   |  | ||||||
| 					t_vehicles v |  | ||||||
| 					left join numbered a on a.vhc_id = v.id |  | ||||||
| 				WHERE  |  | ||||||
| 					v.dlt is null and trip_id != 0  |  | ||||||
| 					and if(? , v.id = ? , 1=1) |  | ||||||
| 				GROUP BY v.id, a.trip_id  |  | ||||||
| 				ORDER BY v.id |  | ||||||
| 				"; |  | ||||||
| 			$d = [$from_date, $to_date, $vid, $vid]; |  | ||||||
|  |  | ||||||
| 			$list = DB::select($q, $d); | 		try { | ||||||
|  | 			// $list = DB::select("WITH  | ||||||
|  | 			// 	gaps AS ( | ||||||
|  | 			// 		SELECT | ||||||
|  | 			// 			-- previous gap since previous row > 1 hour (3600s) | ||||||
|  | 			// 			CASE | ||||||
|  | 			// 				WHEN (crt_d - LAG(crt_d, 1, NULL) OVER (PARTITION BY vhc_id ORDER BY crt_d)) > 3600 | ||||||
|  | 			// 				THEN 1 ELSE 0 | ||||||
|  | 			// 			END AS isStop, | ||||||
|  | 			// 			t.* | ||||||
|  | 			// 		FROM tracks_2509 t | ||||||
|  | 			// 		WHERE  | ||||||
|  | 			// 		t.latitude IS NOT NULL | ||||||
|  | 			// 		AND t.longitude IS NOT NULL | ||||||
|  | 			// 		AND t.action = 'location' | ||||||
|  | 			// 		AND t.crt_d BETWEEN ? AND ? | ||||||
|  | 			// 	) | ||||||
|  | 			// 	, trips AS ( | ||||||
|  | 			// 		SELECT | ||||||
|  | 			// 			-- mark the start of a trip when ignition=4 and previous ignition <> 4 | ||||||
|  | 			// 			CASE | ||||||
|  | 			// 				WHEN ignition = 4  | ||||||
|  | 			// 					AND LAG(ignition, 1, 0) OVER (PARTITION BY vhc_id ORDER BY crt_d) <> 4 | ||||||
|  | 			// 					or LAG(isStop, 1, 0) over (PARTITION BY vhc_id ORDER BY crt_d) = 1 | ||||||
|  | 			// 				THEN 1 ELSE 0 | ||||||
|  | 			// 			END AS trip_start, | ||||||
|  | 			// 			g.* | ||||||
|  | 			// 		FROM gaps g | ||||||
|  | 			// 	) | ||||||
|  | 			// 	, numbered AS ( | ||||||
|  | 			// 		SELECT | ||||||
|  | 			// 			*, | ||||||
|  | 			// 			-- assign a trip_id by cumulative sum of trip_start | ||||||
|  | 			// 			SUM(trip_start) OVER (PARTITION BY vhc_id ORDER BY crt_d) AS trip_id | ||||||
|  | 			// 		FROM trips | ||||||
|  | 			// 		where  | ||||||
|  | 			// 			ignition = 4 | ||||||
|  | 			// 			and isStop = 0 | ||||||
|  | 			// 	), | ||||||
|  | 			// 	agg AS ( | ||||||
|  | 			// 		SELECT | ||||||
|  | 			// 			COUNT(*) AS row_count, | ||||||
|  | 			// 			v.name, | ||||||
|  | 			// 			v.nopol1, | ||||||
|  | 			// 			vhc_id, | ||||||
|  | 			// 			-- trip_id, | ||||||
|  | 			// 			ROW_NUMBER() OVER (PARTITION BY v.id ORDER BY MIN(a.crt_d)) AS trip_id, | ||||||
|  | 			// 			SUM(pre_milleage) AS mileage, | ||||||
|  | 			// 			MIN(a.crt_d) AS start, | ||||||
|  | 			// 			MAX(a.crt_d) AS finish, | ||||||
|  | 			// 			MIN(a.vhc_milleage) AS startMileage, | ||||||
|  | 			// 			MAX(a.vhc_milleage) AS finishMileage, | ||||||
|  | 			// 			(SELECT fulladdress FROM t_gps_tracks_address WHERE master_id = MIN(a.id) LIMIT 1) AS startLoc, | ||||||
|  | 			// 			(SELECT fulladdress FROM t_gps_tracks_address WHERE master_id = MAX(a.id) LIMIT 1) AS finishLoc | ||||||
|  | 			// 		FROM t_vehicles v | ||||||
|  | 			// 		LEFT JOIN numbered a ON a.vhc_id = v.id | ||||||
|  | 			// 		WHERE  | ||||||
|  | 			// 			v.dlt is null and trip_id != 0  | ||||||
|  | 			// 			and if(? , v.id = ? , 1=1) | ||||||
|  | 			// 		GROUP BY v.id, a.trip_id | ||||||
|  | 			// 		HAVING COUNT(*) > 1 | ||||||
|  | 			// 	) | ||||||
|  | 			// 	SELECT | ||||||
|  | 			// 		*, | ||||||
|  | 			// 		SUM(mileage) OVER (PARTITION BY agg.id) AS total_mileage, | ||||||
|  | 			// 		COUNT(trip_id) OVER (PARTITION BY agg.id) AS total_trip, | ||||||
|  | 			// 		tvd.pool_code, tvd.dc_code | ||||||
|  | 			// 	FROM agg agg | ||||||
|  | 			// 		join t_vehicles_detail tvd on tvd.vid = agg.vhc_id | ||||||
|  | 			// 	ORDER BY agg.id, trip_id			 | ||||||
|  | 			// ", [$from_date, $to_date, $vid, $vid]); | ||||||
|  |  | ||||||
|  | 			$list = DB::select("WITH TotalMileage AS ( | ||||||
|  | 					SELECT id, SUM(mileage) AS total_mileage, count(*) total_trip | ||||||
|  | 					FROM trips | ||||||
|  | 					WHERE start BETWEEN ? AND ? | ||||||
|  | 					GROUP BY id | ||||||
|  | 				) | ||||||
|  | 				SELECT  | ||||||
|  | 					t.*, | ||||||
|  | 					tm.total_mileage, total_trip, | ||||||
|  | 					ROW_NUMBER() OVER (PARTITION BY t.id ORDER BY t.start) AS trip_id | ||||||
|  | 				FROM trips t | ||||||
|  | 					JOIN TotalMileage tm ON t.id = tm.id | ||||||
|  | 				WHERE | ||||||
|  | 					t.start BETWEEN ? AND ? | ||||||
|  | 					and if(? , t.id = ? , 1=1) | ||||||
|  | 			", [$from_date, $to_date, $from_date, $to_date, $vid, $vid]); | ||||||
|  |  | ||||||
| 			// // RETURN 1 - LIST | 			// // RETURN 1 - LIST | ||||||
| 			// if($req->type != 'report'){ | 			// if($req->type != 'report'){ | ||||||
| @ -181,6 +237,64 @@ class ReportsController extends Controller | |||||||
| 			// return Responses::json(Responses::SERVER_ERROR, 'An error occurred while generating the report.', (object)[]); | 			// return Responses::json(Responses::SERVER_ERROR, 'An error occurred while generating the report.', (object)[]); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 	public function view_report_trip_detail(Request $req) | ||||||
|  | 	{ | ||||||
|  | 		$vid = $req->vid; | ||||||
|  | 		$tgl0 = $req->tgl0; | ||||||
|  | 		$tgl1 = $req->tgl1; | ||||||
|  | 		$nopol1 = $req->nopol1; | ||||||
|  |  | ||||||
|  | 		$d = [$vid, $tgl0, $tgl1]; | ||||||
|  | 		$list = DB::select("SELECT | ||||||
|  | 				t.crt_d , t.latitude, t.longitude, t.speed, | ||||||
|  | 				tgta.fulladdress, | ||||||
|  | 				t.pre_milleage, t.vhc_milleage  | ||||||
|  | 			FROM  | ||||||
|  | 				t_gps_tracks t | ||||||
|  | 				left join t_gps_tracks_address tgta on tgta.master_id = t.id  | ||||||
|  | 			WHERE  | ||||||
|  | 				t.vhc_id = ? | ||||||
|  | 				and t.latitude IS NOT NULL | ||||||
|  | 				AND t.longitude IS NOT NULL | ||||||
|  | 				AND t.action = 'location' | ||||||
|  | 				AND t.crt_d BETWEEN ? AND ? | ||||||
|  | 			ORDER BY t.crt_d asc | ||||||
|  | 		", $d); | ||||||
|  |  | ||||||
|  | 		$start = [ | ||||||
|  | 			'time' => $list[0]->crt_d, | ||||||
|  | 			'fulladdress' => urldecode($list[0]->fulladdress), | ||||||
|  | 			'mileage' => $list[0]->vhc_milleage, | ||||||
|  | 		]; | ||||||
|  | 		$finish = [ | ||||||
|  | 			'time' => $list[count($list) - 1]->crt_d, | ||||||
|  | 			'fulladdress' => urldecode($list[count($list) - 1]->fulladdress), | ||||||
|  | 			'mileage' => $list[count($list) - 1]->vhc_milleage, | ||||||
|  | 		]; | ||||||
|  |  | ||||||
|  | 		$t0 = Carbon::createFromTimestamp($list[0]->crt_d); | ||||||
|  | 		$t1 = Carbon::createFromTimestamp($list[count($list) - 1]->crt_d); | ||||||
|  | 		$diff = $t1->diff($t0); | ||||||
|  | 		$hours = $diff->h + ($diff->days * 24); // include days converted to hours | ||||||
|  | 		$minutes = $diff->i; | ||||||
|  | 		$duration = "{$hours} hour" . ($hours > 1 ? 's' : '') . " {$minutes} minute" . ($minutes > 1 ? 's' : ''); | ||||||
|  |  | ||||||
|  | 		$distance = $list[count($list) - 1]->vhc_milleage - $list[0]->vhc_milleage; | ||||||
|  |  | ||||||
|  | 		$data = [ | ||||||
|  | 			'nopol1' => $nopol1, | ||||||
|  | 			'vid' => $vid, | ||||||
|  | 			'tgl0' => $tgl0, | ||||||
|  | 			'tgl1' => $tgl1, | ||||||
|  | 			'list' => $list, | ||||||
|  | 			'start' => $start, | ||||||
|  | 			'finish' => $finish, | ||||||
|  | 			'duration' => $duration, | ||||||
|  | 			'distance' => $distance, | ||||||
|  | 		]; | ||||||
|  | 		// dd($list); | ||||||
|  | 		return view('menu_v1.reports._trip_detail', $data); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	public function view_report_abnormalities(Request $req) | 	public function view_report_abnormalities(Request $req) | ||||||
| 	{ | 	{ | ||||||
| @ -191,6 +305,12 @@ class ReportsController extends Controller | |||||||
| 			'listNopol' => $listNopol, | 			'listNopol' => $listNopol, | ||||||
| 		]; | 		]; | ||||||
|  |  | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Abnormalities Report", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Abnormalities Report menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
| 		return view('menu_v1.reports.abnormalities', $data); | 		return view('menu_v1.reports.abnormalities', $data); | ||||||
| 	} | 	} | ||||||
| 	public function api_report_abnormalities_list(Request $req) | 	public function api_report_abnormalities_list(Request $req) | ||||||
| @ -208,16 +328,15 @@ class ReportsController extends Controller | |||||||
| 			return new Response($apiResp, $apiResp["meta"]["code"]); | 			return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		$from_date = $req->input('from_date'); | 		$from_date = $req->input('from_date') - Helper::TIMEFIX; | ||||||
| 		$to_date = $req->input('to_date'); | 		$to_date = $req->input('to_date') - Helper::TIMEFIX; | ||||||
| 		$vid = $req->input('vid'); | 		$vid = $req->input('vid'); | ||||||
|  |  | ||||||
| 		try { | 		try { | ||||||
| 			$q = " | 			$list = DB::select("SELECT | ||||||
| 				select |  | ||||||
| 					tv.name, tv.nopol1,  | 					tv.name, tv.nopol1,  | ||||||
| 					t.crt_d, t.speed, tgta.fulladdress, | 					t.crt_d, t.speed, tgta.fulladdress, | ||||||
| 					tvd.speed_limit | 					tvd.speed_limit, tvd.pool_code, tvd.dc_code | ||||||
| 				from | 				from | ||||||
| 					t_gps_tracks t | 					t_gps_tracks t | ||||||
| 					left join t_vehicles tv on tv.id = t.vhc_id  | 					left join t_vehicles tv on tv.id = t.vhc_id  | ||||||
| @ -229,12 +348,9 @@ class ReportsController extends Controller | |||||||
| 					AND t.crt_d BETWEEN ? AND ? | 					AND t.crt_d BETWEEN ? AND ? | ||||||
| 					and if(? , tv.id = ? , 1=1) | 					and if(? , tv.id = ? , 1=1) | ||||||
| 					-- and t.speed > tvd.speed_limit  | 					-- and t.speed > tvd.speed_limit  | ||||||
| 				having t.speed > tvd.speed_limit | 				having t.speed >= tvd.speed_limit | ||||||
| 				ORDER BY t.crt_d | 				ORDER BY t.crt_d | ||||||
| 			"; | 			", [$from_date, $to_date, $vid, $vid]); | ||||||
| 			$d = [$from_date, $to_date, $vid, $vid]; |  | ||||||
|  |  | ||||||
| 			$list = DB::select($q, $d); |  | ||||||
|  |  | ||||||
| 			// // RETURN 1 - LIST | 			// // RETURN 1 - LIST | ||||||
| 			// if($req->type != 'report'){ | 			// if($req->type != 'report'){ | ||||||
|  | |||||||
| @ -15,6 +15,8 @@ use App\Models\Vehicles; | |||||||
| use App\Models\Banks; | use App\Models\Banks; | ||||||
| use App\Models\UsersMenuPermissions; | use App\Models\UsersMenuPermissions; | ||||||
| use Spatie\Permission\PermissionRegistrar; | use Spatie\Permission\PermissionRegistrar; | ||||||
|  | use Illuminate\Support\Facades\Auth; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  |  | ||||||
| class RolesController extends Controller | class RolesController extends Controller | ||||||
| { | { | ||||||
| @ -34,6 +36,13 @@ class RolesController extends Controller | |||||||
|             }), |             }), | ||||||
|         ]; |         ]; | ||||||
|  |  | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Role", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Role menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|         return view("menu_v1.roles", $data); |         return view("menu_v1.roles", $data); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -118,6 +127,14 @@ class RolesController extends Controller | |||||||
|             app()[PermissionRegistrar::class]->forgetCachedPermissions(); |             app()[PermissionRegistrar::class]->forgetCachedPermissions(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::created("success add new role"); |             $apiResp = Responses::created("success add new role"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Role", | ||||||
|  | 				"action" => "Create", | ||||||
|  | 				"desc" => "Add new role : ".$req->name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
| @ -156,6 +173,13 @@ class RolesController extends Controller | |||||||
|             app()[PermissionRegistrar::class]->forgetCachedPermissions(); |             app()[PermissionRegistrar::class]->forgetCachedPermissions(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::created("success update role"); |             $apiResp = Responses::created("success update role"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Role", | ||||||
|  | 				"action" => "Update", | ||||||
|  | 				"desc" => "Update role : ".$req->name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
| @ -198,6 +222,13 @@ class RolesController extends Controller | |||||||
|             app()[PermissionRegistrar::class]->forgetCachedPermissions(); |             app()[PermissionRegistrar::class]->forgetCachedPermissions(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::created("success delete role"); |             $apiResp = Responses::created("success delete role"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Role", | ||||||
|  | 				"action" => "Delete", | ||||||
|  | 				"desc" => "Delete role : ".$role[0]->name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
|  | |||||||
							
								
								
									
										71
									
								
								app/Http/Controllers/UserLogsController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								app/Http/Controllers/UserLogsController.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace App\Http\Controllers; | ||||||
|  |  | ||||||
|  | use App\Http\Controllers\Controller; | ||||||
|  | use Illuminate\Http\Request; | ||||||
|  | use Illuminate\Http\Response; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
|  | use Illuminate\Support\Facades\Storage; | ||||||
|  | use Validator; | ||||||
|  | use Hidehalo\Nanoid\Client as Nanoid; | ||||||
|  | use Hidehalo\Nanoid\GeneratorInterface as NanoidInterface; | ||||||
|  | use App\Responses; | ||||||
|  | use App\Helper; | ||||||
|  | use App\Models\ConfRates; | ||||||
|  | use App\Models\ConfTruckTypes; | ||||||
|  | use App\Models\Vehicles; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  | use Auth; | ||||||
|  | use App\Models\Users; | ||||||
|  |  | ||||||
|  | class UserLogsController extends Controller | ||||||
|  | { | ||||||
|  |     /** | ||||||
|  |      * View | ||||||
|  |      */ | ||||||
|  |  | ||||||
|  |     public function view_user_logs(Request $req) | ||||||
|  |     { | ||||||
|  | 		$users = Users::listUsers(); | ||||||
|  | 		$data = [ | ||||||
|  | 			"users" => $users, | ||||||
|  | 		]; | ||||||
|  |  | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "User Logs", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open User Logs menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |         return view("menu_v1.userLogs", $data); | ||||||
|  |     } | ||||||
|  |     public function api_user_logs(Request $req) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  | 			$tgl0 = $req->tgl0; | ||||||
|  | 			$tgl1 = $req->tgl1; | ||||||
|  | 			$userId = $req->userId; | ||||||
|  |  | ||||||
|  | 			$d = [$tgl0, $tgl1, $userId, $userId]; | ||||||
|  | 			$list = DB::select("SELECT | ||||||
|  | 					a.*, b.email | ||||||
|  | 				FROM t_user_log a | ||||||
|  | 					join t_users b on a.userId = b.id | ||||||
|  | 				WHERE  | ||||||
|  | 					a.crt BETWEEN ? AND ? | ||||||
|  | 					and if(? , a.userId = ? , 1=1) | ||||||
|  | 				order by a.crt desc | ||||||
|  | 			", $d); | ||||||
|  |  | ||||||
|  | 			$apiResp = Responses::success("success user logs"); | ||||||
|  | 			$apiResp["data"] = $list; | ||||||
|  | 			return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  | 		} catch (\Exception $e) { | ||||||
|  |             DB::rollBack(); | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @ -15,6 +15,8 @@ use App\Models\Clients; | |||||||
| use App\Models\Vehicles; | use App\Models\Vehicles; | ||||||
| use App\Models\Banks; | use App\Models\Banks; | ||||||
| use App\Models\UsersMenuPermissions; | use App\Models\UsersMenuPermissions; | ||||||
|  | use Illuminate\Support\Facades\Auth; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  |  | ||||||
| class UsersController extends Controller | class UsersController extends Controller | ||||||
| { | { | ||||||
| @ -50,6 +52,13 @@ class UsersController extends Controller | |||||||
|             $data["clients"] = Clients::select2Client($req->auth->client_group_id); |             $data["clients"] = Clients::select2Client($req->auth->client_group_id); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "User", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open User menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|         return view("menu_v1.users", $data); |         return view("menu_v1.users", $data); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -173,6 +182,7 @@ class UsersController extends Controller | |||||||
|                 "bank_acc_number" => $req->bank_acc_number, |                 "bank_acc_number" => $req->bank_acc_number, | ||||||
|                 "bank_acc_name" => $req->bank_acc_name, |                 "bank_acc_name" => $req->bank_acc_name, | ||||||
|                 "status" => $req->status, |                 "status" => $req->status, | ||||||
|  |                 "status_sms" => $req->status_sms, | ||||||
|                 "is_tracking" => $req->is_tracking, |                 "is_tracking" => $req->is_tracking, | ||||||
|                 "vehicles" => $req->vehicles, |                 "vehicles" => $req->vehicles, | ||||||
|                 "is_vdr_bcng" => $req->is_vdr_bcng, |                 "is_vdr_bcng" => $req->is_vdr_bcng, | ||||||
| @ -195,6 +205,7 @@ class UsersController extends Controller | |||||||
|                 "bank_acc_number" => "nullable|numeric", |                 "bank_acc_number" => "nullable|numeric", | ||||||
|                 "bank_acc_name" => "nullable|string|max:255", |                 "bank_acc_name" => "nullable|string|max:255", | ||||||
|                 "status" => "required|integer|not_in:0", |                 "status" => "required|integer|not_in:0", | ||||||
|  |                 "status_sms" => "required|integer", | ||||||
|                 "is_tracking" => "nullable|numeric", |                 "is_tracking" => "nullable|numeric", | ||||||
|                 "vehicles" => "nullable|array", |                 "vehicles" => "nullable|array", | ||||||
|                 "is_vdr_bcng" => "nullable|numeric", |                 "is_vdr_bcng" => "nullable|numeric", | ||||||
| @ -294,6 +305,7 @@ class UsersController extends Controller | |||||||
|                 "crt_by" => $req->auth->uid, |                 "crt_by" => $req->auth->uid, | ||||||
|                 "updt" => $now, |                 "updt" => $now, | ||||||
|                 "updt_by" => $req->auth->uid, |                 "updt_by" => $req->auth->uid, | ||||||
|  | 				"status_sms" => $req->status_sms, | ||||||
|             ]; |             ]; | ||||||
|             if ($req->roles == Users::ROLE_CHECKER) { |             if ($req->roles == Users::ROLE_CHECKER) { | ||||||
|                 // $data['chk_type'] = $req->chk_type; |                 // $data['chk_type'] = $req->chk_type; | ||||||
| @ -325,6 +337,14 @@ class UsersController extends Controller | |||||||
|             $apiResp = Responses::created("success add new user"); |             $apiResp = Responses::created("success add new user"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "User", | ||||||
|  | 				"action" => "Create", | ||||||
|  | 				"desc" => "Add new user : ".$req->email, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
| @ -352,6 +372,7 @@ class UsersController extends Controller | |||||||
|                 "bank_acc_number" => $req->bank_acc_number, |                 "bank_acc_number" => $req->bank_acc_number, | ||||||
|                 "bank_acc_name" => $req->bank_acc_name, |                 "bank_acc_name" => $req->bank_acc_name, | ||||||
|                 "is_vdr_bcng" => $req->is_vdr_bcng, |                 "is_vdr_bcng" => $req->is_vdr_bcng, | ||||||
|  | 				"status_sms" => $req->status_sms, | ||||||
|             ]; |             ]; | ||||||
|             $rulesInput = [ |             $rulesInput = [ | ||||||
|                 "uid" => "required|integer|not_in:0", |                 "uid" => "required|integer|not_in:0", | ||||||
| @ -365,6 +386,7 @@ class UsersController extends Controller | |||||||
|                 "bank_acc_number" => "nullable|numeric", |                 "bank_acc_number" => "nullable|numeric", | ||||||
|                 "bank_acc_name" => "nullable|string|max:255", |                 "bank_acc_name" => "nullable|string|max:255", | ||||||
|                 "is_vdr_bcng" => "nullable|numeric", |                 "is_vdr_bcng" => "nullable|numeric", | ||||||
|  | 				"status_sms" => "required|integer", | ||||||
|             ]; |             ]; | ||||||
|             $data = [ |             $data = [ | ||||||
|                 "id" => $req->uid, |                 "id" => $req->uid, | ||||||
| @ -440,6 +462,7 @@ class UsersController extends Controller | |||||||
|                     return new Response($apiResp, $apiResp["meta"]["code"]); |                     return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|  | 			$data["status_sms"] = $req->status_sms; | ||||||
|  |  | ||||||
|             // validasi input |             // validasi input | ||||||
|             $isValidInput = Validator::make($input, $rulesInput); |             $isValidInput = Validator::make($input, $rulesInput); | ||||||
| @ -523,7 +546,15 @@ class UsersController extends Controller | |||||||
|             $apiResp = Responses::created("success update user"); |             $apiResp = Responses::created("success update user"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "User", | ||||||
|  | 				"action" => "Update", | ||||||
|  | 				"desc" => "Update user : ".$req->email, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|  | 			return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
|             $apiResp = Responses::error($e->getMessage()); |             $apiResp = Responses::error($e->getMessage()); | ||||||
| @ -704,6 +735,14 @@ class UsersController extends Controller | |||||||
|             $apiResp = Responses::created("success delete user"); |             $apiResp = Responses::created("success delete user"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "User", | ||||||
|  | 				"action" => "Delete", | ||||||
|  | 				"desc" => "Delete user : ".$getUser[0]->email, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |  | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
| @ -770,4 +809,38 @@ class UsersController extends Controller | |||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | 	public function view_user_logs1(Request $req) | ||||||
|  | 	{ | ||||||
|  | 		$id = $req->id; | ||||||
|  |  | ||||||
|  | 		$user = Users::getUserById($id)[0]; | ||||||
|  | 		$data = [ | ||||||
|  | 			'user' => $user | ||||||
|  | 		]; | ||||||
|  | 		// dd($dtl); | ||||||
|  | 		return view('menu_v1._userLogs', $data); | ||||||
|  | 	} | ||||||
|  |     public function api_user_logs1(Request $req) | ||||||
|  |     { | ||||||
|  |         try { | ||||||
|  | 			$id = $req->id; | ||||||
|  | 			$tgl0 = $req->tgl0; | ||||||
|  | 			$tgl1 = $req->tgl1; | ||||||
|  |  | ||||||
|  | 			$d = [$id, $tgl0, $tgl1]; | ||||||
|  | 			$list = DB::select("SELECT * FROM t_user_log  | ||||||
|  | 				WHERE userId = ? AND crt BETWEEN ? AND ? | ||||||
|  | 				order by crt desc | ||||||
|  | 			", $d); | ||||||
|  |  | ||||||
|  | 			$apiResp = Responses::success("success user logs"); | ||||||
|  | 			$apiResp["data"] = $list; | ||||||
|  | 			return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  | 		} catch (\Exception $e) { | ||||||
|  |             DB::rollBack(); | ||||||
|  |             $apiResp = Responses::error($e->getMessage()); | ||||||
|  |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -15,6 +15,7 @@ use App\Models\Vehicles; | |||||||
| use App\Models\Devices; | use App\Models\Devices; | ||||||
| use App\Models\VehiclesDetail; | use App\Models\VehiclesDetail; | ||||||
| use App\Models\Users; | use App\Models\Users; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  |  | ||||||
| class VehiclesController extends Controller | class VehiclesController extends Controller | ||||||
| { | { | ||||||
| @ -152,6 +153,8 @@ class VehiclesController extends Controller | |||||||
|                 "tax_exp" => $req->tax_exp, |                 "tax_exp" => $req->tax_exp, | ||||||
|                 // "kir_exp" => $req->kir_exp, |                 // "kir_exp" => $req->kir_exp, | ||||||
|                 // "vendor_id" => $req->vendor_id, |                 // "vendor_id" => $req->vendor_id, | ||||||
|  | 				"dc_code" => $req->dc_code, | ||||||
|  | 				"pool_code" => $req->pool_code, | ||||||
|             ]; |             ]; | ||||||
|             $rulesInput = [ |             $rulesInput = [ | ||||||
|                 "front_vehicle_photo" => "required|string", |                 "front_vehicle_photo" => "required|string", | ||||||
| @ -184,6 +187,8 @@ class VehiclesController extends Controller | |||||||
|                 "tax_exp" => "required|date_format:Y-m-d", |                 "tax_exp" => "required|date_format:Y-m-d", | ||||||
|                 // "kir_exp" => "required|date_format:Y-m-d", |                 // "kir_exp" => "required|date_format:Y-m-d", | ||||||
|                 // "vendor_id" => "nullable|integer|not_in:0", |                 // "vendor_id" => "nullable|integer|not_in:0", | ||||||
|  | 				"dc_code" => "nullable|string", | ||||||
|  | 				"pool_code" => "nullable|string", | ||||||
|             ]; |             ]; | ||||||
|  |  | ||||||
|             if ($req->auth->role == Users::ROLE_VENDOR) { |             if ($req->auth->role == Users::ROLE_VENDOR) { | ||||||
| @ -249,6 +254,7 @@ class VehiclesController extends Controller | |||||||
|                 "crt_by" => $req->auth->uid, |                 "crt_by" => $req->auth->uid, | ||||||
|                 "updt" => $now, |                 "updt" => $now, | ||||||
|                 "updt_by" => $req->auth->uid, |                 "updt_by" => $req->auth->uid, | ||||||
|  | 				 | ||||||
|             ]; |             ]; | ||||||
|             // dd($insVhc); |             // dd($insVhc); | ||||||
|             if ($req->model_id) { |             if ($req->model_id) { | ||||||
| @ -316,13 +322,24 @@ class VehiclesController extends Controller | |||||||
|                 "regis_year" => $req->regis_year, |                 "regis_year" => $req->regis_year, | ||||||
|                 "tax_exp" => $req->tax_exp, |                 "tax_exp" => $req->tax_exp, | ||||||
|                 "kir_exp" => $req->kir_exp, |                 "kir_exp" => $req->kir_exp, | ||||||
|  | 				"dc_code" => $req->dc_code, | ||||||
|  | 				"pool_code" => $req->pool_code, | ||||||
|  |  | ||||||
|             ]; |             ]; | ||||||
|             VehiclesDetail::addDetail($insDetail); |             VehiclesDetail::addDetail($insDetail); | ||||||
|  |  | ||||||
|             $apiResp = Responses::created("success add new vehicle"); |             $apiResp = Responses::created("success add new vehicle"); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); | 	 | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Vehicle", | ||||||
|  | 				"action" => "Create", | ||||||
|  | 				"desc" => "Add new vehicle: ".$req->vhc_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|  |      | ||||||
|  | 			return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             Storage::disk("public")->delete($url_fvhc); |             Storage::disk("public")->delete($url_fvhc); | ||||||
|             Storage::disk("public")->delete($url_stnk); |             Storage::disk("public")->delete($url_stnk); | ||||||
| @ -375,6 +392,8 @@ class VehiclesController extends Controller | |||||||
|                 "tax_exp" => $req->tax_exp, |                 "tax_exp" => $req->tax_exp, | ||||||
|                 // "kir_exp" => $req->kir_exp, |                 // "kir_exp" => $req->kir_exp, | ||||||
|                 // "vendor_id" => $req->vendor_id, |                 // "vendor_id" => $req->vendor_id, | ||||||
|  | 				"dc_code" => $req->dc_code, | ||||||
|  | 				"pool_code" => $req->pool_code, | ||||||
|             ]; |             ]; | ||||||
|             $rulesInput = [ |             $rulesInput = [ | ||||||
|                 "vid" => "required|integer|not_in:0", |                 "vid" => "required|integer|not_in:0", | ||||||
| @ -409,6 +428,8 @@ class VehiclesController extends Controller | |||||||
|                 "tax_exp" => "required|date_format:Y-m-d", |                 "tax_exp" => "required|date_format:Y-m-d", | ||||||
|                 // "kir_exp" => "required|date_format:Y-m-d", |                 // "kir_exp" => "required|date_format:Y-m-d", | ||||||
|                 // "vendor_id" => "nullable|integer|not_in:0", |                 // "vendor_id" => "nullable|integer|not_in:0", | ||||||
|  | 				"dc_code" => "nullable|string", | ||||||
|  | 				"pool_code" => "nullable|string", | ||||||
|             ]; |             ]; | ||||||
|  |  | ||||||
|             if ($req->auth->role == Users::ROLE_VENDOR) { |             if ($req->auth->role == Users::ROLE_VENDOR) { | ||||||
| @ -563,6 +584,8 @@ class VehiclesController extends Controller | |||||||
|                 "regis_year" => $req->regis_year, |                 "regis_year" => $req->regis_year, | ||||||
|                 "tax_exp" => $req->tax_exp, |                 "tax_exp" => $req->tax_exp, | ||||||
|                 "kir_exp" => $req->kir_exp, |                 "kir_exp" => $req->kir_exp, | ||||||
|  | 				"dc_code" => $req->dc_code, | ||||||
|  | 				"pool_code" => $req->pool_code, | ||||||
|             ]; |             ]; | ||||||
|             if ($req->fvhc_base64) { |             if ($req->fvhc_base64) { | ||||||
|                 $updtDetail["fvhc_img"] = $url_fvhc; |                 $updtDetail["fvhc_img"] = $url_fvhc; | ||||||
| @ -575,6 +598,13 @@ class VehiclesController extends Controller | |||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success update vehicle"); |             $apiResp = Responses::success("success update vehicle"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Vehicle", | ||||||
|  | 				"action" => "Update", | ||||||
|  | 				"desc" => "Update vehicle: ".$req->vhc_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             Storage::disk("public")->delete($url_fvhc); |             Storage::disk("public")->delete($url_fvhc); | ||||||
| @ -632,6 +662,13 @@ class VehiclesController extends Controller | |||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success delete vehicle"); |             $apiResp = Responses::success("success delete vehicle"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Vehicle", | ||||||
|  | 				"action" => "Delete", | ||||||
|  | 				"desc" => "Delete vehicle: ".$vehicle[0]->name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert(Auth::user()->id, $log); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
|             DB::rollBack(); |             DB::rollBack(); | ||||||
|  | |||||||
| @ -17,6 +17,8 @@ use App\Models\Orders; | |||||||
| use App\Models\OrdersDrops; | use App\Models\OrdersDrops; | ||||||
| // use App\Models\OrdersPckDrop; | // use App\Models\OrdersPckDrop; | ||||||
| use App\Models\OrdersAItems; | use App\Models\OrdersAItems; | ||||||
|  | use App\Models\UserLogs; | ||||||
|  |  | ||||||
|  |  | ||||||
| class ZoneController extends Controller | class ZoneController extends Controller | ||||||
| { | { | ||||||
| @ -25,8 +27,14 @@ class ZoneController extends Controller | |||||||
|      * |      * | ||||||
|      * @return \Illuminate\Http\Response |      * @return \Illuminate\Http\Response | ||||||
|      */ |      */ | ||||||
|     public function view_zone() |     public function view_zone(Request $req) | ||||||
|     { |     { | ||||||
|  | 		$log = [ | ||||||
|  | 			"module" => "Zone", | ||||||
|  | 			"action" => "View", | ||||||
|  | 			"desc" => "Open Zone menu", | ||||||
|  | 		]; | ||||||
|  | 		UserLogs::insert($req->auth->uid, $log); | ||||||
|         return view("menu_v1.zone"); |         return view("menu_v1.zone"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @ -355,6 +363,13 @@ class ZoneController extends Controller | |||||||
|  |  | ||||||
|             $apiResp = Responses::created("success add new zone"); |             $apiResp = Responses::created("success add new zone"); | ||||||
|  |  | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Zone", | ||||||
|  | 				"action" => "Create", | ||||||
|  | 				"desc" => "Add Zone ".$req->zone_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert($req->auth->uid, $log); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
|         } catch (\Exception $e) { |         } catch (\Exception $e) { | ||||||
| @ -481,7 +496,14 @@ class ZoneController extends Controller | |||||||
|  |  | ||||||
|             Zone::updateZone($zid, $updtZone); |             Zone::updateZone($zid, $updtZone); | ||||||
|  |  | ||||||
|             DB::commit(); | 			$log = [ | ||||||
|  | 				"module" => "Zone", | ||||||
|  | 				"action" => "Update", | ||||||
|  | 				"desc" => "Update Zone ".$req->zone_name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert($req->auth->uid, $log); | ||||||
|  |  | ||||||
|  | 			DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success update zone"); |             $apiResp = Responses::success("success update zone"); | ||||||
|             return new Response($apiResp, $apiResp["meta"]["code"]); |             return new Response($apiResp, $apiResp["meta"]["code"]); | ||||||
| @ -524,6 +546,13 @@ class ZoneController extends Controller | |||||||
|                 "dlt_by" => $req->auth->uid, |                 "dlt_by" => $req->auth->uid, | ||||||
|             ]); |             ]); | ||||||
| 			 | 			 | ||||||
|  | 			$log = [ | ||||||
|  | 				"module" => "Zone", | ||||||
|  | 				"action" => "Delete	", | ||||||
|  | 				"desc" => "Delete Zone ".$zone[0]->name, | ||||||
|  | 			]; | ||||||
|  | 			UserLogs::insert($req->auth->uid, $log); | ||||||
|  |  | ||||||
|             DB::commit(); |             DB::commit(); | ||||||
|  |  | ||||||
|             $apiResp = Responses::success("success delete zone"); |             $apiResp = Responses::success("success delete zone"); | ||||||
|  | |||||||
| @ -386,10 +386,10 @@ class Tracks extends Model | |||||||
|             $query .= " AND v.nopol1 = ? AND v.nopol2 = ? AND v.nopol3 = ?"; |             $query .= " AND v.nopol1 = ? AND v.nopol2 = ? AND v.nopol3 = ?"; | ||||||
|             array_push($params, $filter["nopol1"], $filter["nopol2"], $filter["nopol3"]); |             array_push($params, $filter["nopol1"], $filter["nopol2"], $filter["nopol3"]); | ||||||
|         } |         } | ||||||
|         if (isset($filter["vid"])) { |         // if (isset($filter["vid"])) { | ||||||
|             $query .= " AND v.id = ?"; |         //     $query .= " AND v.id = ?"; | ||||||
|             $params[] = $filter["vid"]; |         //     $params[] = $filter["vid"]; | ||||||
|         } |         // } | ||||||
|         if (isset($filter["vids"])) { |         if (isset($filter["vids"])) { | ||||||
|             if ($filter["vids"] && count($filter["vids"]) > 0) { |             if ($filter["vids"] && count($filter["vids"]) > 0) { | ||||||
|                 $placeholders = rtrim(str_repeat("?,", count($filter["vids"])), ","); |                 $placeholders = rtrim(str_repeat("?,", count($filter["vids"])), ","); | ||||||
| @ -433,7 +433,7 @@ class Tracks extends Model | |||||||
|             $params[] = $filter["company"]; |             $params[] = $filter["company"]; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         $query .= " GROUP BY v.id ORDER BY tr.crt_d DESC LIMIT 500"; |         $query .= " GROUP BY v.id ORDER BY tr.crt_s DESC LIMIT 500"; | ||||||
|  |  | ||||||
|         $list = DB::select($query, $params); |         $list = DB::select($query, $params); | ||||||
| 		// dd($list); | 		// dd($list); | ||||||
| @ -543,7 +543,9 @@ class Tracks extends Model | |||||||
|  |  | ||||||
|         if (isset($filter["start_date"]) && isset($filter["end_date"])) { |         if (isset($filter["start_date"]) && isset($filter["end_date"])) { | ||||||
|             $query .= " AND tr.crt_d BETWEEN ? AND ?"; |             $query .= " AND tr.crt_d BETWEEN ? AND ?"; | ||||||
|             array_push($params, $filter["start_date"], $filter["end_date"]); | 			$tgl0 = $filter["start_date"] - Helper::TIMEFIX; | ||||||
|  | 			$tgl1 = $filter["end_date"] - Helper::TIMEFIX; | ||||||
|  |             array_push($params, $tgl0, $tgl1); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (isset($filter["start_at"])) { |         if (isset($filter["start_at"])) { | ||||||
|  | |||||||
							
								
								
									
										20
									
								
								app/Models/UserLogs.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								app/Models/UserLogs.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | namespace App\Models; | ||||||
|  |  | ||||||
|  | use Illuminate\Database\Eloquent\Model; | ||||||
|  | use Illuminate\Support\Facades\DB; | ||||||
|  |  | ||||||
|  | class UserLogs extends Model | ||||||
|  | { | ||||||
|  |     public static function insert($userId, $log) | ||||||
|  |     { | ||||||
|  | 		$now = time(); | ||||||
|  |         return DB::insert("INSERT into t_user_log | ||||||
|  | 			set | ||||||
|  | 				userId = ?, | ||||||
|  | 				log = ?, | ||||||
|  | 				crt = ? | ||||||
|  | 		", [$userId, json_encode($log), $now]); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										350
									
								
								public/assets/vendor/printThis.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								public/assets/vendor/printThis.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,350 @@ | |||||||
|  | /* | ||||||
|  |  * printThis v2.0.0 | ||||||
|  |  * @desc Printing plug-in for jQuery | ||||||
|  |  * @author Jason Day | ||||||
|  |  * @author Samuel Rouse | ||||||
|  |  * | ||||||
|  |  * Resources (based on): | ||||||
|  |  * - jPrintArea: http://plugins.jquery.com/project/jPrintArea | ||||||
|  |  * - jqPrint: https://github.com/permanenttourist/jquery.jqprint | ||||||
|  |  * - Ben Nadal: http://www.bennadel.com/blog/1591-Ask-Ben-Print-Part-Of-A-Web-Page-With-jQuery.htm | ||||||
|  |  * | ||||||
|  |  * Licensed under the MIT licence: | ||||||
|  |  *              http://www.opensource.org/licenses/mit-license.php | ||||||
|  |  * | ||||||
|  |  * (c) Jason Day 2015-2022 | ||||||
|  |  * | ||||||
|  |  * Usage: | ||||||
|  |  * | ||||||
|  |  *  $("#mySelector").printThis({ | ||||||
|  |  *      debug: false,                   // show the iframe for debugging | ||||||
|  |  *      importCSS: true,                // import parent page css | ||||||
|  |  *      importStyle: true,              // import style tags | ||||||
|  |  *      printContainer: true,           // grab outer container as well as the contents of the selector | ||||||
|  |  *      loadCSS: "path/to/my.css",      // path to additional css file - use an array [] for multiple | ||||||
|  |  *      pageTitle: "",                  // add title to print page | ||||||
|  |  *      removeInline: false,            // remove all inline styles from print elements | ||||||
|  |  *      removeInlineSelector: "body *", // custom selectors to filter inline styles. removeInline must be true | ||||||
|  |  *      printDelay: 1000,               // variable print delay | ||||||
|  |  *      header: null,                   // prefix to html | ||||||
|  |  *      footer: null,                   // postfix to html | ||||||
|  |  *      base: false,                    // preserve the BASE tag, or accept a string for the URL | ||||||
|  |  *      formValues: true,               // preserve input/form values | ||||||
|  |  *      canvas: true,                   // copy canvas elements | ||||||
|  |  *      doctypeString: '...',           // enter a different doctype for older markup | ||||||
|  |  *      removeScripts: false,           // remove script tags from print content | ||||||
|  |  *      copyTagClasses: true            // copy classes from the html & body tag | ||||||
|  |  *      copyTagStyles: true,            // copy styles from html & body tag (for CSS Variables) | ||||||
|  |  *      beforePrintEvent: null,         // callback function for printEvent in iframe | ||||||
|  |  *      beforePrint: null,              // function called before iframe is filled | ||||||
|  |  *      afterPrint: null                // function called before iframe is removed | ||||||
|  |  *  }); | ||||||
|  |  * | ||||||
|  |  * Notes: | ||||||
|  |  *  - the loadCSS will load additional CSS (with or without @media print) into the iframe, adjusting layout | ||||||
|  |  */ | ||||||
|  | ; | ||||||
|  | (function($) { | ||||||
|  |  | ||||||
|  |     function appendContent($el, content) { | ||||||
|  |         if (!content) return; | ||||||
|  |  | ||||||
|  |         // Simple test for a jQuery element | ||||||
|  |         $el.append(content.jquery ? content.clone() : content); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function appendBody($body, $element, opt) { | ||||||
|  |         // Clone for safety and convenience | ||||||
|  |         // Calls clone(withDataAndEvents = true) to copy form values. | ||||||
|  |         var $content = $element.clone(opt.formValues); | ||||||
|  |  | ||||||
|  |         if (opt.formValues) { | ||||||
|  |             // Copy original select and textarea values to their cloned counterpart | ||||||
|  |             // Makes up for inability to clone select and textarea values with clone(true) | ||||||
|  |             copyValues($element, $content, 'select, textarea'); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (opt.removeScripts) { | ||||||
|  |             $content.find('script').remove(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (opt.printContainer) { | ||||||
|  |             // grab $.selector as container | ||||||
|  |             $content.appendTo($body); | ||||||
|  |         } else { | ||||||
|  |             // otherwise just print interior elements of container | ||||||
|  |             $content.each(function() { | ||||||
|  |                 $(this).children().appendTo($body) | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Copies values from origin to clone for passed in elementSelector | ||||||
|  |     function copyValues(origin, clone, elementSelector) { | ||||||
|  |         var $originalElements = origin.find(elementSelector); | ||||||
|  |  | ||||||
|  |         clone.find(elementSelector).each(function(index, item) { | ||||||
|  |             $(item).val($originalElements.eq(index).val()); | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     var opt; | ||||||
|  |     $.fn.printThis = function(options) { | ||||||
|  |         opt = $.extend({}, $.fn.printThis.defaults, options); | ||||||
|  |         var $element = this instanceof jQuery ? this : $(this); | ||||||
|  |  | ||||||
|  |         var strFrameName = "printThis-" + (new Date()).getTime(); | ||||||
|  |  | ||||||
|  |         if (window.location.hostname !== document.domain && navigator.userAgent.match(/msie/i)) { | ||||||
|  |             // Ugly IE hacks due to IE not inheriting document.domain from parent | ||||||
|  |             // checks if document.domain is set by comparing the host name against document.domain | ||||||
|  |             var iframeSrc = "javascript:document.write(\"<head><script>document.domain=\\\"" + document.domain + "\\\";</s" + "cript></head><body></body>\")"; | ||||||
|  |             var printI = document.createElement('iframe'); | ||||||
|  |             printI.name = "printIframe"; | ||||||
|  |             printI.id = strFrameName; | ||||||
|  |             printI.className = "MSIE"; | ||||||
|  |             document.body.appendChild(printI); | ||||||
|  |             printI.src = iframeSrc; | ||||||
|  |  | ||||||
|  |         } else { | ||||||
|  |             // other browsers inherit document.domain, and IE works if document.domain is not explicitly set | ||||||
|  |             var $frame = $("<iframe id='" + strFrameName + "' name='printIframe' />"); | ||||||
|  |             $frame.appendTo("body"); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         var $iframe = $("#" + strFrameName); | ||||||
|  |  | ||||||
|  |         // show frame if in debug mode | ||||||
|  |         if (!opt.debug) $iframe.css({ | ||||||
|  |             position: "absolute", | ||||||
|  |             width: "0px", | ||||||
|  |             height: "0px", | ||||||
|  |             left: "-600px", | ||||||
|  |             top: "-600px" | ||||||
|  |         }); | ||||||
|  |  | ||||||
|  |         // before print callback | ||||||
|  |         if (typeof opt.beforePrint === "function") { | ||||||
|  |             opt.beforePrint(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // $iframe.ready() and $iframe.load were inconsistent between browsers | ||||||
|  |         setTimeout(function() { | ||||||
|  |  | ||||||
|  |             // Add doctype to fix the style difference between printing and render | ||||||
|  |             function setDocType($iframe, doctype){ | ||||||
|  |                 var win, doc; | ||||||
|  |                 win = $iframe.get(0); | ||||||
|  |                 win = win.contentWindow || win.contentDocument || win; | ||||||
|  |                 doc = win.document || win.contentDocument || win; | ||||||
|  |                 doc.open(); | ||||||
|  |                 doc.write(doctype); | ||||||
|  |                 doc.close(); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (opt.doctypeString){ | ||||||
|  |                 setDocType($iframe, opt.doctypeString); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var $doc = $iframe.contents(), | ||||||
|  |                 $head = $doc.find("head"), | ||||||
|  |                 $body = $doc.find("body"), | ||||||
|  |                 $base = $('base'), | ||||||
|  |                 baseURL; | ||||||
|  |  | ||||||
|  |             // add base tag to ensure elements use the parent domain | ||||||
|  |             if (opt.base === true && $base.length > 0) { | ||||||
|  |                 // take the base tag from the original page | ||||||
|  |                 baseURL = $base.attr('href'); | ||||||
|  |             } else if (typeof opt.base === 'string') { | ||||||
|  |                 // An exact base string is provided | ||||||
|  |                 baseURL = opt.base; | ||||||
|  |             } else { | ||||||
|  |                 // Use the page URL as the base | ||||||
|  |                 baseURL = document.location.protocol + '//' + document.location.host; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $head.append('<base href="' + baseURL + '">'); | ||||||
|  |  | ||||||
|  |             // import page stylesheets | ||||||
|  |             if (opt.importCSS) $("link[rel=stylesheet]").each(function() { | ||||||
|  |                 var href = $(this).attr("href"); | ||||||
|  |                 if (href) { | ||||||
|  |                     var media = $(this).attr("media") || "all"; | ||||||
|  |                     $head.append("<link type='text/css' rel='stylesheet' href='" + href + "' media='" + media + "'>"); | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             // import style tags | ||||||
|  |             if (opt.importStyle) $("style").each(function() { | ||||||
|  |                 $head.append(this.outerHTML); | ||||||
|  |             }); | ||||||
|  |  | ||||||
|  |             // add title of the page | ||||||
|  |             if (opt.pageTitle) $head.append("<title>" + opt.pageTitle + "</title>"); | ||||||
|  |  | ||||||
|  |             // import additional stylesheet(s) | ||||||
|  |             if (opt.loadCSS) { | ||||||
|  |                 if ($.isArray(opt.loadCSS)) { | ||||||
|  |                     jQuery.each(opt.loadCSS, function(index, value) { | ||||||
|  |                         $head.append("<link type='text/css' rel='stylesheet' href='" + this + "'>"); | ||||||
|  |                     }); | ||||||
|  |                 } else { | ||||||
|  |                     $head.append("<link type='text/css' rel='stylesheet' href='" + opt.loadCSS + "'>"); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             var pageHtml = $('html')[0]; | ||||||
|  |  | ||||||
|  |             // CSS VAR in html tag when dynamic apply e.g.  document.documentElement.style.setProperty("--foo", bar); | ||||||
|  |             $doc.find('html').prop('style', pageHtml.style.cssText); | ||||||
|  |  | ||||||
|  |             // copy 'root' tag classes | ||||||
|  |             var tag = opt.copyTagClasses; | ||||||
|  |             if (tag) { | ||||||
|  |                 tag = tag === true ? 'bh' : tag; | ||||||
|  |                 if (tag.indexOf('b') !== -1) { | ||||||
|  |                     $body.addClass($('body')[0].className); | ||||||
|  |                 } | ||||||
|  |                 if (tag.indexOf('h') !== -1) { | ||||||
|  |                     $doc.find('html').addClass(pageHtml.className); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // copy ':root' tag classes | ||||||
|  |             tag = opt.copyTagStyles; | ||||||
|  |             if (tag) { | ||||||
|  |                 tag = tag === true ? 'bh' : tag; | ||||||
|  |                 if (tag.indexOf('b') !== -1) { | ||||||
|  |                     $body.attr('style', $('body')[0].style.cssText); | ||||||
|  |                 } | ||||||
|  |                 if (tag.indexOf('h') !== -1) { | ||||||
|  |                     $doc.find('html').attr('style', pageHtml.style.cssText); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // print header | ||||||
|  |             appendContent($body, opt.header); | ||||||
|  |  | ||||||
|  |             if (opt.canvas) { | ||||||
|  |                 // add canvas data-ids for easy access after cloning. | ||||||
|  |                 var canvasId = 0; | ||||||
|  |                 // .addBack('canvas') adds the top-level element if it is a canvas. | ||||||
|  |                 $element.find('canvas').addBack('canvas').each(function(){ | ||||||
|  |                     $(this).attr('data-printthis', canvasId++); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             appendBody($body, $element, opt); | ||||||
|  |  | ||||||
|  |             if (opt.canvas) { | ||||||
|  |                 // Re-draw new canvases by referencing the originals | ||||||
|  |                 $body.find('canvas').each(function(){ | ||||||
|  |                     var cid = $(this).data('printthis'), | ||||||
|  |                         $src = $('[data-printthis="' + cid + '"]'); | ||||||
|  |  | ||||||
|  |                     this.getContext('2d').drawImage($src[0], 0, 0); | ||||||
|  |  | ||||||
|  |                     // Remove the markup from the original | ||||||
|  |                     if ($.isFunction($.fn.removeAttr)) { | ||||||
|  |                         $src.removeAttr('data-printthis'); | ||||||
|  |                     } else { | ||||||
|  |                         $.each($src, function(i, el) { | ||||||
|  |                             el.removeAttribute('data-printthis'); | ||||||
|  |                         }); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // remove inline styles | ||||||
|  |             if (opt.removeInline) { | ||||||
|  |                 // Ensure there is a selector, even if it's been mistakenly removed | ||||||
|  |                 var selector = opt.removeInlineSelector || '*'; | ||||||
|  |                 // $.removeAttr available jQuery 1.7+ | ||||||
|  |                 if ($.isFunction($.removeAttr)) { | ||||||
|  |                     $body.find(selector).removeAttr("style"); | ||||||
|  |                 } else { | ||||||
|  |                     $body.find(selector).attr("style", ""); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // print "footer" | ||||||
|  |             appendContent($body, opt.footer); | ||||||
|  |  | ||||||
|  |             // attach event handler function to beforePrint event | ||||||
|  |             function attachOnBeforePrintEvent($iframe, beforePrintHandler) { | ||||||
|  |                 var win = $iframe.get(0); | ||||||
|  |                 win = win.contentWindow || win.contentDocument || win; | ||||||
|  |  | ||||||
|  |                 if (typeof beforePrintHandler === "function") { | ||||||
|  |                     if ('matchMedia' in win) { | ||||||
|  |                         win.matchMedia('print').addListener(function(mql) { | ||||||
|  |                             if(mql.matches)  beforePrintHandler(); | ||||||
|  |                         }); | ||||||
|  |                     } else { | ||||||
|  |                         win.onbeforeprint = beforePrintHandler; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             attachOnBeforePrintEvent($iframe, opt.beforePrintEvent); | ||||||
|  |  | ||||||
|  |             setTimeout(function() { | ||||||
|  |                 if ($iframe.hasClass("MSIE")) { | ||||||
|  |                     // check if the iframe was created with the ugly hack | ||||||
|  |                     // and perform another ugly hack out of neccessity | ||||||
|  |                     window.frames["printIframe"].focus(); | ||||||
|  |                     $head.append("<script>  window.print(); </s" + "cript>"); | ||||||
|  |                 } else { | ||||||
|  |                     // proper method | ||||||
|  |                     if (document.queryCommandSupported("print")) { | ||||||
|  |                         $iframe[0].contentWindow.document.execCommand("print", false, null); | ||||||
|  |                     } else { | ||||||
|  |                         $iframe[0].contentWindow.focus(); | ||||||
|  |                         $iframe[0].contentWindow.print(); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // remove iframe after print | ||||||
|  |                 if (!opt.debug) { | ||||||
|  |                     setTimeout(function() { | ||||||
|  |                         $iframe.remove(); | ||||||
|  |  | ||||||
|  |                     }, 1000); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // after print callback | ||||||
|  |                 if (typeof opt.afterPrint === "function") { | ||||||
|  |                     opt.afterPrint(); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             }, opt.printDelay); | ||||||
|  |  | ||||||
|  |         }, 333); | ||||||
|  |  | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     // defaults | ||||||
|  |     $.fn.printThis.defaults = { | ||||||
|  |         debug: false,                       // show the iframe for debugging | ||||||
|  |         importCSS: true,                    // import parent page css | ||||||
|  |         importStyle: true,                  // import style tags | ||||||
|  |         printContainer: true,               // print outer container/$.selector | ||||||
|  |         loadCSS: "",                        // path to additional css file - use an array [] for multiple | ||||||
|  |         pageTitle: "",                      // add title to print page | ||||||
|  |         removeInline: false,                // remove inline styles from print elements | ||||||
|  |         removeInlineSelector: "*",          // custom selectors to filter inline styles. removeInline must be true | ||||||
|  |         printDelay: 1000,                   // variable print delay | ||||||
|  |         header: null,                       // prefix to html | ||||||
|  |         footer: null,                       // postfix to html | ||||||
|  |         base: false,                        // preserve the BASE tag or accept a string for the URL | ||||||
|  |         formValues: true,                   // preserve input/form values | ||||||
|  |         canvas: true,                       // copy canvas content | ||||||
|  |         doctypeString: '<!DOCTYPE html>',   // enter a different doctype for older markup | ||||||
|  |         removeScripts: false,               // remove script tags from print content | ||||||
|  |         copyTagClasses: true,               // copy classes from the html & body tag | ||||||
|  |         copyTagStyles: true,                // copy styles from html & body tag (for CSS Variables) | ||||||
|  |         beforePrintEvent: null,             // callback function for printEvent in iframe | ||||||
|  |         beforePrint: null,                  // function called before iframe is filled | ||||||
|  |         afterPrint: null                    // function called before iframe is removed | ||||||
|  |     }; | ||||||
|  | })(jQuery); | ||||||
| @ -77,6 +77,7 @@ | |||||||
|     <script src="{{ asset('assets/js/bootstrap-datepicker.min.js') }}"></script> |     <script src="{{ asset('assets/js/bootstrap-datepicker.min.js') }}"></script> | ||||||
|     <script src="{{ asset('assets/js/helper.js') }}"></script> |     <script src="{{ asset('assets/js/helper.js') }}"></script> | ||||||
| 	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.full.min.js" integrity="sha512-AIOTidJAcHBH2G/oZv9viEGXRqDNmfdPVPYOYKGy3fti0xIplnlgMHUGfuNRzC6FkzIo0iIxgFnr9RikFxK+sw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> | 	<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.full.min.js" integrity="sha512-AIOTidJAcHBH2G/oZv9viEGXRqDNmfdPVPYOYKGy3fti0xIplnlgMHUGfuNRzC6FkzIo0iIxgFnr9RikFxK+sw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> | ||||||
|  | 	<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"></script> --> | ||||||
|  |  | ||||||
|     <script> |     <script> | ||||||
|         const AppState = { |         const AppState = { | ||||||
| @ -87,6 +88,8 @@ | |||||||
|             route_segment1: "{{ Request::segment(1) }}", |             route_segment1: "{{ Request::segment(1) }}", | ||||||
|             route_segment2: "{{ Request::segment(2) }}", |             route_segment2: "{{ Request::segment(2) }}", | ||||||
|             current_company: 0, // cptid |             current_company: 0, // cptid | ||||||
|  | 			// TIMEFIX: new Date().getTimezoneOffset() * -60  | ||||||
|  | 			TIMEFIX: 25200 | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // function startTime() { |         // function startTime() { | ||||||
|  | |||||||
							
								
								
									
										208
									
								
								resources/views/menu_v1/_userLogs.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										208
									
								
								resources/views/menu_v1/_userLogs.blade.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,208 @@ | |||||||
|  | <style> | ||||||
|  | 	#map { | ||||||
|  | 		height: 100%; | ||||||
|  | 		margin: 0; | ||||||
|  | 	} | ||||||
|  | 	.my-leaflet-map-container img { | ||||||
|  | 		max-height: none; | ||||||
|  | 	} | ||||||
|  | 	.dtl-text{ | ||||||
|  | 		font-size: 11px; | ||||||
|  | 	} | ||||||
|  | 	.head-text{ | ||||||
|  | 		font-size: 12px !important; | ||||||
|  | 	} | ||||||
|  | 	/* .leaflet-overlay-pane svg { | ||||||
|  | 		transform: none !important; | ||||||
|  | 	} */ | ||||||
|  | 	.leaflet-routing-container { | ||||||
|  | 		display: none !important; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	#viewPdf { | ||||||
|  | 		display: flex; | ||||||
|  | 		justify-content: center; | ||||||
|  | 		width: 794px; | ||||||
|  | 		/* height: auto; */ | ||||||
|  | 		max-width: 100%; /* Ensures it is responsive */ | ||||||
|  | 	} | ||||||
|  | 	/* .modal-dialog{ | ||||||
|  | 		width: 794px; | ||||||
|  | 	} */ | ||||||
|  |  | ||||||
|  | </style> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <div class="modal-dialog modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg"> | ||||||
|  | 	<div class="modal-content"> | ||||||
|  | 		<div class="modal-header"> | ||||||
|  | 			<h5 class="modal-title" id="mdlDetailTripLabel">{{$user->first_name}} Logs</h5> | ||||||
|  | 			<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||||||
|  | 		</div> | ||||||
|  | 		<div class="modal-body"> | ||||||
|  | 			<div class="row"> | ||||||
|  | 				<div class="col-4"> | ||||||
|  | 					<div class="form-group"> | ||||||
|  | 						<label class="text-muted">From</label> | ||||||
|  | 						<!-- default today --> | ||||||
|  | 						<!-- <input class="form-control" id="tgl0" value="02-09-2025 00:00"> --> | ||||||
|  | 						<input class="form-control" id="tgl0" value="{{ date('d-m-Y 00:00') }}"> | ||||||
|  | 					</div> | ||||||
|  | 				</div> | ||||||
|  | 				<div class="col-4"> | ||||||
|  | 					<div class="form-group"> | ||||||
|  | 						<label class="text-muted">To</label> | ||||||
|  | 						<!-- <input class="form-control" id="tgl1" value="02-09-2025 23:00"> --> | ||||||
|  | 						<input class="form-control" id="tgl1" value="{{ date('d-m-Y 23:59') }}"> | ||||||
|  | 					</div> | ||||||
|  | 				</div> | ||||||
|  | 				<div class="col-4 d-flex align-items-end"> | ||||||
|  | 					<button class="btn btn-primary" id="submitFilter">Submit</button> | ||||||
|  | 				</div> | ||||||
|  | 			</div> | ||||||
|  | 			<div class="table-responsive"> | ||||||
|  | 				<table id="tLogs" class="table table-hover dataTable w-100"> | ||||||
|  | 					<thead> | ||||||
|  | 						<tr class=""> | ||||||
|  | 							<th class="">Time</th> | ||||||
|  | 							<th class="">Module</th> | ||||||
|  | 							<th class="">Description</th> | ||||||
|  | 							<th class="">Action</th> | ||||||
|  | 						</tr> | ||||||
|  | 					</thead> | ||||||
|  | 				</table> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  | 		<div class="modal-footer"> | ||||||
|  | 			<button type="button" class="btn btn-sm btn-danger" data-bs-dismiss="modal">Close</button> | ||||||
|  | 		</div> | ||||||
|  | 	</div> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | 	$(document).ready(function(){ | ||||||
|  | 		$('.time').each(function () { | ||||||
|  | 			const unix = parseInt($(this).text().trim()) + AppState.TIMEFIX; | ||||||
|  | 			$(this).text(moment.unix(unix).format('DD MMM YYYY HH:mm:ss')); | ||||||
|  | 		}); | ||||||
|  | 		$('#tgl0, #tgl1').datetimepicker({ | ||||||
|  | 			format:'d-m-Y H:i', | ||||||
|  | 			defaultTime:'00:00', | ||||||
|  | 			closeOnDateSelect: true, | ||||||
|  | 			// mask:true | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		$('#submitFilter').on('click', function() { | ||||||
|  | 			DTable.reload(); | ||||||
|  | 		}); | ||||||
|  | 		// $('#submitFilter').trigger('click'); | ||||||
|  |  | ||||||
|  |         const DTable = { | ||||||
|  | 			table: null, | ||||||
|  |     		lastAjax: null, // keep track of the last ajax request | ||||||
|  |             activate: function() { | ||||||
|  |                 DTable.reload(); | ||||||
|  |             }, | ||||||
|  |             reload: function() { | ||||||
|  | 				// Abort the last request if it's still running | ||||||
|  | 				if (DTable.lastAjax) { | ||||||
|  | 					DTable.lastAjax.abort(); | ||||||
|  | 				} | ||||||
|  | 				if (DTable.table) { | ||||||
|  | 					// If table already exists → reload | ||||||
|  | 					DTable.table.ajax.reload(); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				DTable.table = $('#tLogs').DataTable({ | ||||||
|  | 					searching: false,   // 🔹 remove search box | ||||||
|  | 					ordering: false,    // 🔹 disable sorting for all columns | ||||||
|  | 					processing: true, | ||||||
|  | 					serverSide: false, | ||||||
|  | 					bLengthChange: true, | ||||||
|  | 					deferRender: true, | ||||||
|  | 					destroy: true, | ||||||
|  | 					ajax: function(data, callback, settings) { | ||||||
|  | 						// Abort previous | ||||||
|  | 						if (DTable.lastAjax) { | ||||||
|  | 							DTable.lastAjax.abort(); | ||||||
|  | 						} | ||||||
|  |  | ||||||
|  | 						// Fire new request | ||||||
|  | 						DTable.lastAjax = $.ajax({ | ||||||
|  | 							url: `{{ route('api_user_logs1') }}? | ||||||
|  | 								tgl0=${moment($('#tgl0').val(), "DD-MM-YYYY HH:mm").unix()} | ||||||
|  | 								&tgl1=${moment($('#tgl1').val(), "DD-MM-YYYY HH:mm").unix()} | ||||||
|  | 								&id={{$user->id}} | ||||||
|  | 							`, | ||||||
|  | 							type: 'GET', | ||||||
|  | 							success: function(json) { | ||||||
|  | 								callback(json); | ||||||
|  | 							}, | ||||||
|  | 							error: function(xhr, status, error) { | ||||||
|  | 								if (status !== 'abort') { | ||||||
|  | 									console.error("AJAX error:", error); | ||||||
|  | 								} | ||||||
|  | 							}, | ||||||
|  | 							complete: function() { | ||||||
|  | 								DTable.lastAjax = null; | ||||||
|  | 							} | ||||||
|  | 						}); | ||||||
|  | 					}, | ||||||
|  |                     deferRender: true, | ||||||
|  | 					columns: [ | ||||||
|  | 						{ | ||||||
|  | 							data: 'crt', | ||||||
|  | 							render: (data, type, row, meta) => { | ||||||
|  | 								// let addr = row | ||||||
|  | 								return ` | ||||||
|  | 									${moment.unix(data).format('DD MMM YYYY HH:mm:ss')}<br> | ||||||
|  | 								`; | ||||||
|  | 							}  | ||||||
|  |  | ||||||
|  | 						}, | ||||||
|  | 						{  | ||||||
|  | 							data: 'log', | ||||||
|  | 							render: (data, type, row, meta) => { | ||||||
|  | 								let log = JSON.parse(data); | ||||||
|  | 								let module = log.module || '-'; | ||||||
|  | 								return module; | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  | 						{  | ||||||
|  | 							data: 'log', | ||||||
|  | 							render: (data, type, row, meta) => { | ||||||
|  | 								let log = JSON.parse(data); | ||||||
|  | 								let desc = log.desc || '-'; | ||||||
|  | 								return desc; | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  | 						{  | ||||||
|  | 							data: 'log', | ||||||
|  | 							render: (data, type, row, meta) => { | ||||||
|  | 								let log = JSON.parse(data); | ||||||
|  | 								let action = log.action || '-'; | ||||||
|  |  | ||||||
|  | 								// use badge for action | ||||||
|  | 								// action = `<span class="badge bg-secondary">${action}</span>`; | ||||||
|  | 								let badge = ''; | ||||||
|  | 								if (action.toLowerCase() === 'create') { | ||||||
|  | 									badge = `<span class="badge bg-success">${action}</span>`; | ||||||
|  | 								} else if (action.toLowerCase() === 'update') { | ||||||
|  | 									badge = `<span class="badge bg-warning">${action}</span>`; | ||||||
|  | 								} else if (action.toLowerCase() === 'delete') { | ||||||
|  | 									badge = `<span class="badge bg-danger">${action}</span>`; | ||||||
|  | 								} else { | ||||||
|  | 									badge = `<span class="badge bg-secondary">${action}</span>`; | ||||||
|  | 								} | ||||||
|  | 								return badge; | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  | 					], | ||||||
|  | 					paging: false, | ||||||
|  | 				}); | ||||||
|  |             }, | ||||||
|  |         }; | ||||||
|  | 		DTable.activate(); | ||||||
|  | 	}); | ||||||
|  | </script> | ||||||
| @ -46,6 +46,7 @@ | |||||||
|                                     <th class="text-end">Type</th> |                                     <th class="text-end">Type</th> | ||||||
|                                     <th class="text-center">Status</th> |                                     <th class="text-center">Status</th> | ||||||
|                                     <th class="text-center">Installation</th> |                                     <th class="text-center">Installation</th> | ||||||
|  |                                     <th class="text-center">Vehicle</th> | ||||||
|                                     <th class="text-center">Availability</th> |                                     <th class="text-center">Availability</th> | ||||||
|                                 </tr> |                                 </tr> | ||||||
|                             </thead> |                             </thead> | ||||||
| @ -491,6 +492,13 @@ | |||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         }, |                         }, | ||||||
|  | 						{ | ||||||
|  | 							data: 'vhc_nopol1', | ||||||
|  | 							className: 'text-left text-nowrap', | ||||||
|  | 							visible: true, | ||||||
|  | 							orderable: true, | ||||||
|  | 							searchable: true, | ||||||
|  | 						}, | ||||||
|                         { |                         { | ||||||
|                             data: 'is_available', |                             data: 'is_available', | ||||||
|                             className: 'text-center text-nowrap', |                             className: 'text-center text-nowrap', | ||||||
|  | |||||||
							
								
								
									
										390
									
								
								resources/views/menu_v1/configs/distribution_category.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								resources/views/menu_v1/configs/distribution_category.blade.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,390 @@ | |||||||
|  | @extends('app.app') | ||||||
|  |  | ||||||
|  | @section('title') | ||||||
|  |     Conf Distribution Categorys | ||||||
|  | @endsection | ||||||
|  |  | ||||||
|  | @section('customcss') | ||||||
|  |     <style> | ||||||
|  |  | ||||||
|  |     </style> | ||||||
|  | @endsection | ||||||
|  |  | ||||||
|  | @section('content') | ||||||
|  |     <div class="container-fluid"> | ||||||
|  |         <div class="content"> | ||||||
|  |             <div class="card"> | ||||||
|  |                 <div class="card-header"> | ||||||
|  |                     <div class="row d-flex align-items-center"> | ||||||
|  |                         <div class="col-3"> | ||||||
|  |                             <p class="card-title text-bold mb-0">Distribution Category</p> | ||||||
|  |                         </div> | ||||||
|  |                         @can('config_distribution_category.create') | ||||||
|  |                             <div class="col text-end"> | ||||||
|  |                                 <button id="btnMdlNew" class="btn btn-sm btn-danger">Add New Distribution Category</button> | ||||||
|  |                             </div> | ||||||
|  |                         @endcan | ||||||
|  |  | ||||||
|  |                         <div class="col-auto text-end ps-0"> | ||||||
|  |                             {{-- <button class="btn btn-sm btn-danger">Upload</button> --}} | ||||||
|  |                             {{-- <button class="btn btn-sm btn-danger">Download</button> --}} | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="card-body"> | ||||||
|  |                     <div class="table-responsive"> | ||||||
|  |                         <table id="tList" class="table table-hover dataTable w-100"> | ||||||
|  |                             <thead> | ||||||
|  |                                 <tr class=""> | ||||||
|  |                                     <th class="">#</th> | ||||||
|  |                                     <th class="text-center">Action</th> | ||||||
|  |                                     <th class="">Code</th> | ||||||
|  |                                     <th class="">Name</th> | ||||||
|  |                                 </tr> | ||||||
|  |                             </thead> | ||||||
|  |                             <tbody> | ||||||
|  |  | ||||||
|  |                             </tbody> | ||||||
|  |                         </table> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <div class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" id="mdlNew" aria-labelledby="mdlLabel" aria-hidden="true"> | ||||||
|  |         <div class="modal-dialog modal-dialog modal-dialog-centered modal-dialog-scrollable"> | ||||||
|  |             <div class="modal-content"> | ||||||
|  |                 <div class="modal-header"> | ||||||
|  |                     <h5 class="modal-title" id="mdlLabel">Add New Category</h5> | ||||||
|  |                     <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-body"> | ||||||
|  |                     <form id="fNew">		 | ||||||
|  | 						<!--input hidden  --> | ||||||
|  | 						<input type="hidden" name="tipe" id="tipe" value="new"> | ||||||
|  | 						<input type="hidden" name="id" id="id"> | ||||||
|  |                         <div class="mb-3"> | ||||||
|  |                             <div class="row"> | ||||||
|  |                                 <div class="col-12"> | ||||||
|  |                                     <label for="dc_code" class="col-form-label">Code:</label> | ||||||
|  |                                     <input type="text" name="dc_code" id="dc_code" class="form-control" placeholder="Category code, example: VF, VO, etc"> | ||||||
|  |                                 </div> | ||||||
|  |                                 <div class="col-12"> | ||||||
|  |                                     <label for="dc_name" class="col-form-label">Name:</label> | ||||||
|  |                                     <input type="text" name="dc_name" id="dc_name" class="form-control" placeholder="Category name"> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                     </form> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-footer"> | ||||||
|  |                     @can('config_distribution_category.delete') | ||||||
|  |                         <button type="button" id="btnDel" class="btn btn-sm btn-warning">Delete ?</button> | ||||||
|  |                     @endcan | ||||||
|  |                     <button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button> | ||||||
|  |                     <button id="btnSubmit" type="button" class="btn btn-sm btn-danger">Submit data</button> | ||||||
|  |                     @can('config_distribution_category.edit') | ||||||
|  |                         <button id="btnEdit" type="button" class="btn btn-sm btn-danger">Update data</button> | ||||||
|  |                     @endcan | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <div class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" id="mdlDel" aria-labelledby="mdlDelLabel" aria-hidden="true"> | ||||||
|  |         <div class="modal-dialog modal-dialog-centered modal-sm"> | ||||||
|  |             <div class="modal-content"> | ||||||
|  |                 <div class="modal-header"> | ||||||
|  |                     <h5 class="modal-title" id="mdlDelLabel">Delete TruckType</h5> | ||||||
|  |                     <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-body"> | ||||||
|  |                     <div class="d-flex justify-content-center"> | ||||||
|  |                         <p class="mb-0"> | ||||||
|  |                             Are you sure want to delete this Distribution Category | ||||||
|  |                             <a href="#" class="text-danger"> | ||||||
|  |                                 <span id="del-type_name"></span> | ||||||
|  |                             </a> | ||||||
|  |                         </p> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-footer"> | ||||||
|  |                     <button type="button" class="btn btn-sm btn-danger" data-bs-dismiss="modal">Close</button> | ||||||
|  |                     <button id="btnSubmitDel" type="button" class="btn btn-sm btn-secondary">Yes, delete</button> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | @endsection | ||||||
|  |  | ||||||
|  | @section('customjs') | ||||||
|  |     <script src="{{ asset('assets/js/load-image.all.min.js') }}"></script> | ||||||
|  |     <script> | ||||||
|  |         'use strict'; | ||||||
|  |         const State = { | ||||||
|  |             file_jimp_worker: "{{ asset('assets/js/worker/jimp.js') }}", | ||||||
|  |             storage_lara: "{{ asset('storage') }}/", | ||||||
|  |             delay_typing_front: 1000, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         const Wrapper = { | ||||||
|  |             activate: function() { | ||||||
|  |                 Wrapper.event(); | ||||||
|  |                 DTable.activate(); | ||||||
|  | 			}, | ||||||
|  |             event: function() { | ||||||
|  |                 $('#btnMdlNew').on('click', function() { | ||||||
|  | 					$('#fNew')[0].reset(); | ||||||
|  | 					$('#btnDel').hide(); | ||||||
|  | 					$('#btnEdit').hide(); | ||||||
|  | 					$('#btnSubmit').show(); | ||||||
|  | 					$('#mdlLabel').text('New Distribution Category'); | ||||||
|  | 					$('#dc_code').focus(); | ||||||
|  | 					 | ||||||
|  |                     $('#mdlNew').modal('show'); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  | 				$('#btnSubmit, #btnEdit').on('click', function() { | ||||||
|  | 					let data=$("#fNew").serialize() | ||||||
|  | 					Wrapper.submitData(data); | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  | 				$('#tList').on('click', '.btnUpdt', function(e) { | ||||||
|  | 					// console.log("updt klik"); | ||||||
|  | 					const id = $(this).data('id'); | ||||||
|  |                     $.ajax({ | ||||||
|  |                         url: "{{ route('api_conf_show_distribution_category', '') }}/" + id, | ||||||
|  |                         method: 'GET', | ||||||
|  |                         crossDomain: true, | ||||||
|  |                         processData: true, | ||||||
|  |                         headers: { | ||||||
|  |                             'x-api-key': Helper.getCookie('_trtk'), | ||||||
|  |                         }, | ||||||
|  |                         // data: params, | ||||||
|  |                         success: (data, textStatus, jqXHR) => { | ||||||
|  | 							console.log("res data", data); | ||||||
|  | 							 | ||||||
|  |                             if (data.meta.type != 'success') { | ||||||
|  |                                 resolve({ | ||||||
|  |                                     type: 'fail' | ||||||
|  |                                 }); | ||||||
|  |                                 Helper.toast('Warning', 'just now', data.meta.message); | ||||||
|  |                                 return false; | ||||||
|  |                             } | ||||||
|  |  | ||||||
|  | 							//  insert value | ||||||
|  | 							$('#mdlLabel').text('Edit Distribution Category'); | ||||||
|  | 							$('#btnDel').show(); | ||||||
|  | 							$('#btnEdit').show(); | ||||||
|  | 							$('#btnSubmit').hide(); | ||||||
|  |  | ||||||
|  | 							$('#tipe').val("edit"); | ||||||
|  | 							$('#id').val(id); | ||||||
|  | 							$('#dc_code').val(data.data.dc_code); | ||||||
|  | 							$('#dc_name').val(data.data.dc_name); | ||||||
|  |                         }, | ||||||
|  |                         error: (jqXHR, textStatus, error) => { | ||||||
|  |                             if (jqXHR.status >= 500) { | ||||||
|  |                                 Helper.toast('Error', 'just now', 'please try again'); | ||||||
|  |                             } else { | ||||||
|  |                                 Helper.toast('Error', 'just now', jqXHR.responseJSON.meta | ||||||
|  |                                     .message); | ||||||
|  |                             } | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'error' | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                     }) | ||||||
|  |  | ||||||
|  | 					$('#mdlNew').modal('show'); | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  |                 $('#btnDel').on('click', function(e) { | ||||||
|  |                     $('#mdlDel').modal('show'); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  | 				$('#btnSubmitDel').on('click', function(e) { | ||||||
|  | 					const id = $('#id').val() | ||||||
|  | 					const data = { | ||||||
|  | 						id: $('#mdlDel').data('id'), | ||||||
|  | 					}; | ||||||
|  |                     $('#btnSubmitDel').attr('disabed', true); | ||||||
|  |                     $.ajax({ | ||||||
|  |                         url: "{{ route('api_conf_del_distribution_category', '') }}/" + id, | ||||||
|  |                         method: 'DELETE', | ||||||
|  |                         crossDomain: true, | ||||||
|  |                         processData: true, | ||||||
|  |                         headers: { | ||||||
|  |                             'x-api-key': Helper.getCookie('_trtk'), | ||||||
|  |                             'x-csrf-token': $('meta[name="csrf-token"]').attr('content'), | ||||||
|  |                         }, | ||||||
|  |                         data: data, | ||||||
|  |                         success: (data, textStatus, jqXHR) => { | ||||||
|  |                             $('#btnSubmitDel').removeAttr('disabed'); | ||||||
|  |                             if (data.meta.type != 'success') { | ||||||
|  |                                 resolve({ | ||||||
|  |                                     type: 'fail' | ||||||
|  |                                 }); | ||||||
|  |                                 Helper.toast('Warning', 'just now', data.meta.message); | ||||||
|  |                                 return false; | ||||||
|  |                             } | ||||||
|  |                             Helper.toast('Success', 'just now', 'success delete Distribution Category'); | ||||||
|  |                             $('#mdlDel').modal('hide'); | ||||||
|  |                             $('#mdlNew').modal('hide'); | ||||||
|  |                             $('#tList').DataTable().ajax.reload(); | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'success' | ||||||
|  |                             }); | ||||||
|  |                         }, | ||||||
|  |                         error: (jqXHR, textStatus, error) => { | ||||||
|  |                             $('#btnSubmitDel').removeAttr('disabed'); | ||||||
|  |                             if (jqXHR.status >= 500) { | ||||||
|  |                                 Helper.toast('Error', 'just now', 'Please try again'); | ||||||
|  |                             } else { | ||||||
|  |                                 Helper.toast('Error', 'just now', jqXHR.responseJSON.meta | ||||||
|  |                                     .message); | ||||||
|  |                             } | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'error' | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                     }) | ||||||
|  |                 }) | ||||||
|  |  | ||||||
|  | 				$('#mdlDel').on('show.bs.modal', function () { | ||||||
|  | 					$('#mdlNew').css('opacity', '0.5'); // fade background modal | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  | 				$('#mdlDel').on('hidden.bs.modal', function () { | ||||||
|  | 					$('#mdlNew').css('opacity', '1'); | ||||||
|  | 				}); | ||||||
|  | 			}, | ||||||
|  |             submitData: async function(data) { | ||||||
|  |                 return new Promise((resolve, reject) => { | ||||||
|  |                     if (typeof $('#btnSubmit').attr('disabed') != 'undefined') { | ||||||
|  |                         resolve({ | ||||||
|  |                             type: 'fail' | ||||||
|  |                         }); | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                     $('#btnSubmit').attr('disabed', true); | ||||||
|  |                     $.ajax({ | ||||||
|  |                         url: "{{ route('api_conf_add_distribution_category') }}", | ||||||
|  |                         method: 'POST', | ||||||
|  |                         crossDomain: true, | ||||||
|  |                         processData: true, | ||||||
|  |                         headers: { | ||||||
|  |                             'x-api-key': Helper.getCookie('_trtk'), | ||||||
|  |                             'x-csrf-token': $('meta[name="csrf-token"]').attr('content'), | ||||||
|  |                         }, | ||||||
|  |                         data: data, | ||||||
|  |                         success: (data, textStatus, jqXHR) => { | ||||||
|  |                             $('#btnSubmit').removeAttr('disabed'); | ||||||
|  |                             if (data.meta.type != 'success') { | ||||||
|  |                                 resolve({ | ||||||
|  |                                     type: 'fail' | ||||||
|  |                                 }); | ||||||
|  |                                 Helper.toast('Warning', 'just now', data.meta.message); | ||||||
|  |                                 return false; | ||||||
|  |                             } | ||||||
|  |                             Helper.toast('Success', 'just now', 'success add new Distribution Category'); | ||||||
|  |                             $('#mdlNew').modal('hide'); | ||||||
|  |                             $('#tList').DataTable().ajax.reload(); | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'success' | ||||||
|  |                             }); | ||||||
|  |                         }, | ||||||
|  |                         error: (jqXHR, textStatus, error) => { | ||||||
|  |                             $('#btnSubmit').removeAttr('disabed'); | ||||||
|  |                             if (jqXHR.status >= 500) { | ||||||
|  |                                 Helper.toast('Error', 'just now', 'Please try again'); | ||||||
|  |                             } else { | ||||||
|  |                                 Helper.toast('Error', 'just now', jqXHR.responseJSON.meta | ||||||
|  |                                     .message); | ||||||
|  |                             } | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'error' | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                     }) | ||||||
|  |                 }) | ||||||
|  |             }, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         const DTable = { | ||||||
|  |             activate: function() { | ||||||
|  |                 DTable.reload(); | ||||||
|  |             }, | ||||||
|  |             reload: function() { | ||||||
|  |                 // $('#tList').DataTable(); | ||||||
|  |                 // if (Driver.Table.firstInitDataTable == 1) { loadTableSkeletonLoading() } else { Driver.Table.firstInitDataTable = 1; } | ||||||
|  |                 $('#tList').DataTable({ | ||||||
|  |                     processing: true, | ||||||
|  |                     serverSide: false, | ||||||
|  |                     bLengthChange: true, | ||||||
|  |                     deferRender: true, | ||||||
|  |                     destroy: true, | ||||||
|  |                     ajax: { | ||||||
|  |                         url: "{{ route('api_conf_list_distribution_category') }}", | ||||||
|  |                         type: 'GET', | ||||||
|  |                         complete: function(jqXHR, textStatus, c) { | ||||||
|  |                             let count = jqXHR.responseJSON.count; | ||||||
|  |                             if (typeof count != 'undefined') { | ||||||
|  |                                 $('#count_trucktypes').text(count); | ||||||
|  |                             } | ||||||
|  |                             // removeTableSkeletonLoading() | ||||||
|  |                         }, | ||||||
|  |                     }, | ||||||
|  |                     deferRender: true, | ||||||
|  |                     columns: [{ | ||||||
|  |                             data: 'DT_RowIndex', | ||||||
|  |                             className: 'text-end', | ||||||
|  |                             visible: true, | ||||||
|  |                             orderable: true, | ||||||
|  |                             searchable: true, | ||||||
|  | 							width: "30px" | ||||||
|  |                         }, | ||||||
|  |                         { | ||||||
|  |                             data: 'action', | ||||||
|  |                             className: 'text-center', | ||||||
|  |                             visible: true, | ||||||
|  |                             orderable: true, | ||||||
|  |                             searchable: true, | ||||||
|  | 							width: "100px", | ||||||
|  |                             render: function(data, type, row, meta) { | ||||||
|  |                                 let action = ` | ||||||
|  | 									<a href="#" class="text-decoration-none me-1 btnUpdt" data-id="${row.id}" title="Update" data-bs-toggle="tooltip" data-bs-placement="top"> | ||||||
|  | 										<span class="icon ion-eye fz-16"></span> | ||||||
|  | 									</a> | ||||||
|  | 								`; | ||||||
|  |                                 return action; | ||||||
|  |                             } | ||||||
|  |                         }, | ||||||
|  |                         { | ||||||
|  |                             data: 'dc_code', | ||||||
|  |                             className: 'text-left text-nowrap', | ||||||
|  |                             visible: true, | ||||||
|  |                             orderable: true, | ||||||
|  |                             searchable: true, | ||||||
|  |                             createdCell: function(td, cellData, rowData, row, col) { | ||||||
|  |                                 $(td).attr('data-ttid', rowData.id); | ||||||
|  |                                 $(td).attr('data-type_name', rowData.type_name); | ||||||
|  |                             }, | ||||||
|  |                         }, | ||||||
|  |                         { | ||||||
|  |                             data: 'dc_name', | ||||||
|  |                             className: 'text-left', | ||||||
|  |                             visible: true, | ||||||
|  |                             orderable: true, | ||||||
|  |                             searchable: true, | ||||||
|  |                         }, | ||||||
|  |                     ], | ||||||
|  |                 }); | ||||||
|  |             }, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         Wrapper.activate(); | ||||||
|  |     </script> | ||||||
|  | @endsection | ||||||
							
								
								
									
										390
									
								
								resources/views/menu_v1/configs/pool.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										390
									
								
								resources/views/menu_v1/configs/pool.blade.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,390 @@ | |||||||
|  | @extends('app.app') | ||||||
|  |  | ||||||
|  | @section('title') | ||||||
|  |     Conf Pools | ||||||
|  | @endsection | ||||||
|  |  | ||||||
|  | @section('customcss') | ||||||
|  |     <style> | ||||||
|  |  | ||||||
|  |     </style> | ||||||
|  | @endsection | ||||||
|  |  | ||||||
|  | @section('content') | ||||||
|  |     <div class="container-fluid"> | ||||||
|  |         <div class="content"> | ||||||
|  |             <div class="card"> | ||||||
|  |                 <div class="card-header"> | ||||||
|  |                     <div class="row d-flex align-items-center"> | ||||||
|  |                         <div class="col-3"> | ||||||
|  |                             <p class="card-title text-bold mb-0">Pool / Area</p> | ||||||
|  |                         </div> | ||||||
|  |                         @can('config_pool.create') | ||||||
|  |                             <div class="col text-end"> | ||||||
|  |                                 <button id="btnMdlNew" class="btn btn-sm btn-danger">Add New Pool</button> | ||||||
|  |                             </div> | ||||||
|  |                         @endcan | ||||||
|  |  | ||||||
|  |                         <div class="col-auto text-end ps-0"> | ||||||
|  |                             {{-- <button class="btn btn-sm btn-danger">Upload</button> --}} | ||||||
|  |                             {{-- <button class="btn btn-sm btn-danger">Download</button> --}} | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="card-body"> | ||||||
|  |                     <div class="table-responsive"> | ||||||
|  |                         <table id="tList" class="table table-hover dataTable w-100"> | ||||||
|  |                             <thead> | ||||||
|  |                                 <tr class=""> | ||||||
|  |                                     <th class="">#</th> | ||||||
|  |                                     <th class="text-center">Action</th> | ||||||
|  |                                     <th class="">Code</th> | ||||||
|  |                                     <th class="">Name</th> | ||||||
|  |                                 </tr> | ||||||
|  |                             </thead> | ||||||
|  |                             <tbody> | ||||||
|  |  | ||||||
|  |                             </tbody> | ||||||
|  |                         </table> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <div class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" id="mdlNew" aria-labelledby="mdlLabel" aria-hidden="true"> | ||||||
|  |         <div class="modal-dialog modal-dialog modal-dialog-centered modal-dialog-scrollable"> | ||||||
|  |             <div class="modal-content"> | ||||||
|  |                 <div class="modal-header"> | ||||||
|  |                     <h5 class="modal-title" id="mdlLabel">Add New Pool</h5> | ||||||
|  |                     <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-body"> | ||||||
|  |                     <form id="fNew">		 | ||||||
|  | 						<!--input hidden  --> | ||||||
|  | 						<input type="hidden" name="tipe" id="tipe" value="new"> | ||||||
|  | 						<input type="hidden" name="id" id="id"> | ||||||
|  |                         <div class="mb-3"> | ||||||
|  |                             <div class="row"> | ||||||
|  |                                 <div class="col-12"> | ||||||
|  |                                     <label for="pool_code" class="col-form-label">Code:</label> | ||||||
|  |                                     <input type="text" name="pool_code" id="pool_code" class="form-control" placeholder="Pool code, example: VF, VO, etc"> | ||||||
|  |                                 </div> | ||||||
|  |                                 <div class="col-12"> | ||||||
|  |                                     <label for="pool_name" class="col-form-label">Name:</label> | ||||||
|  |                                     <input type="text" name="pool_name" id="pool_name" class="form-control" placeholder="Pool name"> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|  |                         </div> | ||||||
|  |                     </form> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-footer"> | ||||||
|  |                     @can('config_pool.delete') | ||||||
|  |                         <button type="button" id="btnDel" class="btn btn-sm btn-warning">Delete ?</button> | ||||||
|  |                     @endcan | ||||||
|  |                     <button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button> | ||||||
|  |                     <button id="btnSubmit" type="button" class="btn btn-sm btn-danger">Submit data</button> | ||||||
|  |                     @can('config_pool.edit') | ||||||
|  |                         <button id="btnEdit" type="button" class="btn btn-sm btn-danger">Update data</button> | ||||||
|  |                     @endcan | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  |     <div class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" id="mdlDel" aria-labelledby="mdlDelLabel" aria-hidden="true"> | ||||||
|  |         <div class="modal-dialog modal-dialog-centered modal-sm"> | ||||||
|  |             <div class="modal-content"> | ||||||
|  |                 <div class="modal-header"> | ||||||
|  |                     <h5 class="modal-title" id="mdlDelLabel">Delete TruckType</h5> | ||||||
|  |                     <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-body"> | ||||||
|  |                     <div class="d-flex justify-content-center"> | ||||||
|  |                         <p class="mb-0"> | ||||||
|  |                             Are you sure want to delete this Pool | ||||||
|  |                             <a href="#" class="text-danger"> | ||||||
|  |                                 <span id="del-type_name"></span> | ||||||
|  |                             </a> | ||||||
|  |                         </p> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-footer"> | ||||||
|  |                     <button type="button" class="btn btn-sm btn-danger" data-bs-dismiss="modal">Close</button> | ||||||
|  |                     <button id="btnSubmitDel" type="button" class="btn btn-sm btn-secondary">Yes, delete</button> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | @endsection | ||||||
|  |  | ||||||
|  | @section('customjs') | ||||||
|  |     <script src="{{ asset('assets/js/load-image.all.min.js') }}"></script> | ||||||
|  |     <script> | ||||||
|  |         'use strict'; | ||||||
|  |         const State = { | ||||||
|  |             file_jimp_worker: "{{ asset('assets/js/worker/jimp.js') }}", | ||||||
|  |             storage_lara: "{{ asset('storage') }}/", | ||||||
|  |             delay_typing_front: 1000, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         const Wrapper = { | ||||||
|  |             activate: function() { | ||||||
|  |                 Wrapper.event(); | ||||||
|  |                 DTable.activate(); | ||||||
|  | 			}, | ||||||
|  |             event: function() { | ||||||
|  |                 $('#btnMdlNew').on('click', function() { | ||||||
|  | 					$('#fNew')[0].reset(); | ||||||
|  | 					$('#btnDel').hide(); | ||||||
|  | 					$('#btnEdit').hide(); | ||||||
|  | 					$('#btnSubmit').show(); | ||||||
|  | 					$('#mdlLabel').text('New Pool'); | ||||||
|  | 					$('#pool_code').focus(); | ||||||
|  | 					 | ||||||
|  |                     $('#mdlNew').modal('show'); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  | 				$('#btnSubmit, #btnEdit').on('click', function() { | ||||||
|  | 					let data=$("#fNew").serialize() | ||||||
|  | 					Wrapper.submitData(data); | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  | 				$('#tList').on('click', '.btnUpdt', function(e) { | ||||||
|  | 					// console.log("updt klik"); | ||||||
|  | 					const id = $(this).data('id'); | ||||||
|  |                     $.ajax({ | ||||||
|  |                         url: "{{ route('api_conf_show_pool', '') }}/" + id, | ||||||
|  |                         method: 'GET', | ||||||
|  |                         crossDomain: true, | ||||||
|  |                         processData: true, | ||||||
|  |                         headers: { | ||||||
|  |                             'x-api-key': Helper.getCookie('_trtk'), | ||||||
|  |                         }, | ||||||
|  |                         // data: params, | ||||||
|  |                         success: (data, textStatus, jqXHR) => { | ||||||
|  | 							console.log("res data", data); | ||||||
|  | 							 | ||||||
|  |                             if (data.meta.type != 'success') { | ||||||
|  |                                 resolve({ | ||||||
|  |                                     type: 'fail' | ||||||
|  |                                 }); | ||||||
|  |                                 Helper.toast('Warning', 'just now', data.meta.message); | ||||||
|  |                                 return false; | ||||||
|  |                             } | ||||||
|  |  | ||||||
|  | 							//  insert value | ||||||
|  | 							$('#mdlLabel').text('Edit Pool'); | ||||||
|  | 							$('#btnDel').show(); | ||||||
|  | 							$('#btnEdit').show(); | ||||||
|  | 							$('#btnSubmit').hide(); | ||||||
|  |  | ||||||
|  | 							$('#tipe').val("edit"); | ||||||
|  | 							$('#id').val(id); | ||||||
|  | 							$('#pool_code').val(data.data.pool_code); | ||||||
|  | 							$('#pool_name').val(data.data.pool_name); | ||||||
|  |                         }, | ||||||
|  |                         error: (jqXHR, textStatus, error) => { | ||||||
|  |                             if (jqXHR.status >= 500) { | ||||||
|  |                                 Helper.toast('Error', 'just now', 'please try again'); | ||||||
|  |                             } else { | ||||||
|  |                                 Helper.toast('Error', 'just now', jqXHR.responseJSON.meta | ||||||
|  |                                     .message); | ||||||
|  |                             } | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'error' | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                     }) | ||||||
|  |  | ||||||
|  | 					$('#mdlNew').modal('show'); | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  |                 $('#btnDel').on('click', function(e) { | ||||||
|  |                     $('#mdlDel').modal('show'); | ||||||
|  |                 }); | ||||||
|  |  | ||||||
|  | 				$('#btnSubmitDel').on('click', function(e) { | ||||||
|  | 					const id = $('#id').val() | ||||||
|  | 					const data = { | ||||||
|  | 						id: $('#mdlDel').data('id'), | ||||||
|  | 					}; | ||||||
|  |                     $('#btnSubmitDel').attr('disabed', true); | ||||||
|  |                     $.ajax({ | ||||||
|  |                         url: "{{ route('api_conf_del_pool', '') }}/" + id, | ||||||
|  |                         method: 'DELETE', | ||||||
|  |                         crossDomain: true, | ||||||
|  |                         processData: true, | ||||||
|  |                         headers: { | ||||||
|  |                             'x-api-key': Helper.getCookie('_trtk'), | ||||||
|  |                             'x-csrf-token': $('meta[name="csrf-token"]').attr('content'), | ||||||
|  |                         }, | ||||||
|  |                         data: data, | ||||||
|  |                         success: (data, textStatus, jqXHR) => { | ||||||
|  |                             $('#btnSubmitDel').removeAttr('disabed'); | ||||||
|  |                             if (data.meta.type != 'success') { | ||||||
|  |                                 resolve({ | ||||||
|  |                                     type: 'fail' | ||||||
|  |                                 }); | ||||||
|  |                                 Helper.toast('Warning', 'just now', data.meta.message); | ||||||
|  |                                 return false; | ||||||
|  |                             } | ||||||
|  |                             Helper.toast('Success', 'just now', 'success delete Pool'); | ||||||
|  |                             $('#mdlDel').modal('hide'); | ||||||
|  |                             $('#mdlNew').modal('hide'); | ||||||
|  |                             $('#tList').DataTable().ajax.reload(); | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'success' | ||||||
|  |                             }); | ||||||
|  |                         }, | ||||||
|  |                         error: (jqXHR, textStatus, error) => { | ||||||
|  |                             $('#btnSubmitDel').removeAttr('disabed'); | ||||||
|  |                             if (jqXHR.status >= 500) { | ||||||
|  |                                 Helper.toast('Error', 'just now', 'Please try again'); | ||||||
|  |                             } else { | ||||||
|  |                                 Helper.toast('Error', 'just now', jqXHR.responseJSON.meta | ||||||
|  |                                     .message); | ||||||
|  |                             } | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'error' | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                     }) | ||||||
|  |                 }) | ||||||
|  |  | ||||||
|  | 				$('#mdlDel').on('show.bs.modal', function () { | ||||||
|  | 					$('#mdlNew').css('opacity', '0.5'); // fade background modal | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  | 				$('#mdlDel').on('hidden.bs.modal', function () { | ||||||
|  | 					$('#mdlNew').css('opacity', '1'); | ||||||
|  | 				}); | ||||||
|  | 			}, | ||||||
|  |             submitData: async function(data) { | ||||||
|  |                 return new Promise((resolve, reject) => { | ||||||
|  |                     if (typeof $('#btnSubmit').attr('disabed') != 'undefined') { | ||||||
|  |                         resolve({ | ||||||
|  |                             type: 'fail' | ||||||
|  |                         }); | ||||||
|  |                         return false; | ||||||
|  |                     } | ||||||
|  |                     $('#btnSubmit').attr('disabed', true); | ||||||
|  |                     $.ajax({ | ||||||
|  |                         url: "{{ route('api_conf_add_pool') }}", | ||||||
|  |                         method: 'POST', | ||||||
|  |                         crossDomain: true, | ||||||
|  |                         processData: true, | ||||||
|  |                         headers: { | ||||||
|  |                             'x-api-key': Helper.getCookie('_trtk'), | ||||||
|  |                             'x-csrf-token': $('meta[name="csrf-token"]').attr('content'), | ||||||
|  |                         }, | ||||||
|  |                         data: data, | ||||||
|  |                         success: (data, textStatus, jqXHR) => { | ||||||
|  |                             $('#btnSubmit').removeAttr('disabed'); | ||||||
|  |                             if (data.meta.type != 'success') { | ||||||
|  |                                 resolve({ | ||||||
|  |                                     type: 'fail' | ||||||
|  |                                 }); | ||||||
|  |                                 Helper.toast('Warning', 'just now', data.meta.message); | ||||||
|  |                                 return false; | ||||||
|  |                             } | ||||||
|  |                             Helper.toast('Success', 'just now', 'success add new Pool'); | ||||||
|  |                             $('#mdlNew').modal('hide'); | ||||||
|  |                             $('#tList').DataTable().ajax.reload(); | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'success' | ||||||
|  |                             }); | ||||||
|  |                         }, | ||||||
|  |                         error: (jqXHR, textStatus, error) => { | ||||||
|  |                             $('#btnSubmit').removeAttr('disabed'); | ||||||
|  |                             if (jqXHR.status >= 500) { | ||||||
|  |                                 Helper.toast('Error', 'just now', 'Please try again'); | ||||||
|  |                             } else { | ||||||
|  |                                 Helper.toast('Error', 'just now', jqXHR.responseJSON.meta | ||||||
|  |                                     .message); | ||||||
|  |                             } | ||||||
|  |                             resolve({ | ||||||
|  |                                 type: 'error' | ||||||
|  |                             }); | ||||||
|  |                         } | ||||||
|  |                     }) | ||||||
|  |                 }) | ||||||
|  |             }, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         const DTable = { | ||||||
|  |             activate: function() { | ||||||
|  |                 DTable.reload(); | ||||||
|  |             }, | ||||||
|  |             reload: function() { | ||||||
|  |                 // $('#tList').DataTable(); | ||||||
|  |                 // if (Driver.Table.firstInitDataTable == 1) { loadTableSkeletonLoading() } else { Driver.Table.firstInitDataTable = 1; } | ||||||
|  |                 $('#tList').DataTable({ | ||||||
|  |                     processing: true, | ||||||
|  |                     serverSide: false, | ||||||
|  |                     bLengthChange: true, | ||||||
|  |                     deferRender: true, | ||||||
|  |                     destroy: true, | ||||||
|  |                     ajax: { | ||||||
|  |                         url: "{{ route('api_conf_list_pool') }}", | ||||||
|  |                         type: 'GET', | ||||||
|  |                         complete: function(jqXHR, textStatus, c) { | ||||||
|  |                             let count = jqXHR.responseJSON.count; | ||||||
|  |                             if (typeof count != 'undefined') { | ||||||
|  |                                 $('#count_trucktypes').text(count); | ||||||
|  |                             } | ||||||
|  |                             // removeTableSkeletonLoading() | ||||||
|  |                         }, | ||||||
|  |                     }, | ||||||
|  |                     deferRender: true, | ||||||
|  |                     columns: [{ | ||||||
|  |                             data: 'DT_RowIndex', | ||||||
|  |                             className: 'text-end', | ||||||
|  |                             visible: true, | ||||||
|  |                             orderable: true, | ||||||
|  |                             searchable: true, | ||||||
|  | 							width: "30px" | ||||||
|  |                         }, | ||||||
|  |                         { | ||||||
|  |                             data: 'action', | ||||||
|  |                             className: 'text-center', | ||||||
|  |                             visible: true, | ||||||
|  |                             orderable: true, | ||||||
|  |                             searchable: true, | ||||||
|  | 							width: "100px", | ||||||
|  |                             render: function(data, type, row, meta) { | ||||||
|  |                                 let action = ` | ||||||
|  | 									<a href="#" class="text-decoration-none me-1 btnUpdt" data-id="${row.id}" title="Update" data-bs-toggle="tooltip" data-bs-placement="top"> | ||||||
|  | 										<span class="icon ion-eye fz-16"></span> | ||||||
|  | 									</a> | ||||||
|  | 								`; | ||||||
|  |                                 return action; | ||||||
|  |                             } | ||||||
|  |                         }, | ||||||
|  |                         { | ||||||
|  |                             data: 'pool_code', | ||||||
|  |                             className: 'text-left text-nowrap', | ||||||
|  |                             visible: true, | ||||||
|  |                             orderable: true, | ||||||
|  |                             searchable: true, | ||||||
|  |                             createdCell: function(td, cellData, rowData, row, col) { | ||||||
|  |                                 $(td).attr('data-ttid', rowData.id); | ||||||
|  |                                 $(td).attr('data-type_name', rowData.type_name); | ||||||
|  |                             }, | ||||||
|  |                         }, | ||||||
|  |                         { | ||||||
|  |                             data: 'pool_name', | ||||||
|  |                             className: 'text-left', | ||||||
|  |                             visible: true, | ||||||
|  |                             orderable: true, | ||||||
|  |                             searchable: true, | ||||||
|  |                         }, | ||||||
|  |                     ], | ||||||
|  |                 }); | ||||||
|  |             }, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |         Wrapper.activate(); | ||||||
|  |     </script> | ||||||
|  | @endsection | ||||||
							
								
								
									
										3541
									
								
								resources/views/menu_v1/dashboard.blade copy.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3541
									
								
								resources/views/menu_v1/dashboard.blade copy.php
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -408,10 +408,12 @@ | |||||||
|                         <div class="mb-2"> |                         <div class="mb-2"> | ||||||
|                             <label class="text-muted">From</label> |                             <label class="text-muted">From</label> | ||||||
|                             <input class="form-control" id="historyStartDate"> |                             <input class="form-control" id="historyStartDate"> | ||||||
|  |                             <!-- <input class="form-control" id="historyStartDate" value="11-08-2025 00:00"> --> | ||||||
|                         </div> |                         </div> | ||||||
|                         <div class="mb-2"> |                         <div class="mb-2"> | ||||||
|                             <label class="text-muted">To</label> |                             <label class="text-muted">To</label> | ||||||
|                             <input class="form-control" id="historyEndDate"> |                             <input class="form-control" id="historyEndDate"> | ||||||
|  |                             <!-- <input class="form-control" id="historyEndDate" value="11-08-2025 23:00"> --> | ||||||
|                         </div> |                         </div> | ||||||
| 						<button class="btn btn-primary btn-sm w-100 mb-3" id="historySearch">Search</button> | 						<button class="btn btn-primary btn-sm w-100 mb-3" id="historySearch">Search</button> | ||||||
|                     </div> |                     </div> | ||||||
| @ -533,6 +535,7 @@ | |||||||
|     <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js" integrity="sha512-ozq8xQKq6urvuU6jNgkfqAmT7jKN2XumbrX1JiB3TnF7tI48DPI4Gy1GXKD/V3EExgAs1V+pRO7vwtS1LHg0Gw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> |     <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js" integrity="sha512-ozq8xQKq6urvuU6jNgkfqAmT7jKN2XumbrX1JiB3TnF7tI48DPI4Gy1GXKD/V3EExgAs1V+pRO7vwtS1LHg0Gw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> | ||||||
|     <script src="https://cdn.jsdelivr.net/npm/leaflet-rotatedmarker@0.2.0/leaflet.rotatedMarker.min.js"></script> |     <script src="https://cdn.jsdelivr.net/npm/leaflet-rotatedmarker@0.2.0/leaflet.rotatedMarker.min.js"></script> | ||||||
|     <script src="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.js"></script> |     <script src="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.js"></script> | ||||||
|  | 	<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> | ||||||
| 					 | 					 | ||||||
|     <script> |     <script> | ||||||
|         'use strict'; |         'use strict'; | ||||||
| @ -941,31 +944,120 @@ | |||||||
|                 if (cb) cb(polyline); |                 if (cb) cb(polyline); | ||||||
|                 return polyline; |                 return polyline; | ||||||
|             }, |             }, | ||||||
|             addRoutes: function(locs = [], cb = null) { | 			addRoutes: async function(locs = [], cb = null) { | ||||||
|                 let latLngs = []; | 				let latLngs = []; | ||||||
|                 for (let i = 0; i < locs.length; i++) { | 				for (let i = 0; i < locs.length; i++) { | ||||||
|                     latLngs.push([locs[i].lat, locs[i].lng]); | 					latLngs.push([locs[i].lat, locs[i].lng]); | ||||||
|                 } | 				} | ||||||
| 				let routes = L.Routing.control({ |  | ||||||
| 					waypoints: latLngs.reverse(), // reverse to make first point as start |  | ||||||
| 					// router: L.Routing.osrmv1(), |  | ||||||
| 					router: L.Routing.osrmv1({ |  | ||||||
| 						serviceUrl: "https://brilianapps.britimorleste.tl:5001/route/v1", |  | ||||||
| 					}), |  | ||||||
| 					show: false, |  | ||||||
| 					itinerary: null, // 👈 completely removes the panel |  | ||||||
| 					addWaypoints: false, // ❌ prevent adding points by clicking |  | ||||||
| 					draggableWaypoints: false, // ❌ prevent dragging markers |  | ||||||
| 					routeWhileDragging: false, // optional: don’t reroute while dragging |  | ||||||
| 					createMarker: () => null, |  | ||||||
| 					lineOptions:{ |  | ||||||
| 						styles: [{ color: locs[0]?.options?.color, weight: 3, opacity: 0.7 }], |  | ||||||
| 					}, |  | ||||||
| 				}).addTo(Leaflet.map) |  | ||||||
|  |  | ||||||
|                 if (cb) cb(routes); | 				function chunkArray(arr, size) { | ||||||
|                 return routes; | 					const result = []; | ||||||
|             }, | 					for (let i = 0; i < arr.length; i += size) { | ||||||
|  | 						result.push(arr.slice(i, i + size)); | ||||||
|  | 					} | ||||||
|  | 					return result; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function fetchOsrm(points) { | ||||||
|  | 					const coords = points; | ||||||
|  | 					const hints = ";".repeat(points.length - 1); | ||||||
|  |  | ||||||
|  | 					const body = { | ||||||
|  | 						coordinates: coords, | ||||||
|  | 						overview: "false", | ||||||
|  | 						alternatives: "true", | ||||||
|  | 						steps: "true", | ||||||
|  | 						hints: hints | ||||||
|  | 					}; | ||||||
|  |  | ||||||
|  | 					let config = { | ||||||
|  | 						method: 'post', | ||||||
|  | 						maxBodyLength: Infinity, | ||||||
|  | 						url: 'https://brilianapps.britimorleste.tl/osrm-backend/post-route/v1/driving/', | ||||||
|  | 						headers: { | ||||||
|  | 							'Content-Type': 'application/json' | ||||||
|  | 						}, | ||||||
|  | 						data: body | ||||||
|  | 					}; | ||||||
|  |  | ||||||
|  | 					return axios.request(config) | ||||||
|  | 						.then((response) => { | ||||||
|  | 							return response.data; | ||||||
|  | 						}) | ||||||
|  | 						.catch((err) => { | ||||||
|  | 							console.error("Error:", err.message); | ||||||
|  | 							return null; | ||||||
|  | 						}); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				function decodeOSRMGeometry(encoded) { | ||||||
|  | 					const coordinates = []; | ||||||
|  | 					let index = 0, lat = 0, lng = 0; | ||||||
|  |  | ||||||
|  | 					while (index < encoded.length) { | ||||||
|  | 						let result = 1, shift = 0, b; | ||||||
|  | 						do { | ||||||
|  | 							b = encoded.charCodeAt(index++) - 63 - 1; | ||||||
|  | 							result += b << shift; | ||||||
|  | 							shift += 5; | ||||||
|  | 						} while (b >= 0x1f); | ||||||
|  | 						lat += (result & 1 ? ~(result >> 1) : result >> 1); | ||||||
|  |  | ||||||
|  | 						result = 1; | ||||||
|  | 						shift = 0; | ||||||
|  | 						do { | ||||||
|  | 							b = encoded.charCodeAt(index++) - 63 - 1; | ||||||
|  | 							result += b << shift; | ||||||
|  | 							shift += 5; | ||||||
|  | 						} while (b >= 0x1f); | ||||||
|  | 						lng += (result & 1 ? ~(result >> 1) : result >> 1); | ||||||
|  |  | ||||||
|  | 						coordinates.push([lat / 1e5, lng / 1e5]); | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					return coordinates; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				async function getCoordinates(points) { | ||||||
|  | 					const chunkSize = 500; | ||||||
|  | 					const chunks = chunkArray(points, chunkSize); // Split the points array into chunks of 500 | ||||||
|  | 					let allCoords = []; | ||||||
|  |  | ||||||
|  | 					for (const chunk of chunks) { | ||||||
|  | 						const osrm = await fetchOsrm(chunk); // Fetch OSRM data for each chunk | ||||||
|  |  | ||||||
|  | 						if (!osrm) { | ||||||
|  | 							console.log("OSRM failed for chunk"); | ||||||
|  | 							return; | ||||||
|  | 						} | ||||||
|  |  | ||||||
|  | 						const coords = osrm.routes[0].legs.flatMap(leg => | ||||||
|  | 							leg.steps.flatMap(step => | ||||||
|  | 								decodeOSRMGeometry(step.geometry) | ||||||
|  | 							) | ||||||
|  | 						); | ||||||
|  |  | ||||||
|  | 						allCoords = allCoords.concat(coords); // Combine the result | ||||||
|  | 					} | ||||||
|  |  | ||||||
|  | 					// Now add the polyline to the map | ||||||
|  | 					return L.polyline(allCoords, { | ||||||
|  | 						color: locs[0]?.options?.color, | ||||||
|  | 						weight: 3, | ||||||
|  | 						opacity: 0.8 | ||||||
|  | 					}).addTo(Leaflet.map); | ||||||
|  | 					// map.fitBounds(allCoords.map(c => L.latLng(c[0], c[1]))); | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				// Usage: Pass the array of coordinates to the function | ||||||
|  | 				const routes = await getCoordinates(latLngs); | ||||||
|  |  | ||||||
|  | 				// optionally fit bounds | ||||||
|  | 				// Leaflet.map.fitBounds(coords.map(c => L.latLng(c[0], c[1]))); | ||||||
|  |  | ||||||
|  | 				if (cb) cb(routes); | ||||||
|  | 				return routes; | ||||||
|  | 			}, | ||||||
|             // start custom polylines |             // start custom polylines | ||||||
|             addCustomPolylines: function(locs = [], cb = null) { |             addCustomPolylines: function(locs = [], cb = null) { | ||||||
|                 const radius = 0.5 /* corner smooth radius, keep value in range 0 - 0.5 to avoid artifacts */ |                 const radius = 0.5 /* corner smooth radius, keep value in range 0 - 0.5 to avoid artifacts */ | ||||||
| @ -1310,8 +1402,9 @@ | |||||||
|                     $('#infoMovement').addClass('d-block'); |                     $('#infoMovement').addClass('d-block'); | ||||||
|                     if (State.inShowVid) { |                     if (State.inShowVid) { | ||||||
|                         let cache = !(State.inShowVid != State.loadedLastMoveVid); |                         let cache = !(State.inShowVid != State.loadedLastMoveVid); | ||||||
|                         Trucks.bundleShowRouteTruck(cache); // jika data yang diload sebelumnya beda, maka tidak mengambil dari cache |                         Trucks.bundleShowRouteTruck(cache, false); // jika data yang diload sebelumnya beda, maka tidak mengambil dari cache | ||||||
|                     } |                     } | ||||||
|  | 					// Menu.clearListMovements(); | ||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             eventListVehicle: function() { |             eventListVehicle: function() { | ||||||
| @ -1354,48 +1447,14 @@ | |||||||
|                 }); |                 }); | ||||||
|             }, |             }, | ||||||
|             showToListMovement: function(obj) { |             showToListMovement: function(obj) { | ||||||
|                 /** |  | ||||||
|                  * fix DOMException: Failed to execute 'btoa' on 'Window': The string to be encoded contains |  | ||||||
|                  * because of string Cawang–Pluit |  | ||||||
|                  * solution: https://stackoverflow.com/questions/23223718/failed-to-execute-btoa-on-window-the-string-to-be-encoded-contains-characte |  | ||||||
|                  * window.btoa( unescape(encodeURIComponent(str) ) is deprecated => window.btoa(encodeURIComponent(str)) |  | ||||||
|                  */ |  | ||||||
|                 // <p class="text-muted mb-0">${(obj?.city_text || obj?.state_text || 'address')} - ${(obj?.postcode || 'postcode')}</p> |  | ||||||
|                 // <p class="text-muted mb-0">${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}</p> // yang ini mix |  | ||||||
|  |  | ||||||
|                 // <p class="text-success mb-0">Device Time: ${moment.unix(obj?.lst_loc_crt_d).format('DD MMM YYYY HH:mm')}</p> |  | ||||||
|                 // <p class="text-danger mb-0">Server Time: ${moment.unix(obj?.lst_loc_crt_s).format('DD MMM YYYY HH:mm')}</p> |  | ||||||
|                 // <p class="${(obj.pre_milleage >= 3) ? 'text-warning' : 'text-muted'} mb-0">Pre Milleage: ${(obj.pre_milleage).toFixed(3)} Km</p> |  | ||||||
|  |  | ||||||
|                 // $('#infoMove-plots').append(` |  | ||||||
|             //     <a href="#" class="plotMove-item" data-obj="${window.btoa( encodeURIComponent( JSON.stringify(obj) ) )}"> |  | ||||||
|             //         <li class="list-group-item p-1 px-2"> |  | ||||||
|             //             <p class="text-bold mb-0">${obj.key_index}</p> |  | ||||||
|             //             <p class="text-bold mb-0">Time: ${moment.unix(obj?.lst_loc_crt_d).format('DD MMM YYYY HH:mm')}</p> |  | ||||||
|             //             <p class="text-muted mb-0">Speed: ${(typeof obj.speed != 'undefined') ? obj.speed : '0'}</p> |  | ||||||
|             //             <p class="text-muted mb-0">${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}</p> |  | ||||||
|             //             <p class="text-muted mb-0">${Helper.shortenText(decodeURIComponent(obj?.fulladdress || 'address'), 25)}</p> |  | ||||||
|             //         </li> |  | ||||||
|             //     </a> |  | ||||||
|             // `); |  | ||||||
|                 let arrIdx = Helper.getIndexReversedSequence(obj.key_index - 1, Trucks.last_move.length - 1); |                 let arrIdx = Helper.getIndexReversedSequence(obj.key_index - 1, Trucks.last_move.length - 1); | ||||||
|                 // +7 | 				const unix = parseInt(obj?.lst_loc_crt_d) + AppState.TIMEFIX; | ||||||
|                 // $('#infoMove-plots').append(` |  | ||||||
|             //     <a href="#" class="plotMove-item" data-obj="${window.btoa( encodeURIComponent( JSON.stringify(obj) ) )}"> |  | ||||||
|             //         <li class="list-group-item p-1 px-2"> |  | ||||||
|             //             <p class="text-bold mb-0">${arrIdx + 1}</p> |  | ||||||
|             //             <p class="text-bold mb-0">Time: ${moment.unix(obj?.lst_loc_crt_d).format('DD MMM YYYY HH:mm:ss')}</p> |  | ||||||
|             //             <p class="text-muted mb-0">${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}</p> |  | ||||||
|             //             <p class="text-muted mb-2">${Helper.shortenText(decodeURIComponent(obj?.fulladdress || 'address'), 255)}</p> |  | ||||||
|             //             <p class="mb-0">Current speed: ${Number(obj.speed)}km/h</p> |  | ||||||
|             //         </li> |  | ||||||
|             //     </a> |  | ||||||
|             // `); |  | ||||||
|                 $('#infoMove-plots').append(` |                 $('#infoMove-plots').append(` | ||||||
|                     <a href="#" class="plotMove-item" data-obj="${window.btoa( encodeURIComponent( JSON.stringify(obj) ) )}"> |                     <a href="#" class="plotMove-item" data-obj="${window.btoa( encodeURIComponent( JSON.stringify(obj) ) )}"> | ||||||
|                         <li class="list-group-item p-1 px-2"> |                         <li class="list-group-item p-1 px-2"> | ||||||
|                             <p class="text-bold mb-0">${arrIdx + 1}</p> |                             <p class="text-bold mb-0">${arrIdx + 1}</p> | ||||||
|                             <p class="text-bold mb-0">Time: ${moment.unix(obj?.lst_loc_crt_d).format('DD MMM YYYY HH:mm:ss')}</p> |                             <p class="text-bold mb-0">Time: ${moment.unix(unix).format('DD MMM YYYY HH:mm:ss')}</p> | ||||||
|                             <p class="text-muted mb-0">${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}</p> |                             <p class="text-muted mb-0">${Number(obj.latitude).toFixed(5)} - ${Number(obj.longitude).toFixed(6)}</p> | ||||||
|                             <p class="text-muted mb-2">${Helper.shortenText(decodeURIComponent(obj?.fulladdress || 'address'), 255)}</p> |                             <p class="text-muted mb-2">${Helper.shortenText(decodeURIComponent(obj?.fulladdress || 'address'), 255)}</p> | ||||||
|                             <p class="mb-0">Current speed: ${Number(obj.speed)}km/h</p> |                             <p class="mb-0">Current speed: ${Number(obj.speed)}km/h</p> | ||||||
| @ -1417,11 +1476,12 @@ | |||||||
|             }, |             }, | ||||||
|             createMarkerDetailPlotMovement: function(tr, opt = {}) { |             createMarkerDetailPlotMovement: function(tr, opt = {}) { | ||||||
|                 Leaflet.clearLayer('eventRemoveDetailPlotMovement'); |                 Leaflet.clearLayer('eventRemoveDetailPlotMovement'); | ||||||
|  | 				const unix = parseInt(tr?.lst_loc_crt_d) + AppState.TIMEFIX; | ||||||
|                 let marker = Leaflet.addMarkers({ |                 let marker = Leaflet.addMarkers({ | ||||||
|                     lat: tr.latitude, |                     lat: tr.latitude, | ||||||
|                     lng: tr.longitude, |                     lng: tr.longitude, | ||||||
|                     // label: `<b>${tr.key_index}</b><br>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}<br>${moment.unix(tr?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>Speed: ${(typeof tr.lst_speed != 'undefined') ? tr.lst_speed : '0'}<br>${tr.latitude},${tr.longitude}<br>${decodeURIComponent(tr?.fulladdress || 'address')}`, |                     // label: `<b>${tr.key_index}</b><br>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}<br>${moment.unix(tr?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>Speed: ${(typeof tr.lst_speed != 'undefined') ? tr.lst_speed : '0'}<br>${tr.latitude},${tr.longitude}<br>${decodeURIComponent(tr?.fulladdress || 'address')}`, | ||||||
|                     label: `<b>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}</b><br>${moment.unix(tr?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br>${decodeURIComponent(tr?.fulladdress || 'address')}.<br><br>Current speed: ${tr?.speed}km/h`, |                     label: `<b>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}</b><br>${moment.unix(unix).format('DD MMM YYYY HH:mm')}<br>${decodeURIComponent(tr?.fulladdress || 'address')}.<br><br>Current speed: ${tr?.speed}km/h`, | ||||||
|                     //label: `<b>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}</b><br>${moment.unix(tr?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}<br>${decodeURIComponent(tr?.fulladdress || 'address')}.<br><br>Current speed: ${tr?.speed}km/h`, |                     //label: `<b>${tr.nopol1} ${tr.nopol2} ${tr.nopol3}</b><br>${moment.unix(tr?.lst_loc_crt_d).utcOffset(9 * 60).format('DD MMM YYYY HH:mm:ss')}<br>${decodeURIComponent(tr?.fulladdress || 'address')}.<br><br>Current speed: ${tr?.speed}km/h`, | ||||||
|                     options: { |                     options: { | ||||||
|                         // icon: Icon.destination() |                         // icon: Icon.destination() | ||||||
| @ -1559,7 +1619,7 @@ | |||||||
| 					$('#historyStartDate').val(moment().startOf('day').format('DD-MM-YYYY HH:mm')); | 					$('#historyStartDate').val(moment().startOf('day').format('DD-MM-YYYY HH:mm')); | ||||||
| 					$('#historyEndDate').val(moment().endOf('day').format('DD-MM-YYYY HH:mm')); | 					$('#historyEndDate').val(moment().endOf('day').format('DD-MM-YYYY HH:mm')); | ||||||
|  |  | ||||||
| 					// // for testing purpose | 					// for testing purpose | ||||||
|                     // State.historyStartDate = '1756054800'; |                     // State.historyStartDate = '1756054800'; | ||||||
|                     // State.historyEndDate = '1756141140'; |                     // State.historyEndDate = '1756141140'; | ||||||
| 					// $('#historyStartDate').val("25-08-2025 00:00"); | 					// $('#historyStartDate').val("25-08-2025 00:00"); | ||||||
| @ -2576,19 +2636,21 @@ | |||||||
|                 // last movement |                 // last movement | ||||||
|                 // $('#infoVehicles-infoMove').text('Last 24H from ' + moment.unix(truck?.lst_loc_crt).format('DD MMM YYYY HH:mm')); |                 // $('#infoVehicles-infoMove').text('Last 24H from ' + moment.unix(truck?.lst_loc_crt).format('DD MMM YYYY HH:mm')); | ||||||
|             }, |             }, | ||||||
|             bundleShowRouteTruck: async function(cache = false) { |             bundleShowRouteTruck: async function(cache = false, needUpdate = true) { | ||||||
|                 Menu.clearListMovements(); |                 Menu.clearListMovements(); | ||||||
|                 if (State.inShowVid != State.loadedLastMoveVid) $('#historyStartDate').trigger('clearFilterHistoryDate'); |                 if (State.inShowVid != State.loadedLastMoveVid)$('#historyStartDate').trigger('clearFilterHistoryDate'); | ||||||
|  |  | ||||||
| 				const getLastMove = await Trucks.getLastMove(State.inShowVid, cache); | 				if(needUpdate){ | ||||||
| 				Trucks.last_move = getLastMove.flat() | 					const getLastMove = await Trucks.getLastMove(State.inShowVid, cache); | ||||||
|  | 					Trucks.last_move = getLastMove.flat() | ||||||
| 					 | 					 | ||||||
|                 if (Trucks.last_move.length < 1) { | 					if (Trucks.last_move.length < 1) { | ||||||
|                     Helper.toast('Data Not Found', 'just now', 'There are no last data', 'bg-warning'); | 						Helper.toast('Data Not Found', 'just now', 'There are no last data', 'bg-warning'); | ||||||
|                     Trucks.last_move = null; | 						Trucks.last_move = null; | ||||||
|                     return false; | 						return false; | ||||||
|                 } | 					} | ||||||
|                 Trucks.showLastMoveToView(getLastMove); | 					Trucks.showLastMoveToView(getLastMove);					 | ||||||
|  | 				} | ||||||
|             }, |             }, | ||||||
|             getLastMove: async function(vid, cache = false) { |             getLastMove: async function(vid, cache = false) { | ||||||
|                 State.loadedLastMoveVid = vid; |                 State.loadedLastMoveVid = vid; | ||||||
| @ -2741,7 +2803,7 @@ | |||||||
|  |  | ||||||
| 				//     PgBar.setMinMax(0, truckRoutes.length - 1); | 				//     PgBar.setMinMax(0, truckRoutes.length - 1); | ||||||
|             // }, |             // }, | ||||||
|             routeStartEndGroupTrip:  function(truckRoutes) { |             routeStartEndGroupTrip: async function(truckRoutes) { | ||||||
| 				const colors = [ | 				const colors = [ | ||||||
| 					"#2980B9",  // Dark Blue | 					"#2980B9",  // Dark Blue | ||||||
| 					"#C0392B", // Dark Red | 					"#C0392B", // Dark Red | ||||||
| @ -2750,6 +2812,7 @@ | |||||||
| 					"#F39C12", // Dark Yellow/Gold | 					"#F39C12", // Dark Yellow/Gold | ||||||
| 				] | 				] | ||||||
| 				let i = 1 | 				let i = 1 | ||||||
|  | 				let allStartStop = [] | ||||||
| 				let polyTruckRoutes = truckRoutes.map((groupTrip, key0) => { | 				let polyTruckRoutes = truckRoutes.map((groupTrip, key0) => { | ||||||
| 					return groupTrip.map((obj, key) => { | 					return groupTrip.map((obj, key) => { | ||||||
| 						obj.key_index = i++ | 						obj.key_index = i++ | ||||||
| @ -2758,12 +2821,12 @@ | |||||||
| 						Menu.showToListMovement(obj) | 						Menu.showToListMovement(obj) | ||||||
| 						 | 						 | ||||||
| 						// add start end marker per group trip | 						// add start end marker per group trip | ||||||
| 						if(key == 0 || key == groupTrip.length - 1) | 						if(key == 0 || key == groupTrip.length - 1){ | ||||||
| 							Leaflet.addMarkers({ | 							const marker = Leaflet.addMarkers({ | ||||||
| 								lat: obj.latitude, | 								lat: obj.latitude, | ||||||
| 								lng: obj.longitude, | 								lng: obj.longitude, | ||||||
| 								label: ` | 								label: ` | ||||||
| 									<b>Start Poin</b><br>${obj.nopol1} ${obj.nopol2} ${obj.nopol3}<br> | 									<b>${(key == 0) ? 'Finish' : 'Start'} Poin</b><br>${obj.nopol1} ${obj.nopol2} ${obj.nopol3}<br> | ||||||
| 									${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br> | 									${moment.unix(obj?.lst_loc_crt).format('DD MMM YYYY HH:mm')}<br> | ||||||
| 									Speed: ${(typeof obj.lst_speed != 'undefined') ? obj.lst_speed : '0'}<br> | 									Speed: ${(typeof obj.lst_speed != 'undefined') ? obj.lst_speed : '0'}<br> | ||||||
| 									${Number(obj.latitude).toFixed(5)},${Number(obj.longitude).toFixed(6)}<br> | 									${Number(obj.latitude).toFixed(5)},${Number(obj.longitude).toFixed(6)}<br> | ||||||
| @ -2775,6 +2838,10 @@ | |||||||
| 									// rotationAngle: 290 | 									// rotationAngle: 290 | ||||||
| 								} | 								} | ||||||
| 							}) | 							}) | ||||||
|  | 							allStartStop.push(marker) | ||||||
|  | 						} | ||||||
|  |  | ||||||
|  | 						const unix = parseInt(obj?.lst_loc_crt_d) + AppState.TIMEFIX; | ||||||
|  |  | ||||||
| 						return { | 						return { | ||||||
| 							lat: obj.latitude, | 							lat: obj.latitude, | ||||||
| @ -2789,84 +2856,73 @@ | |||||||
| 								radius: 5, | 								radius: 5, | ||||||
| 								markerOpacity: 0 | 								markerOpacity: 0 | ||||||
| 							}, | 							}, | ||||||
| 							label: `<b>${obj.nopol1} ${obj.nopol2} ${obj.nopol3}</b><br>${moment.unix(obj?.lst_loc_crt_d).format('DD MMM YYYY HH:mm:ss')}<br>${decodeURIComponent(obj?.fulladdress || 'address')}`, | 							label: `<b>${obj.nopol1} ${obj.nopol2} ${obj.nopol3}</b><br>${moment.unix(unix).format('DD MMM YYYY HH:mm:ss')}<br>${decodeURIComponent(obj?.fulladdress || 'address')}`, | ||||||
| 							// startLast : (key == 0) ? 0 : (key == (groupTrip.length - 1)) ? 1 : null, | 							// startLast : (key == 0) ? 0 : (key == (groupTrip.length - 1)) ? 1 : null, | ||||||
| 						} | 						} | ||||||
| 					})					 | 					})					 | ||||||
| 				}) | 				}) | ||||||
| 				// console.log("truckRoutes update", polyTruckRoutes); | 				// console.log("truckRoutes update", polyTruckRoutes); | ||||||
|  |  | ||||||
| 				polyTruckRoutes.forEach(async (poly, idx) => { | 				let circleCounter = 0 | ||||||
|  | 				for (const [idx, poly] of polyTruckRoutes.entries()) { | ||||||
| 					// console.log("poly", poly);					 | 					// console.log("poly", poly);					 | ||||||
| 					let polyline = Leaflet.addRoutes(poly) | 					function addCirclesAsync(polyCircle) { | ||||||
| 					// let polyline = Leaflet.addPolylines(poly) | 						// console.log("circleCounter", circleCounter); | ||||||
| 						 | 						 | ||||||
| 					// let circlesStartStop = [] | 						// return array of circles start end only | ||||||
| 					// Leaflet.addCircles(poly, function(circle, i) { |  | ||||||
| 					// 	if(i == 0 || i == (polyTruckRoutes.length - 1)) |  | ||||||
| 					// 		circlesStartStop.push(circle) |  | ||||||
|  |  | ||||||
| 					// 	window.addEventListener('eventRemoveRouteStartEnd', function handler(e) { |  | ||||||
| 					// 		circle.remove(); |  | ||||||
| 					// 	}); |  | ||||||
| 					// 	circle.on('click', function() { |  | ||||||
| 					// 		PgBar.syncToPlotTravelHistory(i); |  | ||||||
| 					// 	}) |  | ||||||
| 					// }); |  | ||||||
| 					function addCirclesAsync(poly) { |  | ||||||
| 						return new Promise(resolve => { | 						return new Promise(resolve => { | ||||||
| 							let circles = []; | 							let circles = []; | ||||||
|  |  | ||||||
| 							Leaflet.addCircles(poly, function(circle, i) { | 							Leaflet.addCircles(polyCircle, function(circle, i) { | ||||||
| 								if (i === 0 || i === (poly.length - 1)) { | 								// console.log("circle", i, circleCounter); | ||||||
|  | 								 | ||||||
|  | 								if (i === 0 || i === (polyCircle.length - 1)) { | ||||||
| 									circles.push(circle); | 									circles.push(circle); | ||||||
| 								} | 								} | ||||||
|  |  | ||||||
|  | 								const currentCounter = circleCounter; | ||||||
| 								circle.on('click', function() { | 								circle.on('click', function() { | ||||||
| 									PgBar.syncToPlotTravelHistory(i); | 									PgBar.syncToPlotTravelHistory(currentCounter); | ||||||
| 								}); | 								}); | ||||||
|  | 								circleCounter++ | ||||||
|  |  | ||||||
| 								// ✅ When last point processed, resolve | 								// ✅ When last point processed, resolve | ||||||
| 								if (i === poly.length - 1) { | 								if (i === polyCircle.length - 1) { | ||||||
| 									resolve(circles); | 									resolve(circles); | ||||||
| 								} | 								} | ||||||
| 							}); | 							}); | ||||||
| 						}); | 						}); | ||||||
| 					} | 					} | ||||||
|  |  | ||||||
| 					let circlesStartStop = []; | 					let polyline = await Leaflet.addRoutes(poly); | ||||||
| 					for (let [idx, poly] of polyTruckRoutes.entries()) { | 					// console.log("polyline", polyline); | ||||||
| 						let polyline = Leaflet.addRoutes(poly); | 					allStartStop.push(polyline) | ||||||
|  |  | ||||||
| 						// wait for all circles | 					// wait for all circles | ||||||
| 						circlesStartStop = await addCirclesAsync(poly); | 					const ssmarker = await addCirclesAsync(poly); | ||||||
|  | 					// console.log("ssmarker", ssmarker); | ||||||
|  | 					allStartStop.push(...ssmarker) | ||||||
|  | 				} | ||||||
| 					 | 					 | ||||||
| 						// keep event + removal logic here | 				console.log("allStartStop", allStartStop); | ||||||
| 						State.eventRemoveRouteStartEnd = new CustomEvent('eventRemoveRouteStartEnd', { | 				// console.log("circlesStartStop", circlesStartStop); | ||||||
| 							detail: { polyline, circlesStartStop } |  | ||||||
| 						}); |  | ||||||
| 				 | 				 | ||||||
| 						window.addEventListener('eventRemoveRouteStartEnd', function(e) { | 				// // remove marker, circle, event listener and all about this marker | ||||||
| 							polyline.remove(); | 				State.eventRemoveRouteStartEnd = new CustomEvent('eventRemoveRouteStartEnd', { | ||||||
| 							circlesStartStop.forEach(c => c.remove()); | 					// detail: { | ||||||
| 						}); | 						allStartStop, | ||||||
| 					} | 						// circlesStartStop | ||||||
|  | 					// } | ||||||
|  | 				}); | ||||||
|  |  | ||||||
| 					// // remove marker, circle, event listener and all about this marker | 				// window.addEventListener('eventRemoveRouteStartEnd', function (e) { | ||||||
| 					State.eventRemoveRouteStartEnd = new CustomEvent('eventRemoveRouteStartEnd', { | 				// 	// allStartStop.remove(); | ||||||
| 						detail: { | 				// 	allStartStop.forEach(c => c.remove()) | ||||||
| 							polyline, | 				// 	// circlesStartStop.forEach(c => c.remove()) | ||||||
| 							circlesStartStop | 				// }); | ||||||
| 						} |  | ||||||
| 					}); |  | ||||||
|  |  | ||||||
| 					window.addEventListener('eventRemoveRouteStartEnd', function (e) { |  | ||||||
| 						polyline.remove(); |  | ||||||
| 						circlesStartStop.forEach(c => c.remove()) |  | ||||||
| 					}); |  | ||||||
| 				}) |  | ||||||
|  |  | ||||||
|                 window.addEventListener('eventRemoveRouteStartEnd', function handler(e) { |                 window.addEventListener('eventRemoveRouteStartEnd', function handler(e) { | ||||||
|  | 					allStartStop.forEach(c => c.remove()) | ||||||
|                     e.currentTarget.removeEventListener(e.type, |                     e.currentTarget.removeEventListener(e.type, | ||||||
|                         handler); // window.removeEventListener('remove', this.handler, true); |                         handler); // window.removeEventListener('remove', this.handler, true); | ||||||
|                     State.eventRemoveRouteStartEnd = null; |                     State.eventRemoveRouteStartEnd = null; | ||||||
| @ -3436,6 +3492,8 @@ | |||||||
|                 } |                 } | ||||||
|             }, |             }, | ||||||
|             syncToPlotTravelHistory: function(arrIdx) { |             syncToPlotTravelHistory: function(arrIdx) { | ||||||
|  | 				console.log("syncToPlotTravelHistory", arrIdx); | ||||||
|  | 				 | ||||||
|                 const listPlotTravelHistory = document.querySelectorAll('#infoMove-plots .plotMove-item')[arrIdx]; |                 const listPlotTravelHistory = document.querySelectorAll('#infoMove-plots .plotMove-item')[arrIdx]; | ||||||
|                 listPlotTravelHistory.scrollIntoView(); |                 listPlotTravelHistory.scrollIntoView(); | ||||||
|                 listPlotTravelHistory.querySelector('li').classList.add('hover'); |                 listPlotTravelHistory.querySelector('li').classList.add('hover'); | ||||||
|  | |||||||
							
								
								
									
										347
									
								
								resources/views/menu_v1/reports/_trip_detail.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										347
									
								
								resources/views/menu_v1/reports/_trip_detail.blade.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,347 @@ | |||||||
|  | <style> | ||||||
|  | 	#map { | ||||||
|  | 		height: 100%; | ||||||
|  | 		margin: 0; | ||||||
|  | 	} | ||||||
|  | 	.my-leaflet-map-container img { | ||||||
|  | 		max-height: none; | ||||||
|  | 	} | ||||||
|  | 	.dtl-text{ | ||||||
|  | 		font-size: 11px; | ||||||
|  | 	} | ||||||
|  | 	.head-text{ | ||||||
|  | 		font-size: 12px !important; | ||||||
|  | 	} | ||||||
|  | 	/* .leaflet-overlay-pane svg { | ||||||
|  | 		transform: none !important; | ||||||
|  | 	} */ | ||||||
|  | 	.leaflet-routing-container { | ||||||
|  | 		display: none !important; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	#viewPdf { | ||||||
|  | 		display: flex; | ||||||
|  | 		justify-content: center; | ||||||
|  | 		width: 794px; | ||||||
|  | 		/* height: auto; */ | ||||||
|  | 		max-width: 100%; /* Ensures it is responsive */ | ||||||
|  | 	} | ||||||
|  | 	/* .modal-dialog{ | ||||||
|  | 		width: 794px; | ||||||
|  | 	} */ | ||||||
|  |  | ||||||
|  | </style> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <div class="modal-dialog modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg"> | ||||||
|  | 	<div class="modal-content"> | ||||||
|  | 		<div class="modal-header"> | ||||||
|  | 			<h5 class="modal-title" id="mdlDetailTripLabel">{{$nopol1}} Trip Detail</h5> | ||||||
|  | 			<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||||||
|  | 		</div> | ||||||
|  | 		<div class="modal-body"> | ||||||
|  | 			<div class="row head-text" id="viewPdf"> | ||||||
|  | 				<div class="col-12"> | ||||||
|  | 					<h4>{{$nopol1}}</h4> | ||||||
|  | 				</div> | ||||||
|  | 				<div class="col-4"> | ||||||
|  | 					<p class="text-bold mb-0">Start</p> | ||||||
|  | 					<p class="mb-0 time">{{ $start['time'] }}</p>	 | ||||||
|  | 					<p class="mb-0">Vehicle Mileage: {{number_format($start['mileage'], 2)}} km</p> | ||||||
|  | 					<p>{{$start['fulladdress']}}</p> | ||||||
|  | 				</div> | ||||||
|  | 				<div class="col-4"> | ||||||
|  | 					<p class="text-bold mb-0">Finish</p> | ||||||
|  | 					<p class="mb-0 time">{{ $finish['time'] }}</p>	 | ||||||
|  | 					<p class="mb-0">Vehicle Mileage: {{number_format($finish['mileage'], 2)}} km</p> | ||||||
|  | 					<p>{{$finish['fulladdress']}}</p> | ||||||
|  | 				</div> | ||||||
|  | 				<div class="col-2"> | ||||||
|  | 					<p class="text-bold mb-0">Distance</p> | ||||||
|  | 					<p class="mb-0">{{number_format($distance, 2)}} km</p>	 | ||||||
|  | 				</div> | ||||||
|  | 				<div class="col-2"> | ||||||
|  | 					<p class="text-bold mb-0">Duration</p> | ||||||
|  | 					<p class="mb-0">{{$duration}}</p>	 | ||||||
|  | 				</div> | ||||||
|  | 				<div class="col-12"> | ||||||
|  | 					<div id="leafMap" style="height: 400px;"></div> | ||||||
|  | 				</div> | ||||||
|  | 				<div class="col-12"> | ||||||
|  | 					<!-- <li class="list-group-item p-1 px-2"> | ||||||
|  | 						<p class="text-bold mb-0">Time: 25 Aug 2025 07:31:08</p> | ||||||
|  | 						<p class="text-muted mb-0 dtl-text">-8.55387 - 125.542409</p> | ||||||
|  | 						<p class="text-muted mb-0 dtl-text">Avenida Luro Mata, Praia dos Coqueiros, Bebunuk, Dom Aleixo, Dili, Timor-Leste;2066973</p> | ||||||
|  | 						<p class="mb-0 dtl-text">Current speed: 7km/h</p> | ||||||
|  | 					</li> --> | ||||||
|  | 					@foreach ($list as $item) | ||||||
|  | 						<!-- <li class="list-group-item p-1 px-2"> | ||||||
|  | 							<p class="text-bold mb-0">Time: {{date('d-m-Y H:i:s', $item->crt_d)}}</p> | ||||||
|  | 							<p class="text-muted mb-0 dtl-text">Vehicle Mileage: {{number_format($item->vhc_milleage, 2)}} km</p> | ||||||
|  | 							<p class="text-muted mb-0 dtl-text">{{number_format($item->latitude, 6)}} - {{number_format($item->longitude, 6)}}</p> | ||||||
|  | 							<p class="text-muted mb-0 dtl-text">{{urldecode($item->fulladdress)}}</p> | ||||||
|  | 							<p class="text-muted mb-0 dtl-text">Current speed: {{number_format($item->speed, 2)}} km/h</p> | ||||||
|  | 						</li> --> | ||||||
|  | 						<li class="list-group-item p-1 px-2"> | ||||||
|  | 							<div class="row"> | ||||||
|  | 								<div class="col-4"> | ||||||
|  | 									<p class="text-bold mb-0 dtl-text">Time: <span class="time">{{ $item->crt_d }}</span></p> | ||||||
|  | 									<p class="text-muted mb-0 dtl-text">Vehicle Mileage: {{number_format($item->vhc_milleage, 2)}} km</p> | ||||||
|  | 									<p class="text-muted mb-0 dtl-text">Current speed: {{$item->speed}} km/h</p> | ||||||
|  | 								</div> | ||||||
|  | 								<div class="col-8"> | ||||||
|  | 									<p class="text-muted mb-0 dtl-text">{{number_format($item->latitude, 6)}}, {{number_format($item->longitude, 6)}}</p> | ||||||
|  | 									<p class="text-muted mb-0 dtl-text">{{urldecode($item->fulladdress)}}</p> | ||||||
|  | 								</div> | ||||||
|  | 							</div> | ||||||
|  | 						</li>	 | ||||||
|  | 					@endforeach | ||||||
|  | 				</div> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  | 		<div class="modal-footer"> | ||||||
|  | 			<button class="btn btn-sm btn-danger ms-auto" id="btnDownloadReport">Download Report</button> | ||||||
|  | 		</div> | ||||||
|  | 	</div> | ||||||
|  | </div> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | 	$(document).ready(function(){ | ||||||
|  | 		$('.time').each(function () { | ||||||
|  | 			const unix = parseInt($(this).text().trim()) + AppState.TIMEFIX; | ||||||
|  | 			$(this).text(moment.unix(unix).format('DD MMM YYYY HH:mm:ss')); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		let coords | ||||||
|  | 		setTimeout(async() => { | ||||||
|  | 			map.invalidateSize();            // force Leaflet to recalc | ||||||
|  | 			map.fitBounds(polyline.getBounds()); | ||||||
|  | 			// map.fitBounds(await coords.map(c => L.latLng(c[0], c[1]))); | ||||||
|  | 		}, 200); | ||||||
|  |  | ||||||
|  | 		const linesData = (@json($list)); | ||||||
|  |  | ||||||
|  | 		// 1) Initialize map | ||||||
|  | 		const map = L.map("leafMap").setView([-8.90507, 125.9945732], 10) | ||||||
|  |  | ||||||
|  | 		// 2) Add tile layer | ||||||
|  | 		L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", { | ||||||
|  | 			maxZoom: 20, | ||||||
|  | 			crossOrigin: true | ||||||
|  | 		}).addTo(map); | ||||||
|  |  | ||||||
|  | 		// // // 3) Coordinates (Lat, Lng) for polyline | ||||||
|  | 		const points = linesData | ||||||
|  | 			.filter(p => p.latitude && p.longitude) | ||||||
|  | 			.map((point) => [point.latitude, point.longitude]) | ||||||
|  |  | ||||||
|  | 		// 4) Add polyline | ||||||
|  | 		const polyline = L.polyline(points,{ | ||||||
|  | 			color: 'red', | ||||||
|  | 			weight: 3, | ||||||
|  | 			opacity: 0.7, | ||||||
|  | 			smoothFactor: 1 | ||||||
|  | 		}) | ||||||
|  | 		// .addTo(map); | ||||||
|  |  | ||||||
|  | 		// const lines = L.Routing.control({ | ||||||
|  | 		// 	waypoints: points, | ||||||
|  | 		// 	// router: L.Routing.osrmv1(), | ||||||
|  | 		// 	router: L.Routing.osrmv1({ | ||||||
|  | 		// 		serviceUrl: "https://brilianapps.britimorleste.tl:5001/route/v1", | ||||||
|  | 		// 	}), | ||||||
|  | 		// 	show: false, | ||||||
|  | 		// 	itinerary: null, // 👈 completely removes the panel | ||||||
|  | 		// 	addWaypoints: false, // ❌ prevent adding points by clicking | ||||||
|  | 		// 	draggableWaypoints: false, // ❌ prevent dragging markers | ||||||
|  | 		// 	routeWhileDragging: false, // optional: don’t reroute while dragging | ||||||
|  | 		// 	createMarker: () => null, | ||||||
|  | 		// 	routingOptions: { | ||||||
|  | 		// 	radiuses: [100, 100] // tolerance in meters per waypoint | ||||||
|  | 		// 	}, | ||||||
|  | 		// 	lineOptions:{ | ||||||
|  | 		// 		styles: [{ color: "#C0392B", weight: 4, opacity: 0.7 }], | ||||||
|  | 		// 	}, | ||||||
|  | 		// }).addTo(map) | ||||||
|  |  | ||||||
|  | 		function chunkArray(arr, size) { | ||||||
|  | 			const result = []; | ||||||
|  | 			for (let i = 0; i < arr.length; i += size) { | ||||||
|  | 				result.push(arr.slice(i, i + size)); | ||||||
|  | 			} | ||||||
|  | 			return result; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		function fetchOsrm(points) { | ||||||
|  | 			const coords = points; | ||||||
|  | 			const hints = ";".repeat(points.length - 1); | ||||||
|  |  | ||||||
|  | 			const body = { | ||||||
|  | 				coordinates: coords, | ||||||
|  | 				overview: "false", | ||||||
|  | 				alternatives: "false", | ||||||
|  | 				steps: "true", | ||||||
|  | 				hints: hints | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			let config = { | ||||||
|  | 				method: 'post', | ||||||
|  | 				maxBodyLength: Infinity, | ||||||
|  | 				url: 'https://brilianapps.britimorleste.tl/osrm-backend/post-route/v1/driving/', | ||||||
|  | 				headers: { | ||||||
|  | 					'Content-Type': 'application/json' | ||||||
|  | 				}, | ||||||
|  | 				data: body | ||||||
|  | 			}; | ||||||
|  |  | ||||||
|  | 			return axios.request(config) | ||||||
|  | 				.then((response) => { | ||||||
|  | 					return response.data; | ||||||
|  | 				}) | ||||||
|  | 				.catch((error) => { | ||||||
|  | 					console.error("Error:", error.message); | ||||||
|  | 					return null; | ||||||
|  | 				}); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		function decodeOSRMGeometry(encoded) { | ||||||
|  | 			const coordinates = []; | ||||||
|  | 			let index = 0, | ||||||
|  | 				lat = 0, | ||||||
|  | 				lng = 0; | ||||||
|  |  | ||||||
|  | 			while (index < encoded.length) { | ||||||
|  | 				let result = 1, | ||||||
|  | 					shift = 0, | ||||||
|  | 					b; | ||||||
|  | 				do { | ||||||
|  | 					b = encoded.charCodeAt(index++) - 63 - 1; | ||||||
|  | 					result += b << shift; | ||||||
|  | 					shift += 5; | ||||||
|  | 				} while (b >= 0x1f); | ||||||
|  | 				lat += (result & 1 ? ~(result >> 1) : result >> 1); | ||||||
|  |  | ||||||
|  | 				result = 1; | ||||||
|  | 				shift = 0; | ||||||
|  | 				do { | ||||||
|  | 					b = encoded.charCodeAt(index++) - 63 - 1; | ||||||
|  | 					result += b << shift; | ||||||
|  | 					shift += 5; | ||||||
|  | 				} while (b >= 0x1f); | ||||||
|  | 				lng += (result & 1 ? ~(result >> 1) : result >> 1); | ||||||
|  |  | ||||||
|  | 				coordinates.push([lat / 1e5, lng / 1e5]); | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			return coordinates; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		async function getCoordinates(points) { | ||||||
|  | 			const chunkSize = 500; | ||||||
|  | 			const chunks = chunkArray(points, chunkSize); // Split the points array into chunks of 500 | ||||||
|  | 			let allCoords = []; | ||||||
|  |  | ||||||
|  | 			for (const chunk of chunks) { | ||||||
|  | 				const osrm = await fetchOsrm(chunk); // Fetch OSRM data for each chunk | ||||||
|  |  | ||||||
|  | 				if (!osrm) { | ||||||
|  | 					console.log("OSRM failed for chunk"); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				const coords = osrm.routes[0].legs.flatMap(leg => | ||||||
|  | 					leg.steps.flatMap(step => | ||||||
|  | 						decodeOSRMGeometry(step.geometry) | ||||||
|  | 					) | ||||||
|  | 				); | ||||||
|  |  | ||||||
|  | 				allCoords = allCoords.concat(coords); // Combine the result | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// Now add the polyline to the map | ||||||
|  | 			L.polyline(allCoords, { | ||||||
|  | 				color: "#2980B9", | ||||||
|  | 				weight: 3, | ||||||
|  | 				opacity: 0.8 | ||||||
|  | 			}).addTo(map); | ||||||
|  | 			// map.fitBounds(allCoords.map(c => L.latLng(c[0], c[1]))); | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Usage: Pass the array of coordinates to the function | ||||||
|  | 		getCoordinates(points); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 		// start and finish point | ||||||
|  | 		const startIcon = L.icon({ | ||||||
|  | 			iconUrl: "{{ asset('images/start.png') }}", | ||||||
|  | 			iconSize: [30, 30], | ||||||
|  | 			iconAnchor: [15, 28], // lb, rt, bottom, rb. Positive | ||||||
|  | 		}) | ||||||
|  | 		L.marker(points[0], {icon: startIcon}).addTo(map) | ||||||
|  |  | ||||||
|  | 		const finishIcon = L.icon({ | ||||||
|  | 			iconUrl: "{{ asset('images/finish.png') }}", | ||||||
|  | 			iconSize: [30, 30], | ||||||
|  | 			iconAnchor: [15, 28], // lb, rt, bottom, rb. Positive | ||||||
|  | 		}) | ||||||
|  | 		L.marker(points[points.length - 1], {icon: finishIcon}).addTo(map) | ||||||
|  |  | ||||||
|  | 		// // 5) Auto-fit map to polyline bounds | ||||||
|  | 		// map.fitBounds(polyline.getBounds()) | ||||||
|  |  | ||||||
|  | 		// download pdf | ||||||
|  | 		window._downloadReportBound ||= ( | ||||||
|  | 			$(document).on('click', '#btnDownloadReport', function () { | ||||||
|  | 				$('#viewPdf').printThis({ | ||||||
|  | 					debug: false,               // show the iframe for debugging | ||||||
|  | 					importCSS: true,            // copy linked styles | ||||||
|  | 					importStyle: true,          // copy inline styles | ||||||
|  | 				}); | ||||||
|  |  | ||||||
|  | 				// const viewPdf = document.getElementById("viewPdf"); | ||||||
|  |  | ||||||
|  | 				// // find overlay svg (the one holding polylines) | ||||||
|  | 				// const overlaySvg = document.querySelector('.leaflet-overlay-pane svg'); | ||||||
|  | 				// let originalTransform = ''; | ||||||
|  | 				// if (overlaySvg) { | ||||||
|  | 				// 	originalTransform = overlaySvg.style.transform; | ||||||
|  | 				// 	overlaySvg.style.transform = 'none'; | ||||||
|  | 				// } | ||||||
|  | 			 | ||||||
|  | 				// html2canvas(viewPdf, {  | ||||||
|  | 				// 	scale: 2,  | ||||||
|  | 				// 	useCORS: true,  | ||||||
|  | 				// 	logging: true | ||||||
|  | 				// }).then(canvas => { | ||||||
|  | 				// 	const imgData = canvas.toDataURL('image/png'); | ||||||
|  | 				// 	const { jsPDF } = window.jspdf; | ||||||
|  |  | ||||||
|  | 				// 	const pdf = new jsPDF('p', 'mm', 'a4'); | ||||||
|  | 				// 	const pageWidth = pdf.internal.pageSize.getWidth(); | ||||||
|  | 				// 	const pageHeight = pdf.internal.pageSize.getHeight(); | ||||||
|  |  | ||||||
|  | 				// 	const imgWidth = pageWidth - 20; // margin | ||||||
|  | 				// 	const imgHeight = canvas.height * imgWidth / canvas.width; | ||||||
|  |  | ||||||
|  | 				// 	let position = 10; | ||||||
|  |  | ||||||
|  | 				// 	// 👉 Handle multipage content | ||||||
|  | 				// 	let heightLeft = imgHeight; | ||||||
|  | 				// 	while (heightLeft > 0) { | ||||||
|  | 				// 		pdf.addImage(imgData, 'PNG', 10, position, imgWidth, imgHeight); | ||||||
|  | 				// 		heightLeft -= pageHeight; | ||||||
|  | 				// 		if (heightLeft > 0) { | ||||||
|  | 				// 			pdf.addPage(); | ||||||
|  | 				// 			position = 0; | ||||||
|  | 				// 		} | ||||||
|  | 				// 	} | ||||||
|  | 			 | ||||||
|  | 				// 	pdf.save(`{{$nopol1}} Trip Report {{$start['time']}}.pdf`); | ||||||
|  |  | ||||||
|  | 				// }); | ||||||
|  | 			}), | ||||||
|  | 			true | ||||||
|  | 		); | ||||||
|  |  | ||||||
|  | 	}); | ||||||
|  | </script> | ||||||
| @ -43,7 +43,7 @@ | |||||||
| 							<div class="form-group"> | 							<div class="form-group"> | ||||||
| 								<label class="text-muted">From</label> | 								<label class="text-muted">From</label> | ||||||
| 								<!-- default today --> | 								<!-- default today --> | ||||||
| 								<!-- <input type="date" class="form-control" id="tgl0" value="{{ date('Y-m-d') }}"> --> | 								<!-- <input class="form-control" id="tgl0" value="20-08-2025 00:00"> --> | ||||||
| 								<input class="form-control" id="tgl0" value="{{ date('d-m-Y 00:00') }}"> | 								<input class="form-control" id="tgl0" value="{{ date('d-m-Y 00:00') }}"> | ||||||
| 							</div> | 							</div> | ||||||
| 						</div> | 						</div> | ||||||
| @ -65,7 +65,7 @@ | |||||||
| 							</div> | 							</div> | ||||||
| 						</div> | 						</div> | ||||||
| 						<div class="col-1 d-flex align-items-end"> | 						<div class="col-1 d-flex align-items-end"> | ||||||
| 							<button class="btn btn-sm btn-primary" id="submitFilter">Submit</button> | 							<button class="btn btn-primary" id="submitFilter">Submit</button> | ||||||
| 						</div> | 						</div> | ||||||
| 						<div class="col-5 d-flex align-items-end"> | 						<div class="col-5 d-flex align-items-end"> | ||||||
| 							<button class="btn btn-sm btn-danger ms-auto" id="btnDownloadReport">Download Report</button> | 							<button class="btn btn-sm btn-danger ms-auto" id="btnDownloadReport">Download Report</button> | ||||||
| @ -78,8 +78,10 @@ | |||||||
|                                 <tr class=""> |                                 <tr class=""> | ||||||
|                                     <!-- <th class="">Vehicle ID</th> --> |                                     <!-- <th class="">Vehicle ID</th> --> | ||||||
|                                     <!-- <th class="text-center">Action</th> --> |                                     <!-- <th class="text-center">Action</th> --> | ||||||
|                                     <th class="">Vehicle Name</th> |                                     <!-- <th class="">Vehicle Name</th> --> | ||||||
|                                     <th class="">License Plate Number</th> |                                     <th class="">License Plate Number</th> | ||||||
|  | 									<th class="">Dist. Cat.</th> | ||||||
|  | 									<th class="">Pool</th> | ||||||
|                                     <th class="">Time</th> |                                     <th class="">Time</th> | ||||||
|                                     <th class="">Speed (kph)</th> |                                     <th class="">Speed (kph)</th> | ||||||
|                                     <th class="">Location</th> |                                     <th class="">Location</th> | ||||||
| @ -116,8 +118,7 @@ | |||||||
|             activate: function() { |             activate: function() { | ||||||
|                 Wrapper.init(); |                 Wrapper.init(); | ||||||
|                 Wrapper.event(); |                 Wrapper.event(); | ||||||
|                 DTable.activate(); |                 // DTable.activate(); | ||||||
|  |  | ||||||
| 			}, | 			}, | ||||||
| 			init: ()=>{ | 			init: ()=>{ | ||||||
| 				$('#tgl0, #tgl1').datetimepicker({ | 				$('#tgl0, #tgl1').datetimepicker({ | ||||||
| @ -193,19 +194,27 @@ | |||||||
|                     deferRender: true, |                     deferRender: true, | ||||||
| 					columns: [ | 					columns: [ | ||||||
| 						// { data: 'id', visible: false }, // vhc_id | 						// { data: 'id', visible: false }, // vhc_id | ||||||
| 						{ | 						// { | ||||||
| 							data: 'name', | 						// 	data: 'name', | ||||||
| 							className: 'text-start text-nowrap', | 						// 	className: 'text-start text-nowrap', | ||||||
| 						}, | 						// }, | ||||||
| 						{ | 						{ | ||||||
| 							data: 'nopol1', | 							data: 'nopol1', | ||||||
| 							className: 'text-start', | 							className: 'text-start', | ||||||
| 						}, | 						}, | ||||||
|  | 						{ | ||||||
|  | 							data: 'dc_code', | ||||||
|  | 							className: 'text-start', | ||||||
|  | 						}, | ||||||
|  | 						{ | ||||||
|  | 							data: 'pool_code', | ||||||
|  | 							className: 'text-start', | ||||||
|  | 						}, | ||||||
| 						{  | 						{  | ||||||
| 							data: "crt_d", | 							data: "crt_d", | ||||||
| 							className: 'text-nowrap', | 							className: 'text-nowrap', | ||||||
| 							render: (data, type, row, meta) => { | 							render: (data, type, row, meta) => { | ||||||
| 								return moment.unix(data).format('DD MMM YYYY HH:mm:ss'); | 								return moment.unix(data + AppState.TIMEFIX).format('DD MMM YYYY HH:mm:ss'); | ||||||
| 							} | 							} | ||||||
| 						}, | 						}, | ||||||
| 						{ data: "speed", className: 'text-end'}, | 						{ data: "speed", className: 'text-end'}, | ||||||
| @ -220,7 +229,13 @@ | |||||||
| 					buttons: [ | 					buttons: [ | ||||||
| 						{ | 						{ | ||||||
| 							extend: 'excelHtml5', | 							extend: 'excelHtml5', | ||||||
| 							title: `Abnormality Report - ${moment(safeVal('#tgl0')).format('DD MMM YYYY')} to ${moment(safeVal('#tgl1')).format('DD MMM YYYY')}`, | 							title: () => { | ||||||
|  | 								return ` | ||||||
|  | 								Abnormality Trip Report -  | ||||||
|  | 								${moment($('#tgl0').val(), "DD-MM-YYYY HH:mm").format('DD MMM YYYY HH:mm')}  | ||||||
|  | 								to  | ||||||
|  | 								${moment($('#tgl1').val(), "DD-MM-YYYY HH:mm").format('DD MMM YYYY HH:mm')}` | ||||||
|  | 							}, | ||||||
| 							className: 'd-none', // hide default button | 							className: 'd-none', // hide default button | ||||||
| 							exportOptions: { | 							exportOptions: { | ||||||
| 								columns: ':visible:not(:first-child)' // 🔹 exclude first column | 								columns: ':visible:not(:first-child)' // 🔹 exclude first column | ||||||
|  | |||||||
| @ -5,10 +5,16 @@ | |||||||
| @extends('app.app') | @extends('app.app') | ||||||
|  |  | ||||||
| @section('title') | @section('title') | ||||||
|     Vehicles |     Vehicles Trip Report | ||||||
| @endsection | @endsection | ||||||
|  |  | ||||||
| @section('customcss') | @section('customcss') | ||||||
|  | 	<link | ||||||
|  | 		rel="stylesheet" | ||||||
|  | 		href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" | ||||||
|  | 		integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" | ||||||
|  | 		crossorigin="" | ||||||
|  | 	/> | ||||||
| @endsection | @endsection | ||||||
|  |  | ||||||
| @section('content') | @section('content') | ||||||
| @ -43,13 +49,14 @@ | |||||||
| 							<div class="form-group"> | 							<div class="form-group"> | ||||||
| 								<label class="text-muted">From</label> | 								<label class="text-muted">From</label> | ||||||
| 								<!-- default today --> | 								<!-- default today --> | ||||||
| 								<!-- <input type="date" class="form-control" id="tgl0" value="{{ date('Y-m-d') }}"> --> | 								<!-- <input class="form-control" id="tgl0" value="02-09-2025 00:00"> --> | ||||||
| 								<input class="form-control" id="tgl0" value="{{ date('d-m-Y 00:00') }}"> | 								<input class="form-control" id="tgl0" value="{{ date('d-m-Y 00:00') }}"> | ||||||
| 							</div> | 							</div> | ||||||
| 						</div> | 						</div> | ||||||
| 						<div class="col-2"> | 						<div class="col-2"> | ||||||
| 							<div class="form-group"> | 							<div class="form-group"> | ||||||
| 								<label class="text-muted">To</label> | 								<label class="text-muted">To</label> | ||||||
|  | 								<!-- <input class="form-control" id="tgl1" value="02-09-2025 23:00"> --> | ||||||
| 								<input class="form-control" id="tgl1" value="{{ date('d-m-Y 23:59') }}"> | 								<input class="form-control" id="tgl1" value="{{ date('d-m-Y 23:59') }}"> | ||||||
| 							</div> | 							</div> | ||||||
| 						</div> | 						</div> | ||||||
| @ -65,7 +72,7 @@ | |||||||
| 							</div> | 							</div> | ||||||
| 						</div> | 						</div> | ||||||
| 						<div class="col-1 d-flex align-items-end"> | 						<div class="col-1 d-flex align-items-end"> | ||||||
| 							<button class="btn btn-sm btn-primary" id="submitFilter">Submit</button> | 							<button class="btn btn-primary" id="submitFilter">Submit</button> | ||||||
| 						</div> | 						</div> | ||||||
| 						<div class="col-5 d-flex align-items-end"> | 						<div class="col-5 d-flex align-items-end"> | ||||||
| 							<button class="btn btn-sm btn-danger ms-auto" id="btnDownloadReport">Download Report</button> | 							<button class="btn btn-sm btn-danger ms-auto" id="btnDownloadReport">Download Report</button> | ||||||
| @ -76,16 +83,20 @@ | |||||||
|                         <table id="tVehicleTrips" class="table table-hover dataTable w-100"> |                         <table id="tVehicleTrips" class="table table-hover dataTable w-100"> | ||||||
|                             <thead> |                             <thead> | ||||||
|                                 <tr class=""> |                                 <tr class=""> | ||||||
|                                     <th class="">Vehicle ID</th> |                                     <th class="" hidden>Vehicle ID</th> | ||||||
|                                     <!-- <th class="text-center">Action</th> --> |  | ||||||
|                                     <th class="">Vehicle Name</th> |  | ||||||
|                                     <th class="">License Plate Number</th> |                                     <th class="">License Plate Number</th> | ||||||
|  | 									<th class="">Dist. Cat.</th> | ||||||
|  | 									<th class="">Pool</th> | ||||||
|                                     <th class="">Number of Trip</th> |                                     <th class="">Number of Trip</th> | ||||||
|                                     <th class="">Total Mileage (km)</th> |                                     <th class="">Total Mileage (km)</th> | ||||||
|                                     <th class="">Trip #</th> |                                     <th class="">Trip #</th> | ||||||
|                                     <th class="">Start</th> |                                     <th class="">Start</th> | ||||||
|                                     <th class="">Finish</th> |                                     <th class="">Finish</th> | ||||||
|                                     <th class="">Mileage (km)</th> | 									<th class="">Duration</th> | ||||||
|  |                                     <th class="">Start (km)</th> | ||||||
|  |                                     <th class="">Finish (km)</th> | ||||||
|  |                                     <th class="">Distance (km)</th> | ||||||
|  |                                     <th class="">Detail</th> | ||||||
|                                 </tr> |                                 </tr> | ||||||
|                             </thead> |                             </thead> | ||||||
|                             <!-- <tbody> |                             <!-- <tbody> | ||||||
| @ -164,6 +175,20 @@ | |||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
| 	<!-- modal --> | 	<!-- modal --> | ||||||
|  |     <div class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" id="mdlDetailTrip" aria-labelledby="mdlDetailTripLabel" aria-hidden="true"> | ||||||
|  |         <!-- <div class="modal-dialog modal-dialog modal-dialog-centered modal-dialog-scrollable modal-xl"> | ||||||
|  |             <div class="modal-content"> | ||||||
|  |                 <div class="modal-header"> | ||||||
|  |                     <h5 class="modal-title" id="mdlDetailTripLabel">-----</h5> | ||||||
|  |                     <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-body"> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="modal-footer"> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> --> | ||||||
|  |     </div> | ||||||
| @endsection | @endsection | ||||||
|  |  | ||||||
| @section('customjs') | @section('customjs') | ||||||
| @ -172,6 +197,14 @@ | |||||||
| 	<script src="https://cdn.datatables.net/buttons/2.4.2/js/dataTables.buttons.min.js"></script> | 	<script src="https://cdn.datatables.net/buttons/2.4.2/js/dataTables.buttons.min.js"></script> | ||||||
| 	<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script> | 	<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script> | ||||||
| 	<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.html5.min.js"></script> | 	<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.html5.min.js"></script> | ||||||
|  |     <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js" integrity="sha512-ozq8xQKq6urvuU6jNgkfqAmT7jKN2XumbrX1JiB3TnF7tI48DPI4Gy1GXKD/V3EExgAs1V+pRO7vwtS1LHg0Gw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> --> | ||||||
|  | 	<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script> | ||||||
|  |     <script src="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.js"></script> | ||||||
|  | 	<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script> | ||||||
|  | 	<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> | ||||||
|  | 	<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> | ||||||
|  | 	<script src="{{ asset('assets/vendor/printThis.js') }}"></script> | ||||||
|  |  | ||||||
| 	<script> | 	<script> | ||||||
|         'use strict'; |         'use strict'; | ||||||
|         const State = { |         const State = { | ||||||
| @ -187,8 +220,8 @@ | |||||||
|             activate: function() { |             activate: function() { | ||||||
|                 Wrapper.init(); |                 Wrapper.init(); | ||||||
|                 Wrapper.event(); |                 Wrapper.event(); | ||||||
|                 DTable.activate(); | 				// DTable.table = $('#tVehicleTrips').DataTable() | ||||||
|  |                 // DTable.activate(); | ||||||
| 			}, | 			}, | ||||||
| 			init: ()=>{ | 			init: ()=>{ | ||||||
| 				$('#tgl0, #tgl1').datetimepicker({ | 				$('#tgl0, #tgl1').datetimepicker({ | ||||||
| @ -207,6 +240,21 @@ | |||||||
| 				$('#btnDownloadReport').on('click', function() { | 				$('#btnDownloadReport').on('click', function() { | ||||||
| 					DTable.table.button('.buttons-excel').trigger(); | 					DTable.table.button('.buttons-excel').trigger(); | ||||||
| 				}); | 				}); | ||||||
|  |  | ||||||
|  | 				// detail trip | ||||||
|  | 				$('#tVehicleTrips').on('click', '.btnDetailTrip', function(e) { | ||||||
|  | 					e.preventDefault(); | ||||||
|  | 					const vid = $(this).data('vid'); | ||||||
|  | 					const tgl0 = $(this).data('tgl0'); | ||||||
|  | 					const tgl1 = $(this).data('tgl1'); | ||||||
|  | 					const nopol1 = $(this).data('nopol1'); | ||||||
|  |  | ||||||
|  | 					// $("#mdlDetailTrip").load("{{ route('view_report_trip_detail') }}"); | ||||||
|  | 					$('#mdlDetailTrip').empty().load("{{ route('view_report_trip_detail') }}", `vid=${vid}&tgl0=${tgl0}&tgl1=${tgl1}&nopol1=${nopol1}`, () => { | ||||||
|  | 						$('#mdlDetailTrip').modal('show') | ||||||
|  | 					}) | ||||||
|  | 					 | ||||||
|  | 				}); | ||||||
|             }, |             }, | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
| @ -227,10 +275,6 @@ | |||||||
| 					return; | 					return; | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
| 				let mileageSum = {}; |  | ||||||
| 				let tripCount = {}; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| 				DTable.table = $('#tVehicleTrips').DataTable({ | 				DTable.table = $('#tVehicleTrips').DataTable({ | ||||||
| 					searching: false,   // 🔹 remove search box | 					searching: false,   // 🔹 remove search box | ||||||
| 					ordering: false,    // 🔹 disable sorting for all columns | 					ordering: false,    // 🔹 disable sorting for all columns | ||||||
| @ -251,20 +295,10 @@ | |||||||
| 								cptid=${AppState.current_company} | 								cptid=${AppState.current_company} | ||||||
| 								&from_date=${moment($('#tgl0').val(), "DD-MM-YYYY HH:mm").unix()} | 								&from_date=${moment($('#tgl0').val(), "DD-MM-YYYY HH:mm").unix()} | ||||||
| 								&to_date=${moment($('#tgl1').val(), "DD-MM-YYYY HH:mm").unix()} | 								&to_date=${moment($('#tgl1').val(), "DD-MM-YYYY HH:mm").unix()} | ||||||
| 								&vid=${$('#filterNopol').val() || ''}`, | 								&vid=${$('#filterNopol').val() || ''} | ||||||
|  | 							`, | ||||||
| 							type: 'GET', | 							type: 'GET', | ||||||
| 							success: function(json) { | 							success: function(json) { | ||||||
| 								// Precompute totals by vhc_id |  | ||||||
|  |  | ||||||
| 								json.data.forEach(row => { |  | ||||||
| 									const id = row.id; // vhc_id |  | ||||||
| 									if (!mileageSum[id]) { |  | ||||||
| 										mileageSum[id] = 0; |  | ||||||
| 										tripCount[id] = 0; |  | ||||||
| 									} |  | ||||||
| 									mileageSum[id] += parseFloat(row.milleage || 0); |  | ||||||
| 									tripCount[id] += 1; |  | ||||||
| 								}); |  | ||||||
| 								callback(json); | 								callback(json); | ||||||
| 							}, | 							}, | ||||||
| 							error: function(xhr, status, error) { | 							error: function(xhr, status, error) { | ||||||
| @ -280,13 +314,6 @@ | |||||||
|                     deferRender: true, |                     deferRender: true, | ||||||
| 					columns: [ | 					columns: [ | ||||||
| 						{ data: 'id', visible: false }, // vhc_id | 						{ data: 'id', visible: false }, // vhc_id | ||||||
| 						{ |  | ||||||
| 							data: 'name', |  | ||||||
| 							className: 'text-start text-nowrap', |  | ||||||
| 							visible: true, |  | ||||||
| 							orderable: true, |  | ||||||
| 							searchable: true, |  | ||||||
| 						}, |  | ||||||
| 						{ | 						{ | ||||||
| 							data: 'nopol1', | 							data: 'nopol1', | ||||||
| 							className: 'text-start', | 							className: 'text-start', | ||||||
| @ -294,15 +321,17 @@ | |||||||
| 							orderable: true, | 							orderable: true, | ||||||
| 							searchable: true, | 							searchable: true, | ||||||
| 						}, | 						}, | ||||||
|  						{ data: "id", className: 'text-end'}, | 						{ data: "dc_code", className: 'text-start'}, | ||||||
| 						{ data: "id", className: 'text-end'}, | 						{ data: "pool_code", className: 'text-start'}, | ||||||
|  | 						{ data: "total_trip", className: 'text-end'}, | ||||||
|  | 						{ data: "total_mileage", className: 'text-end', render: (data, type, row, meta) => parseFloat(data).toFixed(2)}, | ||||||
| 						{ data: "trip_id", className: 'text-end'}, | 						{ data: "trip_id", className: 'text-end'}, | ||||||
| 						{  | 						{  | ||||||
| 							data: 'start',  | 							data: 'start',  | ||||||
| 							render: (data, type, row, meta) => { | 							render: (data, type, row, meta) => { | ||||||
| 								// let addr = row | 								// let addr = row | ||||||
| 								return ` | 								return ` | ||||||
| 									${moment.unix(data).format('DD MMM YYYY HH:mm:ss')}<br> | 									${moment.unix(data + AppState.TIMEFIX).format('DD MMM YYYY HH:mm:ss')}<br> | ||||||
| 									${Helper.shortenText(decodeURIComponent(row.startLoc || 'address'), 255) || "-"} | 									${Helper.shortenText(decodeURIComponent(row.startLoc || 'address'), 255) || "-"} | ||||||
| 								`; | 								`; | ||||||
| 							}  | 							}  | ||||||
| @ -312,17 +341,57 @@ | |||||||
| 							render: (data, type, row, meta) => { | 							render: (data, type, row, meta) => { | ||||||
| 								// let addr = row | 								// let addr = row | ||||||
| 								return ` | 								return ` | ||||||
| 									${moment.unix(data).format('DD MMM YYYY HH:mm:ss')}<br> | 									${moment.unix(data + AppState.TIMEFIX).format('DD MMM YYYY HH:mm:ss')}<br> | ||||||
| 									${Helper.shortenText(decodeURIComponent(row.finishLoc || 'address'), 255) || "-"} | 									${Helper.shortenText(decodeURIComponent(row.finishLoc || 'address'), 255) || "-"} | ||||||
| 								`; | 								`; | ||||||
| 							}  | 							}  | ||||||
| 						}, | 						}, | ||||||
| 						{  | 						{  | ||||||
| 							data: 'milleage',  | 							className: 'text-start', render: function(data, type, row, meta) { | ||||||
| 							className: 'text-end', render: function(data, type, row, meta) { | 								const start = moment.unix(row.start); | ||||||
| 								return (data === null) ? '0' : parseFloat(data).toFixed(2); | 								const finish = moment.unix(row.finish); | ||||||
|  | 		 | ||||||
|  | 								// calculate duration | ||||||
|  | 								const diff = moment.duration(finish.diff(start)); | ||||||
|  | 								const hours = Math.floor(diff.asHours()); | ||||||
|  | 								const minutes = diff.minutes(); | ||||||
|  |  | ||||||
|  | 								return `${hours}h ${minutes}m`;							 | ||||||
| 							} | 							} | ||||||
| 						}, | 						}, | ||||||
|  | 						{  | ||||||
|  | 							data: 'startMileage',  | ||||||
|  | 							className: 'text-end', render: function(data, type, row, meta) { | ||||||
|  | 								return (data === null) ? '0' : parseFloat(data).toFixed(0); | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  | 						{  | ||||||
|  | 							data: 'finishMileage',  | ||||||
|  | 							className: 'text-end', render: function(data, type, row, meta) { | ||||||
|  | 								return (data === null) ? '0' : parseFloat(data).toFixed(0); | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  | 						{  | ||||||
|  | 							data: 'mileage',  | ||||||
|  | 							className: 'text-end', render: function(data, type, row, meta) { | ||||||
|  | 								const mileage = (row.finishMileage !== null && row.startMileage !== null) ? (row.finishMileage - row.startMileage) : row.mileage; | ||||||
|  | 								return (parseFloat(mileage).toFixed(2)); | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  |                         { | ||||||
|  | 							// visible: false, | ||||||
|  |                             data: 'vhc_id', | ||||||
|  |                             className: 'text-center', | ||||||
|  |                             render: function(data, type, row, meta) { | ||||||
|  |                                 let action = ` | ||||||
|  | 									<a href="#" class="text-decoration-none me-1 btnDetailTrip"  | ||||||
|  | 										data-vid="${data}" data-tgl0="${row.start}" data-tgl1="${row.finish}" data-nopol1="${row.nopol1}"> | ||||||
|  | 										<span class="icon ion-eye fz-16"></span> | ||||||
|  | 									</a> | ||||||
|  | 								`; | ||||||
|  |                                 return action; | ||||||
|  |                             } | ||||||
|  |                         }, | ||||||
| 					], | 					], | ||||||
| 					paging: false, | 					paging: false, | ||||||
| 					drawCallback: function (settings) { | 					drawCallback: function (settings) { | ||||||
| @ -347,16 +416,9 @@ | |||||||
| 									$(rows).eq(i).find('td:eq(1)').attr('rowspan', rowspanCount); | 									$(rows).eq(i).find('td:eq(1)').attr('rowspan', rowspanCount); | ||||||
| 									$(rows).eq(i).find('td:eq(2)').attr('rowspan', rowspanCount); | 									$(rows).eq(i).find('td:eq(2)').attr('rowspan', rowspanCount); | ||||||
| 									$(rows).eq(i).find('td:eq(3)').attr('rowspan', rowspanCount); | 									$(rows).eq(i).find('td:eq(3)').attr('rowspan', rowspanCount); | ||||||
|  | 									$(rows).eq(i).find('td:eq(4)').attr('rowspan', rowspanCount); | ||||||
| 									 | 									 | ||||||
| 									// fill trip count | 									// $(rows).eq(i).find('td:eq(3)').attr('rowspan', rowspanCount); | ||||||
| 									$(rows).eq(i).find('td:eq(2)') |  | ||||||
| 										.attr('rowspan', rowspanCount) |  | ||||||
| 										.text(tripCount[group]); |  | ||||||
|  |  | ||||||
| 									// fill mileage sum |  | ||||||
| 									$(rows).eq(i).find('td:eq(3)') |  | ||||||
| 										.attr('rowspan', rowspanCount) |  | ||||||
| 										.text(mileageSum[group].toFixed(2)); |  | ||||||
|  |  | ||||||
| 									last = group; | 									last = group; | ||||||
| 								} else { | 								} else { | ||||||
| @ -365,16 +427,24 @@ | |||||||
| 									$(rows).eq(i).find('td:eq(0)').remove(); | 									$(rows).eq(i).find('td:eq(0)').remove(); | ||||||
| 									$(rows).eq(i).find('td:eq(0)').remove(); | 									$(rows).eq(i).find('td:eq(0)').remove(); | ||||||
| 									$(rows).eq(i).find('td:eq(0)').remove(); | 									$(rows).eq(i).find('td:eq(0)').remove(); | ||||||
|  | 									$(rows).eq(i).find('td:eq(0)').remove(); | ||||||
|  | 									// $(rows).eq(i).find('td:eq(0)').remove(); | ||||||
| 								} | 								} | ||||||
| 							}); | 							}); | ||||||
| 						}, | 						}, | ||||||
| 					buttons: [ | 					buttons: [ | ||||||
| 						{ | 						{ | ||||||
| 							extend: 'excelHtml5', | 							extend: 'excelHtml5', | ||||||
| 							title: `Vehicle Trip Report - ${moment(safeVal('#tgl0')).format('DD MMM YYYY')} to ${moment(safeVal('#tgl1')).format('DD MMM YYYY')}`, | 							title: () => { | ||||||
|  | 								return ` | ||||||
|  | 								Vehicle Trip Report -  | ||||||
|  | 								${moment($('#tgl0').val(), "DD-MM-YYYY HH:mm").format('DD MMM YYYY HH:mm')}  | ||||||
|  | 								to  | ||||||
|  | 								${moment($('#tgl1').val(), "DD-MM-YYYY HH:mm").format('DD MMM YYYY HH:mm')}` | ||||||
|  | 							}, | ||||||
| 							className: 'd-none', // hide default button | 							className: 'd-none', // hide default button | ||||||
| 							exportOptions: { | 							exportOptions: { | ||||||
| 								columns: ':visible:not(:first-child)' // 🔹 exclude first column | 								columns: ':visible:not(:last-child)' //  | ||||||
| 							} | 							} | ||||||
| 						} | 						} | ||||||
| 					] | 					] | ||||||
| @ -387,16 +457,6 @@ | |||||||
|             return (val === undefined || val === null || val === '') ? null : val; |             return (val === undefined || val === null || val === '') ? null : val; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         const Filter = { |  | ||||||
|             activate: function() { |  | ||||||
|                 Filter.event(); |  | ||||||
|             }, |  | ||||||
|             event: function() {}, |  | ||||||
|             triggerFilterCompany: function() { |  | ||||||
|                 DTable.reload(); |  | ||||||
|             }, |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         async function convertImgHtmlToFile(imgHtml, imgWidth, imgHeight, mimeType, fileName) { |         async function convertImgHtmlToFile(imgHtml, imgWidth, imgHeight, mimeType, fileName) { | ||||||
|             return new Promise((resolve, reject) => { |             return new Promise((resolve, reject) => { | ||||||
|                 try { |                 try { | ||||||
|  | |||||||
| @ -77,7 +77,19 @@ | |||||||
|                         @foreach ($permission as $module => $perms) |                         @foreach ($permission as $module => $perms) | ||||||
|                             <div class="mb-3 row"> |                             <div class="mb-3 row"> | ||||||
|                                 <label for="add-first_name" class="form-label text-capitalize col-3"> |                                 <label for="add-first_name" class="form-label text-capitalize col-3"> | ||||||
|                                     {{ $module == 'transaction' ? 'job' : ($module == 'client' ? 'company' : ($module == 'config_truck_type' ? 'Config Vehicle Type' : ($module == 'config_master_device' ? 'Config Master Devices' : ($module == 'config_logs_gps' ? 'Config Logs GPS' : $module)))) }} |                                     {{  | ||||||
|  | 										$module == 'transaction' ? 'job' :  | ||||||
|  | 											($module == 'client' ? 'company' :  | ||||||
|  | 											($module == 'config_truck_type' ? 'Config Vehicle Type' :  | ||||||
|  | 											($module == 'config_master_device' ? 'Config Master Devices' :  | ||||||
|  | 											($module == 'config_logs_gps' ? 'Config Logs GPS' : | ||||||
|  | 											($module == 'config_distribution_category' ? 'Config Distribution Category' : | ||||||
|  | 											($module == 'config_pool' ? 'Config Pool' : | ||||||
|  | 											($module == 'report_vehicle_trip' ? 'Report Vehicle Trip' : | ||||||
|  | 											($module == 'report_abnormality' ? 'Report Abnormality' : | ||||||
|  | 											($module == 'user_logs' ? 'Config User Activity' : $module | ||||||
|  | 											))))))))) | ||||||
|  | 									}} | ||||||
|                                 </label> |                                 </label> | ||||||
|                                 <div class="col-9"> |                                 <div class="col-9"> | ||||||
|                                     <div class="d-flex flex-wrap align-items-center gap-2"> |                                     <div class="d-flex flex-wrap align-items-center gap-2"> | ||||||
| @ -125,7 +137,19 @@ | |||||||
|                         @foreach ($permission as $module => $perms) |                         @foreach ($permission as $module => $perms) | ||||||
|                             <div class="mb-3 row"> |                             <div class="mb-3 row"> | ||||||
|                                 <label for="add-first_name" class="form-label text-capitalize col-3"> |                                 <label for="add-first_name" class="form-label text-capitalize col-3"> | ||||||
|                                     {{ $module == 'transaction' ? 'job' : ($module == 'client' ? 'company' : ($module == 'config_truck_type' ? 'Config Vehicle Type' : ($module == 'config_master_device' ? 'Config Master Devices' : ($module == 'config_logs_gps' ? 'Config Logs GPS' : $module)))) }} |                                     {{  | ||||||
|  | 										$module == 'transaction' ? 'job' :  | ||||||
|  | 											($module == 'client' ? 'company' :  | ||||||
|  | 											($module == 'config_truck_type' ? 'Config Vehicle Type' :  | ||||||
|  | 											($module == 'config_master_device' ? 'Config Master Devices' :  | ||||||
|  | 											($module == 'config_logs_gps' ? 'Config Logs GPS' : | ||||||
|  | 											($module == 'config_distribution_category' ? 'Config Distribution Category' : | ||||||
|  | 											($module == 'config_pool' ? 'Config Pool' : | ||||||
|  | 											($module == 'report_vehicle_trip' ? 'Report Vehicle Trip' : | ||||||
|  | 											($module == 'report_abnormality' ? 'Report Abnormality' : | ||||||
|  | 											($module == 'user_logs' ? 'Config User Activity' : $module | ||||||
|  | 											))))))))) | ||||||
|  | 									}} | ||||||
|                                 </label> |                                 </label> | ||||||
|                                 <div class="col-9"> |                                 <div class="col-9"> | ||||||
|                                     <div class="d-flex flex-wrap align-items-center gap-2"> |                                     <div class="d-flex flex-wrap align-items-center gap-2"> | ||||||
|  | |||||||
							
								
								
									
										263
									
								
								resources/views/menu_v1/userLogs.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								resources/views/menu_v1/userLogs.blade.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,263 @@ | |||||||
|  | @php | ||||||
|  |     $user_role = Auth::user()->role; | ||||||
|  | @endphp | ||||||
|  |  | ||||||
|  | @extends('app.app') | ||||||
|  |  | ||||||
|  | @section('title') | ||||||
|  |     User Activity | ||||||
|  | @endsection | ||||||
|  |  | ||||||
|  | @section('customcss') | ||||||
|  | 	<link | ||||||
|  | 		rel="stylesheet" | ||||||
|  | 		href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" | ||||||
|  | 		integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" | ||||||
|  | 		crossorigin="" | ||||||
|  | 	/> | ||||||
|  | @endsection | ||||||
|  |  | ||||||
|  | @section('content') | ||||||
|  |     <div class="container-fluid"> | ||||||
|  |         <div class="content"> | ||||||
|  |             <div class="card"> | ||||||
|  |                 <div class="card-header"> | ||||||
|  |                     <div class="row d-flex align-items-center"> | ||||||
|  |                         <div class="col-3"> | ||||||
|  |                             <p class="card-title text-bold mb-0">User Activity</p> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="col-auto text-end ps-0"> | ||||||
|  |                             <!-- <button class="btn btn-sm btn-danger">Download</button> --> | ||||||
|  |                         </div> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |                 <div class="card-body"> | ||||||
|  | 					<!-- filter --> | ||||||
|  | 					<div class="row"> | ||||||
|  | 						<div class="col-2"> | ||||||
|  | 							<div class="form-group"> | ||||||
|  | 								<label class="text-muted">From</label> | ||||||
|  | 								<!-- default today --> | ||||||
|  | 								<!-- <input class="form-control" id="tgl0" value="02-09-2025 00:00"> --> | ||||||
|  | 								<input class="form-control" id="tgl0" value="{{ date('d-m-Y 00:00') }}"> | ||||||
|  | 							</div> | ||||||
|  | 						</div> | ||||||
|  | 						<div class="col-2"> | ||||||
|  | 							<div class="form-group"> | ||||||
|  | 								<label class="text-muted">To</label> | ||||||
|  | 								<!-- <input class="form-control" id="tgl1" value="02-09-2025 23:00"> --> | ||||||
|  | 								<input class="form-control" id="tgl1" value="{{ date('d-m-Y 23:59') }}"> | ||||||
|  | 							</div> | ||||||
|  | 						</div> | ||||||
|  | 						<div class="col-2"> | ||||||
|  | 							<div class="form-group"> | ||||||
|  | 								<label class="text-muted">User</label> | ||||||
|  | 								<select name="user" class="form-control" id="filterUser"> | ||||||
|  | 									<option value="">-- All --</option> | ||||||
|  | 									@foreach ($users as $user) | ||||||
|  | 										<option value="{{ $user->id }}">{{ $user->email }}</option> | ||||||
|  | 									@endforeach | ||||||
|  | 								</select> | ||||||
|  | 							</div> | ||||||
|  | 						</div> | ||||||
|  | 						<div class="col-1 d-flex align-items-end"> | ||||||
|  | 							<button class="btn btn-primary" id="submitFilter">Submit</button> | ||||||
|  | 						</div> | ||||||
|  | 						<div class="col-5 d-flex align-items-end"> | ||||||
|  | 							<button class="btn btn-sm btn-danger ms-auto" id="btnDownloadReport">Download Report</button> | ||||||
|  | 						</div> | ||||||
|  | 					</div> | ||||||
|  | 					</div> | ||||||
|  |                     <div class="table-responsive p-3"> | ||||||
|  |                         <table id="tLogs" class="table table-hover dataTable w-100"> | ||||||
|  |                             <thead> | ||||||
|  |                                 <tr class=""> | ||||||
|  |                                     <th class="">Time</th> | ||||||
|  | 									<th class="">User</th> | ||||||
|  | 									<th class="">Module</th> | ||||||
|  | 									<th class="">Description</th> | ||||||
|  | 									<th class="">Action</th> | ||||||
|  |                                 </tr> | ||||||
|  |                             </thead> | ||||||
|  |                         </table> | ||||||
|  |                     </div> | ||||||
|  |                 </div> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
|  | @endsection | ||||||
|  |  | ||||||
|  | @section('customjs') | ||||||
|  |     <script src="{{ asset('assets/js/load-image.all.min.js') }}"></script> | ||||||
|  | 	<!-- DataTables Buttons + JSZip (for Excel export) --> | ||||||
|  | 	<script src="https://cdn.datatables.net/buttons/2.4.2/js/dataTables.buttons.min.js"></script> | ||||||
|  | 	<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script> | ||||||
|  | 	<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.html5.min.js"></script> | ||||||
|  |     <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js" integrity="sha512-ozq8xQKq6urvuU6jNgkfqAmT7jKN2XumbrX1JiB3TnF7tI48DPI4Gy1GXKD/V3EExgAs1V+pRO7vwtS1LHg0Gw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> --> | ||||||
|  | 	<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script> | ||||||
|  |     <script src="https://unpkg.com/leaflet-routing-machine@3.2.12/dist/leaflet-routing-machine.js"></script> | ||||||
|  | 	<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script> | ||||||
|  | 	<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> | ||||||
|  | 	<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> | ||||||
|  | 	<script src="{{ asset('assets/vendor/printThis.js') }}"></script> | ||||||
|  |  | ||||||
|  | 	<script> | ||||||
|  |         'use strict'; | ||||||
|  |  | ||||||
|  |         const Wrapper = { | ||||||
|  |             activate: function() { | ||||||
|  |                 Wrapper.init(); | ||||||
|  |                 Wrapper.event(); | ||||||
|  |                 DTable.activate(); | ||||||
|  | 			}, | ||||||
|  | 			init: ()=>{ | ||||||
|  | 				$('.time').each(function () { | ||||||
|  | 					const unix = parseInt($(this).text().trim()) + AppState.TIMEFIX; | ||||||
|  | 					$(this).text(moment.unix(unix).format('DD MMM YYYY HH:mm:ss')); | ||||||
|  | 				}); | ||||||
|  | 				$('#tgl0, #tgl1').datetimepicker({ | ||||||
|  | 					format:'d-m-Y H:i', | ||||||
|  | 					defaultTime:'00:00', | ||||||
|  | 					closeOnDateSelect: true, | ||||||
|  | 					// mask:true | ||||||
|  | 				}); | ||||||
|  | 			}, | ||||||
|  |             event: function() { | ||||||
|  | 				$('#submitFilter').on('click', function() { | ||||||
|  | 					DTable.reload(); | ||||||
|  | 				}); | ||||||
|  | 				// Trigger export on external button click | ||||||
|  | 				$('#btnDownloadReport').on('click', function() { | ||||||
|  | 					DTable.table.button('.buttons-excel').trigger(); | ||||||
|  | 				}); | ||||||
|  |             }, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         const DTable = { | ||||||
|  | 			table: null, | ||||||
|  |     		lastAjax: null, // keep track of the last ajax request | ||||||
|  |             activate: function() { | ||||||
|  |                 DTable.reload(); | ||||||
|  |             }, | ||||||
|  |             reload: function() { | ||||||
|  | 				// Abort the last request if it's still running | ||||||
|  | 				if (DTable.lastAjax) { | ||||||
|  | 					DTable.lastAjax.abort(); | ||||||
|  | 				} | ||||||
|  | 				if (DTable.table) { | ||||||
|  | 					// If table already exists → reload | ||||||
|  | 					DTable.table.ajax.reload(); | ||||||
|  | 					return; | ||||||
|  | 				} | ||||||
|  |  | ||||||
|  | 				DTable.table = $('#tLogs').DataTable({ | ||||||
|  | 					searching: false,   // 🔹 remove search box | ||||||
|  | 					ordering: false,    // 🔹 disable sorting for all columns | ||||||
|  | 					processing: true, | ||||||
|  | 					serverSide: false, | ||||||
|  | 					bLengthChange: true, | ||||||
|  | 					deferRender: true, | ||||||
|  | 					destroy: true, | ||||||
|  | 					ajax: function(data, callback, settings) { | ||||||
|  | 						// Abort previous | ||||||
|  | 						if (DTable.lastAjax) { | ||||||
|  | 							DTable.lastAjax.abort(); | ||||||
|  | 						} | ||||||
|  |  | ||||||
|  | 						// Fire new request | ||||||
|  | 						DTable.lastAjax = $.ajax({ | ||||||
|  | 							url: `{{ route('api_user_logs') }}? | ||||||
|  | 								tgl0=${moment($('#tgl0').val(), "DD-MM-YYYY HH:mm").unix()} | ||||||
|  | 								&tgl1=${moment($('#tgl1').val(), "DD-MM-YYYY HH:mm").unix()} | ||||||
|  | 								&userId=${$('#filterUser').val() || ''} | ||||||
|  | 							`, | ||||||
|  | 							type: 'GET', | ||||||
|  | 							success: function(json) { | ||||||
|  | 								callback(json); | ||||||
|  | 							}, | ||||||
|  | 							error: function(xhr, status, error) { | ||||||
|  | 								if (status !== 'abort') { | ||||||
|  | 									console.error("AJAX error:", error); | ||||||
|  | 								} | ||||||
|  | 							}, | ||||||
|  | 							complete: function() { | ||||||
|  | 								DTable.lastAjax = null; | ||||||
|  | 							} | ||||||
|  | 						}); | ||||||
|  | 					}, | ||||||
|  |                     deferRender: true, | ||||||
|  | 					columns: [ | ||||||
|  | 						{ | ||||||
|  | 							data: 'crt', | ||||||
|  | 							render: (data, type, row, meta) => { | ||||||
|  | 								// let addr = row | ||||||
|  | 								return ` | ||||||
|  | 									${moment.unix(data).format('DD MMM YYYY HH:mm:ss')}<br> | ||||||
|  | 								`; | ||||||
|  | 							}  | ||||||
|  |  | ||||||
|  | 						}, | ||||||
|  | 						{ data: 'email' }, | ||||||
|  | 						{  | ||||||
|  | 							data: 'log', | ||||||
|  | 							render: (data, type, row, meta) => { | ||||||
|  | 								let log = JSON.parse(data); | ||||||
|  | 								let module = log.module || '-'; | ||||||
|  | 								return module; | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  | 						{  | ||||||
|  | 							data: 'log', | ||||||
|  | 							render: (data, type, row, meta) => { | ||||||
|  | 								let log = JSON.parse(data); | ||||||
|  | 								let desc = log.desc || '-'; | ||||||
|  | 								return desc; | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  | 						{  | ||||||
|  | 							data: 'log', | ||||||
|  | 							render: (data, type, row, meta) => { | ||||||
|  | 								let log = JSON.parse(data); | ||||||
|  | 								let action = log.action || '-'; | ||||||
|  |  | ||||||
|  | 								// use badge for action | ||||||
|  | 								// action = `<span class="badge bg-secondary">${action}</span>`; | ||||||
|  | 								let badge = ''; | ||||||
|  | 								if (action.toLowerCase() === 'create') { | ||||||
|  | 									badge = `<span class="badge bg-success">${action}</span>`; | ||||||
|  | 								} else if (action.toLowerCase() === 'update') { | ||||||
|  | 									badge = `<span class="badge bg-warning">${action}</span>`; | ||||||
|  | 								} else if (action.toLowerCase() === 'delete') { | ||||||
|  | 									badge = `<span class="badge bg-danger">${action}</span>`; | ||||||
|  | 								} else { | ||||||
|  | 									badge = `<span class="badge bg-secondary">${action}</span>`; | ||||||
|  | 								} | ||||||
|  | 								return badge; | ||||||
|  | 							} | ||||||
|  | 						}, | ||||||
|  | 					], | ||||||
|  | 					paging: false, | ||||||
|  | 					buttons: [ | ||||||
|  | 						{ | ||||||
|  | 							extend: 'excelHtml5', | ||||||
|  | 							title: () => { | ||||||
|  | 								return ` | ||||||
|  | 								User Activity Report -  | ||||||
|  | 								${moment($('#tgl0').val(), "DD-MM-YYYY HH:mm").format('DD MMM YYYY HH:mm')}  | ||||||
|  | 								to  | ||||||
|  | 								${moment($('#tgl1').val(), "DD-MM-YYYY HH:mm").format('DD MMM YYYY HH:mm')}` | ||||||
|  | 							}, | ||||||
|  | 							className: 'd-none', // hide default button | ||||||
|  | 							// exportOptions: { | ||||||
|  | 							// 	columns: ':visible:not(:last-child)' //  | ||||||
|  | 							// } | ||||||
|  | 						} | ||||||
|  | 					] | ||||||
|  | 				}); | ||||||
|  |             }, | ||||||
|  |         }; | ||||||
|  |  | ||||||
|  |         Wrapper.activate(); | ||||||
|  |     </script> | ||||||
|  | @endsection | ||||||
| @ -7,8 +7,8 @@ | |||||||
| @section('customcss') | @section('customcss') | ||||||
|     <style> |     <style> | ||||||
|         /* .select2-container { |         /* .select2-container { | ||||||
|                                                                                                                             z-index: 99999; | 			z-index: 99999; | ||||||
|                                                                                                                         } */ | 		} */ | ||||||
|     </style> |     </style> | ||||||
| @endsection | @endsection | ||||||
|  |  | ||||||
| @ -200,6 +200,13 @@ | |||||||
|                                     <label class="form-check-label" for="add-status"><span class="text-dark" id="add-txtStatus">Inactive</span></label> |                                     <label class="form-check-label" for="add-status"><span class="text-dark" id="add-txtStatus">Inactive</span></label> | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
|  |                             <div class="mb-3"> | ||||||
|  |                                 <label for="add-status-sms" class="form-label">SMS Notification</label> | ||||||
|  |                                 <div class="form-check form-switch"> | ||||||
|  |                                     <input class="form-check-input" type="checkbox" id="add-status-sms"> | ||||||
|  |                                     <label class="form-check-label" for="add-status-sms"><span class="text-dark" id="add-txtStatusSms">Inactive</span></label> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div id="add-group_track_vhc" class="row"> |                     <div id="add-group_track_vhc" class="row"> | ||||||
| @ -382,6 +389,13 @@ | |||||||
|                                     <label class="form-check-label" for="updt-status"><span class="text-dark" id="updt-txtStatus">Inactive</span></label> |                                     <label class="form-check-label" for="updt-status"><span class="text-dark" id="updt-txtStatus">Inactive</span></label> | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
|  |                             <div class="mb-3"> | ||||||
|  |                                 <label for="updt-status-sms" class="form-label">SMS Notification</label> | ||||||
|  |                                 <div class="form-check form-switch"> | ||||||
|  |                                     <input class="form-check-input" type="checkbox" id="updt-status-sms"> | ||||||
|  |                                     <label class="form-check-label" for="updt-status-sms"><span class="text-dark" id="updt-txtStatusSMS">Inactive</span></label> | ||||||
|  |                                 </div> | ||||||
|  |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
| @ -423,6 +437,11 @@ | |||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|  |     <div class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" id="mdlUserLogs" aria-labelledby="mdlUserLogsLabel" aria-hidden="true"> | ||||||
|  | 		<!-- ajax --> | ||||||
|  |     </div> | ||||||
|  |  | ||||||
| @endsection | @endsection | ||||||
|  |  | ||||||
| @section('customjs') | @section('customjs') | ||||||
| @ -456,18 +475,20 @@ | |||||||
|                 Filter.activate(); |                 Filter.activate(); | ||||||
|             }, |             }, | ||||||
|             event: function() { |             event: function() { | ||||||
|                 $('#add-status').bind('change', function() { |                 $('#add-status, #add-status-sms, #updt-status, #updt-status-sms').bind('change', function() { | ||||||
|                     if ($(this).is(':checked')) | 					const labelSpan = $(this).closest('.form-check').find('span'); | ||||||
|                         $('#add-txtStatus').html('Active') | 					labelSpan.html($(this).is(':checked') ? 'Active' : 'Inactive'); | ||||||
|                     else |                     // if ($(this).is(':checked')) | ||||||
|                         $('#add-txtStatus').html('Inactive') |                     //     $('#add-txtStatus').html('Active') | ||||||
|                 }); |                     // else | ||||||
|                 $('#updt-status').bind('change', function() { |                     //     $('#add-txtStatus').html('Inactive') | ||||||
|                     if ($(this).is(':checked')) |  | ||||||
|                         $('#updt-txtStatus').html('Active') |  | ||||||
|                     else |  | ||||||
|                         $('#updt-txtStatus').html('Inactive') |  | ||||||
|                 }); |                 }); | ||||||
|  |                 // $('#updt-status').bind('change', function() { | ||||||
|  |                 //     if ($(this).is(':checked')) | ||||||
|  |                 //         $('#updt-txtStatus').html('Active') | ||||||
|  |                 //     else | ||||||
|  |                 //         $('#updt-txtStatus').html('Inactive') | ||||||
|  |                 // }); | ||||||
|                 // $('#add-roles').on('change', function() { |                 // $('#add-roles').on('change', function() { | ||||||
|                 //     let role = $('#add-roles').val(); |                 //     let role = $('#add-roles').val(); | ||||||
|                 //     if (role == State.user_roles.checker) { |                 //     if (role == State.user_roles.checker) { | ||||||
| @ -619,10 +640,14 @@ | |||||||
|                                 // 	<span class="icon ion-eye fz-16"></span> |                                 // 	<span class="icon ion-eye fz-16"></span> | ||||||
|                                 // </a> |                                 // </a> | ||||||
|                                 let action = ` |                                 let action = ` | ||||||
|                                     <a href="#" class="text-decoration-none me-1 btnEdtUser" data-bs-toggle="tooltip" |                                     <a href="#" class="text-decoration-none me-2 btnEdtUser" data-bs-toggle="tooltip" | ||||||
|                                         data-bs-placement="bottom" title="Edit"> |                                         data-bs-placement="bottom" title="Edit"> | ||||||
|                                         <span class="icon ion-eye fz-16"></span> |                                         <span class="icon ion-eye fz-16"></span> | ||||||
|                                     </a> |                                     </a> | ||||||
|  | 									<a href="#" class="text-decoration-none me-2 btnLogUser" data-bs-toggle="tooltip" data-id="${row.id}" | ||||||
|  | 										data-bs-placement="bottom" title="Logs"> | ||||||
|  | 										<span class="icon ion-android-laptop fz-16"></span> | ||||||
|  | 									</a> | ||||||
| 								`; | 								`; | ||||||
|                                 // <a href="#" class="text-decoration-none text-danger btnDelUser" |                                 // <a href="#" class="text-decoration-none text-danger btnDelUser" | ||||||
|                                 //     data-bs-toggle="tooltip" data-bs-placement="bottom" title="Delete"> |                                 //     data-bs-toggle="tooltip" data-bs-placement="bottom" title="Delete"> | ||||||
| @ -781,6 +806,8 @@ | |||||||
|                     data.status = State.user_status.inactive; |                     data.status = State.user_status.inactive; | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|  | 				data.status_sms = ($('#add-status-sms').prop('checked')) ? 1 : 0; | ||||||
|  |  | ||||||
|                 data.is_tracking = $('#add-is_tracking').val(); |                 data.is_tracking = $('#add-is_tracking').val(); | ||||||
|                 data.vehicles = $('#add-vehicles').val(); |                 data.vehicles = $('#add-vehicles').val(); | ||||||
|                 return data; |                 return data; | ||||||
| @ -859,6 +886,26 @@ | |||||||
|                     } |                     } | ||||||
|                     UUpdate.passDataToView(resp.data); |                     UUpdate.passDataToView(resp.data); | ||||||
|                 }); |                 }); | ||||||
|  |                 $('#tUsers').on('click', '.btnLogUser', async function(e) { | ||||||
|  |                     // let uid = $(e.target).closest('tr').find('td[data-id]').data('id'); | ||||||
|  |                     // UUpdate.clearInput(); | ||||||
|  |                     // let resp = await UUpdate.reqData({ | ||||||
|  |                     //     uid | ||||||
|  |                     // }); | ||||||
|  |                     // if (resp.type != 'success') { | ||||||
|  |                     //     Helper.toast('User Not Found', 'just now', 'please try again'); | ||||||
|  |                     //     return false; | ||||||
|  |                     // } | ||||||
|  |                     // UUpdate.passDataToView(resp.data); | ||||||
|  |  | ||||||
|  | 					e.preventDefault(); | ||||||
|  | 					const id = $(this).data('id'); | ||||||
|  | 					$('#mdlUserLogs').empty().load("{{ route('view_user_logs1') }}", `id=${id}`, () => { | ||||||
|  | 						$('#mdlUserLogs').modal('show') | ||||||
|  | 					}) | ||||||
|  |  | ||||||
|  |                 }); | ||||||
|  | 				 | ||||||
|                 $('#updtUserModal').on('shown.bs.modal', function() { |                 $('#updtUserModal').on('shown.bs.modal', function() { | ||||||
|                     // initiate select2 if there |                     // initiate select2 if there | ||||||
|                 }); |                 }); | ||||||
| @ -920,6 +967,8 @@ | |||||||
|                 }); |                 }); | ||||||
|             }, |             }, | ||||||
|             passDataToView: function(data) { |             passDataToView: function(data) { | ||||||
|  | 				console.log("data", data); | ||||||
|  | 				 | ||||||
|                 $('#updt-first_name').val(data.first_name); |                 $('#updt-first_name').val(data.first_name); | ||||||
|                 $('#updt-fulladdress').val(data.fulladdress); |                 $('#updt-fulladdress').val(data.fulladdress); | ||||||
|                 $('#updt-phone').val(data.phone); |                 $('#updt-phone').val(data.phone); | ||||||
| @ -961,6 +1010,8 @@ | |||||||
|  |  | ||||||
|                 $('#updtUserModal').data('id', data.id); |                 $('#updtUserModal').data('id', data.id); | ||||||
|                 $('#updtUserModal').modal('show'); |                 $('#updtUserModal').modal('show'); | ||||||
|  |  | ||||||
|  | 				$('#updt-status-sms').prop('checked', (data.status_sms == 1) ? true : false).trigger('change'); | ||||||
|             }, |             }, | ||||||
|             getData: function() { |             getData: function() { | ||||||
|                 let data = {}; |                 let data = {}; | ||||||
| @ -996,6 +1047,8 @@ | |||||||
|                 data.is_tracking = $('#updt-is_tracking').val(); |                 data.is_tracking = $('#updt-is_tracking').val(); | ||||||
|                 data.vehicles = $('#updt-vehicles').val(); |                 data.vehicles = $('#updt-vehicles').val(); | ||||||
|  |  | ||||||
|  | 				data.status_sms = ($('#updt-status-sms').prop('checked')) ? 1 : 0; | ||||||
|  |  | ||||||
|                 return data; |                 return data; | ||||||
|             }, |             }, | ||||||
|             submitData: async function(data) { |             submitData: async function(data) { | ||||||
|  | |||||||
| @ -148,7 +148,31 @@ | |||||||
|                                             </div> |                                             </div> | ||||||
|                                         </div> |                                         </div> | ||||||
|                                     </div> |                                     </div> | ||||||
|                                 </div> | 									<div class="row"> | ||||||
|  | 										<div class="col-sm-6"> | ||||||
|  | 											<div class="mb-0"> | ||||||
|  | 												<label for="add-dc_code" class="col-form-label">Distribution Category:</label> | ||||||
|  | 												<select id="add-dc_code" class="form-control" style="width:100%;"> | ||||||
|  | 													<option value="">Choose</option> | ||||||
|  | 													@foreach ($listDistribution as $distribution) | ||||||
|  | 														<option value="{{ $distribution->dc_code }}">{{ $distribution->dc_code }} - {{ $distribution->dc_name }}</option> | ||||||
|  | 													@endforeach | ||||||
|  | 												</select> | ||||||
|  | 											</div> | ||||||
|  | 										</div> | ||||||
|  | 										<div class="col-sm-6"> | ||||||
|  | 											<div class="mb-0"> | ||||||
|  | 												<label for="add-pool_code" class="col-form-label">Pool:</label> | ||||||
|  | 												<select id="add-pool_code" class="form-control" style="width:100%;"> | ||||||
|  | 													<option value="">Choose</option> | ||||||
|  | 													@foreach ($listPool as $pool) | ||||||
|  | 														<option value="{{ $pool->pool_code }}">{{ $pool->pool_code }} - {{ $pool->pool_name }}</option> | ||||||
|  | 													@endforeach | ||||||
|  | 												</select> | ||||||
|  | 											</div> | ||||||
|  | 										</div> | ||||||
|  | 									</div> | ||||||
|  | 								</div> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
|                         {{-- Job Data --}} |                         {{-- Job Data --}} | ||||||
| @ -365,6 +389,31 @@ | |||||||
|                                         </div> |                                         </div> | ||||||
|                                     </div> |                                     </div> | ||||||
|  |  | ||||||
|  | 									<div class="row"> | ||||||
|  | 										<div class="col-sm-6"> | ||||||
|  | 											<div class="mb-0"> | ||||||
|  | 												<label for="edt-dc_code" class="col-form-label">Distribution Category:</label> | ||||||
|  | 												<select id="edt-dc_code" class="form-control" style="width:100%;"> | ||||||
|  | 													<option value="">Choose</option> | ||||||
|  | 													@foreach ($listDistribution as $distribution) | ||||||
|  | 														<option value="{{ $distribution->dc_code }}">{{ $distribution->dc_code }} - {{ $distribution->dc_name }}</option> | ||||||
|  | 													@endforeach | ||||||
|  | 												</select> | ||||||
|  | 											</div> | ||||||
|  | 										</div> | ||||||
|  | 										<div class="col-sm-6"> | ||||||
|  | 											<div class="mb-0"> | ||||||
|  | 												<label for="edt-pool_code" class="col-form-label">Pool:</label> | ||||||
|  | 												<select id="edt-pool_code" class="form-control" style="width:100%;"> | ||||||
|  | 													<option value="">Choose</option> | ||||||
|  | 													@foreach ($listPool as $pool) | ||||||
|  | 														<option value="{{ $pool->pool_code }}">{{ $pool->pool_code }} - {{ $pool->pool_name }}</option> | ||||||
|  | 													@endforeach | ||||||
|  | 												</select> | ||||||
|  | 											</div> | ||||||
|  | 										</div> | ||||||
|  | 									</div> | ||||||
|  |  | ||||||
|                                 </div> |                                 </div> | ||||||
|                             </div> |                             </div> | ||||||
|                         </div> |                         </div> | ||||||
| @ -1044,6 +1093,9 @@ | |||||||
|  |  | ||||||
|                 data.append('vendor_id', safeVal('#add-vendor_id')); |                 data.append('vendor_id', safeVal('#add-vendor_id')); | ||||||
|  |  | ||||||
|  | 				data.append('dc_code', safeVal('#add-dc_code')); | ||||||
|  | 				data.append('pool_code', safeVal('#add-pool_code')); | ||||||
|  |  | ||||||
|                 // File input (cek ada file atau tidak) |                 // File input (cek ada file atau tidak) | ||||||
|                 const fvhcFile = $('#add-fvhc-file')[0].files[0]; |                 const fvhcFile = $('#add-fvhc-file')[0].files[0]; | ||||||
|                 if (fvhcFile) data.append('fvhc_file', fvhcFile); |                 if (fvhcFile) data.append('fvhc_file', fvhcFile); | ||||||
| @ -1265,6 +1317,9 @@ | |||||||
|  |  | ||||||
|                 $('#mdlEdtVhc').data('id', data.vid); |                 $('#mdlEdtVhc').data('id', data.vid); | ||||||
|                 $('#mdlEdtVhc').modal('show'); |                 $('#mdlEdtVhc').modal('show'); | ||||||
|  |  | ||||||
|  | 				$('#edt-dc_code').val(data?.dc_code).trigger('change'); | ||||||
|  | 				$('#edt-pool_code').val(data?.pool_code).trigger('change'); | ||||||
|             }, |             }, | ||||||
|             removeOptionDevice: function(type) { |             removeOptionDevice: function(type) { | ||||||
|                 $(`#edt-deviceid option[data-type='${type}']`).remove(); |                 $(`#edt-deviceid option[data-type='${type}']`).remove(); | ||||||
| @ -1314,6 +1369,9 @@ | |||||||
|                 // data.kir_exp = $('#edt-kirexp').val().split('-').reverse().join('-'); |                 // data.kir_exp = $('#edt-kirexp').val().split('-').reverse().join('-'); | ||||||
| 				 | 				 | ||||||
|                 data.vendor_id = $('#edt-vendor_id').val(); |                 data.vendor_id = $('#edt-vendor_id').val(); | ||||||
|  | 				 | ||||||
|  | 				data.dc_code = $('#edt-dc_code').val(); | ||||||
|  | 				data.pool_code = $('#edt-pool_code').val(); | ||||||
|                 return data; |                 return data; | ||||||
|             }, |             }, | ||||||
|             submitData: async function(data) { |             submitData: async function(data) { | ||||||
|  | |||||||
| @ -42,22 +42,33 @@ | |||||||
|                         </a> |                         </a> | ||||||
|                     </li> |                     </li> | ||||||
|                 @endcan |                 @endcan | ||||||
|                 @if (auth()->user()->can('config_truck_type.view') || auth()->user()->can('config_master_device.view') || auth()->user()->can('config_logs_gps.view')) |                 @if (auth()->user()->can('report_vehicle_trip.view') || auth()->user()->can('report_abnormality.view')) | ||||||
|                     <li class="nav-item dropdown {{ Request::segment(1) == 'reports' ? 'active' : '' }}"> |                     <li class="nav-item dropdown {{ Request::segment(1) == 'reports' ? 'active' : '' }}"> | ||||||
|                         <a class="nav-link dropdown-toggle" href="#" id="dropdownConfig" role="button" data-bs-toggle="dropdown" aria-expanded="false"> |                         <a class="nav-link dropdown-toggle" href="#" id="dropdownConfig" role="button" data-bs-toggle="dropdown" aria-expanded="false"> | ||||||
|                             Reports |                             Reports | ||||||
|                         </a> |                         </a> | ||||||
|                         <ul class="dropdown-menu" style="right: 0; left: auto;" aria-labelledby="dropdownConfig"> |                         <ul class="dropdown-menu" style="right: 0; left: auto;" aria-labelledby="dropdownConfig"> | ||||||
| 							<li> | 							@can('report_vehicle_trip.view') | ||||||
| 								<a class="dropdown-item {{ Request::segment(2) == 'vehicle-trips' ? 'active' : '' }}" href="{{ route('view_report_vehicle_trips') }}" title="">Vehicle Trips</a> | 								<li> | ||||||
| 							</li> | 									<a class="dropdown-item {{ Request::segment(2) == 'vehicle-trips' ? 'active' : '' }}" href="{{ route('view_report_vehicle_trips') }}" title="">Vehicle Trips</a> | ||||||
| 							<li> | 								</li> | ||||||
| 								<a class="dropdown-item {{ Request::segment(2) == 'abnormalities' ? 'active' : '' }}" href="{{ route('view_report_abnormalities') }}" title="">Abnormalities</a> | 							@endcan | ||||||
| 							</li> | 							@can('report_abnormality.view') | ||||||
|  | 								<li> | ||||||
|  | 									<a class="dropdown-item {{ Request::segment(2) == 'abnormalities' ? 'active' : '' }}" href="{{ route('view_report_abnormalities') }}" title="">Abnormalities</a> | ||||||
|  | 								</li> | ||||||
|  | 							@endcan | ||||||
|                         </ul> |                         </ul> | ||||||
|                     </li> |                     </li> | ||||||
|                 @endif |                 @endif | ||||||
|                 @if (auth()->user()->can('config_truck_type.view') || auth()->user()->can('config_master_device.view') || auth()->user()->can('config_logs_gps.view')) |                 @if ( | ||||||
|  | 					auth()->user()->can('config_truck_type.view') ||  | ||||||
|  | 					auth()->user()->can('config_master_device.view') ||  | ||||||
|  | 					auth()->user()->can('config_logs_gps.view') || | ||||||
|  | 					auth()->user()->can('config_distribution_category.view') || | ||||||
|  | 					auth()->user()->can('config_pool.view') || | ||||||
|  | 					auth()->user()->can('user_logs.view') | ||||||
|  | 				) | ||||||
|                     <li class="nav-item dropdown {{ Request::segment(1) == 'config' ? 'active' : '' }}"> |                     <li class="nav-item dropdown {{ Request::segment(1) == 'config' ? 'active' : '' }}"> | ||||||
|                         <a class="nav-link dropdown-toggle" href="#" id="dropdownConfig" role="button" data-bs-toggle="dropdown" aria-expanded="false"> |                         <a class="nav-link dropdown-toggle" href="#" id="dropdownConfig" role="button" data-bs-toggle="dropdown" aria-expanded="false"> | ||||||
|                             Configuration |                             Configuration | ||||||
| @ -74,10 +85,31 @@ | |||||||
|                                 </li> |                                 </li> | ||||||
|                             @endcan |                             @endcan | ||||||
|                             @can('config_logs_gps.view')                                 |                             @can('config_logs_gps.view')                                 | ||||||
|                                 <li> | 								<li> | ||||||
|                                     <a class="dropdown-item {{ Request::segment(2) == 'logs_gps' ? 'active' : '' }}" href="{{ route('view_config_logs_gps') }}" title="">Logs Gps</a> |                                     <a class="dropdown-item {{ Request::segment(2) == 'logs_gps' ? 'active' : '' }}" href="{{ route('view_config_logs_gps') }}" title="">Logs Gps</a> | ||||||
|                                 </li> |                                 </li> | ||||||
|                             @endcan |                             @endcan | ||||||
|  | 							@can('config_distribution_category.view') | ||||||
|  | 								<li> | ||||||
|  |                                     <a class="dropdown-item {{ Request::segment(2) == 'distribution_category' ? 'active' : '' }}" href="{{ route('view_config_distribution_category') }}" title="">Distribution Category</a> | ||||||
|  |                                 </li> | ||||||
|  | 							@endcan | ||||||
|  | 							@can('config_pool.view') | ||||||
|  | 								<li> | ||||||
|  |                                     <a class="dropdown-item {{ Request::segment(2) == 'pool' ? 'active' : '' }}" href="{{ route('view_config_pool') }}" title="">Pool</a> | ||||||
|  |                                 </li> | ||||||
|  | 							@endcan | ||||||
|  | 							@can('user_logs.view') | ||||||
|  | 								<li> | ||||||
|  |                                     <a class="dropdown-item {{ Request::segment(1) == 'user_logs' ? 'active' : '' }}" href="{{ route('view_user_logs') }}" title="">User Activity</a> | ||||||
|  |                                 </li> | ||||||
|  |  | ||||||
|  | 							<!-- <li class="nav-item {{ Request::segment(1) == 'user_logs' ? 'active' : '' }}"> | ||||||
|  | 									<a class="nav-link d-flex align-items-center text-capitalize" aria-current="page" href="{{ route('view_user_logs') }}"> | ||||||
|  | 										User Logs | ||||||
|  | 									</a> | ||||||
|  | 								</li> --> | ||||||
|  | 							@endcan | ||||||
|                         </ul> |                         </ul> | ||||||
|                     </li> |                     </li> | ||||||
|                 @endif |                 @endif | ||||||
|  | |||||||
| @ -120,6 +120,11 @@ Route::middleware(["auth", "auth.user"])->group(function () { | |||||||
|     Route::get("/users", "UsersController@view_users") |     Route::get("/users", "UsersController@view_users") | ||||||
|         ->name("view_users") |         ->name("view_users") | ||||||
|         ->middleware("permission:user.view"); |         ->middleware("permission:user.view"); | ||||||
|  |     Route::get("/users/logs", "UsersController@view_user_logs1")->name("view_user_logs1"); | ||||||
|  |     Route::get("/api/users/logs", "UsersController@api_user_logs1")->name("api_user_logs1"); | ||||||
|  |  | ||||||
|  |     Route::get("/user-logs", "UserLogsController@view_user_logs")->name("view_user_logs"); | ||||||
|  |     Route::get("/api/user-logs", "UserLogsController@api_user_logs")->name("api_user_logs"); | ||||||
|  |  | ||||||
|     Route::get("/roles", "RolesController@view") |     Route::get("/roles", "RolesController@view") | ||||||
|         ->name("view_roles") |         ->name("view_roles") | ||||||
| @ -153,9 +158,29 @@ Route::middleware(["auth", "auth.user"])->group(function () { | |||||||
|     ); |     ); | ||||||
|     Route::get("/config/logbook_keys", "LogbookKeysController@view_lgb_keys")->name("view_config_lgb_keys"); |     Route::get("/config/logbook_keys", "LogbookKeysController@view_lgb_keys")->name("view_config_lgb_keys"); | ||||||
|  |  | ||||||
|  | 	// config distribution category | ||||||
|  |     Route::get("/config/distribution_category", "ConfDistributionController@view_distribution_category") | ||||||
|  |         ->name("view_config_distribution_category") | ||||||
|  |         ->middleware("permission:config_distribution_category.view"); | ||||||
|  |     Route::post("/api/conf/distribution_category", "ConfDistributionController@api_add_distribution_category")->name("api_conf_add_distribution_category"); | ||||||
|  |     Route::get("/api/conf/distribution_category", "ConfDistributionController@api_list_distribution_category")->name("api_conf_list_distribution_category"); | ||||||
|  |     Route::get("/api/conf/distribution_category/{id}", "ConfDistributionController@api_show_distribution_category")->name("api_conf_show_distribution_category"); | ||||||
|  |     Route::delete("/api/conf/distribution_category/{id}", "ConfDistributionController@api_del_distribution_category")->name("api_conf_del_distribution_category"); | ||||||
|  |  | ||||||
|  | 	// config pool | ||||||
|  |     Route::get("/config/pool", "ConfPoolController@view_pool") | ||||||
|  | 		->name("view_config_pool") | ||||||
|  | 		->middleware("permission:config_pool.view"); | ||||||
|  |     Route::post("/api/conf/pool", "ConfPoolController@api_add_pool")->name("api_conf_add_pool"); | ||||||
|  |     Route::get("/api/conf/pool", "ConfPoolController@api_list_pool")->name("api_conf_list_pool"); | ||||||
|  |     Route::get("/api/conf/pool/{id}", "ConfPoolController@api_show_pool")->name("api_conf_show_pool"); | ||||||
|  |     Route::delete("/api/conf/pool/{id}", "ConfPoolController@api_del_pool")->name("api_conf_del_pool")->middleware("permission:config_pool.delete"); | ||||||
|  |  | ||||||
|  |  | ||||||
| 	// reports | 	// reports | ||||||
|     Route::get("/reports/vehicle-trips", "ReportsController@view_report_vehicle_trips")->name("view_report_vehicle_trips"); |     Route::get("/reports/vehicle-trips", "ReportsController@view_report_vehicle_trips")->name("view_report_vehicle_trips"); | ||||||
|     Route::get("/reports/vehicle-trips-list", "ReportsController@api_report_vehicle_trips_list")->name("api_report_vehicle_trips_list"); |     Route::get("/reports/vehicle-trips-list", "ReportsController@api_report_vehicle_trips_list")->name("api_report_vehicle_trips_list"); | ||||||
|  |     Route::get("/reports/vehicle-trip-detail", "ReportsController@view_report_trip_detail")->name("view_report_trip_detail"); | ||||||
|     Route::get("/reports/abnormalities", "ReportsController@view_report_abnormalities")->name("view_report_abnormalities"); |     Route::get("/reports/abnormalities", "ReportsController@view_report_abnormalities")->name("view_report_abnormalities"); | ||||||
|     Route::get("/reports/abnormalities-list", "ReportsController@api_report_abnormalities_list")->name("api_report_abnormalities_list"); |     Route::get("/reports/abnormalities-list", "ReportsController@api_report_abnormalities_list")->name("api_report_abnormalities_list"); | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	