This commit is contained in:
@@ -1,125 +1,357 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title')
|
||||
Dashboard
|
||||
@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>
|
||||
@endsection
|
||||
|
||||
@section('admin-content')
|
||||
<section class="content-header">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-sm-6">
|
||||
<h1>Home</h1>
|
||||
<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>
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<ol class="breadcrumb float-sm-right">
|
||||
<li class="breadcrumb-item"><a href="{{ route('dashboard.index') }}">Dashboard</a></li>
|
||||
</ol>
|
||||
<div class="icon"><i class="fas fa-tags"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="chart-container"><canvas id="chartFastest"></canvas></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="content">
|
||||
<div class="container-fluid">
|
||||
<!-- Statistic Cards Grid -->
|
||||
<div class="row row-cols-2 row-cols-md-2 row-cols-lg-3 g-4">
|
||||
<!-- Statistic Card 1 -->
|
||||
<div class="col">
|
||||
<div class="small-box bg-info">
|
||||
<div class="inner">
|
||||
<h3>Rp {{ number_format($forms['vehicle'] + $forms['entertainment'] + $forms['meeting'] + $forms['upcountry'] + $forms['others'], 0, ',', '.') }}</h3>
|
||||
<p>All Approved Expenses</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
</div>
|
||||
<a href="#" class="small-box-footer">
|
||||
More info <i class="fas fa-arrow-circle-right"></i>
|
||||
</a>
|
||||
</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>
|
||||
</div>
|
||||
<!-- Statistic Card 2 -->
|
||||
<div class="col">
|
||||
<div class="small-box bg-success">
|
||||
<div class="inner">
|
||||
<h3>Rp {{ number_format($forms['upcountry'], 0, ',', '.') }}</h3>
|
||||
<p>Approved Up Country Expenses</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-flag" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a href="{{ route('forms.up-country') }}" class="small-box-footer">
|
||||
More info <i class="fas fa-arrow-circle-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Statistic Card 3 -->
|
||||
<div class="col">
|
||||
<div class="small-box bg-warning">
|
||||
<div class="inner text-white">
|
||||
<h3>Rp {{ number_format($forms['vehicle'], 0, ',', '.') }}</h3>
|
||||
<p>Approved Vehicle Running Cost Expenses</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-car" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a href="{{ route('forms.vehicle') }}" class="small-box-footer text-white">
|
||||
<span class="text-white">More info</span> <i class="fas fa-arrow-circle-right text-white"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Statistic Card 4 -->
|
||||
<div class="col">
|
||||
<div class="small-box bg-purple">
|
||||
<div class="inner">
|
||||
<h3>Rp {{ number_format($forms['entertainment'], 0, ',', '.') }}</h3>
|
||||
<p>Approved Entertainment Presentation Expenses</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-desktop" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a href="{{ route('forms.entertainment') }}" class="small-box-footer">
|
||||
More info <i class="fas fa-arrow-circle-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Statistic Card 5 -->
|
||||
<div class="col">
|
||||
<div class="small-box bg-danger">
|
||||
<div class="inner">
|
||||
<h3>Rp {{ number_format($forms['meeting'], 0, ',', '.') }}</h3>
|
||||
<p>Approved Meeting Seminar Expenses</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-users" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a href="{{ route('forms.meeting') }}" class="small-box-footer">
|
||||
More info <i class="fas fa-arrow-circle-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Statistic Card 6 -->
|
||||
<div class="col">
|
||||
<div class="small-box bg-pink">
|
||||
<div class="inner">
|
||||
<h3>Rp {{ number_format($forms['others'], 0, ',', '.') }}</h3>
|
||||
<p>Approved Other Expenses</p>
|
||||
</div>
|
||||
<div class="icon">
|
||||
<i class="fa fa-bars" aria-hidden="true"></i>
|
||||
</div>
|
||||
<a href="{{ route('forms.other') }}" class="small-box-footer">
|
||||
More info <i class="fas fa-arrow-circle-right"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Welcome Card -->
|
||||
<div class="card card-primary card-outline mt-4">
|
||||
<div class="card-body text-center">
|
||||
<p class="lead">Welcome to {{ config('app.name') }} (development version).</p>
|
||||
<div class="card-body">
|
||||
<div class="chart-container"><canvas id="chartSlowest"></canvas></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</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
|
||||
</div>
|
||||
</div>
|
||||
</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>
|
||||
@endsection
|
||||
Reference in New Issue
Block a user