1st commit: version 1.0 WebGis-Pemetaan-Kemiskinan
This commit is contained in:
@@ -0,0 +1,18 @@
|
|||||||
|
🗺️ WebGIS Pemetaan Kemiskinan dan Distribusi Bantuan (Kota Pontianak)Sebuah Sistem Informasi Geografis (GIS) berbasis web yang dirancang dengan arsitektur Single Page Application (SPA) untuk memetakan demografi kemiskinan, mengkalkulasi kelayakan bantuan secara otomatis, mengelola respons darurat musibah, dan memfasilitasi pendataan talenta untuk program pemberdayaan warga.Sistem ini dibangun dengan kontrol otorisasi tingkat lanjut (RBAC & Geofencing) serta menggunakan algoritma Sistem Pendukung Keputusan (SPK) terintegrasi.✨ Fitur Utama (Core Features)Gatekeeper Authentication: Sistem layar kunci persisten dengan enkripsi kata sandi menggunakan standar BCRYPT dan validasi sesi via API (Anti Client-Side Amnesia).Pemetaan Spasial & Geofencing: Visualisasi interaktif titik infrastruktur dan batas wewenang radius operasional rumah ibadah menggunakan Leaflet.js dan Reverse Geocoding via Nominatim API.SPK Kemiskinan Otomatis: Menghitung Tingkat Kemiskinan (Sangat Miskin, Miskin, Rentan) secara dinamis menggunakan parameter Garis Kemiskinan Regional dan observasi aset fisik (Proxy Means Testing / PMT).Distribusi Bantuan Cerdas (Smart Autofill): Memberikan rekomendasi takaran logistik pro-rata berdasarkan status keparahan kemiskinan.Manajemen Krisis (Visual Alert): Peringatan dini berbasis geospasial menggunakan rendering animasi kelap-kelip merah pada titik lokasi keluarga yang mengalami musibah darurat.Resolusi Musibah Otomatis (Auto-Resolve): Menerapkan Database Transactions di mana penyaluran logistik akan secara otomatis memadamkan status darurat warga.Filter Pelatihan Algoritmik: Guard clause otomatis untuk menyeleksi kandidat pelatihan berdasarkan batas usia produktif, tingkat pendidikan, dan status pengangguran dari tabel Anggota Keluarga.🛠️ Stack Teknologi (Tech Stack)Frontend:HTML5 & CSS3 (Native)JavaScript (ES6+ / Vanilla JS)Leaflet.js (Pustaka Pemetaan Klien)Fetch API (Asynchronous HTTP Requests)Backend:PHP 8.x (API Endpoints & Sesi)PDO (PHP Data Objects) untuk interaksi basis dataMySQL / MariaDB (Database Relasional)⚙️ Persyaratan Sistem (Prerequisites)Untuk menjalankan proyek ini di mesin lokal, Anda membutuhkan:Web Server lokal seperti XAMPP, MAMP, atau Laragon.PHP Engine (Minimal versi 7.4, direkomendasikan versi 8.x).MySQL Database.Koneksi internet stabil (diperlukan untuk memuat aset basemap OpenStreetMap dan fitur Reverse Geocoding).🚀 Panduan Instalasi (Installation Guide)Ikuti langkah-langkah berikut untuk menjalankan sistem di lingkungan pengembangan lokal (localhost):Clone RepositoriBuka terminal/CMD dan jalankan perintah berikut di dalam direktori publik web server Anda (misal: C:\xampp\htdocs\):git clone [https://github.com/username-anda/nama-repositori-anda.git](https://github.com/username-anda/nama-repositori-anda.git)
|
||||||
|
Konfigurasi DatabaseBuka phpMyAdmin (biasanya di http://localhost/phpmyadmin).Buat sebuah database baru dengan nama webgis_kemiskinan (atau sesuai nama database Anda).Import file SQL yang telah disediakan di repositori ini (misal: database_auth.sql atau file dump lengkap sistem Anda) ke dalam database yang baru dibuat.Konfigurasi Koneksi PHPBuka file koneksi.php di dalam root direktori proyek, dan pastikan kredensial basis data sesuai dengan konfigurasi lokal Anda:$host = "localhost";
|
||||||
|
$user = "root"; // Username default XAMPP
|
||||||
|
$pass = ""; // Kosongkan jika XAMPP default
|
||||||
|
$dbname = "webgis_kemiskinan"; // Sesuaikan dengan nama database Anda
|
||||||
|
Jalankan AplikasiBuka web browser dan akses direktori proyek Anda:http://localhost/nama-folder-proyek/
|
||||||
|
🔒 Akses Pengujian (Dummy Credentials)Gunakan kredensial berikut untuk melewati layar kunci (Gatekeeper) pada saat pengujian sistem:Username: admin (contoh)Password: 123456 (contoh)(Catatan: Anda dapat membuat akun baru melalui tab "Daftar" di layar awal sistem).📂 Struktur Direktori (Directory Structure)📦 root-directory
|
||||||
|
┣ 📂 components # Komponen UI modular (Sidebar, Modals)
|
||||||
|
┣ 📂 otak_auth # API Backend untuk Login, Register, Sesi & Logout
|
||||||
|
┣ 📂 otak_kemiskinan # API Backend untuk logika CRUD & SPK warga, anggota, pelatihan
|
||||||
|
┣ 📂 otak_jalan # API Backend manajemen data garis (Polyline)
|
||||||
|
┣ 📂 otak_tanah # API Backend manajemen persil tanah (Polygon)
|
||||||
|
┣ 📂 otak_spbu # API Backend manajemen SPBU
|
||||||
|
┣ 📜 app.js # Otak Utama Sistem (Logika Spasial & State Management)
|
||||||
|
┣ 📜 style.css # Desain Kosmetik UI dan Animasi GPU
|
||||||
|
┣ 📜 koneksi.php # Jembatan penghubung ke Database MySQL
|
||||||
|
┗ 📜 index.php # Entry point aplikasi
|
||||||
|
📝 LisensiProyek ini dikembangkan sebagai bagian dari penelitian akademik/tugas perkuliahan Universitas Tanjungpura (2026). Segala bentuk distribusi dan modifikasi mengacu pada kebijakan hak cipta yang berlaku.Dibangun dengan presisi logika dan ketajaman rasional.
|
||||||
@@ -0,0 +1,691 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="toast-notification">Peringatan: Data SPBU berhasil dihapus!</div>
|
||||||
|
|
||||||
|
<div id="modal-spbu" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h3 id="spbu-modal-title" class="modal-header">Form Data SPBU</h3>
|
||||||
|
|
||||||
|
<input type="hidden" id="spbu-id">
|
||||||
|
<input type="hidden" id="spbu-lat">
|
||||||
|
<input type="hidden" id="spbu-lng">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="spbu-nama">Nama SPBU:</label>
|
||||||
|
<input type="text" id="spbu-nama" placeholder="Misal: SPBU Ahmad Yani">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="spbu-status">Status Operasional:</label>
|
||||||
|
<select id="spbu-status">
|
||||||
|
<option value="Buka 24 Jam">Buka 24 Jam</option>
|
||||||
|
<option value="Tidak 24 Jam">Tidak 24 Jam</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="spbu-telp">No. Telepon:</label>
|
||||||
|
<input type="tel" id="spbu-telp" placeholder="Misal: 0561xxxxxx">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="spbu-alamat">Alamat (Otomatis dari Koordinat):</label>
|
||||||
|
<textarea id="spbu-alamat" rows="3" readonly class="readonly-input" placeholder="Mengambil data lokasi..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="spbu-action-wrapper">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modal-jalan" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h3 id="jalan-modal-title" class="modal-header">Form Data Jalan</h3>
|
||||||
|
|
||||||
|
<input type="hidden" id="jalan-id">
|
||||||
|
<input type="hidden" id="jalan-koordinat">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="jalan-nama">Nama Jalan:</label>
|
||||||
|
<input type="text" id="jalan-nama" placeholder="Misal: Jl. Jenderal Sudirman">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Dropdown dengan id khusus untuk dimanipulasi oleh JS -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="jalan-status">Status Jalan:</label>
|
||||||
|
<select id="jalan-status" class="dynamic-select">
|
||||||
|
<option value="Jalan Nasional">Jalan Nasional</option>
|
||||||
|
<option value="Jalan Provinsi">Jalan Provinsi</option>
|
||||||
|
<option value="Jalan Kabupaten">Jalan Kabupaten</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="jalan-jarak">Jarak (Meter):</label>
|
||||||
|
<input type="text" id="jalan-jarak" readonly class="readonly-input">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="jalan-action-wrapper" style="display: flex; gap: 10px; margin-top: 25px;">
|
||||||
|
<!-- Dinamis oleh JS -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modal-tanah" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h3 id="tanah-modal-title" class="modal-header">Form Parsil Tanah</h3>
|
||||||
|
|
||||||
|
<input type="hidden" id="tanah-id">
|
||||||
|
<input type="hidden" id="tanah-koordinat">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="tanah-nama">Nama Pemilik/Area:</label>
|
||||||
|
<input type="text" id="tanah-nama" placeholder="Misal: Tanah Budi / Area 1">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="tanah-status">Status Kepemilikan:</label>
|
||||||
|
<select id="tanah-status" class="dynamic-select">
|
||||||
|
<option value="SHM">Sertifikat Hak Milik (SHM)</option>
|
||||||
|
<option value="HGB">Sertifikat Hak Guna Bangunan (HGB)</option>
|
||||||
|
<option value="HGU">Sertifikat Hak Guna Usaha (HGU)</option>
|
||||||
|
<option value="HP">Sertifikat Hak Pakai (HP)</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="tanah-luas">Luas (m²):</label>
|
||||||
|
<input type="text" id="tanah-luas" readonly class="readonly-input">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="tanah-action-wrapper" style="display: flex; gap: 10px; margin-top: 25px;">
|
||||||
|
<!-- Dinamis oleh JS -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modal-filter-layer" class="modal-overlay">
|
||||||
|
<div class="modal-content filter-modal">
|
||||||
|
<h3 class="modal-header">Filter Layer Peta</h3>
|
||||||
|
|
||||||
|
<div class="filter-section">
|
||||||
|
<label class="filter-section-title">Status Jalan:</label>
|
||||||
|
<div class="filter-grid">
|
||||||
|
<label class="custom-checkbox-wrapper">
|
||||||
|
<input type="checkbox" class="cb-jalan" value="Jalan Nasional" checked>
|
||||||
|
<span class="custom-checkmark"></span>
|
||||||
|
<span class="filter-text">Jalan Nasional</span>
|
||||||
|
<span class="color-dot" style="background-color: #E53E3E;"></span>
|
||||||
|
</label>
|
||||||
|
<label class="custom-checkbox-wrapper">
|
||||||
|
<input type="checkbox" class="cb-jalan" value="Jalan Provinsi" checked>
|
||||||
|
<span class="custom-checkmark"></span>
|
||||||
|
<span class="filter-text">Jalan Provinsi</span>
|
||||||
|
<span class="color-dot" style="background-color: #3182CE;"></span>
|
||||||
|
</label>
|
||||||
|
<label class="custom-checkbox-wrapper">
|
||||||
|
<input type="checkbox" class="cb-jalan" value="Jalan Kabupaten" checked>
|
||||||
|
<span class="custom-checkmark"></span>
|
||||||
|
<span class="filter-text">Jalan Kabupaten</span>
|
||||||
|
<span class="color-dot" style="background-color: #38A169;"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="filter-section">
|
||||||
|
<label class="filter-section-title">Status Tanah:</label>
|
||||||
|
<div class="filter-grid">
|
||||||
|
<label class="custom-checkbox-wrapper">
|
||||||
|
<input type="checkbox" class="cb-tanah" value="SHM" checked>
|
||||||
|
<span class="custom-checkmark"></span>
|
||||||
|
<span class="filter-text">SHM</span>
|
||||||
|
<span class="color-dot" style="background-color: #38A169;"></span>
|
||||||
|
</label>
|
||||||
|
<label class="custom-checkbox-wrapper">
|
||||||
|
<input type="checkbox" class="cb-tanah" value="HGB" checked>
|
||||||
|
<span class="custom-checkmark"></span>
|
||||||
|
<span class="filter-text">HGB</span>
|
||||||
|
<span class="color-dot" style="background-color: #DD6B20;"></span>
|
||||||
|
</label>
|
||||||
|
<label class="custom-checkbox-wrapper">
|
||||||
|
<input type="checkbox" class="cb-tanah" value="HGU" checked>
|
||||||
|
<span class="custom-checkmark"></span>
|
||||||
|
<span class="filter-text">HGU</span>
|
||||||
|
<span class="color-dot" style="background-color: #3182CE;"></span>
|
||||||
|
</label>
|
||||||
|
<label class="custom-checkbox-wrapper">
|
||||||
|
<input type="checkbox" class="cb-tanah" value="HP" checked>
|
||||||
|
<span class="custom-checkmark"></span>
|
||||||
|
<span class="filter-text">HP</span>
|
||||||
|
<span class="color-dot" style="background-color: #718096;"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-group" style="margin-top: 20px;">
|
||||||
|
<button class="btn btn-save" onclick="terapkanFilterLayer()">Terapkan Filter</button>
|
||||||
|
<button class="btn btn-cancel" onclick="document.getElementById('modal-filter-layer').style.display='none'">Batal</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modal-filter-spbu" class="modal-overlay">
|
||||||
|
<div class="modal-content filter-modal">
|
||||||
|
<h3 class="modal-header">Filter Status SPBU</h3>
|
||||||
|
|
||||||
|
<div class="filter-section">
|
||||||
|
<label class="filter-section-title">Pilih Operasional:</label>
|
||||||
|
<div class="filter-grid">
|
||||||
|
<!-- Kita menggunakan struktur custom radio button -->
|
||||||
|
<label class="custom-radio-wrapper">
|
||||||
|
<input type="radio" name="rad-spbu" value="Semua" checked>
|
||||||
|
<span class="custom-radiomark"></span>
|
||||||
|
<span class="filter-text">Semua SPBU</span>
|
||||||
|
</label>
|
||||||
|
<label class="custom-radio-wrapper">
|
||||||
|
<input type="radio" name="rad-spbu" value="Buka 24 Jam">
|
||||||
|
<span class="custom-radiomark"></span>
|
||||||
|
<span class="filter-text">Buka 24 Jam</span>
|
||||||
|
<span class="color-dot" style="background-color: #38A169;"></span>
|
||||||
|
</label>
|
||||||
|
<label class="custom-radio-wrapper">
|
||||||
|
<input type="radio" name="rad-spbu" value="Tidak 24 Jam">
|
||||||
|
<span class="custom-radiomark"></span>
|
||||||
|
<span class="filter-text">Tidak 24 Jam</span>
|
||||||
|
<span class="color-dot" style="background-color: #E53E3E;"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-group" style="margin-top: 20px;">
|
||||||
|
<button class="btn btn-save" onclick="terapkanFilterSPBU()">Terapkan Filter</button>
|
||||||
|
<button class="btn btn-cancel" onclick="document.getElementById('modal-filter-spbu').style.display='none'">Batal</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- MODAL INTERAKTIF RUMAH PENDUDUK & PMT -->
|
||||||
|
<div id="modal-penduduk" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h3 id="penduduk-modal-title" class="modal-header">Formulir Data Penduduk</h3>
|
||||||
|
|
||||||
|
<input type="hidden" id="penduduk-id">
|
||||||
|
<input type="hidden" id="penduduk-lat">
|
||||||
|
<input type="hidden" id="penduduk-lng">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Nama Kepala Keluarga (KK):</label>
|
||||||
|
<input type="text" id="penduduk-kk" placeholder="Misal: Budi Santoso">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="display:flex; gap:10px;">
|
||||||
|
<div class="form-group" style="flex:1;">
|
||||||
|
<label>Agama:</label>
|
||||||
|
<select id="penduduk-agama">
|
||||||
|
<option value="Islam">Islam</option><option value="Kristen">Kristen</option>
|
||||||
|
<option value="Katolik">Katolik</option><option value="Hindu">Hindu</option>
|
||||||
|
<option value="Buddha">Buddha</option><option value="Konghucu">Konghucu</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" style="width:100px;">
|
||||||
|
<label>Tanggungan:</label>
|
||||||
|
<input type="number" id="penduduk-tanggungan" value="0" min="0">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Pengeluaran Bulanan (Rp):</label>
|
||||||
|
<input type="number" id="penduduk-pengeluaran" placeholder="Misal: 1500000">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr style="border: 0; border-bottom: 1px dashed var(--border); margin: 15px 0;">
|
||||||
|
<h4 style="margin:0 0 10px 0; color:var(--navy); font-size:0.9rem;">Penilaian PMT (0 = Layak, 1 = Buruk)</h4>
|
||||||
|
|
||||||
|
<div style="display:grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Lantai</label>
|
||||||
|
<select class="pmt-score-input" id="pmt-lantai">
|
||||||
|
<option value="0">0 - Bagus/Semen</option><option value="1">1 - Tanah/Bambu</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Dinding</label>
|
||||||
|
<select class="pmt-score-input" id="pmt-dinding">
|
||||||
|
<option value="0">0 - Tembok/Kayu Baik</option><option value="1">1 - Rumbia/Bambu</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Sanitasi (BAB)</label>
|
||||||
|
<select class="pmt-score-input" id="pmt-sanitasi">
|
||||||
|
<option value="0">0 - Toilet Sendiri</option><option value="1">1 - Umum/Sungai</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Listrik/Penerangan</label>
|
||||||
|
<select class="pmt-score-input" id="pmt-penerangan">
|
||||||
|
<option value="0">0 - PLN Resmi</option><option value="1">1 - Numpang/Pelita</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Sumber Air</label>
|
||||||
|
<select class="pmt-score-input" id="pmt-air">
|
||||||
|
<option value="0">0 - Leding/Sumur Bor</option><option value="1">1 - Sungai/Hujan</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 10px;">
|
||||||
|
<label>Alamat Otomatis:</label>
|
||||||
|
<textarea id="penduduk-alamat" rows="2" readonly class="readonly-input"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="penduduk-action-wrapper" class="btn-group"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template id="template-popup-ibadah">
|
||||||
|
<div class="popup-form">
|
||||||
|
<h4>Form Rumah Ibadah</h4>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Nama Ibadah:</label>
|
||||||
|
<input type="text" id="pop-ib-nama" placeholder="Cth: Masjid At-Taqwa">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Jenis:</label>
|
||||||
|
<select id="pop-ib-jenis">
|
||||||
|
<option value="Masjid">Masjid</option>
|
||||||
|
<option value="Gereja">Gereja</option>
|
||||||
|
<option value="Vihara">Vihara</option>
|
||||||
|
<option value="Pura">Pura</option>
|
||||||
|
<option value="Klenteng">Klenteng</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Radius Efektif (m): <span id="pop-ib-rad-val">100</span>m</label>
|
||||||
|
<input type="range" id="pop-ib-rad" min="50" max="3000" step="50" value="100" oninput="document.getElementById('pop-ib-rad-val').innerText=this.value">
|
||||||
|
</div>
|
||||||
|
<textarea id="pop-ib-alamat" readonly rows="2" style="font-size:0.75rem; color:#718096">Sedang melacak alamat dari satelit...</textarea>
|
||||||
|
<button class="btn btn-save" style="width:100%; margin-top:10px;" id="btn-pop-simpan" disabled>Tunggu...</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="template-popup-penduduk">
|
||||||
|
<div class="popup-form">
|
||||||
|
<h4>Form Rumah Penduduk</h4>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Nama KK:</label>
|
||||||
|
<input type="text" id="pop-pd-kk" placeholder="Cth: Budi Santoso">
|
||||||
|
</div>
|
||||||
|
<div style="display:flex; gap:6px;">
|
||||||
|
<div class="form-group" style="flex:1">
|
||||||
|
<label>Agama:</label>
|
||||||
|
<select id="pop-pd-agama">
|
||||||
|
<option>Islam</option><option>Kristen</option><option>Katolik</option>
|
||||||
|
<option>Hindu</option><option>Buddha</option><option>Konghucu</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" style="width:80px">
|
||||||
|
<label>Tanggungan:</label>
|
||||||
|
<input type="number" id="pop-pd-tanggungan" value="0" min="0">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Pengeluaran (Rp):</label>
|
||||||
|
<input type="number" id="pop-pd-pengeluaran" placeholder="Cth: 1500000">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label style="font-size:0.85rem; font-weight:bold; color:var(--navy); border-bottom:1px dashed #A0AEC0; display:block; padding-bottom:4px; margin-top:12px; margin-bottom: 8px;">Indikator Fisik (0=Layak, 1=Buruk)</label>
|
||||||
|
|
||||||
|
<div class="pmt-grid">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Lantai:</label>
|
||||||
|
<select id="pop-pmt-lantai"><option value="0">0 - Bagus</option><option value="1">1 - Tanah</option></select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Dinding:</label>
|
||||||
|
<select id="pop-pmt-dinding"><option value="0">0 - Tembok</option><option value="1">1 - Rumbia</option></select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Sanitasi/WC:</label>
|
||||||
|
<select id="pop-pmt-sanitasi"><option value="0">0 - Sendiri</option><option value="1">1 - Umum</option></select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Listrik:</label>
|
||||||
|
<select id="pop-pmt-listrik"><option value="0">0 - PLN</option><option value="1">1 - Numpang</option></select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group" style="grid-column: span 2;">
|
||||||
|
<label>Sumber Air:</label>
|
||||||
|
<select id="pop-pmt-air"><option value="0">0 - PDAM/Bor</option><option value="1">1 - Sungai/Hujan</option></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<textarea id="pop-pd-alamat" readonly rows="2" style="font-size:0.75rem; color:#718096; margin-top:8px;">Sedang melacak alamat dari satelit...</textarea>
|
||||||
|
<button class="btn btn-save" style="width:100%; margin-top:10px;" id="btn-pop-simpan" disabled>Tunggu...</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="template-popup-read-penduduk">
|
||||||
|
<div class="pop-read-only">
|
||||||
|
<h3 class="pop-read-title" id="read-pd-nama">Nama Keluarga</h3>
|
||||||
|
|
||||||
|
<div class="pop-read-meta">
|
||||||
|
<span id="read-pd-agama">Agama: -</span>
|
||||||
|
<span id="read-pd-anggota">Anggota/Tanggungan: - Jiwa</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="pop-read-alamat" id="read-pd-alamat">Alamat lengkap...</p>
|
||||||
|
|
||||||
|
<div class="pop-badge-container">
|
||||||
|
<span class="pop-badge" id="read-pd-badge">Status</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="read-pd-naungan" class="pop-naungan">Tidak berada di bawah wewenang rumah ibadah manapun</div>
|
||||||
|
|
||||||
|
<hr class="pop-divider">
|
||||||
|
|
||||||
|
<div class="pop-action-main">
|
||||||
|
<button class="btn btn-success" id="btn-pd-bantuan" style="width:100%; padding: 12px; margin-bottom: 8px;">Catat Log Bantuan</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="accordion-wrapper">
|
||||||
|
<button class="btn btn-accordion" id="btn-pd-opsi">Opsi Lainnya</button>
|
||||||
|
|
||||||
|
<div class="accordion-content" id="acc-pd-content">
|
||||||
|
<hr class="pop-divider-sub">
|
||||||
|
<button class="btn btn-success" id="btn-pd-riwayat-pelatihan" style="width:100%; margin-bottom:8px; padding: 10px;">Lihat Log Pelatihan</button>
|
||||||
|
<button class="btn btn-success" id="btn-pd-riwayat-musibah" style="width:100%; margin-bottom:8px; padding: 10px;">Lihat Laporan Musibah</button>
|
||||||
|
<button class="btn btn-success" id="btn-pd-riwayat-bantuan" style="width:100%; margin-bottom:8px; padding: 10px;">Lihat Log Bantuan</button>
|
||||||
|
<div style="display:flex; gap:8px;">
|
||||||
|
<button class="btn btn-warning" id="btn-pd-edit">Edit Data</button>
|
||||||
|
<button class="btn btn-danger" id="btn-pd-hapus">Hapus</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="template-popup-read-ibadah">
|
||||||
|
<div class="pop-read-only">
|
||||||
|
<h3 class="pop-read-title" id="read-ib-nama">Nama Rumah Ibadah</h3>
|
||||||
|
|
||||||
|
<div class="pop-read-meta">
|
||||||
|
<span id="read-ib-jenis">Jenis: -</span>
|
||||||
|
<span id="read-ib-radius">Radius Jangkauan: - m</span>
|
||||||
|
<span id="read-ib-naungan" style="color: var(--navy); font-weight: bold;">Keluarga dalam radius: 0 KK</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="pop-read-alamat" id="read-ib-alamat">Alamat lengkap...</p>
|
||||||
|
|
||||||
|
<hr class="pop-divider">
|
||||||
|
|
||||||
|
<div style="display:flex; gap:8px;">
|
||||||
|
<button class="btn btn-warning" id="btn-ib-edit">Edit Data</button>
|
||||||
|
<button class="btn btn-danger" id="btn-ib-hapus">Hapus</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div id="modal-log-bantuan" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h3 id="log-modal-title" class="modal-header">Catat Bantuan Diberikan</h3>
|
||||||
|
<p style="font-size: 0.85rem; color: #4A5568; margin-top: -10px; margin-bottom: 15px;">Penerima: <span id="log-nama-penerima" style="font-weight: bold; color: var(--navy);"></span></p>
|
||||||
|
|
||||||
|
<input type="hidden" id="log-id-penduduk">
|
||||||
|
|
||||||
|
<div style="display:grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Beras (Kg):</label>
|
||||||
|
<input type="number" id="log-beras" value="0" min="0">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Minyak (Liter):</label>
|
||||||
|
<input type="number" id="log-minyak" value="0" min="0">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Gula (Kg):</label>
|
||||||
|
<input type="number" id="log-gula" value="0" min="0">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Telur (Kg):</label>
|
||||||
|
<input type="number" id="log-telur" value="0" min="0">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Susu (Kaleng):</label>
|
||||||
|
<input type="number" id="log-susu" value="0" min="0">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Uang Tunai (Rp):</label>
|
||||||
|
<input type="number" id="log-tunai" value="0" min="0" step="50000">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" style="margin-top: 5px;">
|
||||||
|
<label>Catatan / Keterangan (Opsional):</label>
|
||||||
|
<textarea id="log-catatan" rows="2" placeholder="Misal: Bantuan paket Idul Fitri"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-save" onclick="eksekusiSimpanLogBantuan()">Simpan Catatan</button>
|
||||||
|
<button class="btn btn-cancel" onclick="document.getElementById('modal-log-bantuan').style.display='none'">Batal</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modal-riwayat-bantuan" class="modal-overlay">
|
||||||
|
<div class="modal-content" style="width: 850px; max-width: 95vw;">
|
||||||
|
<h3 class="modal-header">Riwayat Penerimaan Bantuan</h3>
|
||||||
|
<p style="font-size: 0.85rem; color: #4A5568; margin-top: -10px; margin-bottom: 15px;">Keluarga: <span id="riwayat-nama-penerima" style="font-weight: bold; color: var(--navy);"></span></p>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="riwayat-table" id="tabel-riwayat-bantuan">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Waktu Log</th>
|
||||||
|
<th>Beras (Kg)</th>
|
||||||
|
<th>Minyak (L)</th>
|
||||||
|
<th>Gula (Kg)</th>
|
||||||
|
<th>Telur (Kg)</th>
|
||||||
|
<th>Susu (Klg)</th>
|
||||||
|
<th>Tunai (Rp)</th>
|
||||||
|
<th>Catatan</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="riwayat-tbody">
|
||||||
|
<!-- Data disuntikkan secara dinamis via app.js -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-group" style="margin-top: 20px;">
|
||||||
|
<button class="btn btn-cancel" onclick="document.getElementById('modal-riwayat-bantuan').style.display='none'">Tutup Riwayat</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modal-musibah" class="modal-overlay">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h3 class="modal-header" style="color: var(--red-danger);">Lapor Darurat Musibah</h3>
|
||||||
|
<p style="font-size: 0.85rem; color: #4A5568; margin-top: -10px; margin-bottom: 15px;">
|
||||||
|
Keluarga: <span id="musibah-nama" style="font-weight: bold; color: var(--navy);"></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<input type="hidden" id="musibah-id-penduduk">
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Tanggal Lapor</label>
|
||||||
|
<!-- Dikunci (readonly) karena sistem JS yang akan mengisi secara otomatis -->
|
||||||
|
<input type="date" id="musibah-tgl" readonly style="background: #EDF2F7; cursor: not-allowed; color: #718096;">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Jenis Musibah</label>
|
||||||
|
<select id="musibah-jenis" class="modern-select">
|
||||||
|
<option value="Kecelakaan">Kecelakaan</option>
|
||||||
|
<option value="Kematian">Kematian</option>
|
||||||
|
<option value="Sakit Keras">Sakit Keras</option>
|
||||||
|
<option value="Kebakaran">Kebakaran</option>
|
||||||
|
<option value="Bencana Alam">Bencana Alam</option>
|
||||||
|
<option value="Lainnya">Lainnya</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Deskripsi Kerusakan / Kondisi</label>
|
||||||
|
<textarea id="musibah-deskripsi" rows="3" placeholder="Jelaskan kondisi darurat secara ringkas..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Status Penanganan Awal</label>
|
||||||
|
<select id="musibah-status" class="modern-select">
|
||||||
|
<option value="Belum Ditangani">Belum Ditangani</option>
|
||||||
|
<option value="Sudah Ditangani">Sudah Ditangani</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-group" style="margin-top: 20px;">
|
||||||
|
<button class="btn btn-danger" onclick="simpanMusibah()">Kirim Laporan</button>
|
||||||
|
<button class="btn btn-cancel" onclick="document.getElementById('modal-musibah').style.display='none'">Batal</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- MODAL PROGRAM PELATIHAN -->
|
||||||
|
<div id="modal-master-pelatihan" class="modal-overlay">
|
||||||
|
<div class="modal-content" style="width: 500px;">
|
||||||
|
<h3 class="modal-header">Buat Program Pelatihan Baru</h3>
|
||||||
|
<div class="form-group"><label>Nama Pelatihan</label><input type="text" id="latih-nama"></div>
|
||||||
|
<div class="form-group"><label>Instansi Penyelenggara</label><input type="text" id="latih-instansi"></div>
|
||||||
|
<div style="display:flex; gap:10px;">
|
||||||
|
<div class="form-group" style="flex:1;"><label>Tanggal Mulai</label><input type="date" id="latih-mulai"></div>
|
||||||
|
<div class="form-group" style="flex:1;"><label>Tanggal Selesai</label><input type="date" id="latih-selesai"></div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group"><label>Deskripsi</label><textarea id="latih-deskripsi" rows="2"></textarea></div>
|
||||||
|
<div class="btn-group">
|
||||||
|
<button class="btn btn-save" onclick="eksekusiSimpanPelatihan()">Simpan Program</button>
|
||||||
|
<button class="btn btn-cancel" onclick="document.getElementById('modal-master-pelatihan').style.display='none'">Tutup</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- MODAL DETAIL KELUARGA (ANGGOTA) -->
|
||||||
|
<div id="modal-detail-keluarga" class="modal-overlay">
|
||||||
|
<div class="modal-content" style="width: 950px; max-width: 95vw;">
|
||||||
|
<h3 class="modal-header">Detail Anggota Keluarga</h3>
|
||||||
|
<p style="font-size: 0.85rem; margin-bottom: 15px;">Keluarga: <span id="detail-keluarga-nama" style="font-weight:bold; color: var(--navy);"></span></p>
|
||||||
|
|
||||||
|
<input type="hidden" id="detail-id-penduduk">
|
||||||
|
<input type="hidden" id="detail-is-bernaung"> <!-- Hidden State untuk Auto-Refresh -->
|
||||||
|
|
||||||
|
<div class="table-responsive" style="margin-bottom:20px; max-height: 350px;">
|
||||||
|
<table class="riwayat-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>NIK</th>
|
||||||
|
<th>Nama Lengkap</th>
|
||||||
|
<th>Usia</th>
|
||||||
|
<th>Pendidikan</th>
|
||||||
|
<th>Pekerjaan</th>
|
||||||
|
<th>Status Pelatihan</th>
|
||||||
|
<th>Aksi</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tbody-anggota-keluarga">
|
||||||
|
<!-- Data ditarik oleh Fetch JS -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h4 style="border-bottom:1px solid var(--border); padding-bottom:5px; color: var(--navy);">Tambah Anggota Baru</h4>
|
||||||
|
<div style="display:grid; grid-template-columns: 1fr 1fr 1fr; gap:10px;">
|
||||||
|
<div class="form-group"><label>NIK</label><input type="text" id="anggota-nik" placeholder="16 Digit NIK"></div>
|
||||||
|
<div class="form-group"><label>Nama Lengkap</label><input type="text" id="anggota-nama"></div>
|
||||||
|
<div class="form-group"><label>Tanggal Lahir</label><input type="date" id="anggota-lahir"></div>
|
||||||
|
<div class="form-group"><label>Pendidikan</label>
|
||||||
|
<select id="anggota-pendidikan">
|
||||||
|
<option value="Tidak Sekolah">Tidak Sekolah</option>
|
||||||
|
<option value="SD">SD</option><option value="SMP">SMP</option>
|
||||||
|
<option value="SMA/SMK">SMA/SMK</option><option value="D3">D3</option><option value="S1">S1</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group"><label>Pekerjaan (Kosongkan jika nganggur)</label><input type="text" id="anggota-pekerjaan" placeholder="Contoh: Petani"></div>
|
||||||
|
<div class="form-group" style="display:flex; align-items:flex-end;">
|
||||||
|
<button class="btn btn-success" style="width:100%; padding: 10px;" onclick="eksekusiSimpanAnggota()">Tambah Anggota</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-group" style="margin-top:20px;">
|
||||||
|
<button class="btn btn-cancel" onclick="document.getElementById('modal-detail-keluarga').style.display='none'">Tutup Jendela</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="modal-riwayat-pelatihan" class="modal-overlay">
|
||||||
|
<div class="modal-content" style="width: 850px; max-width: 95vw;">
|
||||||
|
<h3 class="modal-header">Riwayat Mengikuti Pelatihan</h3>
|
||||||
|
<p style="font-size: 0.85rem; color: #4A5568; margin-top: -10px; margin-bottom: 15px;">Keluarga: <span id="riwayat-pelatihan-nama-penerima" style="font-weight: bold; color: var(--navy);"></span></p>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="riwayat-table">
|
||||||
|
<thead>
|
||||||
|
<tr><th>Tgl Daftar</th><th>NIK</th><th>Nama Anggota</th><th>Program Pelatihan</th><th>Instansi</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="riwayat-pelatihan-tbody"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group" style="margin-top: 20px;">
|
||||||
|
<button class="btn btn-cancel" onclick="document.getElementById('modal-riwayat-pelatihan').style.display='none'">Tutup Riwayat</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- MODAL RIWAYAT MUSIBAH -->
|
||||||
|
<div id="modal-riwayat-musibah" class="modal-overlay">
|
||||||
|
<div class="modal-content" style="width: 850px; max-width: 95vw;">
|
||||||
|
<h3 class="modal-header">Riwayat Pelaporan Musibah</h3>
|
||||||
|
<p style="font-size: 0.85rem; color: #4A5568; margin-top: -10px; margin-bottom: 15px;">Keluarga: <span id="riwayat-musibah-nama-penerima" style="font-weight: bold; color: var(--navy);"></span></p>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="riwayat-table">
|
||||||
|
<thead>
|
||||||
|
<tr><th>Tgl Lapor</th><th>Jenis Musibah</th><th>Deskripsi</th><th>Status</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="riwayat-musibah-tbody"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="btn-group" style="margin-top: 20px;">
|
||||||
|
<button class="btn btn-cancel" onclick="document.getElementById('modal-riwayat-musibah').style.display='none'">Tutup Riwayat</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="auth-screen" class="auth-overlay">
|
||||||
|
<div class="auth-box">
|
||||||
|
<h2 style="color: var(--navy); margin-top: 0; text-align: center; border-bottom: 2px solid var(--border); padding-bottom: 10px;">WebGIS Pontianak</h2>
|
||||||
|
|
||||||
|
<!-- Toggle Tabs Form -->
|
||||||
|
<div style="display:flex; margin-bottom: 20px; border-radius: 6px; overflow: hidden; border: 1px solid var(--border);">
|
||||||
|
<button id="tab-login" class="auth-tab active" onclick="switchAuthTab('login')">Masuk</button>
|
||||||
|
<button id="tab-register" class="auth-tab" onclick="switchAuthTab('register')">Daftar</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Form Autentikasi -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Username</label>
|
||||||
|
<input type="text" id="auth-username" placeholder="Masukkan username">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Password</label>
|
||||||
|
<input type="password" id="auth-password" placeholder="Masukkan password">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="btn-submit-auth" class="btn btn-save" style="width: 100%; padding: 12px; margin-top: 15px; font-size: 1rem;" onclick="eksekusiAuth()">Login Sistem</button>
|
||||||
|
|
||||||
|
<p id="auth-error-msg" style="color: var(--red-danger); font-size: 0.8rem; text-align: center; margin-top: 10px; font-weight: bold; min-height: 15px;"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="sidebar-container">
|
||||||
|
<div id="sidebar-header">WebGis-Pontianak</div>
|
||||||
|
<!-- Tab Navigasi -->
|
||||||
|
<div class="sidebar-tabs">
|
||||||
|
<button class="tab-btn active" onclick="switchTab('tab-kemiskinan')">Pemetaan</button>
|
||||||
|
<button class="tab-btn" onclick="switchTab('tab-filter')">Filter Map</button>
|
||||||
|
</div>
|
||||||
|
<!-- TAB 1: KEMISKINAN (BARU) -->
|
||||||
|
<div id="tab-kemiskinan" class="tab-content active">
|
||||||
|
<div class="control-panel">
|
||||||
|
<button class="btn-gps" onclick="lokasiSaya()">📍 Arahkan ke Lokasi Saya</button>
|
||||||
|
<button class="btn btn-danger" onclick="eksekusiLogout()" style="margin-top: 15px; width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px;">
|
||||||
|
<span style="font-size: 1.1rem;">🚪</span> Keluar Sesi (Logout)
|
||||||
|
</button>
|
||||||
|
<!-- Input Garis Kemiskinan -->
|
||||||
|
<div class="add-marker-box" style="margin-bottom: 0; padding: 10px 12px;">
|
||||||
|
<label>Batas Garis Kemiskinan (Rp):</label>
|
||||||
|
<div style="display:flex; gap:8px; margin-top:5px;">
|
||||||
|
<input type="number" id="input-garis-kemiskinan" placeholder="Loading..." class="modern-input">
|
||||||
|
<button class="btn btn-save" onclick="eksekusiUpdateGaris()" style="padding:8px 12px;">Simpan</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Tombol Kelola Program Pelatihan -->
|
||||||
|
<button class="btn btn-warning" onclick="bukaModalPelatihan()" style="margin-bottom: 10px; width: 100%; display: flex; align-items: center; justify-content: center; gap: 8px;">
|
||||||
|
<span style="font-size: 1.2rem;">📋</span> Kelola Program Pelatihan
|
||||||
|
</button>
|
||||||
|
<!-- Tombol Tambah Marker Modern -->
|
||||||
|
<div class="modern-action-box">
|
||||||
|
<label>Mode Penambahan Data:</label>
|
||||||
|
<select id="pilihan-marker-baru" class="modern-select">
|
||||||
|
<option value="ibadah">🕌 Pusat Radius (Rumah Ibadah)</option>
|
||||||
|
<option value="penduduk">🏠 Data Keluarga (Penduduk)</option>
|
||||||
|
</select>
|
||||||
|
<button class="btn-modern-add" id="btn-add-kemiskinan" onclick="toggleKemiskinanMode()">
|
||||||
|
<span class="icon">+</span> Aktifkan Kursor Marker
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<!-- Legenda Peta -->
|
||||||
|
<div class="map-legend">
|
||||||
|
<h4 class="legend-title">Keterangan Marker</h4>
|
||||||
|
<div class="legend-item"><span class="legend-color" style="background-color: var(--gold); border-radius:4px;"></span> Pusat Radius Ibadah</div>
|
||||||
|
<div class="legend-item"><span class="legend-color" style="background-color: #3182CE;"></span> Keluarga Bernaung</div>
|
||||||
|
<div class="legend-item"><span class="legend-color" style="background-color: #805AD5;"></span> Keluarga Luar Naungan</div>
|
||||||
|
<div class="legend-item"><span class="legend-color" style="background-color: #E53E3E;"></span> Kondisi Darurat (Musibah)</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="kemiskinan-card-container" class="card-list-area"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- TAB 2: FILTER & SPBU (LAMA) -->
|
||||||
|
<div id="tab-filter" class="tab-content">
|
||||||
|
<div id="filter-bar">
|
||||||
|
<button class="filter-tool-btn" onclick="bukaModalFilterLayer()">⚙️</button>
|
||||||
|
<span class="filter-label">Status SPBU:</span>
|
||||||
|
<button class="filter-tool-btn" onclick="bukaModalFilterSPBU()">🔍</button>
|
||||||
|
</div>
|
||||||
|
<div id="card-container" class="card-list-area"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button id="toggle-sidebar" onclick="toggleSidebar()">❮</button>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+128
@@ -0,0 +1,128 @@
|
|||||||
|
CREATE TABLE spbu_markers (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama_spbu VARCHAR(100) NOT NULL,
|
||||||
|
status_operasional ENUM('Buka 24 Jam', 'Tidak 24 Jam') NOT NULL,
|
||||||
|
no_telp VARCHAR(20) NOT NULL,
|
||||||
|
latitude DECIMAL(10, 8) NOT NULL,
|
||||||
|
longitude DECIMAL(11, 8) NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
CREATE TABLE jalan_polylines (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama_jalan VARCHAR(100) NOT NULL,
|
||||||
|
status_jalan ENUM('Jalan Nasional', 'Jalan Provinsi', 'Jalan Kabupaten') NOT NULL,
|
||||||
|
jarak_meter INT NOT NULL,
|
||||||
|
koordinat JSON NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
CREATE TABLE tanah_polygons (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama_pemilik VARCHAR(100) NOT NULL,
|
||||||
|
status_kepemilikan ENUM('SHM', 'HGB', 'HGU', 'HP') NOT NULL,
|
||||||
|
luas_meter INT NOT NULL,
|
||||||
|
koordinat JSON NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
ALTER TABLE spbu_markers
|
||||||
|
ADD COLUMN alamat TEXT AFTER no_telp;
|
||||||
|
CREATE TABLE rumah_ibadah (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama VARCHAR(150) NOT NULL,
|
||||||
|
jenis ENUM('Masjid', 'Gereja', 'Vihara', 'Pura', 'Klenteng') NOT NULL,
|
||||||
|
radius_meter INT NOT NULL,
|
||||||
|
alamat TEXT,
|
||||||
|
latitude DOUBLE NOT NULL,
|
||||||
|
longitude DOUBLE NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE rumah_penduduk (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama_kk VARCHAR(100) NOT NULL,
|
||||||
|
agama VARCHAR(50),
|
||||||
|
jml_tanggungan INT DEFAULT 0,
|
||||||
|
pengeluaran INT NOT NULL,
|
||||||
|
pmt_lantai INT DEFAULT 0,
|
||||||
|
pmt_dinding INT DEFAULT 0,
|
||||||
|
pmt_sanitasi INT DEFAULT 0,
|
||||||
|
pmt_penerangan INT DEFAULT 0,
|
||||||
|
pmt_air INT DEFAULT 0,
|
||||||
|
pmt_score INT NOT NULL,
|
||||||
|
status_kemiskinan ENUM('Sangat Miskin', 'Miskin', 'Rentan Miskin', 'Tidak Miskin') NOT NULL,
|
||||||
|
alamat TEXT,
|
||||||
|
latitude DOUBLE NOT NULL,
|
||||||
|
longitude DOUBLE NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE log_bantuan (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
id_penduduk INT NOT NULL,
|
||||||
|
beras_kg INT DEFAULT 0,
|
||||||
|
minyak_l INT DEFAULT 0,
|
||||||
|
gula_kg INT DEFAULT 0,
|
||||||
|
telur_kg INT DEFAULT 0,
|
||||||
|
susu_kaleng INT DEFAULT 0,
|
||||||
|
tunai_rp INT DEFAULT 0,
|
||||||
|
catatan TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (id_penduduk) REFERENCES rumah_penduduk(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
CREATE TABLE IF NOT EXISTS garis_kemiskinan (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
tahun YEAR NOT NULL,
|
||||||
|
nilai_rupiah INT NOT NULL,
|
||||||
|
is_active BOOLEAN DEFAULT FALSE,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
INSERT INTO garis_kemiskinan (tahun, nilai_rupiah, is_active)
|
||||||
|
VALUES (2026, 700000, TRUE);
|
||||||
|
|
||||||
|
CREATE TABLE master_pelatihan (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama_pelatihan VARCHAR(255) NOT NULL,
|
||||||
|
instansi_penyelenggara VARCHAR(255) NOT NULL,
|
||||||
|
tanggal_mulai DATE NOT NULL,
|
||||||
|
tanggal_selesai DATE NOT NULL,
|
||||||
|
deskripsi TEXT,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE anggota_keluarga (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
id_penduduk INT NOT NULL,
|
||||||
|
nik VARCHAR(16) NOT NULL UNIQUE,
|
||||||
|
nama_lengkap VARCHAR(255) NOT NULL,
|
||||||
|
tanggal_lahir DATE NOT NULL,
|
||||||
|
pendidikan_terakhir ENUM('Tidak Sekolah', 'SD', 'SMP', 'SMA/SMK', 'D3', 'S1', 'S2', 'S3') NOT NULL,
|
||||||
|
pekerjaan VARCHAR(255) DEFAULT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (id_penduduk) REFERENCES rumah_penduduk(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE log_pelatihan (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
id_anggota INT NOT NULL,
|
||||||
|
id_pelatihan INT NOT NULL,
|
||||||
|
tanggal_daftar TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (id_anggota) REFERENCES anggota_keluarga(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (id_pelatihan) REFERENCES master_pelatihan(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
CREATE TABLE laporan_musibah (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
id_penduduk INT NOT NULL,
|
||||||
|
tanggal_lapor DATE NOT NULL,
|
||||||
|
jenis_musibah ENUM('Kecelakaan', 'Kematian', 'Sakit Keras', 'Kebakaran', 'Bencana Alam', 'Lainnya') NOT NULL,
|
||||||
|
deskripsi TEXT,
|
||||||
|
status_penanganan ENUM('Belum Ditangani', 'Sudah Ditangani') DEFAULT 'Belum Ditangani',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (id_penduduk) REFERENCES rumah_penduduk(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
|
CREATE TABLE users (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
username VARCHAR(50) NOT NULL UNIQUE,
|
||||||
|
password VARCHAR(255) NOT NULL,
|
||||||
|
role VARCHAR(20) DEFAULT 'admin',
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>WebGIS Pontianak V2</title>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.css" />
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<?php include 'components/sidebar.php'; ?>
|
||||||
|
<?php include 'components/modals.php'; ?>
|
||||||
|
|
||||||
|
<button id="btn-selesai-jalan" onclick="selesaiGambarJalan()">✓ Selesai Gambar Jalan</button>
|
||||||
|
<button id="btn-selesai-tanah" onclick="selesaiGambarTanah()">✓ Selesai Area Tanah</button>
|
||||||
|
|
||||||
|
<div id="map"></div>
|
||||||
|
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.js"></script>
|
||||||
|
<script src="app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
// koneksi.php
|
||||||
|
|
||||||
|
$host = 'localhost';
|
||||||
|
$user = 'root';
|
||||||
|
$pass = ''; // Kosongkan jika Anda menggunakan XAMPP default
|
||||||
|
$db = 'webgis_pontianak'; // Pastikan nama database di phpMyAdmin sama persis dengan ini
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Membangun koneksi PDO
|
||||||
|
$conn = new PDO("mysql:host=$host;dbname=$db;charset=utf8", $user, $pass);
|
||||||
|
|
||||||
|
// Mengatur PDO agar melempar Exception jika terjadi error
|
||||||
|
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
|
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
// Jika koneksi gagal, hentikan eksekusi dan kirim pesan error format JSON
|
||||||
|
die(json_encode(["error" => "Koneksi Database Gagal: " . $e->getMessage()]));
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->username) && !empty($data->password)) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("SELECT id, username, password, role FROM users WHERE username = :username LIMIT 1");
|
||||||
|
$stmt->bindValue(':username', $data->username);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
if($stmt->rowCount() > 0) {
|
||||||
|
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
// Verifikasi hash password
|
||||||
|
if(password_verify($data->password, $user['password'])) {
|
||||||
|
$_SESSION['user_id'] = $user['id'];
|
||||||
|
$_SESSION['username'] = $user['username'];
|
||||||
|
$_SESSION['role'] = $user['role'];
|
||||||
|
echo json_encode(["pesan" => "Login Berhasil!", "user" => $user['username']]);
|
||||||
|
} else {
|
||||||
|
http_response_code(401); echo json_encode(["error" => "Password salah."]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(404); echo json_encode(["error" => "Username tidak ditemukan."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500); echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400); echo json_encode(["error" => "Username dan Password wajib diisi."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
session_unset();
|
||||||
|
session_destroy();
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
echo json_encode(["pesan" => "Anda telah berhasil keluar."]);
|
||||||
|
?>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->username) && !empty($data->password)) {
|
||||||
|
try {
|
||||||
|
// Cek apakah username sudah ada
|
||||||
|
$stmt = $conn->prepare("SELECT id FROM users WHERE username = :username");
|
||||||
|
$stmt->bindValue(':username', $data->username);
|
||||||
|
$stmt->execute();
|
||||||
|
if($stmt->rowCount() > 0) {
|
||||||
|
http_response_code(400); die(json_encode(["error" => "Username sudah terdaftar, gunakan yang lain!"]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enkripsi password menggunakan BCRYPT
|
||||||
|
$query = "INSERT INTO users (username, password) VALUES (:username, :password)";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
$stmt->bindValue(':username', htmlspecialchars(strip_tags($data->username)));
|
||||||
|
$stmt->bindValue(':password', password_hash($data->password, PASSWORD_BCRYPT));
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Registrasi berhasil, silakan login!"]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500); echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400); echo json_encode(["error" => "Username dan Password wajib diisi."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
session_start();
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
|
||||||
|
if(isset($_SESSION['user_id'])) {
|
||||||
|
echo json_encode(["status" => "aktif", "username" => $_SESSION['username']]);
|
||||||
|
} else {
|
||||||
|
http_response_code(401);
|
||||||
|
echo json_encode(["status" => "tidak_aktif", "error" => "Sesi kedaluwarsa atau belum login."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id)) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("DELETE FROM jalan_polylines WHERE id = :id");
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Jalan berhasil dihapus."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->nama) && !empty($data->status) && !empty($data->koordinat)) {
|
||||||
|
try {
|
||||||
|
$query = "INSERT INTO jalan_polylines (nama_jalan, status_jalan, jarak_meter, koordinat)
|
||||||
|
VALUES (:nama, :status, :jarak, :koordinat)";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':status', htmlspecialchars(strip_tags($data->status)));
|
||||||
|
$stmt->bindValue(':jarak', $data->jarak, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':koordinat', $data->koordinat); // Sudah dalam bentuk string JSON dari JS
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Jalan berhasil ditambahkan."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Data tidak lengkap."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $conn->query("SELECT * FROM jalan_polylines ORDER BY created_at DESC");
|
||||||
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Gagal mengambil data: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id) && !empty($data->nama) && !empty($data->status)) {
|
||||||
|
try {
|
||||||
|
$query = "UPDATE jalan_polylines SET nama_jalan = :nama, status_jalan = :status WHERE id = :id";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':status', htmlspecialchars(strip_tags($data->status)));
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Data Jalan berhasil diperbarui."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
if (!empty($data->id)) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("DELETE FROM anggota_keluarga WHERE id = :id");
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
if($stmt->execute()) echo json_encode(["pesan" => "Anggota dihapus."]);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500); echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id)) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("DELETE FROM rumah_ibadah WHERE id = :id");
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Rumah Ibadah berhasil dihapus secara permanen."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "ID tidak ditemukan."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id)) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("DELETE FROM rumah_penduduk WHERE id = :id");
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Data keluarga berhasil dihapus secara permanen."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "ID tidak ditemukan."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id_penduduk) && !empty($data->nik) && !empty($data->nama)) {
|
||||||
|
try {
|
||||||
|
$query = "INSERT INTO anggota_keluarga (id_penduduk, nik, nama_lengkap, tanggal_lahir, pendidikan_terakhir, pekerjaan)
|
||||||
|
VALUES (:id_penduduk, :nik, :nama, :lahir, :pendidikan, :pekerjaan)";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$pekerjaan = (!empty(trim($data->pekerjaan))) ? htmlspecialchars(strip_tags($data->pekerjaan)) : NULL;
|
||||||
|
|
||||||
|
$stmt->bindValue(':id_penduduk', $data->id_penduduk, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':nik', htmlspecialchars(strip_tags($data->nik)));
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':lahir', $data->lahir);
|
||||||
|
$stmt->bindValue(':pendidikan', $data->pendidikan);
|
||||||
|
$stmt->bindValue(':pekerjaan', $pekerjaan);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Anggota keluarga berhasil ditambahkan."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500); echo json_encode(["error" => "Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400); echo json_encode(["error" => "Data NIK dan Nama wajib diisi."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->nama) && isset($data->latitude) && isset($data->longitude)) {
|
||||||
|
try {
|
||||||
|
$query = "INSERT INTO rumah_ibadah (nama, jenis, radius_meter, alamat, latitude, longitude)
|
||||||
|
VALUES (:nama, :jenis, :radius, :alamat, :lat, :lng)";
|
||||||
|
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':jenis', htmlspecialchars(strip_tags($data->jenis)));
|
||||||
|
$stmt->bindValue(':radius', $data->radius_meter, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':alamat', htmlspecialchars(strip_tags($data->alamat)));
|
||||||
|
$stmt->bindValue(':lat', $data->latitude);
|
||||||
|
$stmt->bindValue(':lng', $data->longitude);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Pusat radius ibadah berhasil diarsipkan."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Data rumah ibadah tidak lengkap."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id_penduduk)) {
|
||||||
|
try {
|
||||||
|
$conn->beginTransaction();
|
||||||
|
|
||||||
|
// 1. Catat Logistik Bantuan
|
||||||
|
$query = "INSERT INTO log_bantuan (id_penduduk, beras_kg, minyak_l, gula_kg, telur_kg, susu_kaleng, tunai_rp, catatan)
|
||||||
|
VALUES (:id, :beras, :minyak, :gula, :telur, :susu, :tunai, :catatan)";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
$stmt->bindValue(':id', $data->id_penduduk, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':beras', $data->beras, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':minyak', $data->minyak, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':gula', $data->gula, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':telur', $data->telur, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':susu', $data->susu, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':tunai', $data->tunai, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':catatan', htmlspecialchars(strip_tags($data->catatan)));
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
// 2. KUNCI BABAK 4: Padamkan status darurat jika keluarga ini sedang terkena musibah
|
||||||
|
$updateMusibah = $conn->prepare("UPDATE laporan_musibah SET status_penanganan = 'Sudah Ditangani' WHERE id_penduduk = :id AND status_penanganan = 'Belum Ditangani'");
|
||||||
|
$updateMusibah->bindValue(':id', $data->id_penduduk, PDO::PARAM_INT);
|
||||||
|
$updateMusibah->execute();
|
||||||
|
|
||||||
|
$conn->commit();
|
||||||
|
echo json_encode(["pesan" => "Bantuan disalurkan. Status darurat keluarga ini telah dipadamkan secara otomatis."]);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
$conn->rollBack();
|
||||||
|
http_response_code(500); echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400); echo json_encode(["error" => "ID Keluarga Penerima tidak valid."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
if (!empty($data->id_anggota) && !empty($data->id_pelatihan)) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("INSERT INTO log_pelatihan (id_anggota, id_pelatihan) VALUES (:ida, :idp)");
|
||||||
|
$stmt->bindValue(':ida', $data->id_anggota, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':idp', $data->id_pelatihan, PDO::PARAM_INT);
|
||||||
|
if($stmt->execute()) echo json_encode(["pesan" => "Berhasil didaftarkan ke program pelatihan!"]);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500); echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id_penduduk) && !empty($data->tanggal) && !empty($data->jenis)) {
|
||||||
|
try {
|
||||||
|
$query = "INSERT INTO laporan_musibah (id_penduduk, tanggal_lapor, jenis_musibah, deskripsi, status_penanganan)
|
||||||
|
VALUES (:id, :tgl, :jenis, :deskripsi, :status)";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':id', $data->id_penduduk, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':tgl', $data->tanggal);
|
||||||
|
$stmt->bindValue(':jenis', htmlspecialchars(strip_tags($data->jenis)));
|
||||||
|
$stmt->bindValue(':deskripsi', htmlspecialchars(strip_tags($data->deskripsi)));
|
||||||
|
$stmt->bindValue(':status', htmlspecialchars(strip_tags($data->status)));
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Laporan darurat musibah berhasil dikirim. Menunggu penanganan!"]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500); echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400); echo json_encode(["error" => "Data tanggal dan jenis musibah wajib diisi."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->nama_pelatihan) && !empty($data->instansi) && !empty($data->tgl_mulai) && !empty($data->tgl_selesai)) {
|
||||||
|
try {
|
||||||
|
$query = "INSERT INTO master_pelatihan (nama_pelatihan, instansi_penyelenggara, tanggal_mulai, tanggal_selesai, deskripsi)
|
||||||
|
VALUES (:nama, :instansi, :mulai, :selesai, :deskripsi)";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama_pelatihan)));
|
||||||
|
$stmt->bindValue(':instansi', htmlspecialchars(strip_tags($data->instansi)));
|
||||||
|
$stmt->bindValue(':mulai', $data->tgl_mulai);
|
||||||
|
$stmt->bindValue(':selesai', $data->tgl_selesai);
|
||||||
|
$stmt->bindValue(':deskripsi', htmlspecialchars(strip_tags($data->deskripsi)));
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Program pelatihan berhasil ditambahkan ke dalam Master Data."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Data krusial (Nama, Instansi, Tanggal) tidak boleh kosong."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
// Validasi ketat: Nama, lat, dan lng adalah harga mati
|
||||||
|
if (!empty($data->nama) && isset($data->lat) && isset($data->lng)) {
|
||||||
|
try {
|
||||||
|
$query = "INSERT INTO rumah_penduduk
|
||||||
|
(nama_kk, agama, jml_tanggungan, pengeluaran, pmt_lantai, pmt_dinding, pmt_sanitasi, pmt_penerangan, pmt_air, pmt_score, status_kemiskinan, alamat, latitude, longitude)
|
||||||
|
VALUES
|
||||||
|
(:nama, :agama, :tanggungan, :pengeluaran, :lantai, :dinding, :sanitasi, :penerangan, :air, :score, :status, :alamat, :lat, :lng)";
|
||||||
|
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
// Membersihkan input dari potensi XSS Attack
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':agama', htmlspecialchars(strip_tags($data->agama)));
|
||||||
|
$stmt->bindValue(':tanggungan', $data->tanggungan, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':pengeluaran', $data->pengeluaran, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
// Penilaian 5 Kriteria PMT Biner
|
||||||
|
$stmt->bindValue(':lantai', $data->pmt_lantai, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':dinding', $data->pmt_dinding, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':sanitasi', $data->pmt_sanitasi, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':penerangan', $data->pmt_penerangan, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':air', $data->pmt_air, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
// Hasil Analisis DSS
|
||||||
|
$stmt->bindValue(':score', $data->pmt_score, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':status', htmlspecialchars(strip_tags($data->status)));
|
||||||
|
$stmt->bindValue(':alamat', htmlspecialchars(strip_tags($data->alamat)));
|
||||||
|
$stmt->bindValue(':lat', $data->lat);
|
||||||
|
$stmt->bindValue(':lng', $data->lng);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Data kemiskinan berhasil diarsipkan."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Data krusial tidak lengkap."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$id_penduduk = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||||
|
if ($id_penduduk > 0) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("SELECT * FROM anggota_keluarga WHERE id_penduduk = :id ORDER BY id ASC");
|
||||||
|
$stmt->bindValue(':id', $id_penduduk, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400); echo json_encode(["error" => "ID tidak valid"]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Hanya tarik ID Penduduk yang musibahnya belum ditangani
|
||||||
|
$stmt = $conn->query("SELECT id_penduduk FROM laporan_musibah WHERE status_penanganan = 'Belum Ditangani'");
|
||||||
|
$data = $stmt->fetchAll(PDO::FETCH_COLUMN); // Mengembalikan array [id1, id2, ...]
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500); echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Hanya ambil yang sedang aktif
|
||||||
|
$stmt = $conn->query("SELECT nilai_rupiah FROM garis_kemiskinan WHERE is_active = TRUE LIMIT 1");
|
||||||
|
$data = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
if ($data) {
|
||||||
|
echo json_encode($data);
|
||||||
|
} else {
|
||||||
|
// Fallback darurat jika tabel kosong
|
||||||
|
echo json_encode(["nilai_rupiah" => 700000]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Gagal mengambil data: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $conn->query("SELECT * FROM rumah_ibadah ORDER BY created_at DESC");
|
||||||
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Gagal mengambil data ibadah: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
// Menangkap ID Penduduk dari URL (GET Request)
|
||||||
|
$id_penduduk = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||||
|
|
||||||
|
if ($id_penduduk > 0) {
|
||||||
|
try {
|
||||||
|
// Asumsi tabel Anda memiliki kolom created_at atau minimal id yang Auto Increment
|
||||||
|
$stmt = $conn->prepare("SELECT * FROM log_bantuan WHERE id_penduduk = :id ORDER BY id DESC");
|
||||||
|
$stmt->bindValue(':id', $id_penduduk, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Parameter ID Penduduk tidak ditemukan."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$id_penduduk = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||||
|
|
||||||
|
if ($id_penduduk > 0) {
|
||||||
|
try {
|
||||||
|
// Melakukan JOIN untuk merangkai nama anggota, NIK, dan nama pelatihan
|
||||||
|
$query = "SELECT lp.tanggal_daftar, mp.nama_pelatihan, mp.instansi_penyelenggara, ak.nama_lengkap, ak.nik
|
||||||
|
FROM log_pelatihan lp
|
||||||
|
JOIN anggota_keluarga ak ON lp.id_anggota = ak.id
|
||||||
|
JOIN master_pelatihan mp ON lp.id_pelatihan = mp.id
|
||||||
|
WHERE ak.id_penduduk = :id
|
||||||
|
ORDER BY lp.tanggal_daftar DESC";
|
||||||
|
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
$stmt->bindValue(':id', $id_penduduk, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Parameter ID Penduduk tidak valid."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$id_penduduk = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||||
|
|
||||||
|
if ($id_penduduk > 0) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("SELECT * FROM laporan_musibah WHERE id_penduduk = :id ORDER BY tanggal_lapor DESC, id DESC");
|
||||||
|
$stmt->bindValue(':id', $id_penduduk, PDO::PARAM_INT);
|
||||||
|
$stmt->execute();
|
||||||
|
|
||||||
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Parameter ID Penduduk tidak valid."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $conn->query("SELECT * FROM master_pelatihan ORDER BY id DESC");
|
||||||
|
echo json_encode($stmt->fetchAll(PDO::FETCH_ASSOC));
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// KUNCI ARSITEKTUR: Kalkulasi Dinamis (Subquery)
|
||||||
|
// Menghitung jumlah anggota secara real-time dari tabel relasional
|
||||||
|
$query = "SELECT rp.*,
|
||||||
|
(SELECT COUNT(id) FROM anggota_keluarga WHERE id_penduduk = rp.id) AS real_tanggungan
|
||||||
|
FROM rumah_penduduk rp
|
||||||
|
ORDER BY rp.created_at DESC";
|
||||||
|
|
||||||
|
$stmt = $conn->query($query);
|
||||||
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Gagal mengambil data kemiskinan: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id) && !empty($data->nik) && !empty($data->nama)) {
|
||||||
|
try {
|
||||||
|
$query = "UPDATE anggota_keluarga SET
|
||||||
|
nik = :nik,
|
||||||
|
nama_lengkap = :nama,
|
||||||
|
tanggal_lahir = :lahir,
|
||||||
|
pendidikan_terakhir = :pendidikan,
|
||||||
|
pekerjaan = :pekerjaan
|
||||||
|
WHERE id = :id";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$pekerjaan = (!empty(trim($data->pekerjaan))) ? htmlspecialchars(strip_tags($data->pekerjaan)) : NULL;
|
||||||
|
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':nik', htmlspecialchars(strip_tags($data->nik)));
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':lahir', $data->lahir);
|
||||||
|
$stmt->bindValue(':pendidikan', $data->pendidikan);
|
||||||
|
$stmt->bindValue(':pekerjaan', $pekerjaan);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Informasi anggota keluarga berhasil diperbarui."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500); echo json_encode(["error" => "Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400); echo json_encode(["error" => "Data NIK dan Nama wajib diisi."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->nilai) && is_numeric($data->nilai)) {
|
||||||
|
try {
|
||||||
|
// Mengunci eksekusi agar jika satu gagal, semua dibatalkan (ACID Compliance)
|
||||||
|
$conn->beginTransaction();
|
||||||
|
|
||||||
|
// 1. Matikan semua standar historis lama
|
||||||
|
$conn->exec("UPDATE garis_kemiskinan SET is_active = FALSE");
|
||||||
|
|
||||||
|
// 2. Masukkan standar baru sebagai yang aktif
|
||||||
|
$stmtConfig = $conn->prepare("INSERT INTO garis_kemiskinan (tahun, nilai_rupiah, is_active) VALUES (:tahun, :nilai, TRUE)");
|
||||||
|
$stmtConfig->bindValue(':tahun', date("Y"), PDO::PARAM_INT);
|
||||||
|
$stmtConfig->bindValue(':nilai', $data->nilai, PDO::PARAM_INT);
|
||||||
|
$stmtConfig->execute();
|
||||||
|
|
||||||
|
// 3. KALIBRASI ULANG MASSAL (Cascading Status Update)
|
||||||
|
$updatePenduduk = "UPDATE rumah_penduduk SET status_kemiskinan = CASE
|
||||||
|
WHEN pengeluaran > :nilai THEN 'Tidak Miskin'
|
||||||
|
WHEN pmt_score >= 4 THEN 'Sangat Miskin'
|
||||||
|
WHEN pmt_score >= 2 THEN 'Miskin'
|
||||||
|
WHEN pmt_score = 1 THEN 'Rentan Miskin'
|
||||||
|
ELSE 'Tidak Miskin'
|
||||||
|
END";
|
||||||
|
|
||||||
|
$stmtUpdate = $conn->prepare($updatePenduduk);
|
||||||
|
$stmtUpdate->bindValue(':nilai', $data->nilai, PDO::PARAM_INT);
|
||||||
|
$stmtUpdate->execute();
|
||||||
|
|
||||||
|
$conn->commit();
|
||||||
|
|
||||||
|
echo json_encode(["pesan" => "Garis kemiskinan diubah dan seluruh status penduduk telah dikalibrasi ulang!"]);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
$conn->rollBack();
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Nilai garis kemiskinan tidak valid."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id) && !empty($data->nama)) {
|
||||||
|
try {
|
||||||
|
$query = "UPDATE rumah_ibadah SET
|
||||||
|
nama = :nama,
|
||||||
|
jenis = :jenis,
|
||||||
|
radius_meter = :radius
|
||||||
|
WHERE id = :id";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':jenis', htmlspecialchars(strip_tags($data->jenis)));
|
||||||
|
$stmt->bindValue(':radius', $data->radius, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Data Rumah Ibadah berhasil diperbarui."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Data krusial tidak lengkap."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id) && !empty($data->nama)) {
|
||||||
|
try {
|
||||||
|
$query = "UPDATE rumah_penduduk SET
|
||||||
|
nama_kk = :nama,
|
||||||
|
agama = :agama,
|
||||||
|
jml_tanggungan = :tanggungan,
|
||||||
|
pengeluaran = :pengeluaran,
|
||||||
|
pmt_lantai = :lantai,
|
||||||
|
pmt_dinding = :dinding,
|
||||||
|
pmt_sanitasi = :sanitasi,
|
||||||
|
pmt_penerangan = :penerangan,
|
||||||
|
pmt_air = :air,
|
||||||
|
pmt_score = :score,
|
||||||
|
status_kemiskinan = :status
|
||||||
|
WHERE id = :id";
|
||||||
|
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':agama', htmlspecialchars(strip_tags($data->agama)));
|
||||||
|
$stmt->bindValue(':tanggungan', $data->tanggungan, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':pengeluaran', $data->pengeluaran, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
$stmt->bindValue(':lantai', $data->pmt_lantai, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':dinding', $data->pmt_dinding, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':sanitasi', $data->pmt_sanitasi, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':penerangan', $data->pmt_penerangan, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':air', $data->pmt_air, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
$stmt->bindValue(':score', $data->pmt_score, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':status', htmlspecialchars(strip_tags($data->status)));
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Data kemiskinan berhasil diperbarui."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Database Error: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Data krusial tidak lengkap."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
// otak_spbu/api_hapus_spbu.php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id)) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("DELETE FROM spbu_markers WHERE id = :id");
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "SPBU berhasil dihapus."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->nama) && !empty($data->status) && isset($data->lat) && isset($data->lng)) {
|
||||||
|
try {
|
||||||
|
$query = "INSERT INTO spbu_markers (nama_spbu, status_operasional, no_telp, alamat, latitude, longitude)
|
||||||
|
VALUES (:nama, :status, :telp, :alamat, :lat, :lng)";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':status', htmlspecialchars(strip_tags($data->status)));
|
||||||
|
$stmt->bindValue(':telp', htmlspecialchars(strip_tags($data->telp)));
|
||||||
|
// Alamat dimasukkan
|
||||||
|
$stmt->bindValue(':alamat', htmlspecialchars(strip_tags($data->alamat)));
|
||||||
|
$stmt->bindValue(':lat', $data->lat);
|
||||||
|
$stmt->bindValue(':lng', $data->lng);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "SPBU berhasil ditambahkan."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Data tidak lengkap."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
// otak_spbu/api_tampil_spbu.php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $conn->query("SELECT * FROM spbu_markers ORDER BY created_at DESC");
|
||||||
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Gagal mengambil data: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id) && isset($data->lat) && isset($data->lng)) {
|
||||||
|
try {
|
||||||
|
// Alamat ikut di-update saat marker digeser
|
||||||
|
$stmt = $conn->prepare("UPDATE spbu_markers SET latitude = :lat, longitude = :lng, alamat = :alamat WHERE id = :id");
|
||||||
|
$stmt->bindValue(':lat', $data->lat);
|
||||||
|
$stmt->bindValue(':lng', $data->lng);
|
||||||
|
$stmt->bindValue(':alamat', htmlspecialchars(strip_tags($data->alamat)));
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Koordinat dan alamat diperbarui."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
// otak_spbu/api_update_spbu.php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id) && !empty($data->nama) && !empty($data->status)) {
|
||||||
|
try {
|
||||||
|
$query = "UPDATE spbu_markers SET nama_spbu = :nama, status_operasional = :status, no_telp = :telp WHERE id = :id";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':status', htmlspecialchars(strip_tags($data->status)));
|
||||||
|
$stmt->bindValue(':telp', htmlspecialchars(strip_tags($data->telp)));
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Data SPBU berhasil diperbarui."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id)) {
|
||||||
|
try {
|
||||||
|
$stmt = $conn->prepare("DELETE FROM tanah_polygons WHERE id = :id");
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Parsil tanah berhasil dihapus."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->nama) && !empty($data->status) && !empty($data->koordinat)) {
|
||||||
|
try {
|
||||||
|
$query = "INSERT INTO tanah_polygons (nama_pemilik, status_kepemilikan, luas_meter, koordinat)
|
||||||
|
VALUES (:nama, :status, :luas, :koordinat)";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':status', htmlspecialchars(strip_tags($data->status)));
|
||||||
|
$stmt->bindValue(':luas', $data->luas, PDO::PARAM_INT);
|
||||||
|
$stmt->bindValue(':koordinat', $data->koordinat);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Data tanah berhasil ditambahkan."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http_response_code(400);
|
||||||
|
echo json_encode(["error" => "Data tidak lengkap."]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stmt = $conn->query("SELECT * FROM tanah_polygons ORDER BY created_at DESC");
|
||||||
|
$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
echo json_encode($data);
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => "Gagal mengambil data: " . $e->getMessage()]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
header("Content-Type: application/json; charset=UTF-8");
|
||||||
|
header("Access-Control-Allow-Methods: POST");
|
||||||
|
require_once '../koneksi.php';
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"));
|
||||||
|
|
||||||
|
if (!empty($data->id) && !empty($data->nama) && !empty($data->status)) {
|
||||||
|
try {
|
||||||
|
$query = "UPDATE tanah_polygons SET nama_pemilik = :nama, status_kepemilikan = :status WHERE id = :id";
|
||||||
|
$stmt = $conn->prepare($query);
|
||||||
|
|
||||||
|
$stmt->bindValue(':nama', htmlspecialchars(strip_tags($data->nama)));
|
||||||
|
$stmt->bindValue(':status', htmlspecialchars(strip_tags($data->status)));
|
||||||
|
$stmt->bindValue(':id', $data->id, PDO::PARAM_INT);
|
||||||
|
|
||||||
|
if($stmt->execute()) {
|
||||||
|
echo json_encode(["pesan" => "Data Tanah berhasil diperbarui."]);
|
||||||
|
}
|
||||||
|
} catch(PDOException $e) {
|
||||||
|
http_response_code(500);
|
||||||
|
echo json_encode(["error" => $e->getMessage()]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,740 @@
|
|||||||
|
/* =========================================
|
||||||
|
style.css - WEBGIS PONTIANAK V3 (TERPADU)
|
||||||
|
========================================= */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--navy: #0A2540;
|
||||||
|
--navy-light: #1A365D;
|
||||||
|
--white: #FFFFFF;
|
||||||
|
--gray-bg: #F8F9FA;
|
||||||
|
--border: #E2E8F0;
|
||||||
|
--gold: #D69E2E;
|
||||||
|
--blue: #3182CE;
|
||||||
|
--red-orange: #DD6B20;
|
||||||
|
--green-safe: #38A169;
|
||||||
|
--red-danger: #E53E3E;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#map {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: #e5e5e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- SIDEBAR & TABS --- */
|
||||||
|
#sidebar-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 380px;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--gray-bg);
|
||||||
|
border-right: 1px solid var(--border);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 1000;
|
||||||
|
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow: 2px 0 15px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar-container.collapsed {
|
||||||
|
transform: translateX(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#sidebar-header {
|
||||||
|
background-color: var(--navy);
|
||||||
|
color: var(--white);
|
||||||
|
padding: 15px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tab System */
|
||||||
|
.sidebar-tabs {
|
||||||
|
display: flex;
|
||||||
|
background: var(--navy-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn {
|
||||||
|
flex: 1;
|
||||||
|
padding: 12px 0;
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: #A0AEC0;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
border-bottom: 3px solid transparent;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn:hover {
|
||||||
|
color: var(--white);
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-btn.active {
|
||||||
|
color: var(--white);
|
||||||
|
border-bottom-color: var(--gold);
|
||||||
|
background: rgba(255, 255, 255, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content {
|
||||||
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content.active {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Control Panel (Tab 1 - Kemiskinan) */
|
||||||
|
.control-panel {
|
||||||
|
padding: 15px;
|
||||||
|
background: white;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-gps {
|
||||||
|
background: var(--blue);
|
||||||
|
color: white;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 10px;
|
||||||
|
border: none;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-gps:hover {
|
||||||
|
background: #2B6CB0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-marker-box {
|
||||||
|
background: #F8FAFC;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-marker-box label {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--navy);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modern-input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid #CBD5E0;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--navy);
|
||||||
|
background: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modern-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kotak Aksi Modern */
|
||||||
|
.modern-action-box {
|
||||||
|
background: #FFFFFF;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 15px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
box-shadow: 0 2px 5px rgba(0,0,0,0.02);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modern-action-box label {
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--navy-light);
|
||||||
|
margin-bottom: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modern-select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #CBD5E0;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: #F8FAFC;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--navy);
|
||||||
|
transition: all 0.2s;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modern-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--navy);
|
||||||
|
box-shadow: 0 0 0 3px rgba(10, 37, 64, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-modern-add {
|
||||||
|
background: var(--navy);
|
||||||
|
color: var(--white);
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-modern-add:hover {
|
||||||
|
background: var(--navy-light);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-modern-add.active {
|
||||||
|
background: var(--gold);
|
||||||
|
color: var(--white);
|
||||||
|
box-shadow: inset 0 2px 4px rgba(0,0,0,0.2);
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LEGENDA PETA */
|
||||||
|
.map-legend {
|
||||||
|
background: #F8FAFC;
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 15px;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-title {
|
||||||
|
margin: 0 0 10px 0;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--navy-light);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #4A5568;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-item:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.legend-color {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-list-area {
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toggle-sidebar {
|
||||||
|
position: absolute;
|
||||||
|
right: -28px;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
width: 28px;
|
||||||
|
background: var(--navy);
|
||||||
|
color: var(--white);
|
||||||
|
border: none;
|
||||||
|
padding: 15px 0;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 0 6px 6px 0;
|
||||||
|
box-shadow: 3px 0 5px rgba(0,0,0,0.1);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toggle-sidebar:hover {
|
||||||
|
background: var(--navy-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- CARD & LIST --- */
|
||||||
|
#filter-bar {
|
||||||
|
background-color: var(--navy-light);
|
||||||
|
padding: 10px 15px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-tool-btn {
|
||||||
|
width: 35px;
|
||||||
|
height: 35px;
|
||||||
|
background: var(--white);
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-label {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spbu-card {
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-left: 4px solid var(--border);
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
||||||
|
transition: transform 0.1s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spbu-card:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 3px 6px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spbu-card h4 {
|
||||||
|
margin: 0 0 4px 0;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--navy);
|
||||||
|
}
|
||||||
|
|
||||||
|
.spbu-card p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #4A5568;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hierarki Warna Card */
|
||||||
|
.status-buka { border-left-color: #38A169 !important; }
|
||||||
|
.status-tutup { border-left-color: #E53E3E !important; }
|
||||||
|
.card-ibadah { border-left-color: var(--gold) !important; }
|
||||||
|
.card-penduduk-miskin { border-left-color: #E53E3E !important; background: #FFF5F5; }
|
||||||
|
.card-penduduk-rentan { border-left-color: var(--red-orange) !important; }
|
||||||
|
.card-penduduk-aman { border-left-color: var(--blue) !important; }
|
||||||
|
|
||||||
|
/* --- LEAFLET UI --- */
|
||||||
|
.custom-leaflet-toolbar {
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 6px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
background: var(--white);
|
||||||
|
border: none;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
transition: background 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tool-btn.active {
|
||||||
|
background: var(--navy);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-right .leaflet-control-zoom {
|
||||||
|
margin-right: 15px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --- MODAL GENERAL --- */
|
||||||
|
.modal-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: rgba(0,0,0,0.6);
|
||||||
|
z-index: 9999;
|
||||||
|
display: none;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
background: white;
|
||||||
|
width: 380px;
|
||||||
|
max-height: 90vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 10px 25px rgba(0,0,0,0.2);
|
||||||
|
position: relative;
|
||||||
|
animation: modalFadeIn 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes modalFadeIn {
|
||||||
|
from { opacity: 0; transform: translateY(-15px) scale(0.95); }
|
||||||
|
to { opacity: 1; transform: translateY(0) scale(1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
font-weight: bold;
|
||||||
|
color: var(--navy-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input,
|
||||||
|
.form-group select,
|
||||||
|
.form-group textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border: 1px solid #A0AEC0;
|
||||||
|
border-radius: 6px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
background: #F8FAFC;
|
||||||
|
transition: all 0.3s;
|
||||||
|
resize: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dynamic-select {
|
||||||
|
border-left-width: 6px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input:focus,
|
||||||
|
.form-group select:focus,
|
||||||
|
.form-group textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--navy);
|
||||||
|
background: #FFFFFF;
|
||||||
|
box-shadow: 0 0 0 3px rgba(10, 37, 64, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input[readonly],
|
||||||
|
.form-group select[disabled],
|
||||||
|
.form-group textarea[readonly] {
|
||||||
|
background: #EDF2F7;
|
||||||
|
color: #718096;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=range] {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 100%;
|
||||||
|
background: transparent;
|
||||||
|
padding: 0 !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=range]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--navy);
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: -6px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=range]::-webkit-slider-runnable-track {
|
||||||
|
width: 100%;
|
||||||
|
height: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
background: #CBD5E0;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-group,
|
||||||
|
#spbu-action-wrapper,
|
||||||
|
#jalan-action-wrapper,
|
||||||
|
#tanah-action-wrapper,
|
||||||
|
#penduduk-action-wrapper,
|
||||||
|
#ibadah-action-wrapper {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px 15px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-save { background: var(--navy); color: var(--white); }
|
||||||
|
.btn-save:hover { background: var(--navy-light); transform: translateY(-2px); }
|
||||||
|
.btn-cancel { background: #E2E8F0; color: #4A5568; }
|
||||||
|
.btn-cancel:hover { background: #CBD5E0; }
|
||||||
|
.btn-warning { background: var(--gold); color: var(--white); }
|
||||||
|
.btn-warning:hover { background: #B7791F; transform: translateY(-2px); }
|
||||||
|
.btn-danger { background: #E53E3E; color: var(--white); }
|
||||||
|
.btn-danger:hover { background: #C53030; transform: translateY(-2px); }
|
||||||
|
.btn-success { background: #38A169; color: var(--white); }
|
||||||
|
.btn-success:hover { background: #2F855A; transform: translateY(-2px); }
|
||||||
|
|
||||||
|
/* Tombol Draw Polylines */
|
||||||
|
#btn-selesai-jalan,
|
||||||
|
#btn-selesai-tanah {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 30px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
z-index: 1000;
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
padding: 12px 30px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1rem;
|
||||||
|
border-radius: 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: none;
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#btn-selesai-jalan { background: #38A169; }
|
||||||
|
#btn-selesai-jalan:hover { background: #2F855A; transform: translateX(-50%) translateY(-2px); }
|
||||||
|
#btn-selesai-tanah { background: #D69E2E; }
|
||||||
|
#btn-selesai-tanah:hover { background: #B7791F; transform: translateX(-50%) translateY(-2px); }
|
||||||
|
|
||||||
|
#toast-notification {
|
||||||
|
position: fixed;
|
||||||
|
top: -60px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
background: var(--navy);
|
||||||
|
color: var(--white);
|
||||||
|
padding: 12px 30px;
|
||||||
|
border-radius: 30px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
box-shadow: 0 8px 20px rgba(0,0,0,0.3);
|
||||||
|
z-index: 10005;
|
||||||
|
transition: top 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
border-left: 4px solid #E53E3E;
|
||||||
|
}
|
||||||
|
|
||||||
|
#toast-notification.show { top: 25px; }
|
||||||
|
|
||||||
|
/* --- KOSMETIK MODAL FILTER --- */
|
||||||
|
.filter-modal { width: 320px; }
|
||||||
|
.filter-section { margin-bottom: 20px; }
|
||||||
|
.filter-section-title { display: block; font-size: 0.9rem; font-weight: bold; color: var(--navy); margin-bottom: 10px; border-bottom: 1px solid var(--border); padding-bottom: 5px; }
|
||||||
|
.filter-grid { display: flex; flex-direction: column; gap: 8px; }
|
||||||
|
|
||||||
|
.custom-checkbox-wrapper, .custom-radio-wrapper { display: flex; align-items: center; position: relative; padding: 6px 8px; cursor: pointer; border-radius: 6px; transition: background 0.2s; user-select: none; }
|
||||||
|
.custom-checkbox-wrapper:hover, .custom-radio-wrapper:hover { background-color: #F8FAFC; }
|
||||||
|
.custom-checkbox-wrapper input, .custom-radio-wrapper input { position: absolute; opacity: 0; cursor: pointer; height: 0; width: 0; }
|
||||||
|
|
||||||
|
.custom-checkmark { position: relative; height: 18px; width: 18px; background-color: var(--white); border: 2px solid #A0AEC0; border-radius: 4px; margin-right: 12px; transition: all 0.2s; }
|
||||||
|
.custom-checkbox-wrapper input:checked ~ .custom-checkmark { background-color: var(--navy); border-color: var(--navy); }
|
||||||
|
.custom-checkmark::after { content: ""; position: absolute; display: none; left: 5px; top: 1px; width: 4px; height: 9px; border: solid white; border-width: 0 2px 2px 0; transform: rotate(45deg) scale(0); transition: transform 0.2s; }
|
||||||
|
.custom-checkbox-wrapper input:checked ~ .custom-checkmark::after { display: block; transform: rotate(45deg) scale(1); }
|
||||||
|
|
||||||
|
.custom-radiomark { position: relative; height: 18px; width: 18px; background-color: var(--white); border: 2px solid #A0AEC0; border-radius: 50%; margin-right: 12px; transition: all 0.2s; }
|
||||||
|
.custom-radio-wrapper input:checked ~ .custom-radiomark { background-color: var(--white); border-color: var(--navy); }
|
||||||
|
.custom-radiomark::after { content: ""; position: absolute; display: none; top: 3px; left: 3px; width: 12px; height: 12px; border-radius: 50%; background: var(--navy); transform: scale(0); transition: transform 0.2s; }
|
||||||
|
.custom-radio-wrapper input:checked ~ .custom-radiomark::after { display: block; transform: scale(1); }
|
||||||
|
|
||||||
|
.filter-text { flex-grow: 1; font-size: 0.85rem; color: #2D3748; }
|
||||||
|
.color-dot { width: 12px; height: 12px; border-radius: 50%; box-shadow: inset 0 2px 4px rgba(0,0,0,0.2); }
|
||||||
|
|
||||||
|
/* --- CUSTOM MARKERS DOM --- */
|
||||||
|
.custom-div-icon { background: transparent; border: none; }
|
||||||
|
.marker-wrapper { width: 100%; height: 100%; position: relative; transform-origin: bottom center; transition: transform 0.2s; }
|
||||||
|
.custom-div-icon:hover .marker-wrapper { transform: scale(1.3); }
|
||||||
|
.marker-pin { width: 30px; height: 30px; border-radius: 50% 50% 50% 0; position: absolute; transform: rotate(-45deg); left: 0; top: 6px; box-shadow: -3px 3px 6px rgba(0,0,0,0.4); }
|
||||||
|
.marker-dot { width: 12px; height: 12px; background: white; position: absolute; border-radius: 50%; left: 9px; top: 15px; box-shadow: inset 0 2px 4px rgba(0,0,0,0.3); }
|
||||||
|
|
||||||
|
/* Khusus Rumah Ibadah (Kotak/Emas) */
|
||||||
|
.marker-ibadah { width: 24px; height: 24px; background: var(--gold); border: 2px solid white; border-radius: 4px; position: absolute; left: 3px; top: 9px; transform: rotate(45deg); box-shadow: 0 2px 5px rgba(0,0,0,0.4); }
|
||||||
|
.marker-ibadah-dot { width: 8px; height: 8px; background: white; position: absolute; border-radius: 50%; left: 11px; top: 17px; }
|
||||||
|
|
||||||
|
/* Animasi GPU-Accelerated untuk status Darurat (Musibah) */
|
||||||
|
@keyframes siren-blink {
|
||||||
|
0% { background-color: var(--blue); }
|
||||||
|
50% { background-color: var(--red-danger); transform: scale(1.1); box-shadow: 0 0 15px rgba(229, 62, 62, 0.8); }
|
||||||
|
100% { background-color: var(--blue); }
|
||||||
|
}
|
||||||
|
.marker-darurat .marker-pin { animation: siren-blink 1s infinite; }
|
||||||
|
|
||||||
|
.spbu-tooltip { background: var(--navy); color: var(--white); border: none; border-radius: 6px; padding: 6px 12px; font-weight: normal; font-size: 0.85rem; box-shadow: 0 4px 10px rgba(0,0,0,0.2); }
|
||||||
|
.spbu-tooltip .leaflet-tooltip-top::before { border-top-color: var(--navy); }
|
||||||
|
|
||||||
|
/* ====================================================
|
||||||
|
KOSMETIK KHUSUS CHAT BUBBLE (POPUP FORM)
|
||||||
|
==================================================== */
|
||||||
|
.leaflet-popup-content-wrapper { border-radius: 8px; box-shadow: 0 8px 25px rgba(0,0,0,0.2); }
|
||||||
|
.leaflet-popup-content { width: 350px !important; margin: 15px; }
|
||||||
|
|
||||||
|
.popup-form h4 { margin: 0 0 10px 0; border-bottom: 2px solid var(--border); padding-bottom: 8px; color: var(--navy); font-size: 1.05rem;}
|
||||||
|
.popup-form .form-group { margin-bottom: 8px; display: flex; flex-direction: column; gap: 4px; }
|
||||||
|
.popup-form label { font-size: 0.75rem; font-weight: bold; color: var(--navy-light); }
|
||||||
|
|
||||||
|
.popup-form input, .popup-form select, .popup-form textarea {
|
||||||
|
width: 100%; padding: 8px 8px; border: 1px solid #A0AEC0;
|
||||||
|
border-radius: 4px; font-size: 0.85rem; background: #F8FAFC;
|
||||||
|
box-sizing: border-box; resize: none;
|
||||||
|
}
|
||||||
|
.popup-form input:focus, .popup-form select:focus, .popup-form textarea:focus { outline: none; border-color: var(--navy); }
|
||||||
|
.popup-form .pmt-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 5px; }
|
||||||
|
.popup-form .pmt-grid .form-group { margin-bottom: 0; }
|
||||||
|
.popup-form .pmt-grid select { font-size: 0.75rem; padding: 6px; }
|
||||||
|
|
||||||
|
/* ====================================================
|
||||||
|
UI BACA SAJA & ACCORDION (MARKER PENDUDUK KLIK)
|
||||||
|
==================================================== */
|
||||||
|
.pop-read-only { display: flex; flex-direction: column; }
|
||||||
|
.pop-read-title { font-size: 1.35rem; margin: 0 0 10px 0; color: var(--navy); }
|
||||||
|
|
||||||
|
.pop-read-meta { display: flex; flex-direction: column; gap: 3px; font-size: 0.8rem; color: #4A5568; margin-bottom: 10px; font-weight: 600; }
|
||||||
|
|
||||||
|
.pop-read-alamat { font-size: 0.8rem; color: #4A5568; margin: 0 0 12px 0; line-height: 1.4; border-left: 3px solid #CBD5E0; padding-left: 8px; }
|
||||||
|
|
||||||
|
.pop-badge-container { margin-bottom: 12px; }
|
||||||
|
|
||||||
|
.pop-badge { padding: 6px 12px; border-radius: 6px; font-weight: bold; font-size: 0.95rem; color: white; display: inline-block; box-shadow: 0 2px 4px rgba(0,0,0,0.15); }
|
||||||
|
|
||||||
|
.badge-sangat-miskin { background-color: var(--red-danger); }
|
||||||
|
.badge-miskin { background-color: var(--red-orange); }
|
||||||
|
.badge-rentan { background-color: var(--gold); }
|
||||||
|
.badge-aman { background-color: var(--green-safe); }
|
||||||
|
|
||||||
|
.pop-naungan { margin-top: 10px; padding: 8px; font-size: 0.8rem; font-weight: 600; border-radius: 4px; text-align: center; }
|
||||||
|
.naungan-aktif { background-color: rgba(56, 161, 105, 0.15); color: var(--green-safe); border: 1px solid rgba(56, 161, 105, 0.3); }
|
||||||
|
.naungan-pasif { background-color: rgba(229, 62, 62, 0.1); color: var(--red-danger); border: 1px dashed rgba(229, 62, 62, 0.3); }
|
||||||
|
|
||||||
|
.pop-divider { border: 0; border-bottom: 1px dashed var(--border); margin: 15px 0; width: 100%; }
|
||||||
|
.pop-divider-sub { border: 0; border-top: 1px solid #E2E8F0; margin: 8px 0 12px 0; width: 100%; }
|
||||||
|
|
||||||
|
.accordion-wrapper { display: flex; flex-direction: column; width: 100%; }
|
||||||
|
.btn-accordion { background: #EDF2F7; color: #4A5568; font-weight: bold; padding: 8px; border: none; border-radius: 6px; cursor: pointer; transition: all 0.2s; width: 100%; }
|
||||||
|
.btn-accordion:hover { background: #E2E8F0; }
|
||||||
|
|
||||||
|
.accordion-content { display: none; margin-top: 0; overflow: hidden; opacity: 0; transition: opacity 0.3s; }
|
||||||
|
.accordion-content.show { display: block; opacity: 1; }
|
||||||
|
|
||||||
|
.table-responsive { width: 100%; overflow-x: auto; max-height: 400px; overflow-y: auto; margin-top: 10px; border: 1px solid var(--border); border-radius: 6px; }
|
||||||
|
.riwayat-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; text-align: left; }
|
||||||
|
.riwayat-table th { background-color: var(--navy); color: white; padding: 10px; position: sticky; top: 0; z-index: 1; white-space: nowrap; }
|
||||||
|
.riwayat-table td { padding: 10px; border-bottom: 1px solid var(--border); white-space: nowrap; }
|
||||||
|
.riwayat-table tbody tr:nth-child(even) { background-color: #F8FAFC; }
|
||||||
|
.riwayat-table tbody tr:hover { background-color: #EDF2F7; }
|
||||||
|
|
||||||
|
/* KUNCI PERBAIKAN: CSS UNTUK LAYAR KUNCI AUTENTIKASI (GATEKEEPER) */
|
||||||
|
.auth-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background: rgba(10, 37, 64, 0.95); /* Navy transparent */
|
||||||
|
backdrop-filter: blur(8px);
|
||||||
|
-webkit-backdrop-filter: blur(8px);
|
||||||
|
z-index: 999999; /* Absolut di atas segalanya */
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-box {
|
||||||
|
background: var(--white);
|
||||||
|
padding: 35px 30px;
|
||||||
|
border-radius: 12px;
|
||||||
|
width: 360px;
|
||||||
|
box-shadow: 0 20px 40px rgba(0,0,0,0.5);
|
||||||
|
animation: authPop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes authPop {
|
||||||
|
from { opacity: 0; transform: scale(0.8); }
|
||||||
|
to { opacity: 1; transform: scale(1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-tab {
|
||||||
|
flex: 1;
|
||||||
|
padding: 12px;
|
||||||
|
border: none;
|
||||||
|
background: #EDF2F7;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #718096;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-tab.active {
|
||||||
|
background: var(--blue);
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user