Ubah/extend in-place data lama + search semua-field + statistik hari-minggu-bulan
This commit is contained in:
@@ -0,0 +1,200 @@
|
||||
@extends('layouts.master')
|
||||
|
||||
@section('styles')
|
||||
<style>
|
||||
#tabel-statistik th[data-info] { cursor: default; }
|
||||
.stat-card { border-radius: 10px; }
|
||||
</style>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<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-body">
|
||||
<h4 class="card-title">Statistik Transaksi</h4>
|
||||
<small class="text-muted d-block mb-3">Periode berdasarkan tanggal masuk. Pecah per hari / minggu / bulan.</small>
|
||||
<form id="filter-statistik" action="javascript:void(0)">
|
||||
<div class="row align-items-end g-2">
|
||||
<div class="col-md-2">
|
||||
<label class="form-label" for="grup">Pecah Per</label>
|
||||
<select class="form-select form-select-sm" id="grup">
|
||||
<option value="hari" selected>Hari</option>
|
||||
<option value="minggu">Minggu</option>
|
||||
<option value="bulan">Bulan</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label" for="tgl-awal">Periode Awal</label>
|
||||
<input type="date" class="form-control form-control-sm" id="tgl-awal">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label" for="tgl-akhir">Periode Akhir</label>
|
||||
<input type="date" class="form-control form-control-sm" id="tgl-akhir">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label" for="status-transaksi">Status Transaksi</label>
|
||||
<select class="form-select form-select-sm" id="status-transaksi">
|
||||
<option value="" selected>Semua</option>
|
||||
<option value="0">Casual</option>
|
||||
<option value="3">Member</option>
|
||||
<option value="32">Denda</option>
|
||||
<option value="-1">Masalah</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<label class="form-label" for="cara">Pembayaran</label>
|
||||
<select class="form-select form-select-sm" id="cara">
|
||||
<option value="" selected>Semua</option>
|
||||
<option value="tunai">Tunai</option>
|
||||
<option value="cashless">Cashless</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2 d-flex gap-2">
|
||||
<button type="submit" class="btn btn-sm btn-primary" id="btn-proses">Proses</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<hr class="my-3">
|
||||
<div class="row g-2 mb-3" id="ringkasan">
|
||||
<div class="col-md-2"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Transaksi</small><div class="fw-bold" id="sum-trx">-</div></div></div>
|
||||
<div class="col-md-2"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Keluar</small><div class="fw-bold" id="sum-keluar">-</div></div></div>
|
||||
<div class="col-md-2"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Pendapatan</small><div class="fw-bold text-success" id="sum-pendapatan">-</div></div></div>
|
||||
<div class="col-md-3"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Tunai</small><div class="fw-bold" id="sum-tunai">-</div></div></div>
|
||||
<div class="col-md-3"><div class="border rounded p-2 h-100 stat-card"><small class="text-muted">Cashless</small><div class="fw-bold text-info" id="sum-cashless">-</div></div></div>
|
||||
</div>
|
||||
<div class="mb-3" style="max-height: 320px;"><canvas id="chart-statistik" height="120"></canvas></div>
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered table-striped" id="tabel-statistik">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Periode</th>
|
||||
<th class="text-end">Transaksi</th>
|
||||
<th class="text-end">Keluar</th>
|
||||
<th class="text-end">Pendapatan</th>
|
||||
<th class="text-end">Tunai</th>
|
||||
<th class="text-end">Cashless</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="body-statistik">
|
||||
<tr><td colspan="6" class="text-center text-muted">Pilih filter lalu klik Proses.</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('javascript')
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
|
||||
<script src="{{ asset('vendor/sweetalert2/dist/sweetalert2.min.js') }}"></script>
|
||||
<script src="{{ asset('vendors/chart.js/Chart.min.js') }}"></script>
|
||||
<script>
|
||||
$(function () {
|
||||
const dataUrl = '{{ route('statistik.data', [], false) }}';
|
||||
let chart = null;
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const awal = new Date(Date.now() - 29 * 864e5).toISOString().split('T')[0];
|
||||
$('#tgl-akhir').val(today);
|
||||
$('#tgl-awal').val(awal);
|
||||
|
||||
function fmtRp(v) {
|
||||
return 'Rp ' + Number(v || 0).toLocaleString('id-ID');
|
||||
}
|
||||
function fmtN(v) {
|
||||
return Number(v || 0).toLocaleString('id-ID');
|
||||
}
|
||||
function labelPeriode(p, grup) {
|
||||
if (grup === 'bulan') {
|
||||
const d = new Date(p + 'T00:00:00');
|
||||
return d.toLocaleDateString('id-ID', { month: 'short', year: 'numeric' });
|
||||
}
|
||||
if (grup === 'minggu') return 'Minggu ' + p;
|
||||
const d = new Date(p + 'T00:00:00');
|
||||
return d.toLocaleDateString('id-ID', { day: '2-digit', month: 'short' });
|
||||
}
|
||||
|
||||
function drawChart(rows, grup) {
|
||||
const ctx = document.getElementById('chart-statistik');
|
||||
if (chart) chart.destroy();
|
||||
chart = new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: rows.map(r => labelPeriode(r.periode, grup)),
|
||||
datasets: [
|
||||
{ label: 'Tunai', data: rows.map(r => Number(r.tunai)), backgroundColor: '#198754' },
|
||||
{ label: 'Cashless', data: rows.map(r => Number(r.cashless)), backgroundColor: '#0dcaf0' },
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: { y: { beginAtZero: true, ticks: { callback: v => (v / 1000) + 'rb' } } },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
$('#filter-statistik').on('submit', function () {
|
||||
const btn = $('#btn-proses'); const btnHtml = btn.html();
|
||||
btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1"></span>Memproses...');
|
||||
$('#body-statistik').html('<tr><td colspan="6" class="text-center text-muted py-4"><span class="spinner-border spinner-border-sm me-2"></span>Memuat statistik...</td></tr>');
|
||||
const grup = $('#grup').val();
|
||||
$.ajax({
|
||||
url: dataUrl,
|
||||
type: 'GET',
|
||||
data: {
|
||||
grup: grup,
|
||||
tgl_awal: $('#tgl-awal').val(),
|
||||
tgl_akhir: $('#tgl-akhir').val(),
|
||||
status_transaksi: $('#status-transaksi').val(),
|
||||
cara: $('#cara').val(),
|
||||
},
|
||||
success: function (r) {
|
||||
const s = r.ringkasan || {};
|
||||
$('#sum-trx').text(fmtN(s.transaksi) + ' trx');
|
||||
$('#sum-keluar').text(fmtN(s.keluar) + ' trx');
|
||||
$('#sum-pendapatan').text(fmtRp(s.pendapatan));
|
||||
$('#sum-tunai').text(fmtRp(s.tunai));
|
||||
$('#sum-cashless').text(fmtRp(s.cashless));
|
||||
if (!r.data.length) {
|
||||
$('#body-statistik').html('<tr><td colspan="6" class="text-center">Data tidak ditemukan.</td></tr>');
|
||||
if (chart) chart.destroy();
|
||||
return;
|
||||
}
|
||||
let html = '';
|
||||
r.data.forEach(function (row) {
|
||||
html += '<tr><td>' + labelPeriode(row.periode, grup) + '</td>'
|
||||
+ '<td class="text-end">' + fmtN(row.transaksi) + '</td>'
|
||||
+ '<td class="text-end">' + fmtN(row.keluar) + '</td>'
|
||||
+ '<td class="text-end">' + fmtRp(row.pendapatan) + '</td>'
|
||||
+ '<td class="text-end">' + fmtRp(row.tunai) + '</td>'
|
||||
+ '<td class="text-end">' + fmtRp(row.cashless) + '</td></tr>';
|
||||
});
|
||||
$('#body-statistik').html(html);
|
||||
drawChart(r.data, grup);
|
||||
},
|
||||
error: function (xhr) {
|
||||
let msg = 'Gagal memuat statistik.';
|
||||
if (xhr.responseJSON?.message) msg = xhr.responseJSON.message;
|
||||
else if (xhr.status === 422 && xhr.responseJSON?.errors) msg = Object.values(xhr.responseJSON.errors).flat().join(' ');
|
||||
$('#body-statistik').html('<tr><td colspan="6" class="text-center text-danger">' + msg + '</td></tr>');
|
||||
Swal.fire({icon: 'error', title: 'Gagal memuat', text: msg});
|
||||
},
|
||||
complete: function () {
|
||||
btn.prop('disabled', false).html(btnHtml);
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
$('#filter-statistik').submit();
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user