509 lines
22 KiB
PHP
509 lines
22 KiB
PHP
@extends('layout.app')
|
|
|
|
@section('content')
|
|
|
|
{{-- Tambahan CSS Khusus untuk Mempercantik Tampilan --}}
|
|
<style>
|
|
.card-custom {
|
|
border: none;
|
|
border-radius: 12px;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
|
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
|
}
|
|
.card-custom:hover {
|
|
transform: translateY(-3px);
|
|
box-shadow: 0 8px 15px rgba(0,0,0,0.08);
|
|
}
|
|
.info-stats4 {
|
|
border: none !important;
|
|
border-radius: 12px;
|
|
background: #ffffff;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.03);
|
|
transition: transform 0.2s;
|
|
}
|
|
.info-stats4:hover {
|
|
transform: translateY(-2px);
|
|
}
|
|
.table-modern td, .table-modern th {
|
|
vertical-align: middle !important;
|
|
border-top: none !important;
|
|
border-bottom: 1px solid #f1f3f5;
|
|
padding: 1rem 0.75rem;
|
|
}
|
|
.table-modern thead th {
|
|
color: #6c757d;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
font-size: 0.75rem;
|
|
letter-spacing: 0.5px;
|
|
border-bottom: 2px solid #e9ecef !important;
|
|
}
|
|
.badge-rank {
|
|
font-size: 0.85rem;
|
|
padding: 0.4em 0.8em;
|
|
border-radius: 20px;
|
|
}
|
|
.progress-pill {
|
|
border-radius: 10px;
|
|
}
|
|
</style>
|
|
|
|
<div class="page-header">
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item">Home</li>
|
|
<li class="breadcrumb-item active text-primary font-weight-bold">Dashboard</li>
|
|
</ol>
|
|
|
|
{{-- Filter Dropdown Periode --}}
|
|
<div class="ml-auto">
|
|
<form action="{{ url()->current() }}" method="GET" class="form-inline m-0">
|
|
<div class="input-group shadow-sm" style="border-radius: 8px; overflow: hidden;">
|
|
<div class="input-group-prepend">
|
|
<span class="input-group-text bg-primary text-white border-0">
|
|
<i class="icon-calendar"></i>
|
|
</span>
|
|
</div>
|
|
<select name="periode_id" id="periode_id" class="form-control border-0 bg-white" onchange="this.form.submit()" style="cursor: pointer; font-weight: 500;">
|
|
@forelse($semuaPeriode as $p)
|
|
<option value="{{ $p->id }}" {{ ($periodeDitampilkan && $periodeDitampilkan->id == $p->id) ? 'selected' : '' }}>
|
|
{{ $p->nama_periode }} {{ $p->is_aktif ? '(Aktif Saat Ini)' : '' }}
|
|
</option>
|
|
@empty
|
|
<option value="">Belum Ada Periode</option>
|
|
@endforelse
|
|
</select>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- BAGIAN CARD YANG SUDAH DIBUAT LEBIH SLIM --}}
|
|
<div class="row gutters mb-3">
|
|
@php
|
|
// Helper array untuk merapikan perulangan card 1-3
|
|
$cards = [
|
|
['icon' => 'icon-user1', 'color' => 'primary', 'val' => $countUser, 'lab' => 'Total Pengguna'],
|
|
['icon' => 'icon-users', 'color' => 'info', 'val' => $countWarga, 'lab' => 'Total Warga'],
|
|
['icon' => 'icon-verified_user', 'color' => 'success', 'val' => $countVerif, 'lab' => 'Dokumen Valid'],
|
|
];
|
|
@endphp
|
|
|
|
@foreach($cards as $c)
|
|
<div class="col-xl-3 col-lg-6 col-md-6 col-sm-6 col-12 mb-3">
|
|
<div class="info-stats4 p-3 h-100 d-flex flex-column justify-content-center">
|
|
<div class="d-flex align-items-center">
|
|
<div class="info-icon bg-light text-{{ $c['color'] }} rounded-circle m-0 mr-3" style="width: 40px; height: 40px; line-height: 40px; text-align: center; font-size: 1.2rem;">
|
|
<i class="{{ $c['icon'] }}"></i>
|
|
</div>
|
|
<div class="sale-num">
|
|
<h4 class="mb-0 font-weight-bold" style="font-size: 1.2rem;">{{ $c['val'] }}</h4>
|
|
<p class="text-muted m-0" style="font-size: 0.8rem;">{{ $c['lab'] }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
|
|
{{-- Card 4: Indikator Kuota --}}
|
|
<div class="col-xl-3 col-lg-6 col-md-6 col-sm-6 col-12 mb-3">
|
|
<div class="info-stats4 p-3 h-100 d-flex flex-column">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div class="info-icon bg-light text-warning rounded-circle m-0" style="width: 40px; height: 40px; line-height: 40px; text-align: center; font-size: 1.2rem;">
|
|
<i class="icon-pie-chart1"></i>
|
|
</div>
|
|
<div class="text-right">
|
|
<h4 class="m-0 font-weight-bold" style="font-size: 1.2rem;">{{ $chartUtama }} <span class="text-muted" style="font-size: 0.8rem;">/ {{ $kuota }}</span></h4>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-2">
|
|
<div class="progress progress-pill bg-light" style="height: 6px;">
|
|
<div class="progress-bar progress-pill {{ $persentaseKuota >= 100 ? 'bg-danger' : 'bg-primary' }}"
|
|
role="progressbar"
|
|
style="width: {{ $persentaseKuota }}%"
|
|
aria-valuenow="{{ $persentaseKuota }}" aria-valuemin="0" aria-valuemax="100">
|
|
</div>
|
|
</div>
|
|
<div class="d-flex justify-content-between mt-1">
|
|
<small class="text-muted" style="font-size: 0.7rem;">Terisi ({{ $namaPeriode }})</small>
|
|
<small class="text-muted font-weight-bold" style="font-size: 0.7rem;">{{ $persentaseKuota }}%</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row gutters mt-3">
|
|
<div class="col-xl-5 col-lg-12 col-md-12 col-sm-12 col-12 mb-3">
|
|
<div class="card card-custom h-100">
|
|
<div class="card-header bg-white pt-4 pb-2 border-0">
|
|
<h6 class="card-title mb-0 font-weight-bold text-dark">Proporsi Verifikasi Dokumen</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div style="height: 280px; width: 100%; position: relative;">
|
|
<canvas id="verifikasiPieChart"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-7 col-lg-12 col-md-12 col-sm-12 col-12 mb-3">
|
|
<div class="card card-custom h-100">
|
|
<div class="card-header bg-white pt-4 pb-2 border-0 d-flex justify-content-between align-items-center">
|
|
<h6 class="card-title mb-0 font-weight-bold text-dark">Hasil Seleksi: {{ $namaPeriode }}</h6>
|
|
<span class="badge badge-pill badge-info px-3 py-2 text-white shadow-sm">Berdasarkan Kuota</span>
|
|
</div>
|
|
<div class="card-body">
|
|
@if($countRanking == 0)
|
|
<div class="text-center d-flex flex-column justify-content-center align-items-center bg-light rounded" style="height: 280px; border: 1px dashed #ced4da;">
|
|
<i class="icon-inbox text-muted mb-3" style="font-size: 3rem;"></i>
|
|
<p class="text-muted mb-0">Belum ada data seleksi untuk periode ini.<br>Silakan lakukan proses perangkingan.</p>
|
|
</div>
|
|
@else
|
|
<div style="height: 280px; width: 100%; position: relative;">
|
|
<canvas id="peringkatBarChart"></canvas>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row gutters mt-3">
|
|
{{-- Tabel Top 5 --}}
|
|
<div class="col-xl-8 col-lg-12 col-md-12 col-sm-12 col-12 mb-3">
|
|
<div class="card card-custom h-100">
|
|
<div class="card-header bg-white pt-4 pb-3 border-bottom d-flex justify-content-between align-items-center">
|
|
<h6 class="card-title mb-0 font-weight-bold text-dark">
|
|
<i class="icon-award text-warning mr-2"></i>Top 5 Prioritas Utama
|
|
</h6>
|
|
<a href="{{ route('seleksi.index') }}" class="btn btn-sm btn-light text-primary font-weight-bold border shadow-sm px-3 rounded-pill">Lihat Detail Lengkap</a>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover table-modern m-0">
|
|
<thead class="bg-light">
|
|
<tr>
|
|
<th class="pl-4">Rank</th>
|
|
<th>Profil Warga</th>
|
|
<th>Alamat Terdaftar</th>
|
|
<th class="text-center">Skor Kelayakan</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($topWarga as $top)
|
|
<tr>
|
|
<td class="pl-4">
|
|
<span class="badge badge-warning badge-rank text-dark shadow-sm">
|
|
<i class="icon-star mr-1"></i>{{ $top->ranking }}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<strong class="d-block text-dark" style="font-size: 0.95rem;">{{ $top->warga->nama }}</strong>
|
|
<small class="text-muted"><i class="icon-credit-card mr-1"></i>{{ $top->warga->nik }}</small>
|
|
</td>
|
|
<td>
|
|
<span class="text-dark">{{ $top->warga->alamat }}</span><br>
|
|
<small class="text-muted">RT {{ $top->warga->rt }} / RW {{ $top->warga->rw }}</small>
|
|
</td>
|
|
<td class="text-center">
|
|
<span class="font-weight-bold text-success" style="font-size: 1.1rem;">{{ number_format($top->skor_akhir, 4) }}</span>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="4" class="text-center py-5 text-muted">Belum ada warga yang diseleksi.</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- Notifikasi --}}
|
|
<div class="col-xl-4 col-lg-12 col-md-12 col-sm-12 col-12 mb-3">
|
|
<div class="card card-custom h-100">
|
|
<div class="card-header bg-white pt-4 pb-2 border-0">
|
|
<h6 class="card-title mb-0 font-weight-bold text-dark"><i class="icon-bell text-danger mr-2"></i>Perhatian Khusus</h6>
|
|
</div>
|
|
<div class="card-body p-3">
|
|
<ul class="list-group list-group-flush border-0">
|
|
@if($countPending > 0)
|
|
<li class="list-group-item d-flex justify-content-between align-items-center rounded bg-light mb-2 border-0">
|
|
<div>
|
|
<i class="icon-alert-circle text-warning mr-2"></i>
|
|
<span class="text-dark font-weight-500">Verifikasi Tertunda</span>
|
|
</div>
|
|
<span class="badge badge-warning badge-pill shadow-sm px-2 py-1">{{ $countPending }}</span>
|
|
</li>
|
|
@endif
|
|
|
|
@if($persentaseKuota >= 100)
|
|
<li class="list-group-item d-flex justify-content-between align-items-center rounded bg-light mb-2 border-0">
|
|
<div>
|
|
<i class="icon-info text-info mr-2"></i>
|
|
<span class="text-dark font-weight-500">Kuota Terisi Penuh</span>
|
|
</div>
|
|
<i class="icon-check-circle text-success"></i>
|
|
</li>
|
|
@endif
|
|
|
|
@if($periodeDitampilkan && $periodeDitampilkan->is_aktif && $countRanking == 0)
|
|
<li class="list-group-item d-flex flex-column align-items-center justify-content-center rounded bg-light p-4 text-center border-0 mt-2">
|
|
<i class="icon-activity text-danger mb-2" style="font-size: 2rem;"></i>
|
|
<span class="text-dark font-weight-500 mb-3">Belum ada proses perhitungan.</span>
|
|
<a href="{{ route('seleksi.index') }}" class="btn btn-danger btn-sm shadow-sm rounded-pill px-4">Proses Seleksi Sekarang</a>
|
|
</li>
|
|
@endif
|
|
|
|
@if($countPending == 0 && ($countRanking > 0 || !$periodeDitampilkan?->is_aktif) && $persentaseKuota < 100)
|
|
<li class="list-group-item text-center text-muted border-0 py-5">
|
|
<div class="bg-light rounded-circle mx-auto d-flex justify-content-center align-items-center" style="width: 80px; height: 80px;">
|
|
<i class="icon-check text-success" style="font-size: 2.5rem;"></i>
|
|
</div>
|
|
<h6 class="mt-4 font-weight-bold text-dark">Sistem Aman</h6>
|
|
<span class="d-block text-muted" style="font-size: 0.9rem;">Tidak ada peringatan mendesak saat ini.</span>
|
|
</li>
|
|
@endif
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- TAMBAHAN BARU: Baris untuk Grafik Tren (Line Chart) --}}
|
|
<div class="row gutters mt-3">
|
|
<div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 mb-3">
|
|
<div class="card card-custom h-100">
|
|
<div class="card-header bg-white pt-4 pb-2 border-0">
|
|
<h6 class="card-title mb-0 font-weight-bold text-dark">
|
|
<i class="icon-trending-up text-primary mr-2"></i>Tren Penerima Prioritas Utama Lintas Periode
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
@if(count($labelTren) < 1)
|
|
<div class="text-center py-5 text-muted bg-light rounded" style="border: 1px dashed #ced4da;">
|
|
Belum ada data periode untuk ditampilkan trennya.
|
|
</div>
|
|
@else
|
|
<div style="height: 300px; width: 100%; position: relative;">
|
|
<canvas id="trendLineChart"></canvas>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{-- TAMBAHAN BARU 2: Baris untuk Grafik Demografi Kriteria --}}
|
|
<div class="row gutters mt-3">
|
|
<div class="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12 mb-3">
|
|
<div class="card card-custom h-100">
|
|
<div class="card-header bg-white pt-4 pb-2 border-0 d-flex justify-content-between align-items-center">
|
|
<h6 class="card-title mb-0 font-weight-bold text-dark">
|
|
<i class="icon-pie-chart text-success mr-2"></i>Demografi Warga
|
|
</h6>
|
|
{{-- Dropdown Pilih Kriteria --}}
|
|
<form action="{{ url()->current() }}" method="GET" class="form-inline m-0">
|
|
{{-- Pertahankan filter periode_id agar tidak hilang saat ganti chart --}}
|
|
<input type="hidden" name="periode_id" value="{{ request('periode_id') }}">
|
|
<select name="kriteria_chart" class="form-control form-control-sm border bg-light shadow-sm" onchange="this.form.submit()" style="border-radius: 20px; cursor: pointer;">
|
|
@foreach($semuaKriteria as $k)
|
|
<option value="{{ $k->id }}" {{ ($kriteriaDitampilkan && $kriteriaDitampilkan->id == $k->id) ? 'selected' : '' }}>
|
|
Berdasarkan {{ $k->nama ?? 'Kriteria' }}
|
|
</option>
|
|
@endforeach
|
|
</select>
|
|
</form>
|
|
</div>
|
|
<div class="card-body">
|
|
@if($statistikKriteria->isEmpty())
|
|
<div class="text-center py-5 text-muted bg-light rounded" style="border: 1px dashed #ced4da;">
|
|
Belum ada data detail warga untuk kriteria ini.
|
|
</div>
|
|
@else
|
|
<div style="height: 300px; width: 100%; position: relative;">
|
|
<canvas id="demografiChart"></canvas>
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{-- tutup dulu --}}
|
|
@endsection
|
|
|
|
@push('scripts')
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
// Chart 1: Doughnut Chart
|
|
const ctx1 = document.getElementById('verifikasiPieChart').getContext('2d');
|
|
new Chart(ctx1, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: ['Terverifikasi', 'Menunggu', 'Ditolak'],
|
|
datasets: [{
|
|
data: [{{ $countVerif }}, {{ $countPending }}, {{ $countTolak }}],
|
|
backgroundColor: [
|
|
'rgba(40, 167, 69, 0.85)',
|
|
'rgba(255, 193, 7, 0.85)',
|
|
'rgba(220, 53, 69, 0.85)'
|
|
],
|
|
borderWidth: 0,
|
|
hoverOffset: 4
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
cutout: '70%',
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom',
|
|
labels: { padding: 20, usePointStyle: true, pointStyle: 'circle' }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Chart 2: Bar Chart
|
|
@if($countRanking > 0)
|
|
const ctx2 = document.getElementById('peringkatBarChart').getContext('2d');
|
|
new Chart(ctx2, {
|
|
type: 'bar',
|
|
data: {
|
|
labels: ['Utama', 'Cadangan', 'Tidak Layak', 'Dialihkan'],
|
|
datasets: [{
|
|
label: 'Jumlah Warga',
|
|
data: [{{ $chartUtama }}, {{ $chartCadangan }}, {{ $chartTidakLayak }}, {{ $chartDialihkan }}],
|
|
backgroundColor: [
|
|
'rgba(0, 123, 255, 0.85)',
|
|
'rgba(23, 162, 184, 0.85)',
|
|
'rgba(108, 117, 125, 0.85)',
|
|
'rgba(111, 66, 193, 0.85)'
|
|
],
|
|
borderWidth: 0,
|
|
borderRadius: 8,
|
|
barPercentage: 0.6
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
x: {
|
|
grid: { display: false }
|
|
},
|
|
y: {
|
|
beginAtZero: true,
|
|
border: { display: false },
|
|
grid: {
|
|
color: '#f1f3f5'
|
|
}
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: { display: false },
|
|
tooltip: {
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
padding: 12,
|
|
titleFont: { size: 14 },
|
|
bodyFont: { size: 14 }
|
|
}
|
|
}
|
|
}
|
|
});
|
|
@endif
|
|
|
|
// Chart 3: Trend Line Chart (Grafik Garis Perbandingan Periode)
|
|
@if(count($labelTren) > 0)
|
|
const ctx3 = document.getElementById('trendLineChart').getContext('2d');
|
|
new Chart(ctx3, {
|
|
type: 'line',
|
|
data: {
|
|
// Label dari Controller (Misal: ['Maret 2026', 'April 2026', 'Mei 2026'])
|
|
labels: {!! json_encode($labelTren) !!},
|
|
datasets: [{
|
|
label: 'Penerima Prioritas Utama',
|
|
data: {!! json_encode($dataUtamaTren) !!},
|
|
borderColor: 'rgba(0, 123, 255, 1)',
|
|
backgroundColor: 'rgba(0, 123, 255, 0.1)', // Efek warna tipis di bawah garis
|
|
borderWidth: 3,
|
|
pointBackgroundColor: '#ffffff',
|
|
pointBorderColor: 'rgba(0, 123, 255, 1)',
|
|
pointBorderWidth: 2,
|
|
pointRadius: 5,
|
|
pointHoverRadius: 7,
|
|
fill: true, // Menyalakan efek background bawah garis
|
|
tension: 0.4 // Membuat garisnya melengkung halus (tidak kaku)
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
x: {
|
|
grid: { display: false }
|
|
},
|
|
y: {
|
|
beginAtZero: true,
|
|
border: { display: false },
|
|
grid: { color: '#f1f3f5' }
|
|
}
|
|
},
|
|
plugins: {
|
|
legend: { display: false },
|
|
tooltip: {
|
|
backgroundColor: 'rgba(0, 0, 0, 0.8)',
|
|
padding: 12,
|
|
titleFont: { size: 14 },
|
|
bodyFont: { size: 14 },
|
|
displayColors: false
|
|
}
|
|
}
|
|
}
|
|
});
|
|
@endif
|
|
|
|
// grafik demografi kriteria
|
|
// Chart 4: Demografi Chart (Berdasarkan Dropdown)
|
|
@if($statistikKriteria->isNotEmpty())
|
|
const ctx4 = document.getElementById('demografiChart').getContext('2d');
|
|
new Chart(ctx4, {
|
|
type: 'bar', // Kamu bisa ubah jadi 'doughnut' kalau mau bentuk lingkaran
|
|
data: {
|
|
labels: {!! json_encode($statistikKriteria->keys()) !!},
|
|
datasets: [{
|
|
label: 'Jumlah Warga',
|
|
data: {!! json_encode($statistikKriteria->values()) !!},
|
|
backgroundColor: [
|
|
'rgba(23, 162, 184, 0.85)',
|
|
'rgba(255, 193, 7, 0.85)',
|
|
'rgba(40, 167, 69, 0.85)',
|
|
'rgba(220, 53, 69, 0.85)',
|
|
'rgba(111, 66, 193, 0.85)',
|
|
'rgba(0, 123, 255, 0.85)'
|
|
],
|
|
borderWidth: 0,
|
|
borderRadius: 6
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: { display: false } // Ubah ke true jika kamu mengganti type chart menjadi 'doughnut'
|
|
},
|
|
scales: {
|
|
x: { grid: { display: false } },
|
|
y: { beginAtZero: true, grid: { color: '#f1f3f5' } }
|
|
}
|
|
}
|
|
});
|
|
@endif
|
|
|
|
</script>
|
|
@endpush
|