Files
backend_parkir/resources/views/setup/gate/gate.blade.php
T

590 lines
30 KiB
PHP

@extends('layouts.master')
@section('styles')
<style>
.card-body label {
font-size: 13px;
color: #6c757d;
}
.card-body .form-control,
.card-body .form-select {
font-size: 14px;
}
#search-button {
font-weight: 600;
letter-spacing: .3px;
}
.table-garis, .garis {
border: 0.1px solid black; /* Sets a 1px solid black border */
border-collapse: collapse;
}
.text-label {
color: #000000;
}
#example tbody tr:not(.edit-row) {
cursor: pointer;
}
#example tbody tr.table-active td {
background-color: #e7f1ff;
}
/*
.table-selectable tbody tr {
cursor: pointer;
transition: 0.15s;
}
.table-selectable tbody tr:hover {
background-color: #f2f6ff;
}
.table-selectable tbody tr.selected {
background-color: #0d6efd !important;
color: #fff;
}
.table-selectable tbody tr.selected td {
color: #fff !important;
} */
</style>
@endsection
@section('content')
<!-- partial -->
<div class="container-fluid page-body-wrapper">
<div class="main-panel">
<div class="content-wrapper">
<div class="row">
<div class="col-2">
</div>
<div class="col-12 col-md-8 grid-margin justify-content-center stretch-card">
<div class="card">
<div class="card-body">
<h4 class="card-title">Daftar Pintu/Pos</h4>
<div class="table-responsive mb-2">
<table class="table table-bordered table-selectable" id="example" data-url="{{ route('getMember') }}">
<thead>
<tr>
<th class="p-3" width="5%">No.</th>
<th style="text-align: center;">Nama Pintu</th>
<th style="text-align: center;">Mode Pintu</th>
<th style="text-align: center;">Grace Periode</th>
<th style="text-align: center;">Manless?</th>
<th style="text-align: center;" width="15%">Area Parkir</th>
<th style="text-align: center;">Pengaturan</th>
</tr>
</thead>
<tbody>
@foreach ($Gate as $pintu)
@php
if ($pintu->jenis === 0 ) {
$jenis = 'Masuk';
} elseif ($pintu->jenis === 1) {
$jenis = 'Keluar';
}
$isManless = $pintu->manless === 1
? '<span class="d-inline-block rounded-circle bg-success" style="width:12px;height:12px;"></span>'
: '<span class="d-inline-block rounded-circle bg-danger" style="width:12px;height:12px;"></span>';
@endphp
<tr data-gate-id="{{ $pintu->id }}"
data-gate-nama="{{ $pintu->nama }}"
data-gate-jenis="{{ $pintu->jenis }}"
data-gate-grace="{{ $pintu->grace_period }}"
data-gate-manless="{{ $pintu->manless }}"
data-gate-area="{{ $pintu->area }}"
data-gate-tanggal="{{ $pintu->tanggal }}">
<td class="text-center">{{ $loop->iteration }}</td>
{{-- <td class="text-center" width="7%">{{ $pintu->id }}</td> --}}
<td>{{ $pintu->nama }} <strong> - ({{ $pintu->id }})</strong></td>
<td width="10%">{{
match($pintu->jenis) {
0 => 'Masuk',
1 => 'Keluar',
2 => 'Transit',
3 => 'Emergency',
default => '-'
}
}}</td>
<td class="text-center" width="7%"><span class="d-inline-block rounded-circle
{{ $pintu->grace_period === 1 ? 'bg-success' : 'bg-danger' }}"
style="width:12px;height:12px;">
</span></td>
<td class="text-center" width="7%"><span class="d-inline-block rounded-circle
{{ $pintu->manless === 1 ? 'bg-success' : 'bg-danger' }}"
style="width:12px;height:12px;">
</span>
</td>
<td class="text-center">
@if ($pintu->areaParkir)
<span class="badge bg-primary">{{ $pintu->areaParkir->nama_lokasi }}</span>
<small class="text-muted d-block">{{ $pintu->areaParkir->id_lokasi }}</small>
@elseif ($pintu->area)
<span class="badge bg-warning text-dark">{{ $pintu->area }}</span>
<small class="text-muted d-block">Area tidak ditemukan</small>
@else
<span class="badge bg-secondary">Belum diset</span>
@endif
</td>
<td class="text-center text-nowrap" width="18%">
<a class="btn btn-warning btn-sm parameter-button" id="parameter" data-bs-toggle="modal" data-bs-target=".bd-ubah-modal-lg">Pos</a>
<button class="btn btn-primary btn-sm hardware-button" data-id="{{ $pintu->id }}" data-nama="{{ $pintu->nama }}">Hardware</button>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="d-flex justify-content-center align-items-center mt-2">
<div>
<button class="btn btn-primary btn-sm add-button" id="btnAddGate" type="button">Tambah</button>
<button class="btn btn-warning btn-sm" id="btnEdit" type="button" disabled>Ubah</button>
<button class="btn btn-danger btn-sm" id="btnDeleteGate" type="button" disabled>Hapus</button>
<button class="btn btn-info btn-sm" id="btnDetailGate" type="button" disabled>Detail</button>
</div>
</div>
<!-- ADD MEMMBER MODAL -->
{{-- @include('stiker.tambah-stiker')
@include('stiker.ubah-stiker') --}}
<!-- END MEMMBER MODAL -->
</div>
</div>
</div>
<div class="col-2">
</div>
</div>
</div>
</div>
</div>
<div class="modal fade" id="gate-form-modal" tabindex="-1">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<form id="form-gate">
<div class="modal-header">
<h5 class="modal-title" id="gate-form-title">Tambah Pintu/Pos</h5>
<button class="btn-close" data-bs-dismiss="modal" type="button"></button>
</div>
<div class="modal-body">
<input type="hidden" id="gate-mode">
<div class="row g-3">
<div class="col-md-4">
<label class="form-label" for="gate-id">ID Pintu/Pos</label>
<input class="form-control text-uppercase" id="gate-id" name="id" maxlength="10" required>
</div>
<div class="col-md-8">
<label class="form-label" for="gate-nama">Nama Pintu/Pos</label>
<input class="form-control" id="gate-nama" name="nama" maxlength="100" required>
</div>
<div class="col-md-4">
<label class="form-label" for="gate-jenis">Mode Pintu</label>
<select class="form-select" id="gate-jenis" name="jenis" required>
<option value="0">Masuk</option>
<option value="1">Keluar</option>
<option value="2">Transit</option>
<option value="3">Emergency</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label" for="gate-grace">Grace Periode</label>
<select class="form-select" id="gate-grace" name="grace_period">
<option value="1">Aktif</option>
<option value="0">Nonaktif</option>
</select>
</div>
<div class="col-md-4">
<label class="form-label" for="gate-manless">Manless</label>
<select class="form-select" id="gate-manless" name="manless">
<option value="1">Ya</option>
<option value="0">Tidak</option>
</select>
</div>
<div class="col-md-6">
<label class="form-label" for="gate-area">Area Parkir</label>
<select class="form-select" id="gate-area" name="area">
<option value="">-- Tanpa Area --</option>
@foreach ($Area as $area)
<option value="{{ $area->id_lokasi }}">{{ $area->nama_lokasi }} ({{ $area->id_lokasi }})</option>
@endforeach
</select>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-light border" data-bs-dismiss="modal" type="button">Batal</button>
<button class="btn btn-primary" id="btn-save-gate" type="submit">Simpan</button>
</div>
</form>
</div>
</div>
</div>
<div class="modal fade" id="gate-detail-modal" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Detail Pintu/Pos</h5>
<button class="btn-close" data-bs-dismiss="modal" type="button"></button>
</div>
<div class="modal-body" id="gate-detail-body"></div>
</div>
</div>
</div>
@endsection
@section('javascript')
<!--********* Scripts *********-->
<!-- Datatable -->
<!--********* Scripts *********-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.5/jquery.validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/metisMenu/3.0.7/metisMenu.min.js"></script>
<script src="{{asset ('vendor/moment/moment.min.js') }}"></script>
<script src="{{asset ('vendor/bootstrap-daterangepicker/daterangepicker.js') }}"></script>
<script src="{{asset ('vendor/bootstrap-select/dist/js/bootstrap-select.min.js') }}"></script>
<script src="{{asset ('vendor/sweetalert2/dist/sweetalert2.min.js') }}"></script>
<script src="{{asset ('js/custom.min.js') }}"></script>
<script src="{{asset ('js/dlabnav-init.js') }}"></script>
<script src="{{asset ('js/member/index.js') }}"></script>
<script src="{{asset ('js/member/member-register.js') }}"></script>
<script>
$(document).ready(function () {
const routes = {
store: "{{ route('gate.store', [], false) }}",
show: "{{ route('gate.show', ':id', false) }}",
update: "{{ route('gate.update', ':id', false) }}",
destroy: "{{ route('gate.destroy', ':id', false) }}"
};
const csrfToken = "{{ csrf_token() }}";
let selectedGate = null;
function openGateForm(mode, gate) {
const isEdit = mode === 'edit';
$('#form-gate')[0].reset();
$('#gate-mode').val(mode);
$('#gate-form-title').text(isEdit ? 'Ubah Pintu/Pos' : 'Tambah Pintu/Pos');
$('#gate-id').val(gate?.gateId || '').prop('readonly', isEdit);
$('#gate-nama').val(gate?.gateNama || '');
$('#gate-jenis').val(gate?.gateJenis ?? 0);
$('#gate-grace').val(gate?.gateGrace ?? 1);
$('#gate-manless').val(gate?.gateManless ?? 0);
$('#gate-area').val(gate?.gateArea || '');
new bootstrap.Modal(document.getElementById('gate-form-modal')).show();
}
$('#example tbody').on('click', 'tr:not(.edit-row)', function () {
$('#example tbody tr').removeClass('table-active');
$(this).addClass('table-active');
selectedGate = $(this).data();
$('#btnEdit, #btnDeleteGate, #btnDetailGate').prop('disabled', false);
});
$('#btnAddGate').on('click', function () {
openGateForm('create');
});
$('#btnEdit').on('click', function () {
if (!selectedGate) return;
openGateForm('edit', selectedGate);
});
$('#form-gate').on('submit', function (event) {
event.preventDefault();
const isEdit = $('#gate-mode').val() === 'edit';
const id = $('#gate-id').val();
const btn = $('#btn-save-gate');
const btnHtml = btn.html();
btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1"></span>Menyimpan...');
$.ajax({
url: isEdit ? routes.update.replace(':id', encodeURIComponent(id)) : routes.store,
type: isEdit ? 'PUT' : 'POST',
data: $('#form-gate').serialize(),
headers: { 'X-CSRF-TOKEN': csrfToken },
success: function (r) {
bootstrap.Modal.getInstance(document.getElementById('gate-form-modal'))?.hide();
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: r.message || 'Data pintu/pos disimpan.',
timer: 1300,
showConfirmButton: false
}).then(() => window.location.reload());
},
error: function (xhr) {
btn.prop('disabled', false).html(btnHtml);
Swal.fire({
icon: 'error',
title: 'Gagal menyimpan',
text: xhr.responseJSON?.message || Object.values(xhr.responseJSON?.errors || {}).flat().join('\n') || 'Gagal menyimpan pintu/pos.'
});
}
});
});
$('#btnDeleteGate').on('click', function () {
if (!selectedGate) return;
Swal.fire({
title: 'Hapus pintu/pos?',
text: `${selectedGate.gateId} - ${selectedGate.gateNama}`,
icon: 'warning',
showCancelButton: true,
confirmButtonText: 'Ya, hapus',
cancelButtonText: 'Batal',
confirmButtonColor: '#dc3545',
showLoaderOnConfirm: true,
preConfirm: () => $.ajax({
url: routes.destroy.replace(':id', encodeURIComponent(selectedGate.gateId)),
type: 'DELETE',
headers: { 'X-CSRF-TOKEN': csrfToken }
}).catch(xhr => {
Swal.showValidationMessage(xhr.responseJSON?.message || 'Pintu/pos tidak dapat dihapus.');
})
}).then(result => {
if (result.isConfirmed && result.value) {
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: 'Pintu/pos dihapus.',
timer: 1300,
showConfirmButton: false
}).then(() => window.location.reload());
}
});
});
$('#btnDetailGate').on('click', function () {
if (!selectedGate) return;
const btn = $(this);
const btnHtml = btn.html();
btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1"></span>Memuat...');
$('#gate-detail-body').html('<div class="text-center py-3"><span class="spinner-border spinner-border-sm me-2"></span>Memuat detail...</div>');
new bootstrap.Modal(document.getElementById('gate-detail-modal')).show();
$.get(routes.show.replace(':id', encodeURIComponent(selectedGate.gateId)), function (r) {
const d = r.data;
const jenis = { 0: 'Masuk', 1: 'Keluar', 2: 'Transit', 3: 'Emergency' };
const area = d.area_parkir
? `${esc(d.area_parkir.nama_lokasi)} (${esc(d.area_parkir.id_lokasi)})`
: (d.area ? esc(d.area) + ' (tidak ditemukan)' : 'Tanpa Area');
$('#gate-detail-body').html(`<dl class="row mb-0"><dt class="col-5">ID Pintu/Pos</dt><dd class="col-7">${esc(d.id)}</dd><dt class="col-5">Nama</dt><dd class="col-7">${esc(d.nama)}</dd><dt class="col-5">Mode Pintu</dt><dd class="col-7">${jenis[d.jenis] ?? '-'}</dd><dt class="col-5">Grace Periode</dt><dd class="col-7">${Number(d.grace_period) === 1 ? 'Aktif' : 'Nonaktif'}</dd><dt class="col-5">Manless</dt><dd class="col-7">${Number(d.manless) === 1 ? 'Ya' : 'Tidak'}</dd><dt class="col-5">Area Parkir</dt><dd class="col-7">${area}</dd><dt class="col-5">Dibuat</dt><dd class="col-7">${esc(d.tanggal || '-')}</dd></dl>`);
}).fail(function (xhr) {
$('#gate-detail-body').html('<div class="text-danger text-center">' + (xhr.responseJSON?.message || 'Gagal memuat detail.') + '</div>');
}).always(function () {
btn.prop('disabled', false).html(btnHtml);
});
});
$(document).on('click', '.hardware-button', function () {
let btn = $(this);
let btnHtml = btn.html();
let row = $(this).closest('tr');
// kalau sudah ada baris edit, hapus dulu
$('.edit-row').remove();
let id = $(this).data('id');
let nama = $(this).data('nama');
// # base url tanpa parameter biar tidak dobel slash
let baseUrl = "{{ url('setup/master/gate-hardware') }}";
btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1"></span>Memuat...');
$.ajax({
url: baseUrl + "/" + id,
type: 'GET',
success: function (r) {
r = r || {};
console.log(r);
let colSpan = row.children('td').length;
// # daftar field yang ditampilkan (key database + label)
let fields = [
['printer1_avail', 'Printer Status'],
['printer1_conn', 'Printer Connection'],
['printer1_spd', 'Printer Speed/Baudrate'],
['printer1_dummy', 'Jarak Potong Kertas'],
['video1_avail', 'Kamera Status'],
['video1_conn', 'Kamera URL/Path'],
['sound_avail', 'Sound Status'],
['bg_avail', 'BGate Status'],
['bg_conn', 'BGate Connection'],
['bank_reader_avail', 'Reader BANK Status'],
['bank_reader_comm', 'Reader BANK Connection'],
['bank_reader_key', 'Reader BANK Key/Parameter'],
['smartcard_avail', 'Smartcard Status'],
['smartcard_speed', 'Smartcard Speed/Baudrate'],
['smartcard_port', 'Smartcard Port'],
];
let cards = '';
for (let i = 0; i < fields.length; i ++) {
let f1 = fields[i];
let val = r[f1[0]] ?? '';
cards += `
<div class="col-12 col-sm-6 col-lg-3 mb-2">
<div class="border rounded p-2 h-100">
<div class="fw-semibold text-muted text-label mb-1"><strong>${f1[1]}</strong></div>
<div>
<span class="view-mode">${formatValue(f1[0], r[f1[0]])}</span>
<input type="text"
class="form-control form-control-sm edit-mode d-none"
data-key="${f1[0]}"
data-orig="${esc(val)}"
value="${esc(val)}">
</div>
</div>
</div>
`;
}
let editHtml = `
<tr class="edit-row" data-id="${id}">
<td colspan="${colSpan}">
<div class="card shadow-sm">
<div class="card-header d-flex justify-content-between align-items-center">
<strong>Hardware Configuration - ${esc(nama)} (${esc(id)})</strong>
<div>
<button class="btn btn-sm btn-primary btn-edit">Edit</button>
<button class="btn btn-sm btn-success btn-save d-none">Save</button>
<button class="btn btn-sm btn-secondary btn-cancel d-none">Cancel</button>
</div>
</div>
<div class="card-body p-2">
<div class="row">
${cards}
</div>
</div>
</div>
</td>
</tr>
`;
row.after(editHtml);
},
error: function (xhr) {
console.error(xhr.responseText);
Swal.fire({icon: 'error', title: 'Gagal memuat hardware', text: xhr.responseJSON?.message || 'Cek koneksi / hubungi admin.'});
},
complete: function () {
btn.prop('disabled', false).html(btnHtml);
}
});
});
// MODE EDIT
$(document).on('click', '.btn-edit', function () {
$('.view-mode').addClass('d-none');
$('.edit-mode').removeClass('d-none');
$('.btn-edit').addClass('d-none');
$('.btn-save, .btn-cancel').removeClass('d-none');
});
// CANCEL
$(document).on('click', '.btn-cancel', function () {
// # kembalikan isian ke nilai semula
$('.edit-mode').each(function () {
$(this).val($(this).data('orig') ?? '');
});
$('.edit-mode').addClass('d-none');
$('.view-mode').removeClass('d-none');
$('.btn-save, .btn-cancel').addClass('d-none');
$('.btn-edit').removeClass('d-none');
});
// SAVE
$(document).on('click', '.btn-save', function () {
const btn = $(this);
const origHtml = btn.html();
let dataToSend = {};
let gateId = $('.edit-row').data('id');
$('.edit-mode').each(function () {
let key = $(this).data('key');
dataToSend[key] = $(this).val();
});
console.log(dataToSend);
// # base url tanpa parameter biar tidak dobel slash
let baseUrl = "{{ url('setup/master/gate-hardware') }}";
btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1"></span>Menyimpan...');
$.ajax({
url: baseUrl + "/" + gateId,
type: "POST",
data: {
_token: "{{ csrf_token() }}",
_method: "PUT",
data: dataToSend
},
success: function (res) {
// # tampilkan ulang nilai yang baru disimpan
$('.edit-mode').each(function () {
let key = $(this).data('key');
let val = $(this).val();
$(this).data('orig', val);
$(this).siblings('.view-mode').html(formatValue(key, val));
});
$('.btn-cancel').click();
Swal.fire({icon: 'success', title: 'Berhasil', text: 'Konfigurasi hardware tersimpan.'});
},
error: function (xhr) {
console.error(xhr.responseText);
Swal.fire({icon: 'error', title: 'Gagal menyimpan', text: xhr.responseJSON?.message || 'Cek koneksi / hubungi admin.'});
},
complete: function () {
btn.prop('disabled', false).html(origHtml);
}
});
});
// # amankan teks biar tanda kutip tidak merusak HTML
function esc(value) {
if (value === null || value === undefined) return '';
return String(value)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
function formatValue(key, value) {
// kalau field *_avail kita kasih badge
if (key.includes('_avail')) {
if (value == 1) {
return `<span class="badge rounded-pill bg-success px-3">ON</span>`;
} else {
return `<span class="badge rounded-pill bg-danger px-3">OFF</span>`;
}
}
// default
if (value === null || value === undefined || value === '') {
return '-';
}
return esc(value);
}
});
</script>
@endsection