342 lines
21 KiB
PHP
342 lines
21 KiB
PHP
@extends('layouts.master')
|
|
|
|
@section('styles')
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
|
|
<link rel="stylesheet" href="{{ asset('vendors/select2/select2.min.css') }}">
|
|
<style>
|
|
.select2-container .select2-selection--single {
|
|
height: 48px;
|
|
}
|
|
|
|
.select2-container--default
|
|
.select2-selection--single
|
|
.select2-selection__rendered {
|
|
line-height: 38px;
|
|
}
|
|
|
|
.select2-container--default
|
|
.select2-selection--single
|
|
.select2-selection__arrow {
|
|
height: 38px;
|
|
}
|
|
/* .table th {
|
|
text-align: center;
|
|
}
|
|
.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
|
|
|
|
@section('content')
|
|
<!-- partial -->
|
|
<div class="container-fluid page-body-wrapper">
|
|
<div class="main-panel">
|
|
<div class="content-wrapper">
|
|
<div class="row">
|
|
<div class="col-md-12 grid-margin stretch-card">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
</div>
|
|
<div class="card-body">
|
|
<form id="filter-parkir" action="javascript:void(0)">
|
|
<div class="row align-items-end g-2">
|
|
<!-- CARI DATA -->
|
|
<div class="col-md-1">
|
|
<div class="form-group">
|
|
<label for="q">Cari Data</label>
|
|
<input type="text" class="form-control form-control-sm" id="q" placeholder="Keyword">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-1">
|
|
<div class="form-group">
|
|
<label for="field">Field</label>
|
|
<select class="form-control form-control-sm js-example-basic-single" id="field">
|
|
<option value="id" selected>No. ID</option>
|
|
<option value="no_pol">No. Pol</option>
|
|
<option value="no_barcode">No. Transaksi</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<!-- PERIODE -->
|
|
<div class="col-md-2">
|
|
<div class="form-group">
|
|
<label for="tgl_awal">Periode Awal</label>
|
|
<input type="date" class="form-control form-control-sm" id="tgl_awal" name="tgl_awal">
|
|
</div>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<div class="form-group">
|
|
<label for="tgl_akhir">Periode Akhir</label>
|
|
<input type="date" class="form-control form-control-sm" id="tgl_akhir" name="tgl_akhir">
|
|
</div>
|
|
</div>
|
|
<!-- STATUS KENDARAAN : 1 masuk, 0 keluar -->
|
|
<div class="col-md-1">
|
|
<div class="form-group">
|
|
<label for="status_kendaraan">Kendaraan</label>
|
|
<select class="form-control form-control-sm js-example-basic-single" id="status_kendaraan">
|
|
<option value="" selected>Semua</option>
|
|
<option value="1">Masuk</option>
|
|
<option value="0">Keluar</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<!-- STATUS TRANSAKSI : 0 casual, 3 member, 32 denda -->
|
|
<div class="col-md-2">
|
|
<div class="form-group">
|
|
<label for="status_transaksi">Transaksi</label>
|
|
<select class="form-control form-control-sm js-example-basic-single" id="status_transaksi">
|
|
<option value="" selected>Semua</option>
|
|
<option value="0">Casual</option>
|
|
<option value="3">Member</option>
|
|
<option value="32">Denda</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<!-- AKSI -->
|
|
<div class="col-md-2 d-flex align-items-end gap-1">
|
|
<button type="submit" class="btn btn-sm btn-primary" id="btn-cari">
|
|
<i class="fa fa-search me-1"></i>Cari
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-secondary" id="btn-reset">Reset</button>
|
|
</div>
|
|
<!-- BUTTON EXPORT -->
|
|
<div class="col-md-1 text-end">
|
|
<div class="btn-list d-inline-flex gap-1">
|
|
<button type="button"
|
|
class="btn btn-sm btn-icon btn-success btn-export-excel" title="Export CSV">
|
|
<i class="fa fa-file-excel-o"></i>
|
|
</button>
|
|
<button type="button"
|
|
class="btn btn-sm btn-icon btn-danger btn-export-pdf" title="Cetak">
|
|
<i class="fa fa-file-pdf-o"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</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>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-striped" id="tabel-parkir">
|
|
<thead>
|
|
<tr>
|
|
<th width="4%">No.</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="14" class="text-center">Memuat data...</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="d-flex justify-content-between align-items-center mt-3">
|
|
<button class="btn btn-sm btn-outline-primary" id="btn-prev" type="button">« Sebelumnya</button>
|
|
<span class="text-muted" id="label-halaman"></span>
|
|
<button class="btn btn-sm btn-outline-primary" id="btn-next" type="button">Berikutnya »</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('javascript')
|
|
<script src="{{ asset('vendors/select2/select2.min.js') }}"></script>
|
|
<script src="{{ asset('js/select2.js') }}"></script>
|
|
<script>
|
|
$(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'};
|
|
|
|
function badge(text, color) {
|
|
return '<span class="badge bg-' + color + '">' + text + '</span>';
|
|
}
|
|
|
|
function statusKendaraan(v) {
|
|
if (v == 1) return badge('Masuk', 'success');
|
|
if (v == 0) return badge('Keluar', 'secondary');
|
|
return badge(v ?? '-', 'light text-dark');
|
|
}
|
|
|
|
function statusTransaksi(v) {
|
|
const t = labelTransaksi[v] !== undefined ? labelTransaksi[v] : (v ?? '-');
|
|
const c = v == 0 ? 'primary' : (v == 3 ? 'info' : (v == 32 ? 'warning' : 'light text-dark'));
|
|
return badge(t, c);
|
|
}
|
|
|
|
function esc(v) {
|
|
return (v === null || v === undefined) ? '' : String(v)
|
|
.replace(/&/g, '&').replace(/</g, '<')
|
|
.replace(/>/g, '>').replace(/"/g, '"');
|
|
}
|
|
|
|
function params(extra) {
|
|
const p = {
|
|
q: $('#q').val().trim(),
|
|
field: $('#field').val(),
|
|
tgl_awal: $('#tgl_awal').val(),
|
|
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="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="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>'
|
|
+ '<td>' + esc(row.no_pol) + '</td>'
|
|
+ '<td>' + esc(row.no_barcode) + '</td>'
|
|
+ '<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>';
|
|
});
|
|
$('#body-parkir').html(html);
|
|
}
|
|
$('#info-paging').text('Total ' + r.meta.total + ' data');
|
|
$('#label-halaman').text('Halaman ' + r.meta.current_page + ' / ' + Math.max(r.meta.last_page, 1));
|
|
$('#btn-prev').prop('disabled', r.meta.current_page <= 1);
|
|
$('#btn-next').prop('disabled', r.meta.current_page >= r.meta.last_page);
|
|
page = r.meta.current_page;
|
|
},
|
|
error: function (xhr) {
|
|
let msg = 'Gagal memuat data.';
|
|
if (xhr.status === 422 && xhr.responseJSON?.errors) {
|
|
msg = Object.values(xhr.responseJSON.errors).flat().join(' ');
|
|
}
|
|
$('#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');
|
|
}
|
|
});
|
|
}
|
|
|
|
$('#filter-parkir').on('submit', function () { page = 1; load(); });
|
|
$('#btn-reset').on('click', function () {
|
|
$('#filter-parkir')[0].reset();
|
|
$('#field, #status_kendaraan, #status_transaksi').val('').trigger('change');
|
|
$('#field').val('id').trigger('change');
|
|
page = 1; load();
|
|
});
|
|
$('#btn-prev').on('click', function () { if (page > 1) { page--; load(); } });
|
|
$('#btn-next').on('click', function () { page++; load(); });
|
|
|
|
$('.btn-export-excel').on('click', function () {
|
|
window.location = dataUrl + '?' + params({export: 'csv'});
|
|
});
|
|
$('.btn-export-pdf').on('click', function () { window.print(); });
|
|
|
|
paintSort();
|
|
load();
|
|
});
|
|
</script>
|
|
@endsection
|