MIF_E31231754/resources/views/admin/gis/index.blade.php

308 lines
13 KiB
PHP

@extends('admin.layouts.app')
@section('title', 'GIS Penerima BLT')
@section('content')
{{-- Page Header --}}
<div class="d-flex align-items-center justify-content-between mb-3">
<div>
<h5 class="fw-bold mb-0" style="color:#1a3c2e;">
<i class="bi bi-geo-alt-fill me-2" style="color:#2d7a4f;"></i>GIS Sebaran Penerima BLT
</h5>
<nav aria-label="breadcrumb" class="mt-1">
<ol class="breadcrumb mb-0" style="font-size:0.8rem;">
<li class="breadcrumb-item"><a href="{{ route('admin.dashboard') }}" class="text-decoration-none" style="color:#2d7a4f;">Dashboard</a></li>
<li class="breadcrumb-item active text-muted">GIS Penerima</li>
</ol>
</nav>
</div>
{{-- Filter Periode --}}
<form method="GET" action="{{ route('admin.gis.index') }}" class="d-flex align-items-center gap-2" id="formPeriode">
<label class="form-label mb-0 fw-semibold text-muted" style="font-size:0.85rem; white-space:nowrap;">
<i class="bi bi-funnel me-1"></i>Filter Periode:
</label>
<select name="periode_id" id="selectPeriode" class="form-select form-select-sm" style="min-width:220px;" onchange="this.form.submit()">
@foreach($periodeList as $p)
<option value="{{ $p->id }}" {{ $periodeAktif && $periodeAktif->id == $p->id ? 'selected' : '' }}>
{{ $p->nama }}
</option>
@endforeach
@if($periodeList->isEmpty())
<option value="">-- Belum ada periode selesai --</option>
@endif
</select>
</form>
</div>
{{-- Stat Cards --}}
<div class="row g-3 mb-3">
<div class="col-6 col-md-3">
<div class="card p-3 text-center">
<div style="font-size:1.6rem;font-weight:800;color:#2d7a4f;" id="statPenerima">{{ $totalPenerima }}</div>
<div style="font-size:0.78rem;color:#6b7280;">Penerima Periode Ini</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card p-3 text-center">
<div style="font-size:1.6rem;font-weight:800;color:#2563eb;" id="statWilayah">{{ $totalWilayah }}</div>
<div style="font-size:0.78rem;color:#6b7280;">RW Terdampak</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card p-3 text-center">
<div style="font-size:1.6rem;font-weight:800;color:#d97706;">{{ $periodeAktif ? $periodeAktif->kuota_penerima : '-' }}</div>
<div style="font-size:0.78rem;color:#6b7280;">Kuota Periode</div>
</div>
</div>
<div class="col-6 col-md-3">
<div class="card p-3 text-center">
<div style="font-size:1.6rem;font-weight:800;color:#7c3aed;">{{ $periodeList->count() }}</div>
<div style="font-size:0.78rem;color:#6b7280;">Total Periode Selesai</div>
</div>
</div>
</div>
<div class="row g-3">
{{-- PETA --}}
<div class="col-lg-8">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<span>
<i class="bi bi-map me-2"></i>Peta Sebaran per RW
@if($periodeAktif)
<span class="badge ms-2" style="background:#e0f2e9;color:#2d7a4f;font-size:0.75rem;">
{{ $periodeAktif->nama }}
</span>
@endif
</span>
<div class="d-flex gap-2 align-items-center" style="font-size:0.78rem;">
<span><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#2d7a4f;"></span> Ada penerima</span>
<span><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#6c757d;"></span> Tidak ada</span>
</div>
</div>
<div class="card-body p-0" style="position:relative;">
<div id="map" style="height:480px; width:100%; border-radius:0 0 12px 12px;"></div>
</div>
</div>
</div>
{{-- RINGKASAN PER DUSUN --}}
<div class="col-lg-4">
<div class="card h-100">
<div class="card-header">
<i class="bi bi-bar-chart-fill me-2"></i>Ringkasan per Dusun
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table mb-0">
<thead>
<tr>
<th>Dusun</th>
<th class="text-center">Penerima</th>
<th class="text-center">%</th>
</tr>
</thead>
<tbody>
@forelse($statistikDusun as $dusun => $jumlah)
<tr>
<td>
<i class="bi bi-geo-alt-fill text-success me-1"></i>
<strong>{{ $dusun }}</strong>
</td>
<td class="text-center">
<span class="badge" style="background:#e0f2e9;color:#2d7a4f;">{{ $jumlah }}</span>
</td>
<td class="text-center text-muted" style="font-size:0.8rem;">
{{ $totalPenerima > 0 ? number_format($jumlah / $totalPenerima * 100, 0) : 0 }}%
</td>
</tr>
@empty
<tr>
<td colspan="3" class="text-center text-muted py-4">
<i class="bi bi-inbox d-block mb-1 fs-5"></i>
Belum ada data
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{{-- TABEL DETAIL PER RW --}}
<div class="card mt-3">
<div class="card-header">
<i class="bi bi-table me-2"></i>Detail Per RW
@if($periodeAktif)
<span class="text-muted fw-normal" style="font-size:0.85rem;">{{ $periodeAktif->nama }}</span>
@endif
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table mb-0">
<thead>
<tr>
<th>Dusun</th>
<th>RW</th>
<th class="text-center">Jumlah Penerima</th>
<th class="text-center">Rata-rata Skor SAW</th>
</tr>
</thead>
<tbody>
@forelse($markers as $m)
<tr>
<td><i class="bi bi-geo-alt-fill text-success me-1"></i>{{ $m['dusun'] }}</td>
<td>RW {{ $m['rw'] }}</td>
<td class="text-center">
@if($m['jumlah_penerima'] > 0)
<span class="badge" style="background:#e0f2e9;color:#2d7a4f;">
{{ $m['jumlah_penerima'] }} orang
</span>
@else
<span class="text-muted" style="font-size:0.8rem;"></span>
@endif
</td>
<td class="text-center font-monospace" style="font-size:0.82rem;">
{{ $m['avg_skor'] > 0 ? $m['avg_skor'] : '—' }}
</td>
</tr>
@empty
<tr>
<td colspan="4" class="text-center text-muted py-4">
<i class="bi bi-inbox d-block mb-1 fs-4"></i>
Belum ada data penerima.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
@endsection
@push('styles')
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<style>
#map { z-index: 1; }
</style>
@endpush
@push('scripts')
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
var map = L.map('map', {
center: [-7.529855, 112.578704],
zoom: 14,
zoomControl: true,
});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors',
maxZoom: 19,
}).addTo(map);
var markersData = JSON.parse('{!! addslashes(json_encode($markers->values())) !!}');
var wargaData = {}; // akan diisi via AJAX
var leafletMarkers = [];
function warnaMaker(jumlah) {
if (jumlah === 0) return '#6c757d';
if (jumlah <= 1) return '#86efac';
if (jumlah <= 2) return '#4ade80';
if (jumlah <= 3) return '#22c55e';
return '#15803d';
}
function buatIcon(jumlah) {
var warna = warnaMaker(jumlah);
return L.divIcon({
className: '',
html: `<div style="
background:${warna};
width:38px; height:38px;
border-radius:50% 50% 50% 0;
transform: rotate(-45deg);
border: 3px solid white;
box-shadow: 0 2px 8px rgba(0,0,0,0.3);
display:flex; align-items:center; justify-content:center;">
<span style="transform:rotate(45deg);color:white;font-weight:bold;font-size:13px;">${jumlah}</span>
</div>`,
iconSize: [38, 38],
iconAnchor: [19, 38],
popupAnchor: [0, -40],
});
}
function buatPopup(item, wargaList) {
var daftarWarga = '';
if (wargaList && wargaList.length > 0) {
daftarWarga = '<div style="margin-top:8px;border-top:1px solid #e5e7eb;padding-top:8px;">' +
'<div style="font-size:11px;font-weight:600;color:#374151;margin-bottom:4px;">Daftar Penerima:</div>';
wargaList.forEach(function(w) {
daftarWarga += `<div style="font-size:11px;padding:2px 0;">
<span style="color:#2d7a4f;font-weight:bold;">#${w.ranking}</span>
${w.nama}
<span style="color:#9ca3af;font-size:10px;">(${w.skor})</span>
</div>`;
});
daftarWarga += '</div>';
} else if (item.jumlah_penerima === 0) {
daftarWarga = '<div style="margin-top:8px;font-size:11px;color:#9ca3af;text-align:center;">Tidak ada penerima</div>';
}
return `<div style="min-width:220px;font-family:sans-serif;">
<div style="background:#2d7a4f;color:white;padding:8px 12px;margin:-14px -20px 10px;border-radius:4px 4px 0 0;">
<strong>📍 ${item.label}</strong>
</div>
<table style="width:100%;font-size:12px;">
<tr><td style="color:#6b7280;padding:3px 0;">Dusun</td><td><strong>${item.dusun}</strong></td></tr>
<tr><td style="color:#6b7280;padding:3px 0;">RW</td><td><strong>${item.rw}</strong></td></tr>
<tr><td style="color:#6b7280;padding:3px 0;">Penerima</td>
<td><strong style="color:${item.jumlah_penerima > 0 ? '#2d7a4f' : '#9ca3af'};">
${item.jumlah_penerima} orang</strong></td></tr>
${item.jumlah_penerima > 0 ? `<tr><td style="color:#6b7280;padding:3px 0;">Rata Skor</td><td><strong>${item.avg_skor}</strong></td></tr>` : ''}
</table>
${daftarWarga}
</div>`;
}
function renderMarkers(data, wargaPerWilayah) {
leafletMarkers.forEach(m => map.removeLayer(m));
leafletMarkers = [];
data.forEach(function(item) {
var key = item.dusun + '_' + item.rw;
var wargaList = wargaPerWilayah[key] || [];
var marker = L.marker([item.latitude, item.longitude], { icon: buatIcon(item.jumlah_penerima) });
marker.bindPopup(buatPopup(item, wargaList), { maxWidth: 280 });
marker.addTo(map);
leafletMarkers.push(marker);
});
if (data.length > 0) {
var bounds = data.map(m => [m.latitude, m.longitude]);
map.fitBounds(bounds, { padding: [60, 60], maxZoom: 14 });
}
}
// Load AJAX data untuk daftar nama penerima
var periodeId = '{{ $periodeAktif ? $periodeAktif->id : "" }}';
if (periodeId) {
fetch('{{ route("admin.gis.data") }}?periode_id=' + periodeId)
.then(r => r.json())
.then(function(res) {
wargaData = res.wargaPerWilayah;
renderMarkers(markersData, wargaData);
});
} else {
renderMarkers(markersData, {});
}
</script>
@endpush