Kumpulan perubahan yang udah numpuk di working tree: refactor Setup (Gate/Vehicle/Member), rapihin memberin & stiker, service parking baru (ParkingUtilsServices, NetworkService), model/migration lot-parking & DHCP reservation, dan fitur baru Intercom (controller/model/migration/ view). ReportTransaksiController versi lokal ini WIP (~90%, masih didebug) - versi yang bener ada di server, jadi dikeluarin dari git (ditambahin ke .gitignore) biar gak numpuk nindihin punya server pas git pull di sana. Sekalian keluarin dump mentah tabel softseting (1.8MB, nyasar ke-commit), file .bak, dan arsip ad-hoc (api.tgz, c.zip) yang emang bukan source code. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01EAJc2mrpj2cSTe4oowLPzQ
264 lines
14 KiB
PHP
264 lines
14 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;
|
|
} */
|
|
</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="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>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>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="body-parkir">
|
|
<tr><td colspan="9" 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;
|
|
|
|
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(),
|
|
page: page
|
|
};
|
|
return $.param(Object.assign(p, extra || {}));
|
|
}
|
|
|
|
function load() {
|
|
$('#body-parkir').html('<tr><td colspan="9" class="text-center">Memuat data...</td></tr>');
|
|
$.ajax({
|
|
url: dataUrl + '?' + params(),
|
|
type: 'GET',
|
|
success: function (r) {
|
|
if (!r.data.length) {
|
|
$('#body-parkir').html('<tr><td colspan="9" 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) {
|
|
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 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="9" class="text-center text-danger">' + esc(msg) + '</td></tr>');
|
|
}
|
|
});
|
|
}
|
|
|
|
$('#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(); });
|
|
|
|
load();
|
|
});
|
|
</script>
|
|
@endsection
|