First commit / commit pertama

This commit is contained in:
Mr.Haruna
2026-06-13 11:24:58 +07:00
commit 522c4f7200
166 changed files with 13326 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/auth_check.php';
requireAnyRole(['pimpinan']);
$pdo = Database::getConnection();
$pageTitle = 'Analisis Spasial';
$activeNav = 'analisis';
$extraHead = '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">';
require_once __DIR__ . '/partials/header.php';
require_once __DIR__ . '/../partials/analisis_body.php';
require_once __DIR__ . '/partials/footer.php';
+108
View File
@@ -0,0 +1,108 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/auth_check.php';
requireAnyRole(['pimpinan']);
$pdo = Database::getConnection();
$user = currentUser();
// KPI
$total = (int)$pdo->query("SELECT COUNT(*) FROM warga_miskin")->fetchColumn();
$dibantu = (int)$pdo->query("SELECT COUNT(DISTINCT warga_id) FROM bantuan_sosial WHERE is_aktif=1")->fetchColumn();
$terverif = (int)$pdo->query("SELECT COUNT(*) FROM warga_miskin WHERE status_verifikasi='terverifikasi'")->fetchColumn();
$cakupan = $total > 0 ? round($dibantu / $total * 100, 1) : 0;
// Zona prioritas (skor sama dgn api/zona_prioritas)
$zrows = $pdo->query("
SELECT w.nama, w.jumlah_penduduk,
COUNT(DISTINCT wm.id) AS miskin,
COUNT(DISTINCT CASE WHEN bs.id IS NOT NULL THEN wm.id END) AS dibantu
FROM wilayah w
LEFT JOIN warga_miskin wm ON ST_Contains(w.geom, wm.geom)
LEFT JOIN bantuan_sosial bs ON bs.warga_id=wm.id AND bs.is_aktif=1
GROUP BY w.id
")->fetchAll();
$zona = [];
foreach ($zrows as $r) {
$m = (int)$r['miskin']; $p = (int)$r['jumlah_penduduk'];
$persen = $p > 0 ? round($m/$p*100,2) : 0;
$cak = $m > 0 ? round($r['dibantu']/$m*100,1) : 0;
$gap = $m > 0 ? (100-$cak) : 0;
$skor = round($persen*2 + $gap*0.2 + $m*1, 1);
$level = $skor > 35 ? 'Tinggi' : ($skor > 20 ? 'Sedang' : 'Rendah');
$zona[] = ['nama'=>$r['nama'],'skor'=>$skor,'level'=>$level,'persen'=>$persen,'cakupan'=>$cak];
}
usort($zona, fn($a,$b)=>$b['skor']<=>$a['skor']);
$zonaTinggi = count(array_filter($zona, fn($z)=>$z['level']==='Tinggi'));
$pageTitle = 'Dashboard Eksekutif';
$activeNav = 'dashboard';
$extraHead = '';
require_once __DIR__ . '/partials/header.php';
?>
<div class="page-header" style="margin-bottom:18px;">
<h1 style="font-size:1.4rem;">👋 Selamat datang, <?= htmlspecialchars($user['nama_lengkap'] ?: $user['username']) ?></h1>
<p>Ringkasan eksekutif kondisi kemiskinan & penyaluran bantuan sosial kota.</p>
</div>
<div class="stats-grid">
<div class="stat-card primary"><div class="stat-icon"><i class="fas fa-house-user"></i></div>
<div class="stat-body"><div class="stat-label">Total RT Miskin</div><div class="stat-value"><?= $total ?></div><div class="stat-change"><?= count($zona) ?> kelurahan</div></div></div>
<div class="stat-card info"><div class="stat-icon"><i class="fas fa-hand-holding-heart"></i></div>
<div class="stat-body"><div class="stat-label">Cakupan Bantuan</div><div class="stat-value"><?= $cakupan ?>%</div><div class="stat-change"><?= $dibantu ?> RT dibantu</div></div></div>
<div class="stat-card success"><div class="stat-icon"><i class="fas fa-check-circle"></i></div>
<div class="stat-body"><div class="stat-label">Terverifikasi</div><div class="stat-value"><?= $terverif ?></div><div class="stat-change">dari <?= $total ?> data</div></div></div>
<div class="stat-card danger"><div class="stat-icon"><i class="fas fa-triangle-exclamation"></i></div>
<div class="stat-body"><div class="stat-label">Zona Prioritas Tinggi</div><div class="stat-value"><?= $zonaTinggi ?></div><div class="stat-change">kelurahan</div></div></div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:18px;margin-bottom:18px;">
<div class="card"><h3 style="font-size:0.95rem;margin-bottom:10px;">Cakupan Bantuan</h3><canvas id="cPie" height="200"></canvas></div>
<div class="card"><h3 style="font-size:0.95rem;margin-bottom:10px;">Penerima per Jenis Bantuan</h3><canvas id="cBar" height="200"></canvas></div>
</div>
<div style="display:grid;grid-template-columns:1.4fr 1fr;gap:18px;margin-bottom:18px;">
<div class="card"><h3 style="font-size:0.95rem;margin-bottom:10px;">Tren 12 Bulan</h3><canvas id="cTren" height="150"></canvas></div>
<div class="card"><h3 style="font-size:0.95rem;margin-bottom:10px;">Komparatif Kelurahan (radar)</h3><canvas id="cRadar" height="150"></canvas></div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:18px;">
<div class="card">
<h3 style="font-size:0.95rem;margin-bottom:10px;">🏆 Zona Prioritas Teratas</h3>
<?php foreach (array_slice($zona,0,4) as $i=>$z): $c=['Tinggi'=>'#EF4444','Sedang'=>'#FB923C','Rendah'=>'#10B981'][$z['level']]; ?>
<div style="display:flex;justify-content:space-between;align-items:center;padding:9px 0;border-bottom:1px solid #F3F4F6;">
<div><strong>#<?= $i+1 ?> <?= htmlspecialchars($z['nama']) ?></strong>
<div style="font-size:0.74rem;color:#9CA3AF;">% miskin <?= $z['persen'] ?>% · cakupan <?= $z['cakupan'] ?>%</div></div>
<span class="badge" style="background:<?= $c ?>22;color:<?= $c ?>;">Skor <?= $z['skor'] ?> · <?= $z['level'] ?></span>
</div>
<?php endforeach; ?>
</div>
<div class="card" style="display:flex;flex-direction:column;justify-content:center;gap:10px;">
<h3 style="font-size:0.95rem;">Tindak Lanjut</h3>
<a href="<?= app_url('pimpinan/analisis.php') ?>" class="btn btn-primary"><i class="fas fa-chart-line"></i> Buka Analisis Spasial</a>
<a href="<?= app_url('pimpinan/pelaporan.php') ?>" class="btn btn-success"><i class="fas fa-file-pdf"></i> Laporan & Cetak</a>
<a href="<?= app_url('pimpinan/peta.php') ?>" class="btn btn-ghost"><i class="fas fa-map"></i> Peta Interaktif</a>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
<script>
const DAPI = APP_BASE + '/api';
(async ()=>{
const cak = (await (await fetch(`${DAPI}/cakupan_bantuan.php`)).json()).data;
new Chart(cPie,{type:'doughnut',data:{labels:['Dibantu','Belum'],datasets:[{data:[cak.dibantu,cak.belum_dibantu],backgroundColor:['#10B981','#E5E7EB']}]},options:{plugins:{legend:{position:'bottom'}}}});
new Chart(cBar,{type:'bar',data:{labels:cak.per_jenis.map(j=>j.kode),datasets:[{label:'Penerima',data:cak.per_jenis.map(j=>j.penerima),backgroundColor:'#2563EB'}]},options:{plugins:{legend:{display:false}},scales:{y:{beginAtZero:true,ticks:{precision:0}}}}});
const tr = (await (await fetch(`${DAPI}/tren.php`)).json()).data;
new Chart(cTren,{type:'line',data:{labels:tr.labels,datasets:[
{label:'Kumulatif Warga',data:tr.kumulatif,borderColor:'#2563EB',backgroundColor:'#2563EB22',fill:true,tension:.3},
{label:'Bantuan Baru',data:tr.bantuan_baru,borderColor:'#10B981',tension:.3}
]},options:{scales:{y:{beginAtZero:true,ticks:{precision:0}}}}});
const km = (await (await fetch(`${DAPI}/komparatif.php`)).json()).data;
new Chart(cRadar,{type:'radar',data:{labels:km.labels,datasets:[
{label:'% Miskin',data:km.persentase_miskin,borderColor:'#EF4444',backgroundColor:'#EF444422'},
{label:'Cakupan %',data:km.cakupan_bantuan,borderColor:'#10B981',backgroundColor:'#10B98122'}
]},options:{scales:{r:{beginAtZero:true}}}});
})();
</script>
<?php require_once __DIR__ . '/partials/footer.php'; ?>
+191
View File
@@ -0,0 +1,191 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/auth_check.php';
requireAnyRole(['pimpinan']);
$pdo = Database::getConnection();
// Fetch user's own reports
$stmt = $pdo->prepare("SELECT id, kategori, deskripsi, status, created_at FROM laporan_warga WHERE user_id = ? ORDER BY id DESC");
$stmt->execute([$_SESSION['user_id']]);
$rows = $stmt->fetchAll();
$pageTitle = 'Laporan Warga';
$activeNav = 'laporan';
$extraHead = '<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">';
require_once __DIR__ . '/partials/header.php';
function badgeStatus($status) {
if($status === 'menunggu') return 'badge-warning';
if($status === 'diproses') return 'badge-info';
if($status === 'selesai') return 'badge-success';
if($status === 'ditolak') return 'badge-danger';
return 'badge-primary';
}
?>
<div class="page-header">
<div class="breadcrumb"><span>User</span><span class="sep">/</span><span>Laporan Warga</span></div>
<h1>📢 Laporan Fasilitas & Infrastruktur</h1>
<p>Laporkan masalah infrastruktur seperti jalan rusak, banjir, atau fasilitas umum yang terbengkalai.</p>
</div>
<div class="page-toolbar">
<div class="search-box">
<i class="fas fa-search search-icon"></i>
<input type="text" id="searchInput" placeholder="Cari laporan saya..." oninput="filterTable('searchInput','lapTable')">
</div>
<button class="btn btn-primary" onclick="openModal('modalTambah')">
<i class="fas fa-plus"></i> Buat Laporan Baru
</button>
</div>
<div class="table-wrap">
<table class="data-table" id="lapTable">
<thead>
<tr>
<th>#</th>
<th>Kategori</th>
<th>Deskripsi Singkat</th>
<th>Status</th>
<th>Tanggal</th>
<th>Aksi</th>
</tr>
</thead>
<tbody>
<?php foreach ($rows as $i => $r): ?>
<tr>
<td style="color:var(--text-muted)"><?= $i+1 ?></td>
<td><strong><?= htmlspecialchars($r['kategori']) ?></strong></td>
<td style="color:var(--text-secondary); max-width: 250px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
<?= htmlspecialchars($r['deskripsi']) ?>
</td>
<td><span class="badge <?= badgeStatus($r['status']) ?>"><?= ucfirst($r['status']) ?></span></td>
<td style="color:var(--text-muted); font-size:0.8rem;"><?= date('d M Y, H:i', strtotime($r['created_at'])) ?></td>
<td>
<div class="actions">
<?php if($r['status'] === 'menunggu'): ?>
<button class="btn btn-danger btn-sm btn-icon" onclick="hapus(<?= $r['id'] ?>)" title="Batalkan Laporan"><i class="fas fa-trash"></i></button>
<?php else: ?>
<span style="font-size:0.75rem; color:var(--text-muted);">Dikunci</span>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php if (!$rows): ?>
<tr>
<td colspan="6" style="text-align:center;padding:40px;color:var(--text-muted);">
Anda belum pernah membuat laporan.
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<!-- Modal Tambah Laporan -->
<div class="modal-overlay" id="modalTambah">
<div class="modal">
<div class="modal-header">
<span class="modal-title">📢 Buat Laporan Baru</span>
<button class="modal-close" onclick="closeModal('modalTambah')">×</button>
</div>
<form id="formTambah">
<div class="form-group">
<label class="form-label">Kategori Masalah *</label>
<select name="kategori" class="form-control" required>
<option value="Jalan Rusak">Jalan Rusak</option>
<option value="Banjir">Banjir</option>
<option value="Fasilitas Terbengkalai">Fasilitas Terbengkalai</option>
<option value="Lampu Jalan Mati">Lampu Jalan Mati</option>
<option value="Lainnya">Lainnya</option>
</select>
</div>
<div class="form-group">
<label class="form-label">Deskripsi Lengkap *</label>
<textarea name="deskripsi" class="form-control" placeholder="Jelaskan detail masalahnya..." required rows="3"></textarea>
</div>
<div class="form-group">
<label class="form-label">Pilih Lokasi di Peta *</label>
<div id="miniMapTambah" style="height:200px;border-radius:8px;border:1px solid #E5E7EB;margin-bottom:10px;z-index:1;"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
<input type="number" name="lat" id="latTambah" class="form-control" placeholder="Latitude" step="any" required readonly style="background:#F9FAFB;">
<input type="number" name="lng" id="lngTambah" class="form-control" placeholder="Longitude" step="any" required readonly style="background:#F9FAFB;">
</div>
</div>
</form>
<div class="modal-footer">
<button class="btn btn-ghost" onclick="closeModal('modalTambah')">Batal</button>
<button class="btn btn-primary" onclick="simpan()"><i class="fas fa-paper-plane"></i> Kirim Laporan</button>
</div>
</div>
</div>
<?php $extraScript = <<<'JS'
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
const API = APP_BASE + '/api/laporan.php';
let miniMap = null, miniMarker = null;
const originalOpenModal = window.openModal;
window.openModal = function(id) {
originalOpenModal(id);
if(id === 'modalTambah') {
setTimeout(() => {
if(!miniMap) {
miniMap = L.map('miniMapTambah').setView([-0.0583, 109.3448], 13);
L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png').addTo(miniMap);
miniMap.on('click', function(e) {
const lat = e.latlng.lat;
const lng = e.latlng.lng;
if(!miniMarker) miniMarker = L.marker([lat, lng]).addTo(miniMap);
else miniMarker.setLatLng([lat, lng]);
document.getElementById('latTambah').value = lat.toFixed(6);
document.getElementById('lngTambah').value = lng.toFixed(6);
});
} else {
miniMap.invalidateSize();
}
}, 100);
}
};
async function simpan() {
const f = document.getElementById('formTambah');
const lat = parseFloat(f.lat.value), lng = parseFloat(f.lng.value);
if (!f.kategori.value || !f.deskripsi.value || isNaN(lat) || isNaN(lng)) {
showToast('Lengkapi kategori, deskripsi, dan pilih lokasi!','error');
return;
}
const res = await fetch(API, {
method:'POST',
headers:{'Content-Type':'application/json'},
body: JSON.stringify({
kategori: f.kategori.value,
deskripsi: f.deskripsi.value,
geometry: { type:'Point', coordinates:[lng, lat] }
})
});
const d = await res.json();
if(d.status === 'success') {
showToast('Laporan berhasil dikirim!');
setTimeout(() => location.reload(), 900);
} else {
showToast(d.message,'error');
}
}
async function hapus(id) {
if(!confirm('Apakah Anda yakin ingin membatalkan laporan ini?')) return;
const res = await fetch(API + '?id=' + id, { method:'DELETE' });
const d = await res.json();
if(d.status === 'success') {
showToast('Laporan dibatalkan!');
setTimeout(() => location.reload(), 900);
} else {
showToast(d.message,'error');
}
}
</script>
JS; ?>
<?php require_once __DIR__ . '/partials/footer.php'; ?>
@@ -0,0 +1,54 @@
</div><!-- /admin-content -->
</main><!-- /admin-main -->
<!-- Toast Container -->
<div class="toast-container" id="toastContainer"></div>
<script>
// ── Clock ──
function updateClock() {
const now = new Date();
document.getElementById('clockText').textContent =
now.toLocaleTimeString('id-ID', { hour:'2-digit', minute:'2-digit', second:'2-digit' });
}
updateClock();
setInterval(updateClock, 1000);
// ── Toast utility ──
window.showToast = function(msg, type = 'success') {
const t = document.createElement('div');
t.className = `toast ${type}`;
const icons = { success: 'check-circle', error: 'exclamation-circle', info: 'info-circle' };
t.innerHTML = `<i class="fas fa-${icons[type]||'info-circle'}" style="margin-right:8px;"></i>${msg}`;
document.getElementById('toastContainer').appendChild(t);
setTimeout(() => { t.style.opacity = '0'; setTimeout(() => t.remove(), 400); }, 3000);
};
// ── Modal helpers ──
window.openModal = function(id) {
document.getElementById(id)?.classList.add('active');
document.body.style.overflow = 'hidden';
};
window.closeModal = function(id) {
document.getElementById(id)?.classList.remove('active');
document.body.style.overflow = '';
};
// Close modal on overlay click
document.querySelectorAll('.modal-overlay').forEach(overlay => {
overlay.addEventListener('click', e => {
if (e.target === overlay) closeModal(overlay.id);
});
});
// ── Search filter ──
window.filterTable = function(inputId, tableId) {
const q = document.getElementById(inputId)?.value.toLowerCase() || '';
document.querySelectorAll(`#${tableId} tbody tr`).forEach(row => {
row.style.display = row.textContent.toLowerCase().includes(q) ? '' : 'none';
});
};
</script>
<?= $extraScript ?? '' ?>
</body>
</html>
@@ -0,0 +1,93 @@
<?php
/**
* User Layout — sidebar + topbar (read-only mode, beda style dari admin)
* Variables expected from parent: $pageTitle, $activeNav
*/
$user = currentUser();
$initial = strtoupper(substr($user['nama_lengkap'] ?: $user['username'], 0, 1));
?>
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($pageTitle ?? 'Portal Pimpinan') ?> — WebGIS Kemiskinan</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
<link rel="stylesheet" href="<?= app_url('assets/css/main.css') ?>?v=20260610-spbu-snackbar">
<link rel="stylesheet" href="<?= app_url('assets/css/admin.css') ?>">
<script>const APP_BASE = '<?= app_url() ?>';</script>
<?= $extraHead ?? '' ?>
</head>
<body class="admin-page user-portal <?= $bodyClass ?? '' ?>">
<!-- ══ SIDEBAR ══ -->
<aside class="sidebar" id="sidebar">
<div class="sidebar-brand">
<div class="brand-icon" style="background:linear-gradient(135deg,#10B981,#059669);">🗺️</div>
<div class="brand-text">
<span class="brand-name">WebGIS</span>
<span class="brand-sub">Pimpinan</span>
</div>
</div>
<nav class="sidebar-nav">
<div class="nav-section-title">Menu</div>
<a href="<?= app_url('pimpinan/index.php') ?>"
class="nav-item <?= ($activeNav==='dashboard') ? 'active' : '' ?>">
<span class="nav-icon"><i class="fas fa-chart-pie"></i></span> Dashboard Eksekutif
</a>
<a href="<?= app_url('pimpinan/peta.php') ?>"
class="nav-item <?= ($activeNav==='peta') ? 'active' : '' ?>">
<span class="nav-icon"><i class="fas fa-map-marked-alt"></i></span> Peta Interaktif
</a>
<a href="<?= app_url('pimpinan/analisis.php') ?>"
class="nav-item <?= ($activeNav==='analisis') ? 'active' : '' ?>">
<span class="nav-icon"><i class="fas fa-chart-line"></i></span> Analisis Spasial
</a>
<a href="<?= app_url('pimpinan/pelaporan.php') ?>"
class="nav-item <?= ($activeNav==='pelaporan') ? 'active' : '' ?>">
<span class="nav-icon"><i class="fas fa-file-pdf"></i></span> Laporan &amp; Cetak
</a>
<a href="<?= app_url('pimpinan/laporan.php') ?>"
class="nav-item <?= ($activeNav==='laporan') ? 'active' : '' ?>">
<span class="nav-icon"><i class="fas fa-bullhorn"></i></span> Laporan Warga
</a>
<div class="nav-section-title">Informasi</div>
<div class="user-info" style="background:rgba(16,185,129,0.08);border-color:rgba(16,185,129,0.2);">
<i class="fas fa-info-circle" style="color:#059669;font-size:1.1rem;"></i>
<div style="font-size:0.78rem;color:var(--text-secondary);line-height:1.4;">
Anda masuk sebagai <strong style="color:#059669">Pimpinan</strong>. Akses penuh data &amp; laporan eksekutif (mode baca).
</div>
</div>
</nav>
<div class="sidebar-footer">
<div class="user-info">
<div class="user-avatar" style="background:linear-gradient(135deg,#10B981,#059669);"><?= $initial ?></div>
<div class="user-details">
<div class="user-name"><?= htmlspecialchars($user['nama_lengkap'] ?: $user['username']) ?></div>
<div class="user-role">Pimpinan</div>
</div>
<a href="<?= app_url('logout.php') ?>" class="user-logout" title="Keluar">
<i class="fas fa-sign-out-alt"></i>
</a>
</div>
</div>
</aside>
<!-- ══ MAIN CONTENT ══ -->
<main class="admin-main">
<div class="topbar">
<span class="topbar-title"><?= htmlspecialchars($pageTitle ?? 'Beranda') ?></span>
<div class="topbar-actions">
<div class="topbar-time" id="clock">
<i class="fas fa-clock"></i> <span id="clockText"></span>
</div>
<span class="badge badge-success" style="font-size:0.7rem;padding:5px 10px;">
<i class="fas fa-eye"></i> Mode Baca
</span>
</div>
</div>
<div class="admin-content">
+10
View File
@@ -0,0 +1,10 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/auth_check.php';
requireAnyRole(['pimpinan']);
$pdo = Database::getConnection();
$pageTitle = 'Laporan & Cetak';
$activeNav = 'pelaporan';
require_once __DIR__ . '/partials/header.php';
require_once __DIR__ . '/../partials/laporan_body.php';
require_once __DIR__ . '/partials/footer.php';
+27
View File
@@ -0,0 +1,27 @@
<?php
require_once __DIR__ . '/../config/db.php';
require_once __DIR__ . '/../config/auth_check.php';
requireAnyRole(['pimpinan']);
$pageTitle = 'Peta Interaktif';
$activeNav = 'peta';
$extraHead = '
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
';
require_once __DIR__ . '/partials/header.php';
?>
<div class="page-header" style="margin-bottom:12px;">
<h1>🗺️ Peta Pemetaan Kemiskinan</h1>
<p>Sebaran rumah tangga miskin, choropleth tingkat kemiskinan, heatmap kepadatan, dan fasilitas publik.</p>
</div>
<div style="position:relative;">
<div id="skpl-map" style="height:74vh;border-radius:12px;border:1px solid #E5E7EB;z-index:1;"></div>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet.heat@0.2.0/dist/leaflet-heat.js"></script>
<script src="<?= app_url('assets/js/skpl-layers.js') ?>?v=2"></script>
<script>const SKPL_ROLE = 'pimpinan';</script>
<script src="<?= app_url('assets/js/skpl-map.js') ?>?v=1"></script>
<?php $extraScript = ''; ?>
<?php require_once __DIR__ . '/partials/footer.php'; ?>