CRUD petugas/pegawai + filter-sort-rekap transaksi parkir + fix save member kartu + hilangkan alert ganti Swal-loading

This commit is contained in:
2026-10-14 11:21:07 +07:00
parent ee1f43977a
commit f3818f03f5
23 changed files with 747 additions and 53 deletions
@@ -25,6 +25,17 @@
.table td {
text-align: right;
} */
#tabel-parkir th[data-sort] {
cursor: pointer;
white-space: nowrap;
user-select: none;
}
#tabel-parkir th[data-sort]:hover {
background-color: #f2f6ff;
}
#tabel-parkir .sort-ind {
font-size: 11px;
}
</style>
@endsection
@@ -117,6 +128,17 @@ class="btn btn-sm btn-icon btn-danger btn-export-pdf" title="Cetak">
</div>
</form>
<hr class="my-3">
<div class="row g-2 mb-3" id="rekap-parkir">
<div class="col-md-3"><div class="border rounded p-2 h-100"><small class="text-muted">Total (filter aktif)</small><div class="fw-bold" id="sum-total">-</div><small class="text-muted" id="sum-total-rp"></small></div></div>
<div class="col-md-3"><div class="border rounded p-2 h-100"><small class="text-muted">Keluar (status 0)</small><div class="fw-bold" id="sum-keluar">-</div><small class="text-muted" id="sum-keluar-rp"></small></div></div>
<div class="col-md-3"><div class="border rounded p-2 h-100"><small class="text-muted">Tunai</small><div class="fw-bold text-success" id="sum-tunai">-</div><small class="text-muted" id="sum-tunai-rp"></small></div></div>
<div class="col-md-3"><div class="border rounded p-2 h-100"><small class="text-muted">Cashless</small><div class="fw-bold text-info" id="sum-cashless">-</div><small class="text-muted" id="sum-cashless-rp"></small></div></div>
<div class="col-md-2"><div class="border rounded p-2 h-100"><small class="text-muted">Casual</small><div class="fw-bold" id="sum-casual">-</div><small class="text-muted" id="sum-casual-rp"></small></div></div>
<div class="col-md-2"><div class="border rounded p-2 h-100"><small class="text-muted">Member</small><div class="fw-bold" id="sum-member">-</div><small class="text-muted" id="sum-member-rp"></small></div></div>
<div class="col-md-2"><div class="border rounded p-2 h-100"><small class="text-muted">Denda</small><div class="fw-bold" id="sum-denda">-</div><small class="text-muted" id="sum-denda-rp"></small></div></div>
<div class="col-md-3"><div class="border rounded p-2 h-100"><small class="text-muted">Manual</small><div class="fw-bold" id="sum-manual">-</div><small class="text-muted" id="sum-manual-rp"></small></div></div>
<div class="col-md-3"><div class="border rounded p-2 h-100"><small class="text-muted">Masalah (-1)</small><div class="fw-bold text-warning" id="sum-masalah">-</div><small class="text-muted" id="sum-masalah-rp"></small></div></div>
</div>
<div class="d-flex justify-content-between align-items-center mb-2">
<h5 class="card-title mb-0">Hasil Transaksi</h5>
<small class="text-muted" id="info-paging"></small>
@@ -126,18 +148,23 @@ class="btn btn-sm btn-icon btn-danger btn-export-pdf" title="Cetak">
<thead>
<tr>
<th width="4%">No.</th>
<th>ID</th>
<th>No. Pol</th>
<th>Barcode</th>
<th>Kendaraan</th>
<th>Waktu Masuk</th>
<th>Waktu Keluar</th>
<th>Status Kendaraan</th>
<th>Status Transaksi</th>
<th data-sort="id">ID <span class="sort-ind"></span></th>
<th data-sort="no_pol">No. Pol <span class="sort-ind"></span></th>
<th data-sort="no_barcode">Barcode <span class="sort-ind"></span></th>
<th data-sort="nama_kendaraan">Kendaraan <span class="sort-ind"></span></th>
<th data-sort="waktu_masuk">Waktu Masuk <span class="sort-ind"></span></th>
<th data-sort="waktu_keluar">Waktu Keluar <span class="sort-ind"></span></th>
<th data-sort="id_op_masuk">Op Masuk <span class="sort-ind"></span></th>
<th data-sort="id_op_keluar">Op Keluar <span class="sort-ind"></span></th>
<th data-sort="id_pintu_masuk">Pintu Masuk <span class="sort-ind"></span></th>
<th data-sort="id_pintu_keluar">Pintu Keluar <span class="sort-ind"></span></th>
<th data-sort="bayar_keluar">Bayar Keluar <span class="sort-ind"></span></th>
<th data-sort="status">Status Kendaraan <span class="sort-ind"></span></th>
<th data-sort="status_transaksi">Status Transaksi <span class="sort-ind"></span></th>
</tr>
</thead>
<tbody id="body-parkir">
<tr><td colspan="9" class="text-center">Memuat data...</td></tr>
<tr><td colspan="14" class="text-center">Memuat data...</td></tr>
</tbody>
</table>
</div>
@@ -162,6 +189,8 @@ class="btn btn-sm btn-icon btn-danger btn-export-pdf" title="Cetak">
$(function () {
const dataUrl = '{{ route('transaksiparkir.data', [], false) }}';
let page = 1;
let sortBy = 'tanggal';
let sortDir = 'desc';
const labelKendaraan = {1: 'Masuk', 0: 'Keluar'};
const labelTransaksi = {0: 'Casual', 3: 'Member', 32: 'Denda'};
@@ -196,23 +225,62 @@ function params(extra) {
tgl_akhir: $('#tgl_akhir').val(),
status_kendaraan: $('#status_kendaraan').val(),
status_transaksi: $('#status_transaksi').val(),
sort_by: sortBy,
sort_dir: sortDir,
page: page
};
return $.param(Object.assign(p, extra || {}));
}
function paintSort() {
$('#tabel-parkir th[data-sort] .sort-ind').text('');
const th = $('#tabel-parkir th[data-sort="' + sortBy + '"] .sort-ind');
if (th.length) th.text(sortDir === 'asc' ? '▲' : '▼');
}
$('#tabel-parkir').on('click', 'th[data-sort]', function () {
const col = $(this).data('sort');
if (sortBy === col) {
sortDir = sortDir === 'asc' ? 'desc' : 'asc';
} else {
sortBy = col;
sortDir = 'asc';
}
page = 1;
paintSort();
load();
});
function fmtRp(v) {
if (v === null || v === undefined || v === '') return '';
return 'Rp ' + Number(v).toLocaleString('id-ID');
}
function paintSummary(s) {
if (!s) return;
const segs = ['total', 'keluar', 'tunai', 'cashless', 'casual', 'member', 'denda', 'manual', 'masalah'];
segs.forEach(function (k) {
$('#sum-' + k).text((Number(s[k + '_rows']) || 0).toLocaleString('id-ID') + ' trx');
$('#sum-' + k + '-rp').text(fmtRp(s[k + '_bayar']));
});
}
function load() {
$('#body-parkir').html('<tr><td colspan="9" class="text-center">Memuat data...</td></tr>');
$('#body-parkir').html('<tr><td colspan="14" class="text-center text-muted py-4"><span class="spinner-border spinner-border-sm me-2"></span>Memuat data...</td></tr>');
$('#btn-cari').prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1"></span>Mencari...');
$('#btn-prev, #btn-next').prop('disabled', true);
$.ajax({
url: dataUrl + '?' + params(),
type: 'GET',
success: function (r) {
paintSummary(r.summary);
if (!r.data.length) {
$('#body-parkir').html('<tr><td colspan="9" class="text-center">Data tidak ditemukan.</td></tr>');
$('#body-parkir').html('<tr><td colspan="14" class="text-center">Data tidak ditemukan.</td></tr>');
} else {
let html = '';
const offset = (r.meta.current_page - 1) * r.meta.per_page;
r.data.forEach(function (row, i) {
const bayar = row.bayar_keluar === null || row.bayar_keluar === undefined || row.bayar_keluar === '' ? '' : Number(row.bayar_keluar).toLocaleString('id-ID');
html += '<tr>'
+ '<td class="text-center">' + (offset + i + 1) + '</td>'
+ '<td>' + esc(row.id) + '</td>'
@@ -221,6 +289,11 @@ function load() {
+ '<td>' + esc([row.id_kendaraan, row.nama_kendaraan].filter(Boolean).join(' - ')) + '</td>'
+ '<td>' + esc(row.waktu_masuk) + '</td>'
+ '<td>' + esc(row.waktu_keluar) + '</td>'
+ '<td>' + esc(row.id_op_masuk) + '</td>'
+ '<td>' + esc(row.id_op_keluar) + '</td>'
+ '<td>' + esc(row.id_pintu_masuk) + '</td>'
+ '<td>' + esc(row.id_pintu_keluar) + '</td>'
+ '<td class="text-end">' + bayar + '</td>'
+ '<td class="text-center">' + statusKendaraan(row.status) + '</td>'
+ '<td class="text-center">' + statusTransaksi(row.status_transaksi) + '</td>'
+ '</tr>';
@@ -238,7 +311,11 @@ function load() {
if (xhr.status === 422 && xhr.responseJSON?.errors) {
msg = Object.values(xhr.responseJSON.errors).flat().join(' ');
}
$('#body-parkir').html('<tr><td colspan="9" class="text-center text-danger">' + esc(msg) + '</td></tr>');
$('#body-parkir').html('<tr><td colspan="14" class="text-center text-danger">' + esc(msg) + '</td></tr>');
Swal.fire({icon: 'error', title: 'Gagal memuat data', text: msg});
},
complete: function () {
$('#btn-cari').prop('disabled', false).html('<i class="fa fa-search me-1"></i>Cari');
}
});
}
@@ -258,6 +335,7 @@ function load() {
});
$('.btn-export-pdf').on('click', function () { window.print(); });
paintSort();
load();
});
</script>