2024-12-02 01:18:34 +07:00
|
|
|
@extends('layouts.app')
|
|
|
|
|
|
2026-06-01 15:01:03 +07:00
|
|
|
@section('title', 'Dashboard Operational Analytics')
|
|
|
|
|
|
|
|
|
|
@section('styles')
|
|
|
|
|
<link rel="stylesheet" href="https://cdn.datatables.net/1.13.7/css/dataTables.bootstrap4.min.css">
|
|
|
|
|
<link rel="stylesheet" href="https://cdn.datatables.net/buttons/2.4.2/css/buttons.bootstrap4.min.css">
|
|
|
|
|
{{-- Tambahan CDN Select2 untuk menjamin inisialisasi select2 dropdown berjalan lancar --}}
|
|
|
|
|
<link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" />
|
|
|
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@ttskch/select2-bootstrap4-theme@x.x.x/dist/select2-bootstrap4.min.css">
|
|
|
|
|
<style>
|
|
|
|
|
.chart-container { position: relative; height: 300px; width: 100%; }
|
|
|
|
|
.select2-container--bootstrap4 .select2-selection--single { height: calc(1.8125rem + 2px) !important; }
|
|
|
|
|
#table-monitoring thead th a { color: inherit; text-decoration: none; display: block; width: 100%; }
|
|
|
|
|
#table-monitoring tbody tr:hover { background-color: rgba(0,123,255,0.05); transition: 0.2s; }
|
|
|
|
|
.section-title { border-left: 5px solid #007bff; padding-left: 15px; margin-bottom: 20px; font-weight: 700; color: #333; text-transform: uppercase; }
|
|
|
|
|
.row-region-group { background-color: #f4f6f9 !important; border-top: 2px solid #dee2e6; }
|
|
|
|
|
</style>
|
2024-12-02 01:18:34 +07:00
|
|
|
@endsection
|
|
|
|
|
|
|
|
|
|
@section('admin-content')
|
2026-06-01 15:01:03 +07:00
|
|
|
<div class="container-fluid pt-5">
|
|
|
|
|
|
|
|
|
|
{{-- 1. HEADER & LIVE CLOCK --}}
|
|
|
|
|
<div class="alert bg-primary text-white shadow-sm d-flex justify-content-between align-items-center mb-4" style="border-radius: 15px; border: none;">
|
|
|
|
|
<div>
|
|
|
|
|
<span class="font-weight-bold"><i class="fas fa-clock mr-2"></i> Waktu Sistem: </span>
|
|
|
|
|
<span id="live-clock" class="badge badge-light text-primary px-3 py-2 shadow-sm" style="font-size: 0.95rem; border-radius: 10px;">
|
|
|
|
|
Memuat...
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="d-flex align-items-center">
|
|
|
|
|
<div class="bg-white text-primary px-4 py-2 shadow-sm d-none d-md-block ml-3" style="border-radius: 50px;">
|
|
|
|
|
<i class="far fa-calendar-alt mr-2"></i>
|
|
|
|
|
<span class="font-weight-bold">Periode Input: {{ $periodeLabel ?? '-' }}</span>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{{-- 2. KARTU STATISTIK --}}
|
|
|
|
|
<div class="row">
|
|
|
|
|
<div class="col-lg-3 col-6 mb-3">
|
|
|
|
|
<div class="small-box bg-info shadow-sm h-100" style="border-radius: 15px;">
|
|
|
|
|
<div class="inner p-4"><h3>{{ $totalRegions ?? 0 }}</h3><p>Total Region</p></div>
|
|
|
|
|
<div class="icon"><i class="fas fa-map-marked-alt"></i></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-lg-3 col-6 mb-3">
|
|
|
|
|
<div class="small-box bg-success shadow-sm h-100" style="border-radius: 15px;">
|
|
|
|
|
<div class="inner p-4"><h3>{{ $totalCabangs ?? 0 }}</h3><p>Cabang Aktif</p></div>
|
|
|
|
|
<div class="icon"><i class="fas fa-building"></i></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-lg-3 col-6 mb-3">
|
|
|
|
|
<div class="small-box bg-warning shadow-sm h-100" style="border-radius: 15px;">
|
|
|
|
|
<div class="inner p-4 text-white"><h3>{{ $pendingCount ?? 0 }}</h3><p>Total Dokumen Pending</p></div>
|
|
|
|
|
<div class="icon"><i class="fas fa-file-signature"></i></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-lg-3 col-6 mb-3">
|
|
|
|
|
<div class="small-box bg-danger shadow-sm h-100" style="border-radius: 15px;">
|
|
|
|
|
<div class="inner p-4">
|
|
|
|
|
<h3>{{ $totalKategori ?? 0 }}</h3>
|
|
|
|
|
<p>Master Kategori</p>
|
2024-12-02 01:18:34 +07:00
|
|
|
</div>
|
2026-06-01 15:01:03 +07:00
|
|
|
<div class="icon"><i class="fas fa-tags"></i></div>
|
2024-12-02 01:18:34 +07:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-06-01 15:01:03 +07:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{{-- FILTER KHUSUS GRAFIK PERFORMA --}}
|
|
|
|
|
<div class="card shadow-sm mb-4 mt-2" style="border-radius: 15px; background-color: #f8f9fa; border-left: 5px solid #17a2b8;">
|
|
|
|
|
<div class="card-body py-2 px-3">
|
|
|
|
|
<form action="{{ route('admin.dashboard') }}" method="GET" id="chart-filter-form" class="m-0">
|
|
|
|
|
<input type="hidden" name="region_id" value="{{ request('region_id') }}">
|
|
|
|
|
<input type="hidden" name="cabang_id" value="{{ request('cabang_id') }}">
|
|
|
|
|
<input type="hidden" name="category" value="{{ request('category') }}">
|
|
|
|
|
<input type="hidden" name="search" value="{{ request('search') }}">
|
|
|
|
|
|
|
|
|
|
<div class="d-flex justify-content-between align-items-center flex-wrap">
|
|
|
|
|
<h6 class="m-0 font-weight-bold text-info"><i class="fas fa-filter mr-2"></i>Filter Performa Closing Expense</h6>
|
|
|
|
|
<div class="d-flex align-items-center mt-2 mt-md-0">
|
|
|
|
|
<label class="small font-weight-bold text-muted mr-2 mb-0">Bulan:</label>
|
|
|
|
|
<select name="chart_month" class="form-control form-control-sm mr-3" style="width: 130px;" onchange="this.form.submit()">
|
|
|
|
|
<option value="">Semua Bulan</option>
|
|
|
|
|
@foreach(range(1, 12) as $m)
|
|
|
|
|
<option value="{{ sprintf('%02d', $m) }}" {{ (request('chart_month') ?? date('m')) == sprintf('%02d', $m) ? 'selected' : '' }}>
|
|
|
|
|
{{ Carbon\Carbon::create()->month($m)->translatedFormat('F') }}
|
|
|
|
|
</option>
|
|
|
|
|
@endforeach
|
|
|
|
|
</select>
|
|
|
|
|
|
|
|
|
|
<label class="small font-weight-bold text-muted mr-2 mb-0">Tahun:</label>
|
|
|
|
|
<select name="chart_year" class="form-control form-control-sm" style="width: 100px;" onchange="this.form.submit()">
|
|
|
|
|
@php $currentYear = date('Y'); @endphp
|
|
|
|
|
@for($y = $currentYear; $y >= 2023; $y--)
|
|
|
|
|
<option value="{{ $y }}" {{ (request('chart_year') ?? date('Y')) == $y ? 'selected' : '' }}>{{ $y }}</option>
|
|
|
|
|
@endfor
|
|
|
|
|
</select>
|
2025-01-01 23:59:49 +07:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-06-01 15:01:03 +07:00
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{{-- 3. GRAFIK PERFORMA CLOSING EXPENSE --}}
|
|
|
|
|
<h5 class="section-title mt-4">Respon Speed Expense</h5>
|
|
|
|
|
<div class="row mt-2">
|
|
|
|
|
<div class="col-md-6 mb-4">
|
|
|
|
|
<div class="card shadow-sm h-100" style="border-radius: 15px;">
|
|
|
|
|
<div class="card-header bg-white border-0 pt-3">
|
|
|
|
|
<h3 class="card-title font-weight-bold text-success text-uppercase small"><i class="fas fa-bolt mr-2"></i> 5 Cabang Tercepat</h3>
|
2025-01-01 23:59:49 +07:00
|
|
|
</div>
|
2026-06-01 15:01:03 +07:00
|
|
|
<div class="card-body">
|
|
|
|
|
<div class="chart-container"><canvas id="chartFastest"></canvas></div>
|
2025-01-01 23:59:49 +07:00
|
|
|
</div>
|
2026-06-01 15:01:03 +07:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-md-6 mb-4">
|
|
|
|
|
<div class="card shadow-sm h-100" style="border-radius: 15px;">
|
|
|
|
|
<div class="card-header bg-white border-0 pt-3">
|
|
|
|
|
<h3 class="card-title font-weight-bold text-danger text-uppercase small"><i class="fas fa-snail mr-2"></i> 5 Cabang Terlama</h3>
|
2025-01-01 23:59:49 +07:00
|
|
|
</div>
|
2026-06-01 15:01:03 +07:00
|
|
|
<div class="card-body">
|
|
|
|
|
<div class="chart-container"><canvas id="chartSlowest"></canvas></div>
|
2025-01-01 23:59:49 +07:00
|
|
|
</div>
|
2026-06-01 15:01:03 +07:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{{-- 4. FILTER PANEL TABEL PENDING --}}
|
|
|
|
|
<div class="card shadow-sm mb-4" style="border-radius: 15px;">
|
|
|
|
|
<div class="card-body py-3">
|
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
|
|
|
<h6 class="font-weight-bold text-muted m-0 small text-uppercase">Tabel Monitoring Dokumen Pending</h6>
|
|
|
|
|
{{-- Container Tombol Excel --}}
|
|
|
|
|
<div id="export-button-container"></div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<form action="{{ route('admin.dashboard') }}" method="GET" id="filter-form">
|
|
|
|
|
<input type="hidden" name="chart_month" value="{{ request('chart_month') }}">
|
|
|
|
|
<input type="hidden" name="chart_year" value="{{ request('chart_year') }}">
|
|
|
|
|
|
|
|
|
|
<div class="row align-items-end">
|
|
|
|
|
<div class="col-md-3 mb-2 mb-md-0">
|
|
|
|
|
<label class="small font-weight-bold text-muted text-uppercase">Region</label>
|
|
|
|
|
<select name="region_id" class="form-control form-control-sm select2" onchange="this.form.submit()">
|
|
|
|
|
<option value="">Semua Region</option>
|
|
|
|
|
@foreach($regions as $reg)
|
|
|
|
|
<option value="{{ $reg->id }}" {{ request('region_id') == $reg->id ? 'selected' : '' }}>{{ $reg->name }}</option>
|
|
|
|
|
@endforeach
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-md-3 mb-2 mb-md-0">
|
|
|
|
|
<label class="small font-weight-bold text-muted text-uppercase">Cabang</label>
|
|
|
|
|
<select name="cabang_id" class="form-control form-control-sm select2" onchange="this.form.submit()">
|
|
|
|
|
<option value="">Semua Cabang</option>
|
|
|
|
|
@foreach($cabangOptions as $cab)
|
|
|
|
|
<option value="{{ $cab->id }}" {{ request('cabang_id') == $cab->id ? 'selected' : '' }}>{{ $cab->name }}</option>
|
|
|
|
|
@endforeach
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-md-3 mb-2 mb-md-0">
|
|
|
|
|
<label class="small font-weight-bold text-muted text-uppercase">Highlight Kategori</label>
|
|
|
|
|
<select name="category" class="form-control form-control-sm" onchange="this.form.submit()">
|
|
|
|
|
<option value="">Pilih Kategori</option>
|
|
|
|
|
@php
|
|
|
|
|
$categories = [
|
|
|
|
|
'up_country' => 'Up Country',
|
|
|
|
|
'vehicle' => 'Vehicle Running Cost',
|
|
|
|
|
'entertainment' => 'Entertainment',
|
|
|
|
|
'meeting' => 'Meeting Seminar',
|
|
|
|
|
'others' => 'Others'
|
|
|
|
|
];
|
|
|
|
|
@endphp
|
|
|
|
|
@foreach($categories as $key => $val)
|
|
|
|
|
<option value="{{ $key }}" {{ request('category') == $key ? 'selected' : '' }}>{{ $val }}</option>
|
|
|
|
|
@endforeach
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="col-md-3">
|
|
|
|
|
<div class="d-flex">
|
|
|
|
|
<input type="text" name="search" class="form-control form-control-sm mr-2" placeholder="Cari..." value="{{ request('search') }}">
|
|
|
|
|
<button type="submit" class="btn btn-sm btn-primary px-3 shadow-sm">Filter</button>
|
|
|
|
|
<a href="{{ route('admin.dashboard') }}" class="btn btn-sm btn-secondary ml-1 shadow-sm" title="Reset Filter"><i class="fas fa-sync-alt"></i></a>
|
2025-01-01 23:59:49 +07:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-06-01 15:01:03 +07:00
|
|
|
</form>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{{-- 5. TABEL MONITORING --}}
|
|
|
|
|
<div class="card shadow-sm" style="border-radius: 15px; overflow: hidden;">
|
|
|
|
|
<div class="card-body p-0 table-responsive">
|
|
|
|
|
<table id="table-monitoring" class="table table-bordered m-0">
|
|
|
|
|
<thead class="bg-light text-center small text-uppercase font-weight-bold">
|
|
|
|
|
<tr>
|
|
|
|
|
<th rowspan="2" class="align-middle">
|
|
|
|
|
<a href="{{ request()->fullUrlWithQuery(['sort' => 'region', 'direction' => request('direction') == 'asc' ? 'desc' : 'asc']) }}">Region <i class="fas fa-sort ml-1 opacity-50"></i></a>
|
|
|
|
|
</th>
|
|
|
|
|
<th rowspan="2" class="align-middle text-left">
|
|
|
|
|
<a href="{{ request()->fullUrlWithQuery(['sort' => 'name', 'direction' => request('direction') == 'asc' ? 'desc' : 'asc']) }}">Cabang <i class="fas fa-sort ml-1 opacity-50"></i></a>
|
|
|
|
|
</th>
|
|
|
|
|
<th colspan="5" class="bg-white text-center align-middle">Rincian Dokumen Pending</th>
|
|
|
|
|
<th rowspan="2" class="align-middle text-center">
|
|
|
|
|
<a href="{{ request()->fullUrlWithQuery(['sort' => 'total_pending', 'direction' => request('direction') == 'asc' ? 'desc' : 'asc']) }}">Total <i class="fas fa-sort ml-1 opacity-50"></i></a>
|
|
|
|
|
</th>
|
|
|
|
|
<th rowspan="2" class="align-middle no-export text-center">Aksi</th>
|
|
|
|
|
</tr>
|
|
|
|
|
<tr class="bg-white">
|
|
|
|
|
<th class="{{ request('category') == 'up_country' ? 'bg-warning' : '' }}">UC</th>
|
|
|
|
|
<th class="{{ request('category') == 'vehicle' ? 'bg-warning' : '' }}">VC</th>
|
|
|
|
|
<th class="{{ request('category') == 'entertainment' ? 'bg-warning' : '' }}">EN</th>
|
|
|
|
|
<th class="{{ request('category') == 'meeting' ? 'bg-warning' : '' }}">MT</th>
|
|
|
|
|
<th class="{{ request('category') == 'others' ? 'bg-warning' : '' }}">OT</th>
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody class="text-center">
|
|
|
|
|
@php $currentRegion = null; @endphp
|
|
|
|
|
@forelse($cabangDetails as $detail)
|
|
|
|
|
@if($currentRegion != ($detail->region_id ?? null))
|
|
|
|
|
<tr class="row-region-group">
|
|
|
|
|
<td colspan="9" class="text-left font-weight-bold text-primary text-uppercase" style="letter-spacing: 1px;">
|
|
|
|
|
<i class="fas fa-map-marked-alt mr-2 text-warning"></i> REGION: {{ $detail->region->name ?? 'TANPA REGION' }}
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
@php $currentRegion = $detail->region_id ?? null; @endphp
|
|
|
|
|
@endif
|
|
|
|
|
|
|
|
|
|
<tr>
|
|
|
|
|
<td class="text-left small text-muted"><i class="fas fa-level-up-alt fa-rotate-90 text-muted mr-1 ml-2"></i> {{ $detail->region->name ?? '-' }}</td>
|
|
|
|
|
<td class="text-left font-weight-bold text-dark">{{ $detail->name }}</td>
|
|
|
|
|
<td>{{ $detail->pending_details['up_country'] ?? 0 }}</td>
|
|
|
|
|
<td>{{ $detail->pending_details['vehicle'] ?? 0 }}</td>
|
|
|
|
|
<td>{{ $detail->pending_details['entertainment'] ?? 0 }}</td>
|
|
|
|
|
<td>{{ $detail->pending_details['meeting'] ?? 0 }}</td>
|
|
|
|
|
<td>{{ $detail->pending_details['others'] ?? 0 }}</td>
|
|
|
|
|
<td class="bg-light font-weight-bold text-center align-middle">{{ $detail->total_pending }}</td>
|
|
|
|
|
<td class="no-export text-center align-middle">
|
|
|
|
|
<a href="{{ route('admin.dashboard.show', $detail->id) }}" class="btn btn-xs btn-info shadow-sm" title="Lihat Detail"><i class="fas fa-eye"></i></a>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
@empty
|
|
|
|
|
<tr>
|
|
|
|
|
<td colspan="9" class="py-5 text-center text-muted">
|
|
|
|
|
<i class="fas fa-info-circle mr-2"></i> Data tidak ditemukan untuk filter ini.
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
@endforelse
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="card-footer bg-white border-0 py-3">
|
|
|
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
|
|
|
@if(isset($cabangDetails) && method_exists($cabangDetails, 'firstItem'))
|
|
|
|
|
<div class="small text-muted">Menampilkan <b>{{ $cabangDetails->firstItem() ?? 0 }}</b> - <b>{{ $cabangDetails->lastItem() ?? 0 }}</b> dari <b>{{ $cabangDetails->total() ?? 0 }}</b> Cabang.</div>
|
|
|
|
|
<div>{{ $cabangDetails->appends(request()->query())->links('pagination::bootstrap-4') }}</div>
|
|
|
|
|
@endif
|
2024-12-02 01:18:34 +07:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-06-01 15:01:03 +07:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@endsection
|
|
|
|
|
|
|
|
|
|
@section('scripts')
|
|
|
|
|
{{-- Library Wajib DataTables --}}
|
|
|
|
|
<script src="https://cdn.datatables.net/1.13.7/js/jquery.dataTables.min.js"></script>
|
|
|
|
|
<script src="https://cdn.datatables.net/1.13.7/js/dataTables.bootstrap4.min.js"></script>
|
|
|
|
|
{{-- Library Wajib untuk Tombol Export --}}
|
|
|
|
|
<script src="https://cdn.datatables.net/buttons/2.4.2/js/dataTables.buttons.min.js"></script>
|
|
|
|
|
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.bootstrap4.min.js"></script>
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
|
|
|
|
<script src="https://cdn.datatables.net/buttons/2.4.2/js/buttons.html5.min.js"></script>
|
|
|
|
|
{{-- Library Grafik --}}
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.0.0"></script>
|
|
|
|
|
{{-- Library Select2 untuk keindahan select input --}}
|
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
// 1. LIVE CLOCK
|
|
|
|
|
function updateClock() {
|
|
|
|
|
const now = new Date();
|
|
|
|
|
const options = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', second: '2-digit' };
|
|
|
|
|
const clockEl = document.getElementById('live-clock');
|
|
|
|
|
if(clockEl) clockEl.innerText = now.toLocaleDateString('id-ID', options) + ' WIB';
|
|
|
|
|
}
|
|
|
|
|
setInterval(updateClock, 1000); updateClock();
|
|
|
|
|
|
|
|
|
|
$(document).ready(function() {
|
|
|
|
|
// Inisialisasi Select2
|
|
|
|
|
$('.select2').select2({
|
|
|
|
|
theme: 'bootstrap4',
|
|
|
|
|
width: '100%'
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Hindari pesan error alert bawaan browser
|
|
|
|
|
$.fn.dataTable.ext.errMode = 'none';
|
|
|
|
|
|
|
|
|
|
// Inisialisasi DataTable
|
|
|
|
|
var table = $('#table-monitoring').DataTable({
|
|
|
|
|
paging: false,
|
|
|
|
|
searching: false,
|
|
|
|
|
info: false,
|
|
|
|
|
ordering: false,
|
|
|
|
|
autoWidth: false,
|
|
|
|
|
buttons: [
|
|
|
|
|
{
|
|
|
|
|
extend: 'excelHtml5',
|
|
|
|
|
text: '<i class="fas fa-file-excel mr-1"></i> Export Excel',
|
|
|
|
|
className: 'btn btn-sm btn-success font-weight-bold shadow-sm',
|
|
|
|
|
title: 'Laporan Pending - {{ $periodeLabel ?? "Mei 2026" }}',
|
|
|
|
|
exportOptions: {
|
|
|
|
|
columns: ':not(.no-export)'
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Append tombol ke container
|
|
|
|
|
if (table.buttons().container().length) {
|
|
|
|
|
table.buttons().container().appendTo('#export-button-container');
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 3. CHARTS PERFORMA
|
|
|
|
|
Chart.register(ChartDataLabels);
|
|
|
|
|
|
|
|
|
|
const configChart = (ctxId, labels, data, color, rawDurations) => {
|
|
|
|
|
const ctx = document.getElementById(ctxId);
|
|
|
|
|
if(!ctx || !labels || labels.length === 0) return;
|
|
|
|
|
new Chart(ctx, {
|
|
|
|
|
type: 'bar',
|
|
|
|
|
data: {
|
|
|
|
|
labels: labels,
|
|
|
|
|
datasets: [{ data: data, backgroundColor: color, borderRadius: 8, barThickness: 20 }]
|
|
|
|
|
},
|
|
|
|
|
options: {
|
|
|
|
|
indexAxis: 'y', responsive: true, maintainAspectRatio: false,
|
|
|
|
|
layout: { padding: { right: 85 } },
|
|
|
|
|
plugins: {
|
|
|
|
|
legend: { display: false },
|
|
|
|
|
datalabels: {
|
|
|
|
|
anchor: 'end', align: 'right', color: '#444', font: { weight: 'bold', size: 10 },
|
|
|
|
|
formatter: (val, ctx) => rawDurations[ctx.dataIndex] || ''
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
scales: { x: { display: false }, y: { ticks: { font: { size: 10, weight: 'bold' } } } }
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
configChart('chartFastest', {!! json_encode($chartFastest['labels'] ?? []) !!}, {!! json_encode($chartFastest['data'] ?? []) !!}, '#28a745', {!! json_encode($chartFastest['raw'] ?? []) !!});
|
|
|
|
|
configChart('chartSlowest', {!! json_encode($chartSlowest['labels'] ?? []) !!}, {!! json_encode($chartSlowest['data'] ?? []) !!}, '#dc3545', {!! json_encode($chartSlowest['raw'] ?? []) !!});
|
|
|
|
|
</script>
|
2025-01-19 19:11:29 +07:00
|
|
|
@endsection
|