update vehicles history maintenance
This commit is contained in:
102
app/Http/Controllers/MaintenanceHistoryController.php
Normal file
102
app/Http/Controllers/MaintenanceHistoryController.php
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Auth;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Http\Response;
|
||||||
|
use App\Responses;
|
||||||
|
use App\Models\UserLogs;
|
||||||
|
use Validator;
|
||||||
|
|
||||||
|
class MaintenanceHistoryController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* API Get data history maintenance
|
||||||
|
*/
|
||||||
|
public function api_get_data_maintenance($vehicleid)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = DB::table('t_vehicles_maintenance_history as h')
|
||||||
|
->leftJoin('t_maintenance_vhc_type as t', function ($join) {
|
||||||
|
$join->whereRaw('FIND_IN_SET(t.id, h.idservice)');
|
||||||
|
})
|
||||||
|
->select(
|
||||||
|
'h.*',
|
||||||
|
DB::raw('GROUP_CONCAT(t.service_type SEPARATOR ", ") as service_names')
|
||||||
|
)
|
||||||
|
->where('h.vhc_id', $vehicleid)
|
||||||
|
->groupBy('h.id')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
$apiResp = Responses::success("success list maintenance vehicles");
|
||||||
|
$apiResp["data"] = $data;
|
||||||
|
return new Response($apiResp, $apiResp["meta"]["code"]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$apiResp = Responses::error($e->getMessage());
|
||||||
|
return new Response($apiResp, $apiResp["meta"]["code"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* API Update data history maintenance
|
||||||
|
*/
|
||||||
|
public function api_update_data_maintenance(Request $req, $vehicleid, $id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$now = time();
|
||||||
|
|
||||||
|
$input = [
|
||||||
|
"idservice" => $req->idservice,
|
||||||
|
"odometer" => $req->odometer,
|
||||||
|
"dates" => $req->dates,
|
||||||
|
"ismaintenance"=> $req->ismaintenance
|
||||||
|
];
|
||||||
|
$rulesInput = [
|
||||||
|
"idservice" => "required|string",
|
||||||
|
"odometer" => "required|numeric",
|
||||||
|
"dates" => "required|string",
|
||||||
|
"ismaintenance" => "required|numeric"
|
||||||
|
];
|
||||||
|
|
||||||
|
// validasi input
|
||||||
|
$isValidInput = Validator::make($input, $rulesInput);
|
||||||
|
if (!$isValidInput->passes()) {
|
||||||
|
$apiResp = Responses::bad_input($isValidInput->messages()->first());
|
||||||
|
return new Response($apiResp, $apiResp["meta"]["code"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
DB::beginTransaction();
|
||||||
|
|
||||||
|
$update = [
|
||||||
|
"idservice" => $req->idservice,
|
||||||
|
"vhc_id" => $vehicleid,
|
||||||
|
"odometer" => $req->odometer,
|
||||||
|
"dates" => $req->dates,
|
||||||
|
"ismaintenance" => $req->ismaintenance,
|
||||||
|
// "created_at" => date("Y-m-d H:i:s", $now),
|
||||||
|
// "udt" => date("Y-m-d H:i:s", $now),
|
||||||
|
// "created_by" => Auth::user()->id,
|
||||||
|
// "uby" => Auth::user()->id
|
||||||
|
];
|
||||||
|
DB::table('t_vehicles_maintenance_history')->where('id', $id)->update($update);
|
||||||
|
$apiResp = Responses::created("success update maintenance vehicles");
|
||||||
|
|
||||||
|
DB::commit();
|
||||||
|
|
||||||
|
|
||||||
|
$log = [
|
||||||
|
"module" => "Vehicle Type",
|
||||||
|
"action" => "Create",
|
||||||
|
"desc" => "Add new vehicle maintenance type: " . $req->service_type,
|
||||||
|
];
|
||||||
|
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"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -72,7 +72,7 @@ class VehiclesController extends Controller
|
|||||||
$filter["company"] = $req->cptid;
|
$filter["company"] = $req->cptid;
|
||||||
}
|
}
|
||||||
$list = DB::select("SELECT
|
$list = DB::select("SELECT
|
||||||
v.id, v.name, v.device_id, nopol1, nopol2, nopol3, v.sum_milleage,
|
v.id, v.name, v.device_id, nopol1, nopol2, nopol3, v.sum_milleage,
|
||||||
fvhc_img, vyear, t.`desc` type_name, c_name company_name, rltm.crt_d, rltm.crt crt_rltm,
|
fvhc_img, vyear, t.`desc` type_name, c_name company_name, rltm.crt_d, rltm.crt crt_rltm,
|
||||||
dvc.crt, dvc.simcard, fuel_curr, dvc.protocol, v.cat_id, vc.name cat_name
|
dvc.crt, dvc.simcard, fuel_curr, dvc.protocol, v.cat_id, vc.name cat_name
|
||||||
FROM t_vehicles as v
|
FROM t_vehicles as v
|
||||||
@ -84,7 +84,7 @@ class VehiclesController extends Controller
|
|||||||
left join t_gps_tracks_rltm rltm on rltm.vhc_id = v.id
|
left join t_gps_tracks_rltm rltm on rltm.vhc_id = v.id
|
||||||
LEFT JOIN t_vehicles_cats AS vc ON v.cat_id = vc.id
|
LEFT JOIN t_vehicles_cats AS vc ON v.cat_id = vc.id
|
||||||
WHERE v.dlt is null
|
WHERE v.dlt is null
|
||||||
ORDER BY v.id ASC
|
ORDER BY v.id ASC
|
||||||
");
|
");
|
||||||
|
|
||||||
foreach ($list as $key => $row) {
|
foreach ($list as $key => $row) {
|
||||||
|
|||||||
@ -679,6 +679,41 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="modal fade" data-bs-backdrop="static" data-bs-keyboard="false" id="mdlHistoryMaintenance"
|
||||||
|
aria-labelledby="mdlHistoryMaintenanceLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable modal-lg">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="mdlHistoryMaintenanceLabel">Maintenance History</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-bordered table-sm align-middle" id="tHistoryMaintenance">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width:35%">Service Type</th>
|
||||||
|
<th style="width:15%">Odometer</th>
|
||||||
|
<th style="width:15%">Date</th>
|
||||||
|
<th style="width:15%" class="text-center">Maintenance?</th>
|
||||||
|
<th style="width:20%" class="text-center">Action</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tHistoryMaintenanceBody">
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="text-center">No data</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-sm btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@section('customjs')
|
@section('customjs')
|
||||||
@ -705,6 +740,7 @@
|
|||||||
VNew.activate();
|
VNew.activate();
|
||||||
VEdt.activate();
|
VEdt.activate();
|
||||||
VDel.activate();
|
VDel.activate();
|
||||||
|
VHistory.activate();
|
||||||
Filter.activate();
|
Filter.activate();
|
||||||
// images
|
// images
|
||||||
DUploadAdd.activate('fvhc');
|
DUploadAdd.activate('fvhc');
|
||||||
@ -805,14 +841,14 @@
|
|||||||
searchable: true,
|
searchable: true,
|
||||||
render: function (data, type, row, meta) {
|
render: function (data, type, row, meta) {
|
||||||
let action = `
|
let action = `
|
||||||
<a href="#" class="text-decoration-none me-1 btnEdtVhc" data-vid="${data}">
|
<a href="#" class="text-decoration-none me-1 btnEdtVhc" data-vid="${data}">
|
||||||
<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-1 btnHistoryVhc" data-vid="${data}" data-catid="${row.cat_id}" title="Maintenance History">
|
||||||
// <a href="#" class="text-decoration-none text-danger btnDelVhc">
|
<span class="icon ion-clipboard fz-16"></span>
|
||||||
// <span class="icon ion-trash-b fz-16"></span>
|
</a>
|
||||||
// </a>
|
`;
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -2003,6 +2039,219 @@
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VHistory = {
|
||||||
|
options_service: [],
|
||||||
|
activate: function () {
|
||||||
|
this.event();
|
||||||
|
},
|
||||||
|
event: function () {
|
||||||
|
// buka modal
|
||||||
|
$('#tVehicles').on('click', '.btnHistoryVhc', function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
const vid = $(this).data('vid');
|
||||||
|
const catid = $(this).data('catid');
|
||||||
|
$('#mdlHistoryMaintenance').data('vid', vid);
|
||||||
|
VHistory.load(vid, catid);
|
||||||
|
$('#mdlHistoryMaintenance').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
// toggle Edit -> enable row
|
||||||
|
$('#tHistoryMaintenanceBody').on('click', '.btnEditRow', function () {
|
||||||
|
const $row = $(this).closest('tr');
|
||||||
|
VHistory.enableRow($row);
|
||||||
|
$(this)
|
||||||
|
.text('Save')
|
||||||
|
.removeClass('btn-outline-primary btnEditRow')
|
||||||
|
.addClass('btn-success btnSaveRow');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save row
|
||||||
|
$('#tHistoryMaintenanceBody').on('click', '.btnSaveRow', function () {
|
||||||
|
const $row = $(this).closest('tr');
|
||||||
|
VHistory.saveRow($row, $(this));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
load: async function (vid, catid) {
|
||||||
|
$('#tHistoryMaintenanceBody').html('<tr><td colspan="5" class="text-center">Loading...</td></tr>');
|
||||||
|
try {
|
||||||
|
const respTypes = await VHistory.loadServiceTypes(catid);
|
||||||
|
VHistory.options_service = respTypes || [];
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "{{ route('api_get_data_maintenance', '') }}/" + vid,
|
||||||
|
method: 'GET',
|
||||||
|
headers: { 'x-api-key': Helper.getCookie('_trtk') },
|
||||||
|
success: (res) => {
|
||||||
|
if (res.meta.type != 'success') {
|
||||||
|
Helper.toast('Warning', 'just now', res.meta.message);
|
||||||
|
$('#tHistoryMaintenanceBody').html('<tr><td colspan="5" class="text-center">Failed to load data</td></tr>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
VHistory.render(res.data);
|
||||||
|
},
|
||||||
|
error: (jqXHR) => {
|
||||||
|
$('#tHistoryMaintenanceBody').html('<tr><td colspan="5" class="text-center">Failed to load data</td></tr>');
|
||||||
|
Helper.toast('Error', 'just now', jqXHR.responseJSON?.meta?.message || 'Failed to load history');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
$('#tHistoryMaintenanceBody').html('<tr><td colspan="5" class="text-center">Failed to load data</td></tr>');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadServiceTypes: function (catid) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
$.ajax({
|
||||||
|
url: "{{ route('api_list_vehicle_maintenance_type') }}",
|
||||||
|
method: 'GET',
|
||||||
|
headers: { 'x-api-key': Helper.getCookie('_trtk') },
|
||||||
|
success: (res) => resolve(res.data || []),
|
||||||
|
error: () => resolve([]),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
render: function (rows) {
|
||||||
|
if (!rows || rows.length < 1) {
|
||||||
|
$('#tHistoryMaintenanceBody').html('<tr><td colspan="5" class="text-center">No data</td></tr>');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = '';
|
||||||
|
rows.forEach((row) => {
|
||||||
|
const selectedIds = (row.idservice || '').split(',').map((v) => v.trim());
|
||||||
|
const options = VHistory.options_service
|
||||||
|
.map((opt) => `<option value="${opt.id}" ${selectedIds.includes(String(opt.id)) ? 'selected' : ''}>${opt.service_type}</option>`)
|
||||||
|
.join('');
|
||||||
|
|
||||||
|
const isChecked = Number(row.ismaintenance) === 1 ? 'checked' : '';
|
||||||
|
|
||||||
|
html += `
|
||||||
|
<tr data-hid="${row.id}">
|
||||||
|
<td>
|
||||||
|
<select class="form-select form-select-sm history-service" multiple disabled style="width:100%;">
|
||||||
|
${options}
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="number" class="form-control form-control-sm history-odometer" value="${row.odometer ?? ''}" disabled>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" class="form-control form-control-sm history-date" value="${row.dates ?? ''}" disabled autocomplete="off">
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<div class="form-check form-switch d-flex justify-content-center">
|
||||||
|
<input class="form-check-input history-ismaintenance" type="checkbox" role="switch" ${isChecked} disabled>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-primary btnEditRow">Edit</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#tHistoryMaintenanceBody').html(html);
|
||||||
|
|
||||||
|
// init select2 tiap row (tetap disabled dulu)
|
||||||
|
$('#tHistoryMaintenanceBody .history-service').each(function () {
|
||||||
|
$(this).select2({
|
||||||
|
dropdownParent: $('#mdlHistoryMaintenance'),
|
||||||
|
width: '100%',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// init datepicker tiap row
|
||||||
|
$('#tHistoryMaintenanceBody .history-date').datepicker({
|
||||||
|
format: 'yyyy-mm-dd',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
enableRow: function ($row) {
|
||||||
|
$row.find('.history-odometer').prop('disabled', false);
|
||||||
|
$row.find('.history-date').prop('disabled', false);
|
||||||
|
$row.find('.history-ismaintenance').prop('disabled', false);
|
||||||
|
|
||||||
|
const $select = $row.find('.history-service');
|
||||||
|
$select.prop('disabled', false);
|
||||||
|
$select.select2('destroy');
|
||||||
|
$select.select2({
|
||||||
|
dropdownParent: $('#mdlHistoryMaintenance'),
|
||||||
|
width: '100%',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
disableRow: function ($row) {
|
||||||
|
$row.find('.history-odometer').prop('disabled', true);
|
||||||
|
$row.find('.history-date').prop('disabled', true);
|
||||||
|
$row.find('.history-ismaintenance').prop('disabled', true);
|
||||||
|
|
||||||
|
const $select = $row.find('.history-service');
|
||||||
|
$select.prop('disabled', true);
|
||||||
|
$select.select2('destroy');
|
||||||
|
$select.select2({
|
||||||
|
dropdownParent: $('#mdlHistoryMaintenance'),
|
||||||
|
width: '100%',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
saveRow: function ($row, $btn) {
|
||||||
|
const vid = $('#mdlHistoryMaintenance').data('vid');
|
||||||
|
const hid = $row.data('hid');
|
||||||
|
const idservice = $row.find('.history-service').val(); // array
|
||||||
|
const odometer = $row.find('.history-odometer').val();
|
||||||
|
const dates = $row.find('.history-date').val();
|
||||||
|
const ismaintenance = $row.find('.history-ismaintenance').is(':checked') ? 1 : 0;
|
||||||
|
|
||||||
|
if (!idservice || idservice.length < 1) {
|
||||||
|
Helper.toast('Validasi', 'just now', 'Service type wajib diisi');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!odometer) {
|
||||||
|
Helper.toast('Validasi', 'just now', 'Odometer wajib diisi');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!dates) {
|
||||||
|
Helper.toast('Validasi', 'just now', 'Tanggal wajib diisi');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$btn.prop('disabled', true).text('Saving...');
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "{{ route('api_update_data_maintenance', ['vehicleid' => '__VID__', 'id' => '__ID__']) }}"
|
||||||
|
.replace('__VID__', vid)
|
||||||
|
.replace('__ID__', hid),
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'x-api-key': Helper.getCookie('_trtk'),
|
||||||
|
'x-csrf-token': $('meta[name="csrf-token"]').attr('content'),
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
idservice: idservice.join(','),
|
||||||
|
odometer: odometer,
|
||||||
|
dates: dates,
|
||||||
|
ismaintenance: ismaintenance,
|
||||||
|
},
|
||||||
|
success: (res) => {
|
||||||
|
$btn.prop('disabled', false);
|
||||||
|
if (res.meta.type != 'success') {
|
||||||
|
Helper.toast('Warning', 'just now', res.meta.message);
|
||||||
|
$btn.text('Save');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Helper.toast('Success', 'just now', 'Berhasil update maintenance history');
|
||||||
|
VHistory.disableRow($row);
|
||||||
|
$btn.text('Edit')
|
||||||
|
.removeClass('btn-success btnSaveRow')
|
||||||
|
.addClass('btn-outline-primary btnEditRow');
|
||||||
|
},
|
||||||
|
error: (jqXHR) => {
|
||||||
|
$btn.prop('disabled', false).text('Save');
|
||||||
|
if (jqXHR.status >= 500) {
|
||||||
|
Helper.toast('Error', 'just now', 'Please try again');
|
||||||
|
} else {
|
||||||
|
Helper.toast('Error', 'just now', jqXHR.responseJSON?.meta?.message || 'Gagal menyimpan');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
Wrapper.activate();
|
Wrapper.activate();
|
||||||
</script>
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|||||||
@ -334,6 +334,9 @@ Route::middleware(["auth", "auth.user"])->group(function () {
|
|||||||
"api_search_nopol"
|
"api_search_nopol"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Route::get("/api/maintenances/{vid}", "MaintenanceHistoryController@api_get_data_maintenance")->name("api_get_data_maintenance");
|
||||||
|
Route::put("/api/maintenances/{vehicleid}/{id}", "MaintenanceHistoryController@api_update_data_maintenance")->name("api_update_data_maintenance");
|
||||||
|
|
||||||
Route::get("/api/zones", "ZoneController@api_list_zones")->name("api_list_zones");
|
Route::get("/api/zones", "ZoneController@api_list_zones")->name("api_list_zones");
|
||||||
Route::get("/api/zones/{zid}", "ZoneController@api_show_zone")->name("api_show_zone");
|
Route::get("/api/zones/{zid}", "ZoneController@api_show_zone")->name("api_show_zone");
|
||||||
Route::post("/api/zones", "ZoneController@api_add_zone")->name("api_add_zone");
|
Route::post("/api/zones", "ZoneController@api_add_zone")->name("api_add_zone");
|
||||||
|
|||||||
Reference in New Issue
Block a user