From 7b487332830f4fa5ae7675d083db352584b76a2f Mon Sep 17 00:00:00 2001 From: TalithaSyakirah Date: Tue, 9 Jun 2026 15:29:53 +0700 Subject: [PATCH] Project UAS WEBGIS SIG Talitha --- .dockerignore | 10 + .env.example | 15 + .gitignore | 51 + 1_Pemetaan_SPBU/index.php | 567 +++++ 1_Pemetaan_SPBU/style.css | 111 + 2_SPBU_Jalan_ParsilTanah_dan_Layer/index.php | 1139 ++++++++++ 2_SPBU_Jalan_ParsilTanah_dan_Layer/style.css | 110 + 3_PovertyMapping/dashboard.php | 739 +++++++ 3_PovertyMapping/index.php | 2010 ++++++++++++++++++ 3_PovertyMapping/style.css | 1612 ++++++++++++++ CARA_PAKAI_ENV_DAN_GITIGNORE.md | 86 + Dockerfile | 13 + README.md | 410 ++++ database/sig.sql | 300 +++ env.php | 54 + index.php | 255 +++ 16 files changed, 7482 insertions(+) create mode 100644 .dockerignore create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 1_Pemetaan_SPBU/index.php create mode 100644 1_Pemetaan_SPBU/style.css create mode 100644 2_SPBU_Jalan_ParsilTanah_dan_Layer/index.php create mode 100644 2_SPBU_Jalan_ParsilTanah_dan_Layer/style.css create mode 100644 3_PovertyMapping/dashboard.php create mode 100644 3_PovertyMapping/index.php create mode 100644 3_PovertyMapping/style.css create mode 100644 CARA_PAKAI_ENV_DAN_GITIGNORE.md create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 database/sig.sql create mode 100644 env.php create mode 100644 index.php diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0f146ab --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.git +.env +.DS_Store +__MACOSX +*.zip +*.rar +*.7z +.vscode +.idea +*.log diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..82bd1d2 --- /dev/null +++ b/.env.example @@ -0,0 +1,15 @@ +# ========================================================= +# CONTOH FILE ENVIRONMENT UNTUK WEBGIS POVERTY MAPPING +# ========================================================= +# Simpan file asli dengan nama: .env +# File .env JANGAN dipush ke Git. +# Yang boleh dipush hanya .env.example. +# +# Isi value di bawah sesuai database lokal atau database Coolify. +# ========================================================= + +DB_HOST=127.0.0.1 +DB_USER=root +DB_PASS= +DB_NAME=sig +DB_PORT=3306 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de1233a --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +# ========================================================= +# GIT IGNORE UNTUK PROJECT UAS SIG / WEBGIS POVERTY MAPPING +# ========================================================= + +# macOS +.DS_Store +__MACOSX/ + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini + +# Archive / file kompres +*.zip +*.rar +*.7z +*.tar +*.gz + +# Environment / credential +.env +.env.local +.env.production +.env.development + +# Log / temporary +*.log +logs/ +tmp/ +temp/ +cache/ + +# Editor / IDE +.vscode/ +.idea/ + +# Backup file +*.bak +*.backup +*.old +*.swp + +# Database dump lokal yang berisi data sensitif +# Kalau file SQL untuk tugas memang perlu dikumpulkan, boleh hapus baris *.sql ini. +# Lebih aman simpan SQL final di folder database/ dan pastikan tidak berisi password. +# *.sql + +# Node/PHP dependency jika suatu saat ada +node_modules/ +vendor/ diff --git a/1_Pemetaan_SPBU/index.php b/1_Pemetaan_SPBU/index.php new file mode 100644 index 0000000..09923c7 --- /dev/null +++ b/1_Pemetaan_SPBU/index.php @@ -0,0 +1,567 @@ +connect_error) { + die("Koneksi database gagal."); +} + +$conn->set_charset("utf8mb4"); + +if (isset($_GET['action'])) { + header('Content-Type: application/json; charset=utf-8'); + $action = $_GET['action']; + + if ($action == 'get_spbu') { + $data = []; + $result = $conn->query("SELECT * FROM spbu ORDER BY id DESC"); + while ($row = $result->fetch_assoc()) { + $data[] = $row; + } + echo json_encode($data); + exit; + } + + if ($action == 'add_spbu') { + $nama_spbu = $_POST['nama_spbu'] ?? ''; + $no_telepon = $_POST['no_telepon'] ?? ''; + $buka_24_jam = isset($_POST['buka_24_jam']) ? (int) $_POST['buka_24_jam'] : 0; + $latitude = $_POST['latitude'] ?? ''; + $longitude = $_POST['longitude'] ?? ''; + + if ($nama_spbu == '' || $no_telepon == '' || $latitude == '' || $longitude == '') { + echo json_encode(['status' => false, 'message' => 'Data belum lengkap']); + exit; + } + + $stmt = $conn->prepare("INSERT INTO spbu (nama_spbu, no_telepon, buka_24_jam, latitude, longitude) VALUES (?, ?, ?, ?, ?)"); + $stmt->bind_param("ssidd", $nama_spbu, $no_telepon, $buka_24_jam, $latitude, $longitude); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data SPBU berhasil ditambahkan']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal menambahkan data']); + } + exit; + } + + if ($action == 'update_spbu') { + $id = (int) ($_POST['id'] ?? 0); + $nama_spbu = $_POST['nama_spbu'] ?? ''; + $no_telepon = $_POST['no_telepon'] ?? ''; + $buka_24_jam = isset($_POST['buka_24_jam']) ? (int) $_POST['buka_24_jam'] : 0; + $latitude = $_POST['latitude'] ?? ''; + $longitude = $_POST['longitude'] ?? ''; + + $stmt = $conn->prepare("UPDATE spbu SET nama_spbu=?, no_telepon=?, buka_24_jam=?, latitude=?, longitude=? WHERE id=?"); + $stmt->bind_param("ssiddi", $nama_spbu, $no_telepon, $buka_24_jam, $latitude, $longitude, $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data SPBU berhasil diupdate']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal update data']); + } + exit; + } + + if ($action == 'delete_spbu') { + $id = (int) ($_POST['id'] ?? 0); + + $stmt = $conn->prepare("DELETE FROM spbu WHERE id=?"); + $stmt->bind_param("i", $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data SPBU berhasil dihapus']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal hapus data']); + } + exit; + } + + if ($action == 'update_position') { + $id = (int) ($_POST['id'] ?? 0); + $latitude = $_POST['latitude'] ?? ''; + $longitude = $_POST['longitude'] ?? ''; + + $stmt = $conn->prepare("UPDATE spbu SET latitude=?, longitude=? WHERE id=?"); + $stmt->bind_param("ddi", $latitude, $longitude, $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Posisi berhasil diupdate']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal update posisi']); + } + exit; + } + + if ($action == 'get_shapes') { + $data = []; + $result = $conn->query("SELECT * FROM map_shapes ORDER BY id DESC"); + while ($row = $result->fetch_assoc()) { + $data[] = $row; + } + echo json_encode($data); + exit; + } + + if ($action == 'save_shape') { + $shape_type = $_POST['shape_type'] ?? ''; + $coordinates = $_POST['coordinates'] ?? ''; + + if ($shape_type == '' || $coordinates == '') { + echo json_encode(['status' => false, 'message' => 'Data shape tidak lengkap']); + exit; + } + + $stmt = $conn->prepare("INSERT INTO map_shapes (shape_type, coordinates) VALUES (?, ?)"); + $stmt->bind_param("ss", $shape_type, $coordinates); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Shape berhasil disimpan']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal menyimpan shape']); + } + exit; + } + + if ($action == 'update_shape') { + $id = (int) ($_POST['id'] ?? 0); + $shape_type = $_POST['shape_type'] ?? ''; + $coordinates = $_POST['coordinates'] ?? ''; + + if ($id <= 0 || $shape_type == '' || $coordinates == '') { + echo json_encode(['status' => false, 'message' => 'Data update shape tidak lengkap']); + exit; + } + + $stmt = $conn->prepare("UPDATE map_shapes SET shape_type=?, coordinates=? WHERE id=?"); + $stmt->bind_param("ssi", $shape_type, $coordinates, $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Shape berhasil diupdate']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal update shape']); + } + exit; + } + + if ($action == 'delete_shape') { + $id = (int) ($_POST['id'] ?? 0); + + $stmt = $conn->prepare("DELETE FROM map_shapes WHERE id=?"); + $stmt->bind_param("i", $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Shape berhasil dihapus']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal hapus shape']); + } + exit; + } + + echo json_encode(['status' => false, 'message' => 'Action tidak dikenal']); + exit; +} +?> + + + + + + SPBU Pontianak - Leaflet CRUD + + + + + + + + + +
+ + + + + + + + + + \ No newline at end of file diff --git a/1_Pemetaan_SPBU/style.css b/1_Pemetaan_SPBU/style.css new file mode 100644 index 0000000..ee16623 --- /dev/null +++ b/1_Pemetaan_SPBU/style.css @@ -0,0 +1,111 @@ +html, body { + margin: 0; + padding: 0; + height: 100%; + font-family: Arial, sans-serif; +} + +#map { + width: 100%; + height: 100vh; +} + +.form-panel { + position: fixed; + top: 20px; + right: 20px; + width: 320px; + background: #fff; + padding: 16px; + border-radius: 12px; + box-shadow: 0 4px 18px rgba(0,0,0,0.2); + z-index: 9999; +} + +.form-panel h3 { + margin: 0 0 12px; + font-size: 20px; +} + +.form-panel input[type="text"] { + width: 100%; + padding: 10px; + margin-bottom: 10px; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 8px; + outline: none; +} + +.form-panel input[type="text"]:focus { + border-color: #007bff; +} + +.form-panel label { + display: block; + margin-bottom: 10px; + font-size: 14px; +} + +.btn-group { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +button { + padding: 10px 14px; + border: none; + border-radius: 8px; + cursor: pointer; + background: #007bff; + color: #fff; + font-size: 14px; +} + +button:hover { + opacity: 0.9; +} + +.btn-secondary { + background: #6c757d; +} + +.hidden { + display: none; +} + +.leaflet-popup-content button { + margin-top: 6px; + margin-right: 5px; + padding: 6px 10px; + font-size: 12px; +} + +.custom-div-icon { + background: transparent; + border: none; +} + +@media (max-width: 768px) { + .form-panel { + top: auto; + right: 10px; + left: 10px; + bottom: 10px; + width: auto; + padding: 14px; + } + + .form-panel h3 { + font-size: 18px; + } + + .form-panel input[type="text"] { + font-size: 14px; + } + + button { + flex: 1; + } +} \ No newline at end of file diff --git a/2_SPBU_Jalan_ParsilTanah_dan_Layer/index.php b/2_SPBU_Jalan_ParsilTanah_dan_Layer/index.php new file mode 100644 index 0000000..63e07bb --- /dev/null +++ b/2_SPBU_Jalan_ParsilTanah_dan_Layer/index.php @@ -0,0 +1,1139 @@ +connect_error) { + die("Koneksi database gagal."); +} + +$conn->set_charset("utf8mb4"); + +if (isset($_GET['action'])) { + header('Content-Type: application/json; charset=utf-8'); + $action = $_GET['action']; + + // ========================= + // CRUD SPBU (POINT) + // ========================= + if ($action == 'get_spbu') { + $data = []; + $result = $conn->query("SELECT * FROM spbu ORDER BY id DESC"); + while ($row = $result->fetch_assoc()) { + $data[] = $row; + } + echo json_encode($data); + exit; + } + + if ($action == 'add_spbu') { + $nama_spbu = trim($_POST['nama_spbu'] ?? ''); + $no_telepon = trim($_POST['no_telepon'] ?? ''); + $buka_24_jam = isset($_POST['buka_24_jam']) ? (int) $_POST['buka_24_jam'] : 0; + $latitude = $_POST['latitude'] ?? ''; + $longitude = $_POST['longitude'] ?? ''; + + if ($nama_spbu === '' || $no_telepon === '' || $latitude === '' || $longitude === '') { + echo json_encode(['status' => false, 'message' => 'Data SPBU belum lengkap']); + exit; + } + + $stmt = $conn->prepare("INSERT INTO spbu (nama_spbu, no_telepon, buka_24_jam, latitude, longitude) VALUES (?, ?, ?, ?, ?)"); + $stmt->bind_param("ssidd", $nama_spbu, $no_telepon, $buka_24_jam, $latitude, $longitude); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data SPBU berhasil ditambahkan']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal menambahkan data SPBU']); + } + exit; + } + + if ($action == 'update_spbu') { + $id = (int) ($_POST['id'] ?? 0); + $nama_spbu = trim($_POST['nama_spbu'] ?? ''); + $no_telepon = trim($_POST['no_telepon'] ?? ''); + $buka_24_jam = isset($_POST['buka_24_jam']) ? (int) $_POST['buka_24_jam'] : 0; + $latitude = $_POST['latitude'] ?? ''; + $longitude = $_POST['longitude'] ?? ''; + + if ($id <= 0 || $nama_spbu === '' || $no_telepon === '' || $latitude === '' || $longitude === '') { + echo json_encode(['status' => false, 'message' => 'Data update SPBU belum lengkap']); + exit; + } + + $stmt = $conn->prepare("UPDATE spbu SET nama_spbu=?, no_telepon=?, buka_24_jam=?, latitude=?, longitude=? WHERE id=?"); + $stmt->bind_param("ssiddi", $nama_spbu, $no_telepon, $buka_24_jam, $latitude, $longitude, $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data SPBU berhasil diupdate']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal update data SPBU']); + } + exit; + } + + if ($action == 'delete_spbu') { + $id = (int) ($_POST['id'] ?? 0); + + $stmt = $conn->prepare("DELETE FROM spbu WHERE id=?"); + $stmt->bind_param("i", $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data SPBU berhasil dihapus']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal menghapus data SPBU']); + } + exit; + } + + if ($action == 'update_position') { + $id = (int) ($_POST['id'] ?? 0); + $latitude = $_POST['latitude'] ?? ''; + $longitude = $_POST['longitude'] ?? ''; + + if ($id <= 0 || $latitude === '' || $longitude === '') { + echo json_encode(['status' => false, 'message' => 'Data posisi tidak lengkap']); + exit; + } + + $stmt = $conn->prepare("UPDATE spbu SET latitude=?, longitude=? WHERE id=?"); + $stmt->bind_param("ddi", $latitude, $longitude, $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Posisi SPBU berhasil diupdate']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal update posisi SPBU']); + } + exit; + } + + // ========================= + // CRUD JALAN (POLYLINE) + // ========================= + if ($action == 'get_jalan') { + $data = []; + $result = $conn->query("SELECT * FROM jalan ORDER BY id DESC"); + while ($row = $result->fetch_assoc()) { + $data[] = $row; + } + echo json_encode($data); + exit; + } + + if ($action == 'add_jalan') { + $nama_jalan = trim($_POST['nama_jalan'] ?? ''); + $status_jalan = trim($_POST['status_jalan'] ?? ''); + $panjang_meter = (float) ($_POST['panjang_meter'] ?? 0); + $geojson = $_POST['geojson'] ?? ''; + + if ($nama_jalan === '' || $status_jalan === '' || $geojson === '' || $panjang_meter <= 0) { + echo json_encode(['status' => false, 'message' => 'Data jalan belum lengkap']); + exit; + } + + $stmt = $conn->prepare("INSERT INTO jalan (nama_jalan, status_jalan, panjang_meter, geojson) VALUES (?, ?, ?, ?)"); + $stmt->bind_param("ssds", $nama_jalan, $status_jalan, $panjang_meter, $geojson); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data jalan berhasil ditambahkan']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal menambahkan data jalan']); + } + exit; + } + + if ($action == 'update_jalan') { + $id = (int) ($_POST['id'] ?? 0); + $nama_jalan = trim($_POST['nama_jalan'] ?? ''); + $status_jalan = trim($_POST['status_jalan'] ?? ''); + $panjang_meter = (float) ($_POST['panjang_meter'] ?? 0); + $geojson = $_POST['geojson'] ?? ''; + + if ($id <= 0 || $nama_jalan === '' || $status_jalan === '' || $geojson === '' || $panjang_meter <= 0) { + echo json_encode(['status' => false, 'message' => 'Data update jalan belum lengkap']); + exit; + } + + $stmt = $conn->prepare("UPDATE jalan SET nama_jalan=?, status_jalan=?, panjang_meter=?, geojson=? WHERE id=?"); + $stmt->bind_param("ssdsi", $nama_jalan, $status_jalan, $panjang_meter, $geojson, $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data jalan berhasil diupdate']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal update data jalan']); + } + exit; + } + + if ($action == 'delete_jalan') { + $id = (int) ($_POST['id'] ?? 0); + + $stmt = $conn->prepare("DELETE FROM jalan WHERE id=?"); + $stmt->bind_param("i", $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data jalan berhasil dihapus']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal menghapus data jalan']); + } + exit; + } + + // ========================= + // CRUD PARSIL TANAH (POLYGON) + // ========================= + if ($action == 'get_parsil') { + $data = []; + $result = $conn->query("SELECT * FROM parsil_tanah ORDER BY id DESC"); + while ($row = $result->fetch_assoc()) { + $data[] = $row; + } + echo json_encode($data); + exit; + } + + if ($action == 'add_parsil') { + $nama_pemilik = trim($_POST['nama_pemilik'] ?? ''); + $status_kepemilikan = trim($_POST['status_kepemilikan'] ?? ''); + $luas_meter = (float) ($_POST['luas_meter'] ?? 0); + $geojson = $_POST['geojson'] ?? ''; + + if ($nama_pemilik === '' || $status_kepemilikan === '' || $geojson === '' || $luas_meter <= 0) { + echo json_encode(['status' => false, 'message' => 'Data parsil belum lengkap']); + exit; + } + + $stmt = $conn->prepare("INSERT INTO parsil_tanah (nama_pemilik, status_kepemilikan, luas_meter, geojson) VALUES (?, ?, ?, ?)"); + $stmt->bind_param("ssds", $nama_pemilik, $status_kepemilikan, $luas_meter, $geojson); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data parsil berhasil ditambahkan']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal menambahkan data parsil']); + } + exit; + } + + if ($action == 'update_parsil') { + $id = (int) ($_POST['id'] ?? 0); + $nama_pemilik = trim($_POST['nama_pemilik'] ?? ''); + $status_kepemilikan = trim($_POST['status_kepemilikan'] ?? ''); + $luas_meter = (float) ($_POST['luas_meter'] ?? 0); + $geojson = $_POST['geojson'] ?? ''; + + if ($id <= 0 || $nama_pemilik === '' || $status_kepemilikan === '' || $geojson === '' || $luas_meter <= 0) { + echo json_encode(['status' => false, 'message' => 'Data update parsil belum lengkap']); + exit; + } + + $stmt = $conn->prepare("UPDATE parsil_tanah SET nama_pemilik=?, status_kepemilikan=?, luas_meter=?, geojson=? WHERE id=?"); + $stmt->bind_param("ssdsi", $nama_pemilik, $status_kepemilikan, $luas_meter, $geojson, $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data parsil berhasil diupdate']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal update data parsil']); + } + exit; + } + + if ($action == 'delete_parsil') { + $id = (int) ($_POST['id'] ?? 0); + + $stmt = $conn->prepare("DELETE FROM parsil_tanah WHERE id=?"); + $stmt->bind_param("i", $id); + + if ($stmt->execute()) { + echo json_encode(['status' => true, 'message' => 'Data parsil berhasil dihapus']); + } else { + echo json_encode(['status' => false, 'message' => 'Gagal menghapus data parsil']); + } + exit; + } + + echo json_encode(['status' => false, 'message' => 'Action tidak dikenal']); + exit; +} +?> + + + + + WebGIS SPBU, Jalan, dan Parsil Tanah + + + + + + + +
+ + + + + + + + + + diff --git a/2_SPBU_Jalan_ParsilTanah_dan_Layer/style.css b/2_SPBU_Jalan_ParsilTanah_dan_Layer/style.css new file mode 100644 index 0000000..a84c13b --- /dev/null +++ b/2_SPBU_Jalan_ParsilTanah_dan_Layer/style.css @@ -0,0 +1,110 @@ +html, body { + margin: 0; + padding: 0; + height: 100%; + font-family: Arial, sans-serif; +} + +#map { + width: 100%; + height: 100vh; +} + +.form-panel { + position: fixed; + top: 20px; + right: 20px; + width: 340px; + background: #fff; + padding: 16px; + border-radius: 12px; + box-shadow: 0 4px 18px rgba(0,0,0,0.2); + z-index: 9999; +} + +.form-panel h3 { + margin: 0 0 12px; + font-size: 20px; +} + +.form-panel input[type="text"], +.form-panel select { + width: 100%; + padding: 10px; + margin-bottom: 10px; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 8px; + outline: none; + background: #fff; +} + +.form-panel input[type="text"]:focus, +.form-panel select:focus { + border-color: #007bff; +} + +.checkbox-label { + display: block; + margin-bottom: 10px; + font-size: 14px; +} + +.btn-group { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +button { + padding: 10px 14px; + border: none; + border-radius: 8px; + cursor: pointer; + background: #007bff; + color: #fff; + font-size: 14px; +} + +button:hover { + opacity: 0.9; +} + +.btn-secondary { + background: #6c757d; +} + +.hidden { + display: none; +} + +.leaflet-popup-content button { + margin-top: 6px; + margin-right: 5px; + padding: 6px 10px; + font-size: 12px; +} + +@media (max-width: 768px) { + .form-panel { + top: auto; + right: 10px; + left: 10px; + bottom: 10px; + width: auto; + padding: 14px; + } + + .form-panel h3 { + font-size: 18px; + } + + .form-panel input[type="text"], + .form-panel select { + font-size: 14px; + } + + button { + flex: 1; + } +} \ No newline at end of file diff --git a/3_PovertyMapping/dashboard.php b/3_PovertyMapping/dashboard.php new file mode 100644 index 0000000..ce2beb0 --- /dev/null +++ b/3_PovertyMapping/dashboard.php @@ -0,0 +1,739 @@ + 'Admin Pengelola', 'walikota' => 'Wali Kota', 'dinas' => 'Dinas Terkait'][$_SESSION['user']['role'] ?? ''] ?? 'Masyarakat Umum'; +$instansiLabel = current_instansi(); +$admin = is_admin(); +$canAddHistori = can_add_histori(); +?> + + + + + + Dashboard WebGIS Kemiskinan Pontianak + + + +
+
+
+

Dashboard WebGIS Kemiskinan Pontianak

+

+ Login: + () +

+
+ +
+ +
+ Dashboard ini berisi ringkasan dan tabel utama sistem: laporan cepat, histori bantuan, masyarakat prasejahtera, + dan rumah ibadah. Pilih tombol data di bawah untuk membuka tabel yang ingin dilihat. Data SPBU, jalan, + dan parsil tanah tidak ditampilkan di dashboard ini. +
+ +
+
+
+

Ringkasan Utama

+

Angka penting untuk memantau laporan masyarakat, bantuan, dan data sosial.

+
+
+
+
+ +
+

Pilih Data Dashboard

+

Klik salah satu tombol. Tabel akan muncul penuh di bawah agar lebih mudah dibaca.

+
+ + + + + + + + +
+
+ +
+
+
+

Laporan Cepat Masyarakat

+

+
+ Download CSV +
+
+
+ + + + + + + + + + + + +
+ + + + diff --git a/3_PovertyMapping/index.php b/3_PovertyMapping/index.php new file mode 100644 index 0000000..4596cc2 --- /dev/null +++ b/3_PovertyMapping/index.php @@ -0,0 +1,2010 @@ +connect_error) { + die("Koneksi database gagal."); +} + +$conn->set_charset("utf8mb4"); + +$conn = new mysqli($host, $user, $pass, $db); +if ($conn->connect_error) { + die("Koneksi gagal: " . $conn->connect_error); +} +$conn->set_charset("utf8mb4"); + +function is_logged_in() { + return isset($_SESSION['user']); +} + +function current_role() { + return $_SESSION['user']['role'] ?? 'masyarakat'; +} + +function current_instansi() { + return $_SESSION['user']['instansi'] ?? ''; +} + +function is_admin() { + return current_role() === 'admin'; +} + +function is_walikota() { + return current_role() === 'walikota'; +} + +function is_dinas() { + return current_role() === 'dinas'; +} + +function can_view_dashboard() { + return is_admin() || is_walikota() || is_dinas(); +} + +function can_download_data() { + return is_admin() || is_walikota() || is_dinas(); +} + +function can_add_histori() { + return is_admin() || is_dinas(); +} + +function json_out($arr) { + header('Content-Type: application/json; charset=utf-8'); + echo json_encode($arr); + exit; +} + +function post($key, $default = '') { + return trim($_POST[$key] ?? $default); +} + +function ipost($key, $default = 0) { + return (int) ($_POST[$key] ?? $default); +} + +function fpost($key, $default = 0) { + return (float) ($_POST[$key] ?? $default); +} + +function require_admin() { + if (!is_admin()) { + json_out([ + 'status' => false, + 'message' => 'Akses ditolak. Fitur ini hanya untuk admin pengelola.' + ]); + } +} + +function require_dashboard_access() { + if (!can_view_dashboard()) { + json_out([ + 'status' => false, + 'message' => 'Akses ditolak. Silakan login terlebih dahulu.' + ]); + } +} + +function require_download_access() { + if (!can_download_data()) { + json_out([ + 'status' => false, + 'message' => 'Akses download hanya untuk admin, wali kota, atau dinas terkait.' + ]); + } +} + +function require_histori_write() { + if (!can_add_histori()) { + json_out([ + 'status' => false, + 'message' => 'Akses ditolak. Histori bantuan hanya dapat ditambahkan oleh admin atau dinas terkait.' + ]); + } +} + +function valid_enum($value, $allowed, $default) { + return in_array($value, $allowed, true) ? $value : $default; +} + +function allowed_aktor_tujuan() { + return [ + 'RT/RW', + 'Kelurahan', + 'Kecamatan', + 'Dinas Sosial', + 'Dinas Kesehatan', + 'Wali Kota' + ]; +} + +function dinas_filter_sql($field = 'aktor_tujuan') { + if (!is_dinas()) return ['', []]; + $instansi = current_instansi() ?: 'Dinas Sosial'; + return [" WHERE $field = ? ", [$instansi]]; +} + +function find_matching_penduduk_id($conn, $namaKepalaKeluarga, $nik) { + $namaKepalaKeluarga = trim((string) $namaKepalaKeluarga); + $nik = trim((string) $nik); + + if ($nik !== '') { + $stmt = $conn->prepare("SELECT id FROM penduduk_kemiskinan WHERE nik = ? LIMIT 1"); + $stmt->bind_param("s", $nik); + $stmt->execute(); + $row = $stmt->get_result()->fetch_assoc(); + if ($row) { + return (int) $row['id']; + } + } + + if ($namaKepalaKeluarga !== '') { + $stmt = $conn->prepare("SELECT id FROM penduduk_kemiskinan WHERE LOWER(TRIM(nama_kepala_keluarga)) = LOWER(TRIM(?)) LIMIT 1"); + $stmt->bind_param("s", $namaKepalaKeluarga); + $stmt->execute(); + $row = $stmt->get_result()->fetch_assoc(); + if ($row) { + return (int) $row['id']; + } + } + + return 0; +} + +if (isset($_GET['logout'])) { + session_destroy(); + header('Location: index.php'); + exit; +} + +if (isset($_POST['login'])) { + $username = post('username'); + $password = $_POST['password'] ?? ''; + + $stmt = $conn->prepare("SELECT * FROM users WHERE username=? LIMIT 1"); + $stmt->bind_param("s", $username); + $stmt->execute(); + $userRow = $stmt->get_result()->fetch_assoc(); + + if ($userRow && password_verify($password, $userRow['password'])) { + $_SESSION['user'] = [ + 'id' => $userRow['id'], + 'nama' => $userRow['nama'], + 'username' => $userRow['username'], + 'role' => $userRow['role'], + 'instansi' => $userRow['instansi'] ?? '' + ]; + + header('Location: index.php'); + exit; + } + + $login_error = "Username atau password salah."; +} + +/* ========================= + DOWNLOAD CSV + ========================= */ +if (isset($_GET['download'])) { + require_download_access(); + + $type = $_GET['download']; + + if ($type === 'laporan') { + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename=laporan_masyarakat.csv'); + + $out = fopen('php://output', 'w'); + fputcsv($out, [ + 'ID', 'Nama Pelapor', 'No HP', 'Kategori', 'Aktor Tujuan', + 'Status', 'Deskripsi Publik', + 'Nama Warga Dilaporkan', 'NIK', 'Tanggal Lahir', 'Pendidikan', + 'Riwayat Penyakit', 'Jumlah KK', 'Alamat', 'Kecamatan', 'Kelurahan', + 'Status Bantuan Awal', 'Latitude', 'Longitude', 'Tanggal' + ]); + + if (is_dinas()) { + $instansi = current_instansi() ?: 'Dinas Sosial'; + $stmt = $conn->prepare("SELECT * FROM laporan_masyarakat WHERE aktor_tujuan=? ORDER BY id DESC"); + $stmt->bind_param("s", $instansi); + $stmt->execute(); + $result = $stmt->get_result(); + } else { + $result = $conn->query("SELECT * FROM laporan_masyarakat ORDER BY id DESC"); + } + while ($row = $result->fetch_assoc()) { + fputcsv($out, [ + $row['id'], $row['nama_pelapor'], $row['no_hp'], $row['kategori_laporan'], + $row['aktor_tujuan'], $row['status_laporan'], $row['deskripsi'], + $row['data_nama_kepala_keluarga'] ?? '', $row['data_nik'] ?? '', $row['data_tanggal_lahir'] ?? '', + $row['data_pendidikan'] ?? '', $row['data_riwayat_penyakit'] ?? '', $row['data_jumlah_kk'] ?? '', + $row['data_alamat'] ?? '', $row['data_kecamatan'] ?? '', $row['data_kelurahan'] ?? '', + $row['data_status_bantuan'] ?? '', + $row['latitude'], $row['longitude'], $row['created_at'] + ]); + } + exit; + } + + if ($type === 'histori') { + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename=histori_bantuan.csv'); + + $out = fopen('php://output', 'w'); + fputcsv($out, [ + 'ID', 'Kepala Keluarga', 'Jenis Bantuan', 'Tanggal', + 'Nominal', 'Sumber Bantuan', 'Rumah Ibadah', 'Keterangan' + ]); + + $sql = "SELECT hb.*, pk.nama_kepala_keluarga, m.nama_masjid, m.jenis_rumah_ibadah + FROM histori_bantuan hb + JOIN penduduk_kemiskinan pk ON pk.id = hb.penduduk_id + LEFT JOIN masjid m ON m.id = hb.masjid_id + ORDER BY hb.id DESC"; + + $result = $conn->query($sql); + while ($row = $result->fetch_assoc()) { + fputcsv($out, [ + $row['id'], + $row['nama_kepala_keluarga'], + $row['jenis_bantuan'], + $row['tanggal_bantuan'], + $row['nominal'], + $row['sumber_bantuan'], + $row['nama_masjid'] ?? '', + $row['keterangan'] + ]); + } + exit; + } + + if ($type === 'penduduk') { + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename=masyarakat_miskin.csv'); + + $out = fopen('php://output', 'w'); + fputcsv($out, [ + 'ID', 'Nama Kepala Keluarga', 'NIK', 'Tanggal Lahir', 'Pendidikan', + 'Riwayat Penyakit', 'Jumlah KK', 'Alamat', 'Kecamatan', 'Kelurahan', + 'Status Bantuan', 'Latitude', 'Longitude', 'Tanggal Input' + ]); + + $result = $conn->query("SELECT * FROM penduduk_kemiskinan ORDER BY id DESC"); + while ($row = $result->fetch_assoc()) { + fputcsv($out, [ + $row['id'], $row['nama_kepala_keluarga'], $row['nik'], $row['tanggal_lahir'], + $row['pendidikan'], $row['riwayat_penyakit'], $row['jumlah_kk'], $row['alamat'], + $row['kecamatan'], $row['kelurahan'], $row['status_bantuan'], + $row['latitude'], $row['longitude'], $row['created_at'] + ]); + } + exit; + } + + if ($type === 'rumah_ibadah') { + header('Content-Type: text/csv; charset=utf-8'); + header('Content-Disposition: attachment; filename=rumah_ibadah.csv'); + + $out = fopen('php://output', 'w'); + fputcsv($out, [ + 'ID', 'Jenis', 'Nama Rumah Ibadah', 'PIC', 'Alamat', + 'Latitude', 'Longitude', 'Radius Meter', 'Tanggal Input' + ]); + + $result = $conn->query("SELECT * FROM masjid ORDER BY id DESC"); + while ($row = $result->fetch_assoc()) { + fputcsv($out, [ + $row['id'], $row['jenis_rumah_ibadah'], $row['nama_masjid'], $row['pic_masjid'], + $row['alamat_masjid'], $row['latitude'], $row['longitude'], $row['radius_meter'], + $row['created_at'] + ]); + } + exit; + } +} + +/* ========================= + API ACTIONS + ========================= */ +if (isset($_GET['action'])) { + $action = $_GET['action']; + + if ($action === 'get_all') { + $data = []; + + $tables = [ + 'penduduk_kemiskinan', + 'masjid', + 'laporan_masyarakat' + ]; + + foreach ($tables as $table) { + $data[$table] = []; + + if ($table === 'laporan_masyarakat' && is_dinas()) { + $instansi = current_instansi() ?: 'Dinas Sosial'; + $stmt = $conn->prepare("SELECT * FROM laporan_masyarakat WHERE aktor_tujuan=? ORDER BY id DESC"); + $stmt->bind_param("s", $instansi); + $stmt->execute(); + $result = $stmt->get_result(); + } else { + $result = $conn->query("SELECT * FROM $table ORDER BY id DESC"); + } + + if ($result) { + while ($row = $result->fetch_assoc()) { + $data[$table][] = $row; + } + } + } + + $data['users'] = []; + if (is_admin()) { + $resultUsers = $conn->query("SELECT id, nama, username, role, instansi, created_at FROM users ORDER BY role, nama"); + if ($resultUsers) { + while ($row = $resultUsers->fetch_assoc()) { + $data['users'][] = $row; + } + } + } + + $data['histori_bantuan'] = []; + $sqlHistori = "SELECT hb.*, pk.nama_kepala_keluarga, m.nama_masjid, m.jenis_rumah_ibadah + FROM histori_bantuan hb + JOIN penduduk_kemiskinan pk ON pk.id = hb.penduduk_id + LEFT JOIN masjid m ON m.id = hb.masjid_id + ORDER BY hb.id DESC"; + $result = $conn->query($sqlHistori); + if ($result) { + while ($row = $result->fetch_assoc()) { + $data['histori_bantuan'][] = $row; + } + } + + json_out($data); + } + + /* ========================= + PENDUDUK KEMISKINAN + ========================= */ + if ($action === 'add_penduduk' || $action === 'update_penduduk') { + require_admin(); + + $id = ipost('id'); + $nama = post('nama_kepala_keluarga'); + $nik = post('nik'); + $tanggalLahir = post('tanggal_lahir') ?: null; + $pendidikan = valid_enum(post('pendidikan'), ['Tidak sekolah', 'SD', 'SMP', 'SMA/SMK', 'Diploma', 'S1', 'S2', 'S3', 'Tidak diketahui'], 'Tidak diketahui'); + $riwayat = post('riwayat_penyakit'); + $jumlahKk = ipost('jumlah_kk', 1); + $alamat = post('alamat'); + $kecamatan = post('kecamatan'); + $kelurahan = post('kelurahan'); + $statusBantuan = valid_enum(post('status_bantuan'), ['Belum menerima', 'Sudah menerima', 'Perlu verifikasi'], 'Belum menerima'); + $lat = fpost('latitude'); + $lng = fpost('longitude'); + + if ($nama === '' || $jumlahKk <= 0 || $alamat === '' || $lat == 0 || $lng == 0) { + json_out(['status' => false, 'message' => 'Data masyarakat prasejahtera belum lengkap']); + } + + if ($action === 'add_penduduk') { + $stmt = $conn->prepare("INSERT INTO penduduk_kemiskinan + (nama_kepala_keluarga, nik, tanggal_lahir, pendidikan, riwayat_penyakit, jumlah_kk, alamat, kecamatan, kelurahan, status_bantuan, latitude, longitude) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $stmt->bind_param("sssssissssdd", $nama, $nik, $tanggalLahir, $pendidikan, $riwayat, $jumlahKk, $alamat, $kecamatan, $kelurahan, $statusBantuan, $lat, $lng); + } else { + if ($id <= 0) json_out(['status' => false, 'message' => 'ID masyarakat prasejahtera tidak valid']); + $stmt = $conn->prepare("UPDATE penduduk_kemiskinan SET + nama_kepala_keluarga=?, nik=?, tanggal_lahir=?, pendidikan=?, riwayat_penyakit=?, jumlah_kk=?, alamat=?, kecamatan=?, kelurahan=?, status_bantuan=?, latitude=?, longitude=? + WHERE id=?"); + $stmt->bind_param("sssssissssddi", $nama, $nik, $tanggalLahir, $pendidikan, $riwayat, $jumlahKk, $alamat, $kecamatan, $kelurahan, $statusBantuan, $lat, $lng, $id); + } + + json_out($stmt->execute() + ? ['status' => true, 'message' => $action === 'add_penduduk' ? 'Data masyarakat prasejahtera berhasil ditambahkan' : 'Data masyarakat prasejahtera berhasil diupdate'] + : ['status' => false, 'message' => 'Gagal menyimpan data masyarakat prasejahtera'] + ); + } + + if ($action === 'update_position_penduduk') { + require_admin(); + + $id = ipost('id'); + $lat = fpost('latitude'); + $lng = fpost('longitude'); + + $stmt = $conn->prepare("UPDATE penduduk_kemiskinan SET latitude=?, longitude=? WHERE id=?"); + $stmt->bind_param("ddi", $lat, $lng, $id); + + json_out($stmt->execute() + ? ['status' => true, 'message' => 'Posisi masyarakat prasejahtera berhasil diupdate'] + : ['status' => false, 'message' => 'Gagal update posisi masyarakat prasejahtera'] + ); + } + + /* ========================= + RUMAH IBADAH / MASJID + ========================= */ + if ($action === 'add_masjid' || $action === 'update_masjid') { + require_admin(); + + $id = ipost('id'); + $jenis = valid_enum(post('jenis_rumah_ibadah'), ['Masjid', 'Gereja', 'Vihara', 'Kelenteng', 'Pura'], 'Masjid'); + $nama = post('nama_masjid'); + $pic = post('pic_masjid'); + $alamat = post('alamat_masjid'); + $lat = fpost('latitude'); + $lng = fpost('longitude'); + $radius = max(100, min(5000, ipost('radius_meter', 500))); + + if ($nama === '' || $pic === '' || $alamat === '' || $lat == 0 || $lng == 0) { + json_out(['status' => false, 'message' => 'Data rumah ibadah belum lengkap']); + } + + if ($action === 'add_masjid') { + $stmt = $conn->prepare("INSERT INTO masjid + (jenis_rumah_ibadah, nama_masjid, pic_masjid, alamat_masjid, latitude, longitude, radius_meter) + VALUES (?, ?, ?, ?, ?, ?, ?)"); + $stmt->bind_param("ssssddi", $jenis, $nama, $pic, $alamat, $lat, $lng, $radius); + } else { + if ($id <= 0) json_out(['status' => false, 'message' => 'ID rumah ibadah tidak valid']); + $stmt = $conn->prepare("UPDATE masjid SET + jenis_rumah_ibadah=?, nama_masjid=?, pic_masjid=?, alamat_masjid=?, latitude=?, longitude=?, radius_meter=? + WHERE id=?"); + $stmt->bind_param("ssssddii", $jenis, $nama, $pic, $alamat, $lat, $lng, $radius, $id); + } + + json_out($stmt->execute() + ? ['status' => true, 'message' => $action === 'add_masjid' ? 'Data rumah ibadah berhasil ditambahkan' : 'Data rumah ibadah berhasil diupdate'] + : ['status' => false, 'message' => 'Gagal menyimpan data rumah ibadah'] + ); + } + + if ($action === 'update_position_masjid') { + require_admin(); + + $id = ipost('id'); + $lat = fpost('latitude'); + $lng = fpost('longitude'); + + $stmt = $conn->prepare("UPDATE masjid SET latitude=?, longitude=? WHERE id=?"); + $stmt->bind_param("ddi", $lat, $lng, $id); + + json_out($stmt->execute() + ? ['status' => true, 'message' => 'Posisi rumah ibadah berhasil diupdate'] + : ['status' => false, 'message' => 'Gagal update posisi rumah ibadah'] + ); + } + + /* ========================= + LAPORAN MASYARAKAT + ========================= */ + if ($action === 'add_laporan' || $action === 'update_laporan') { + if ($action === 'add_laporan' && is_logged_in()) { + json_out([ + 'status' => false, + 'message' => 'Laporan cepat hanya dibuat dari mode masyarakat umum. Admin cukup memperbarui status laporan.' + ]); + } + + if ($action === 'update_laporan') { + require_admin(); + } + + $id = ipost('id'); + $pendudukIdInput = ipost('penduduk_id'); + $pendudukId = $pendudukIdInput > 0 ? $pendudukIdInput : null; + + // Data publik laporan + $nama = post('nama_pelapor'); + $hp = post('no_hp'); + $kategori = valid_enum(post('kategori_laporan'), ['Data kemiskinan', 'Bantuan belum diterima', 'Kondisi kesehatan', 'Data tidak sesuai', 'Lainnya'], 'Data kemiskinan'); + $deskripsi = post('deskripsi'); + $aktor = valid_enum(post('aktor_tujuan'), allowed_aktor_tujuan(), 'Dinas Sosial'); + $status = valid_enum(post('status_laporan'), ['Masuk', 'Ditinjau', 'Diproses', 'Selesai', 'Dijadikan Data Masyarakat', 'Ditolak'], 'Masuk'); + + // Data lengkap calon masyarakat prasejahtera dari laporan + $dataNamaKK = post('data_nama_kepala_keluarga'); + $dataNik = post('data_nik'); + $dataTanggalLahir = post('data_tanggal_lahir') ?: null; + $dataPendidikan = valid_enum(post('data_pendidikan'), ['Tidak sekolah', 'SD', 'SMP', 'SMA/SMK', 'Diploma', 'S1', 'S2', 'S3', 'Tidak diketahui'], 'Tidak diketahui'); + $dataRiwayat = post('data_riwayat_penyakit'); + $dataJumlahKk = max(1, ipost('data_jumlah_kk', 1)); + $dataAlamat = post('data_alamat'); + $dataKecamatan = post('data_kecamatan'); + $dataKelurahan = post('data_kelurahan'); + $dataStatusBantuan = valid_enum(post('data_status_bantuan'), ['Belum menerima', 'Sudah menerima', 'Perlu verifikasi'], 'Belum menerima'); + + // Logika auto-terhubung: + // Jika NIK sama dengan data masyarakat yang sudah ada, sistem langsung menghubungkan laporan ke data tersebut. + // Jika NIK kosong, sistem mencoba mencocokkan dari nama kepala keluarga/warga yang dilaporkan. + // Status laporan tetap Masuk agar kebutuhan bantuan terbaru tetap terlihat di dashboard. + if (!$pendudukId) { + $matchedPendudukId = find_matching_penduduk_id($conn, $dataNamaKK, $dataNik); + $pendudukId = $matchedPendudukId > 0 ? $matchedPendudukId : null; + } + + $lat = fpost('latitude'); + $lng = fpost('longitude'); + + if ($nama === '' || $hp === '' || $deskripsi === '' || $dataNamaKK === '' || $dataAlamat === '' || $lat == 0 || $lng == 0) { + json_out(['status' => false, 'message' => 'Data laporan belum lengkap. Isi data pelapor, data warga yang dilaporkan, alamat, deskripsi, dan titik lokasi.']); + } + + if ($action === 'add_laporan') { + $stmt = $conn->prepare("INSERT INTO laporan_masyarakat + (penduduk_id, nama_pelapor, no_hp, kategori_laporan, deskripsi, aktor_tujuan, status_laporan, + data_nama_kepala_keluarga, data_nik, data_tanggal_lahir, data_pendidikan, data_riwayat_penyakit, + data_jumlah_kk, data_alamat, data_kecamatan, data_kelurahan, data_status_bantuan, + latitude, longitude) + VALUES (?, ?, ?, ?, ?, ?, 'Masuk', ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + if (!$stmt) { + json_out(['status' => false, 'message' => 'Gagal menyiapkan query laporan: ' . $conn->error]); + } + $stmt->bind_param("issssssssssissssdd", $pendudukId, $nama, $hp, $kategori, $deskripsi, $aktor, + $dataNamaKK, $dataNik, $dataTanggalLahir, $dataPendidikan, $dataRiwayat, + $dataJumlahKk, $dataAlamat, $dataKecamatan, $dataKelurahan, $dataStatusBantuan, + $lat, $lng); + } else { + if ($id <= 0) json_out(['status' => false, 'message' => 'ID laporan tidak valid']); + $stmt = $conn->prepare("UPDATE laporan_masyarakat SET + penduduk_id=?, nama_pelapor=?, no_hp=?, kategori_laporan=?, deskripsi=?, aktor_tujuan=?, status_laporan=?, + data_nama_kepala_keluarga=?, data_nik=?, data_tanggal_lahir=?, data_pendidikan=?, data_riwayat_penyakit=?, + data_jumlah_kk=?, data_alamat=?, data_kecamatan=?, data_kelurahan=?, data_status_bantuan=?, + latitude=?, longitude=? + WHERE id=?"); + if (!$stmt) { + json_out(['status' => false, 'message' => 'Gagal menyiapkan query update laporan: ' . $conn->error]); + } + $stmt->bind_param("isssssssssssissssddi", $pendudukId, $nama, $hp, $kategori, $deskripsi, $aktor, $status, + $dataNamaKK, $dataNik, $dataTanggalLahir, $dataPendidikan, $dataRiwayat, + $dataJumlahKk, $dataAlamat, $dataKecamatan, $dataKelurahan, $dataStatusBantuan, + $lat, $lng, $id); + } + + if ($stmt->execute()) { + $linkedText = $pendudukId + ? ' Sistem mendeteksi nama/NIK yang sama, sehingga laporan otomatis terhubung ke data masyarakat prasejahtera yang sudah ada.' + : ''; + + json_out([ + 'status' => true, + 'message' => ($action === 'add_laporan' + ? 'Laporan berhasil dikirim dan menunggu tindak lanjut admin.' + : 'Laporan berhasil diupdate.') . $linkedText + ]); + } + + json_out([ + 'status' => false, + 'message' => 'Gagal menyimpan laporan: ' . ($stmt ? $stmt->error : $conn->error) + ]); + } + + if ($action === 'update_position_laporan') { + require_admin(); + + $id = ipost('id'); + $lat = fpost('latitude'); + $lng = fpost('longitude'); + + $stmt = $conn->prepare("UPDATE laporan_masyarakat SET latitude=?, longitude=? WHERE id=?"); + $stmt->bind_param("ddi", $lat, $lng, $id); + + json_out($stmt->execute() + ? ['status' => true, 'message' => 'Posisi laporan berhasil diupdate'] + : ['status' => false, 'message' => 'Gagal update posisi laporan'] + ); + } + + if ($action === 'update_status_laporan') { + require_admin(); + + $id = ipost('id'); + $status = valid_enum(post('status_laporan'), ['Masuk', 'Ditinjau', 'Diproses', 'Selesai', 'Dijadikan Data Masyarakat', 'Ditolak'], 'Masuk'); + + $stmt = $conn->prepare("UPDATE laporan_masyarakat SET status_laporan=? WHERE id=?"); + $stmt->bind_param("si", $status, $id); + + json_out($stmt->execute() + ? ['status' => true, 'message' => 'Status laporan berhasil diperbarui'] + : ['status' => false, 'message' => 'Gagal update status laporan'] + ); + } + + + /* ========================= + KONVERSI LAPORAN MENJADI DATA MASYARAKAT PRASEJAHTERA + ========================= */ + if ($action === 'convert_laporan_to_penduduk') { + require_admin(); + + $id = ipost('id'); + if ($id <= 0) { + json_out(['status' => false, 'message' => 'ID laporan tidak valid']); + } + + $stmt = $conn->prepare("SELECT * FROM laporan_masyarakat WHERE id=? LIMIT 1"); + $stmt->bind_param("i", $id); + $stmt->execute(); + $laporan = $stmt->get_result()->fetch_assoc(); + + if (!$laporan) { + json_out(['status' => false, 'message' => 'Laporan tidak ditemukan']); + } + + if (($laporan['status_laporan'] ?? '') !== 'Selesai') { + json_out([ + 'status' => false, + 'message' => 'Laporan belum bisa dijadikan data masyarakat. Ubah status laporan menjadi Selesai setelah laporan benar-benar valid.' + ]); + } + + if (!empty($laporan['penduduk_id'])) { + $update = $conn->prepare("UPDATE laporan_masyarakat SET status_laporan='Dijadikan Data Masyarakat' WHERE id=?"); + $update->bind_param("i", $id); + $update->execute(); + + json_out([ + 'status' => true, + 'message' => 'Laporan ini sudah terhubung dengan data masyarakat prasejahtera.' + ]); + } + + $namaKK = trim($laporan['data_nama_kepala_keluarga'] ?? ''); + $alamat = trim($laporan['data_alamat'] ?? ''); + + $matchedPendudukId = find_matching_penduduk_id($conn, $namaKK, $laporan['data_nik'] ?? ''); + if ($matchedPendudukId > 0) { + $update = $conn->prepare("UPDATE laporan_masyarakat + SET penduduk_id=?, status_laporan='Dijadikan Data Masyarakat' + WHERE id=?"); + $update->bind_param("ii", $matchedPendudukId, $id); + $update->execute(); + + json_out([ + 'status' => true, + 'message' => 'Nama/NIK pada laporan cocok dengan data masyarakat yang sudah ada. Laporan otomatis dihubungkan, sehingga tidak membuat data masyarakat ganda.' + ]); + } + + if ($namaKK === '' || $alamat === '') { + json_out([ + 'status' => false, + 'message' => 'Data warga pada laporan belum lengkap. Isi nama kepala keluarga/warga dan alamat terlebih dahulu.' + ]); + } + + $nik = $laporan['data_nik'] ?? null; + $tanggalLahir = $laporan['data_tanggal_lahir'] ?: null; + $pendidikan = $laporan['data_pendidikan'] ?: 'Tidak diketahui'; + $riwayat = $laporan['data_riwayat_penyakit'] ?? ''; + $jumlahKk = (int)($laporan['data_jumlah_kk'] ?? 1); + if ($jumlahKk <= 0) $jumlahKk = 1; + $kecamatan = $laporan['data_kecamatan'] ?? ''; + $kelurahan = $laporan['data_kelurahan'] ?? ''; + $statusBantuan = $laporan['data_status_bantuan'] ?: 'Belum menerima'; + $lat = (float)$laporan['latitude']; + $lng = (float)$laporan['longitude']; + + $insert = $conn->prepare("INSERT INTO penduduk_kemiskinan + (nama_kepala_keluarga, nik, tanggal_lahir, pendidikan, riwayat_penyakit, jumlah_kk, alamat, kecamatan, kelurahan, status_bantuan, latitude, longitude) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + $insert->bind_param("sssssissssdd", $namaKK, $nik, $tanggalLahir, $pendidikan, $riwayat, $jumlahKk, $alamat, $kecamatan, $kelurahan, $statusBantuan, $lat, $lng); + + if (!$insert->execute()) { + json_out(['status' => false, 'message' => 'Gagal menjadikan laporan sebagai data masyarakat prasejahtera']); + } + + $pendudukIdBaru = $conn->insert_id; + + $update = $conn->prepare("UPDATE laporan_masyarakat + SET penduduk_id=?, status_laporan='Dijadikan Data Masyarakat' + WHERE id=?"); + $update->bind_param("ii", $pendudukIdBaru, $id); + $update->execute(); + + json_out([ + 'status' => true, + 'message' => 'Laporan berhasil dijadikan data masyarakat prasejahtera. Bubble laporan akan disembunyikan dari peta, tetapi tetap tersimpan di dashboard/statistik.' + ]); + } + + /* ========================= + HUBUNGKAN LAPORAN DENGAN DATA MASYARAKAT YANG SUDAH ADA + ========================= */ + if ($action === 'link_laporan_to_penduduk') { + require_admin(); + + $id = ipost('id'); + $pendudukId = ipost('penduduk_id'); + + if ($id <= 0 || $pendudukId <= 0) { + json_out(['status' => false, 'message' => 'Pilih laporan dan data masyarakat yang valid']); + } + + $cekLaporan = $conn->prepare("SELECT id, status_laporan, penduduk_id FROM laporan_masyarakat WHERE id=? LIMIT 1"); + $cekLaporan->bind_param("i", $id); + $cekLaporan->execute(); + $laporan = $cekLaporan->get_result()->fetch_assoc(); + + if (!$laporan) { + json_out(['status' => false, 'message' => 'Laporan tidak ditemukan']); + } + + if (($laporan['status_laporan'] ?? '') !== 'Selesai') { + json_out([ + 'status' => false, + 'message' => 'Laporan belum bisa dihubungkan. Ubah status laporan menjadi Selesai setelah laporan benar-benar valid.' + ]); + } + + if (!empty($laporan['penduduk_id'])) { + json_out([ + 'status' => true, + 'message' => 'Laporan ini sudah terhubung dengan data masyarakat prasejahtera.' + ]); + } + + $cekPenduduk = $conn->prepare("SELECT id FROM penduduk_kemiskinan WHERE id=? LIMIT 1"); + $cekPenduduk->bind_param("i", $pendudukId); + $cekPenduduk->execute(); + if (!$cekPenduduk->get_result()->fetch_assoc()) { + json_out(['status' => false, 'message' => 'Data masyarakat prasejahtera tidak ditemukan']); + } + + $stmt = $conn->prepare("UPDATE laporan_masyarakat SET penduduk_id=?, status_laporan='Dijadikan Data Masyarakat' WHERE id=?"); + $stmt->bind_param("ii", $pendudukId, $id); + + json_out($stmt->execute() + ? ['status' => true, 'message' => 'Laporan berhasil dihubungkan ke data masyarakat yang sudah ada. Laporan tetap tersimpan untuk arsip/statistik, tetapi bubble laporan disembunyikan dari peta.'] + : ['status' => false, 'message' => 'Gagal menghubungkan laporan ke data masyarakat'] + ); + } + + /* ========================= + HISTORI BANTUAN + ========================= */ + if ($action === 'add_histori') { + require_histori_write(); + + $pendudukId = ipost('penduduk_id'); + $masjidIdInput = ipost('masjid_id'); + $masjidId = $masjidIdInput > 0 ? $masjidIdInput : null; + + $jenis = post('jenis_bantuan'); + $tanggal = post('tanggal_bantuan'); + $nominal = fpost('nominal'); + $sumber = post('sumber_bantuan'); + + if ($sumber === '' && $masjidId) { + $stmtMasjid = $conn->prepare("SELECT nama_masjid FROM masjid WHERE id=? LIMIT 1"); + $stmtMasjid->bind_param("i", $masjidId); + $stmtMasjid->execute(); + $rowMasjid = $stmtMasjid->get_result()->fetch_assoc(); + + if ($rowMasjid) { + $sumber = $rowMasjid['nama_masjid']; + } + } + + if ($sumber === '') { + $sumber = is_dinas() ? (current_instansi() ?: 'Dinas Terkait') : 'Pemkot Pontianak / Rumah Ibadah / Donatur'; + } + + $keterangan = post('keterangan'); + + if ($pendudukId <= 0 || $jenis === '' || $tanggal === '') { + json_out(['status' => false, 'message' => 'Data histori bantuan belum lengkap']); + } + + $stmt = $conn->prepare("INSERT INTO histori_bantuan + (penduduk_id, masjid_id, jenis_bantuan, tanggal_bantuan, nominal, sumber_bantuan, keterangan) + VALUES (?, ?, ?, ?, ?, ?, ?)"); + $stmt->bind_param("iissdss", $pendudukId, $masjidId, $jenis, $tanggal, $nominal, $sumber, $keterangan); + + if ($stmt->execute()) { + $updateStatus = $conn->prepare("UPDATE penduduk_kemiskinan SET status_bantuan='Sudah menerima' WHERE id=?"); + $updateStatus->bind_param("i", $pendudukId); + $updateStatus->execute(); + + json_out([ + 'status' => true, + 'message' => 'Histori bantuan berhasil ditambahkan dan status bantuan warga menjadi Sudah menerima' + ]); + } + + json_out([ + 'status' => false, + 'message' => 'Gagal menyimpan histori bantuan' + ]); + } + + + /* ========================= + KELOLA AKUN ROLE + ========================= */ + if ($action === 'add_user') { + require_admin(); + + $nama = post('nama'); + $username = post('username'); + $password = $_POST['password'] ?? ''; + $role = valid_enum(post('role'), ['admin', 'walikota', 'dinas'], 'dinas'); + $instansi = post('instansi'); + + if ($nama === '' || $username === '' || $password === '') { + json_out(['status' => false, 'message' => 'Nama, username, dan password wajib diisi']); + } + + if ($role === 'walikota') { + $instansi = 'Wali Kota'; + } elseif ($role === 'admin') { + $instansi = 'Admin Pengelola'; + } elseif ($instansi === '') { + $instansi = 'Dinas Sosial'; + } + + $hash = password_hash($password, PASSWORD_DEFAULT); + $stmt = $conn->prepare("INSERT INTO users (nama, username, password, role, instansi) VALUES (?, ?, ?, ?, ?)"); + $stmt->bind_param("sssss", $nama, $username, $hash, $role, $instansi); + + json_out($stmt->execute() + ? ['status' => true, 'message' => 'Akun berhasil ditambahkan'] + : ['status' => false, 'message' => 'Gagal menambahkan akun. Username mungkin sudah digunakan.'] + ); + } + + if ($action === 'delete_user') { + require_admin(); + + $id = ipost('id'); + if ($id <= 0) json_out(['status' => false, 'message' => 'ID akun tidak valid']); + if ($id === (int)($_SESSION['user']['id'] ?? 0)) { + json_out(['status' => false, 'message' => 'Akun yang sedang login tidak boleh dihapus']); + } + + $stmt = $conn->prepare("DELETE FROM users WHERE id=?"); + $stmt->bind_param("i", $id); + + json_out($stmt->execute() + ? ['status' => true, 'message' => 'Akun berhasil dihapus'] + : ['status' => false, 'message' => 'Gagal menghapus akun'] + ); + } + + /* ========================= + DELETE GENERIC + ========================= */ + if ($action === 'delete') { + require_admin(); + + $allowed = [ + 'penduduk_kemiskinan', + 'masjid', + 'laporan_masyarakat', + 'histori_bantuan' + ]; + + $table = post('table'); + $id = ipost('id'); + + if (!in_array($table, $allowed, true)) { + json_out(['status' => false, 'message' => 'Tabel tidak valid']); + } + + $stmt = $conn->prepare("DELETE FROM $table WHERE id=?"); + $stmt->bind_param("i", $id); + + json_out($stmt->execute() + ? ['status' => true, 'message' => 'Data berhasil dihapus'] + : ['status' => false, 'message' => 'Gagal menghapus data'] + ); + } + + json_out(['status' => false, 'message' => 'Action tidak dikenal']); +} + +$admin = is_admin(); +$loggedIn = is_logged_in(); +$canViewDashboard = can_view_dashboard(); +$roleLabel = ['admin' => 'Admin Pengelola', 'walikota' => 'Wali Kota', 'dinas' => 'Dinas Terkait'][$_SESSION['user']['role'] ?? ''] ?? 'Masyarakat Umum'; +$instansiLabel = current_instansi(); +?> + + + + + + + WebGIS Prasejahtera Pontianak + + + + + + +
+
+
+
+

Sistem Informasi Geografis

+

WebGIS Prasejahtera Pontianak

+

+ Pemetaan masyarakat prasejahtera, rumah ibadah, laporan cepat, dan histori bantuan berbasis lokasi. +

+

+ +

+
+ +
+ + Dashboard + Logout + + + +
+
+
+ +
+
+
+
+

Peta WebGIS Poverty Mapping

+

+ Pilih mode, klik titik pada peta, lalu isi form pada panel kanan sesuai kebutuhan data. +

+
+ +
+ Luar radius + Dalam radius +
+
+ +
+
+
+
+ + +
+
+
+ +
+ WebGIS Kemiskinan Pontianak + © 2026 - Talitha Syakirah Artanti | D1041231013 | Sistem Informasi Geografis +
+
+ + + + + + + + + diff --git a/3_PovertyMapping/style.css b/3_PovertyMapping/style.css new file mode 100644 index 0000000..f8a5a40 --- /dev/null +++ b/3_PovertyMapping/style.css @@ -0,0 +1,1612 @@ +html, +body { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + font-family: Arial, sans-serif; + background: #f3f4f6; + overflow: hidden; +} + +* { + box-sizing: border-box; +} + +.hidden { + display: none !important; +} + +/* ========================= + LAYOUT UTAMA + ========================= */ +.app-shell { + width: 100vw; + height: 100vh; + display: grid; + grid-template-columns: 420px minmax(0, 1fr); + background: #f3f4f6; +} + +.sidebar { + height: 100vh; + overflow-y: auto; + overflow-x: hidden; + background: #ffffff; + border-right: 1px solid #e5e7eb; + padding: 18px; + display: flex; + flex-direction: column; + gap: 14px; + box-shadow: 6px 0 20px rgba(15, 23, 42, 0.08); + z-index: 1000; +} + +.map-area { + position: relative; + min-width: 0; + height: 100vh; + background: #e5e7eb; +} + +#map { + width: 100%; + height: 100%; +} + +/* ========================= + CARD UMUM + ========================= */ +.topbar, +.mode-panel, +.form-panel, +.login-box, +.table-panel { + position: static; + width: 100%; + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 16px; + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08); + padding: 14px; + z-index: auto; +} + +/* ========================= + TOP BAR / HEADER SIDEBAR + ========================= */ +.topbar { + display: grid; + grid-template-columns: 1fr; + gap: 8px; + min-height: auto; + padding: 16px; + background: linear-gradient(135deg, #0d6efd, #0b5ed7); + color: #ffffff; +} + +.topbar b { + display: block; + font-size: 18px; + line-height: 1.25; + color: #ffffff; +} + +.topbar span { + font-size: 13px; + color: rgba(255, 255, 255, 0.9); +} + +.topbar a, +.topbar button, +.table-panel a { + display: inline-flex; + align-items: center; + justify-content: center; + width: fit-content; + background: #ffffff; + color: #0d6efd; + text-decoration: none; + border: 0; + border-radius: 10px; + padding: 8px 12px; + cursor: pointer; + font-size: 13px; + font-weight: 700; + white-space: nowrap; +} + +/* ========================= + MODE PANEL + ========================= */ +.mode-panel b, +.form-panel h3, +.login-box h3, +.table-panel h3 { + display: block; + margin: 0 0 10px; + color: #111827; + font-size: 16px; + line-height: 1.3; +} + +.mode-panel small { + display: block; + font-size: 12px; + color: #4b5563; + line-height: 1.45; + margin-top: 2px; +} + +.mode-panel select, +.form-panel input, +.form-panel select, +.form-panel textarea, +.login-box input, +.table-panel input, +.table-panel select { + width: 100%; + padding: 10px 11px; + margin-bottom: 9px; + border: 1px solid #d1d5db; + border-radius: 10px; + background: #ffffff; + color: #111827; + font-size: 14px; + outline: none; +} + +.mode-panel select:focus, +.form-panel input:focus, +.form-panel select:focus, +.form-panel textarea:focus, +.login-box input:focus, +.table-panel input:focus, +.table-panel select:focus { + border-color: #0d6efd; + box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.12); +} + +.mini-legend { + margin-top: 12px; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 8px; + font-size: 12px; +} + +.mini-legend span { + display: flex; + align-items: center; + gap: 7px; + color: #374151; +} + +.legend-dot { + width: 14px; + height: 14px; + border-radius: 50%; + display: inline-block; + border: 2px solid #ffffff; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.22); +} + +.legend-dot.poor-out { + background: #dc3545; +} + +.legend-dot.poor-in { + background: #198754; +} + +/* ========================= + FORM PANEL + ========================= */ +.form-panel, +.login-box { + max-height: none; + overflow: visible; +} + +.form-panel textarea { + min-height: 74px; + resize: vertical; +} + +.form-panel input[readonly] { + background: #f9fafb; + color: #374151; + font-size: 13px; +} + +.checkbox-label { + display: flex; + align-items: center; + gap: 8px; + margin: 4px 0 10px; + font-size: 14px; + color: #374151; +} + +.checkbox-label input, +.form-panel input[type="checkbox"] { + width: auto !important; + margin: 0 !important; + padding: 0 !important; +} + +.range-label { + display: block; + margin: 2px 0 6px; + font-size: 13px; + color: #374151; +} + +.form-panel input[type="range"] { + padding: 0; +} + +.btn-group { + display: flex; + gap: 8px; + flex-wrap: wrap; + margin-top: 4px; +} + +button { + padding: 9px 12px; + border: 0; + border-radius: 10px; + background: #0d6efd; + color: #ffffff; + cursor: pointer; + font-size: 14px; + font-weight: 700; +} + +button:hover { + opacity: 0.92; +} + +.btn-secondary { + background: #6c757d !important; +} + +.danger { + background: #dc3545 !important; +} + +.err { + background: #ffe0e0; + color: #9a0000; + padding: 9px; + border-radius: 10px; + font-size: 13px; +} + +/* ========================= + PANEL TABEL DI SIDEBAR + ========================= */ +.table-panel { + max-height: none; + overflow: visible; +} + +.tabs { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 8px; + margin-bottom: 12px; +} + +.tabs button { + width: 100%; + padding: 9px 8px; + font-size: 13px; +} + +.table-panel h3 { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + margin-bottom: 10px; +} + +.table-panel h3 a { + background: #0d6efd; + color: #ffffff; + font-size: 12px; + padding: 7px 9px; +} + +.table-wrap { + width: 100%; + max-height: 260px; + overflow: auto; + border: 1px solid #e5e7eb; + border-radius: 12px; + background: #ffffff; +} + +table { + width: 100%; + min-width: 620px; + border-collapse: collapse; + font-size: 12px; + background: #ffffff; +} + +th, +td { + border-bottom: 1px solid #e5e7eb; + padding: 8px; + text-align: left; + vertical-align: top; +} + +th { + position: sticky; + top: 0; + z-index: 1; + background: #f3f5f7; + color: #111827; + font-weight: 700; +} + +td { + color: #374151; +} + +td button { + padding: 6px 8px; + font-size: 12px; + margin: 2px; +} + +.inline-form { + display: grid; + grid-template-columns: 1fr; + gap: 8px; + margin-bottom: 12px; +} + +.inline-form input, +.inline-form select { + margin: 0; +} + +.inline-form button { + width: fit-content; +} + +/* ========================= + LEAFLET CUSTOM + ========================= */ +.leaflet-control-layers { + margin-top: 12px !important; + border-radius: 12px !important; + box-shadow: 0 4px 18px rgba(0, 0, 0, 0.16) !important; + overflow: hidden; +} + +.leaflet-popup-content { + font-size: 13px; + line-height: 1.4; +} + +.leaflet-popup-content button { + font-size: 12px; + padding: 6px 8px; + margin: 5px 4px 0 0; +} + +.leaflet-div-icon, +.svg-map-icon { + background: transparent; + border: none; +} + +.svg-marker { + filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.35)); +} + +/* ========================= + RESPONSIVE + ========================= */ +@media (max-width: 900px) { + html, + body { + overflow: auto; + } + + .app-shell { + min-height: 100vh; + height: auto; + grid-template-columns: 1fr; + } + + .sidebar { + height: auto; + max-height: none; + overflow: visible; + border-right: 0; + border-bottom: 1px solid #e5e7eb; + padding: 12px; + } + + .map-area { + height: 72vh; + min-height: 520px; + } + + .table-wrap { + max-height: 220px; + } +} + +@media (max-width: 520px) { + .tabs, + .mini-legend { + grid-template-columns: 1fr; + } + + .topbar b { + font-size: 16px; + } + + table { + min-width: 560px; + } +} + + +/* ========================= + PANEL ALUR & DOWNLOAD + ========================= */ +.alur-panel { + width: 100%; + background: #f8fafc; + border: 1px solid #e5e7eb; + border-radius: 16px; + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.05); + padding: 14px; +} + +.alur-panel b { + display: block; + margin-bottom: 8px; + color: #111827; + font-size: 15px; +} + +.alur-panel ol { + margin: 0; + padding-left: 18px; + color: #374151; + font-size: 12px; + line-height: 1.5; +} + +.alur-panel li { + margin-bottom: 6px; +} + +.info-note { + margin: 0 0 10px; + padding: 10px; + background: #eef6ff; + border: 1px solid #bfdbfe; + border-radius: 10px; + color: #1e3a8a; + font-size: 12px; + line-height: 1.45; +} + +.download-grid { + display: grid; + grid-template-columns: 1fr; + gap: 8px; +} + +.download-grid a { + display: flex; + align-items: center; + justify-content: center; + background: #0d6efd; + color: #ffffff; + text-decoration: none; + border-radius: 10px; + padding: 10px; + font-size: 13px; + font-weight: 700; +} + +.download-grid a:hover { + opacity: 0.92; +} + +.tabs { + grid-template-columns: repeat(2, 1fr); +} + +/* ========================= + DASHBOARD TERPISAH + ========================= */ +.topbar-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; +} + +.dashboard-link-panel { + width: 100%; + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 16px; + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08); + padding: 14px; +} + +.dashboard-link-panel b { + display: block; + margin-bottom: 6px; + color: #111827; + font-size: 16px; +} + +.dashboard-link-panel p { + margin: 0 0 12px; + color: #4b5563; + font-size: 13px; + line-height: 1.45; +} + +.dashboard-link-panel a, +.dashboard-header-actions a, +.small-action { + display: inline-flex; + align-items: center; + justify-content: center; + background: #0d6efd; + color: #ffffff; + text-decoration: none; + border-radius: 10px; + padding: 9px 12px; + font-size: 13px; + font-weight: 700; +} + +.dashboard-body { + overflow: auto; + min-height: 100vh; + background: #f3f4f6; +} + +.dashboard-shell { + width: min(1500px, calc(100% - 32px)); + margin: 16px auto 28px; + display: flex; + flex-direction: column; + gap: 16px; +} + +.dashboard-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + background: linear-gradient(135deg, #0d6efd, #0b5ed7); + color: #ffffff; + border-radius: 18px; + padding: 20px; + box-shadow: 0 10px 26px rgba(15, 23, 42, 0.14); +} + +.dashboard-header h1 { + margin: 0 0 6px; + font-size: 24px; + line-height: 1.2; +} + +.dashboard-header p { + margin: 0; + color: rgba(255, 255, 255, 0.92); + font-size: 14px; +} + +.dashboard-header-actions { + display: flex; + flex-wrap: wrap; + gap: 10px; + justify-content: flex-end; +} + +.dashboard-header-actions a { + background: #ffffff; + color: #0d6efd; +} + +.dashboard-note { + padding: 13px 15px; + background: #eef6ff; + border: 1px solid #bfdbfe; + color: #1e3a8a; + border-radius: 14px; + font-size: 14px; + line-height: 1.45; +} + +.stat-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 12px; +} + +.stat-card { + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 16px; + padding: 15px; + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.07); +} + +.stat-card span { + display: block; + color: #4b5563; + font-size: 13px; + margin-bottom: 8px; +} + +.stat-card b { + display: block; + color: #111827; + font-size: 24px; + line-height: 1.15; + margin-bottom: 4px; +} + +.stat-card small { + color: #6b7280; + font-size: 12px; +} + +.dashboard-card { + background: #ffffff; + border: 1px solid #e5e7eb; + border-radius: 18px; + padding: 16px; + box-shadow: 0 8px 24px rgba(15, 23, 42, 0.08); +} + +.dashboard-card h2 { + margin: 0 0 6px; + color: #111827; + font-size: 20px; + line-height: 1.25; +} + +.section-title-row { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 12px; + margin-bottom: 12px; +} + +.section-subtitle { + margin: 0; + color: #4b5563; + font-size: 13px; + line-height: 1.45; +} + +.dashboard-table-wrap { + width: 100%; + overflow: auto; + border: 1px solid #e5e7eb; + border-radius: 14px; + background: #ffffff; +} + +.dashboard-table { + width: 100%; + min-width: 980px; + border-collapse: collapse; + font-size: 13px; +} + +.dashboard-table.wide-table { + min-width: 1320px; +} + +.dashboard-table th, +.dashboard-table td { + padding: 10px; + border-bottom: 1px solid #e5e7eb; + vertical-align: top; + text-align: left; +} + +.dashboard-table th { + position: sticky; + top: 0; + z-index: 2; + background: #1f3f6f; + color: #ffffff; + font-weight: 700; +} + +.dashboard-table td { + color: #374151; +} + +.dashboard-table select, +.dashboard-inline-form input, +.dashboard-inline-form select { + width: 100%; + padding: 9px 10px; + border: 1px solid #d1d5db; + border-radius: 10px; + background: #ffffff; + color: #111827; + font-size: 13px; +} + +.dashboard-table button, +.dashboard-inline-form button { + padding: 8px 10px; + border-radius: 9px; + font-size: 12px; + margin: 2px 2px 2px 0; +} + +.dashboard-inline-form { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 10px; + margin-bottom: 14px; + padding: 12px; + background: #f8fafc; + border: 1px solid #e5e7eb; + border-radius: 14px; +} + +.dashboard-download-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +@media (max-width: 1100px) { + .stat-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .dashboard-inline-form, + .dashboard-download-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 640px) { + .dashboard-shell { + width: calc(100% - 20px); + margin: 10px auto 20px; + } + + .dashboard-header, + .section-title-row { + flex-direction: column; + align-items: stretch; + } + + .dashboard-header h1 { + font-size: 19px; + } + + .stat-grid, + .dashboard-inline-form, + .dashboard-download-grid { + grid-template-columns: 1fr; + } +} + +/* ========================= + DASHBOARD TOMBOL PER TABEL - FINAL + ========================= */ +.dashboard-shell-wide { + max-width: 1440px; +} + +.dashboard-summary-card { + background: #ffffff; +} + +.compact-stat-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +.stat-card.important { + border-color: #bfdbfe; + background: #eff6ff; +} + +.dashboard-menu-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; + margin-top: 14px; +} + +.dashboard-menu-btn { + width: 100%; + min-height: 46px; + border-radius: 12px; + background: #0d6efd; + color: #ffffff; + font-size: 14px; + font-weight: 800; + box-shadow: 0 4px 12px rgba(13, 110, 253, 0.16); +} + +.dashboard-menu-btn.active { + background: #0b5ed7; + box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.18); +} + +.dashboard-section.hidden { + display: none !important; +} + +.dashboard-section { + scroll-margin-top: 18px; +} + +.dashboard-card .small-action { + white-space: nowrap; +} + +@media (max-width: 1100px) { + .compact-stat-grid, + .dashboard-menu-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 640px) { + .compact-stat-grid, + .dashboard-menu-grid { + grid-template-columns: 1fr; + } +} + +/* ========================= + FORM LAPORAN DATA LENGKAP + ========================= */ +.form-note { + margin: 0 0 10px; + padding: 10px; + background: #eef6ff; + border: 1px solid #bfdbfe; + border-radius: 10px; + color: #1e3a8a; + font-size: 12px; + line-height: 1.45; +} + +.form-divider { + border: 0; + border-top: 1px solid #e5e7eb; + margin: 10px 0 12px; +} + +.form-subtitle { + display: block; + margin: 0 0 9px; + color: #111827; + font-size: 14px; +} + +.dashboard-table small { + color: #6b7280; + line-height: 1.4; +} + +/* ========================= + LINK LAPORAN KE DATA MASYARAKAT EXISTING + ========================= */ +.mini-link-box { + display: grid; + grid-template-columns: minmax(170px, 1fr) auto; + gap: 6px; + margin: 6px 0; + align-items: center; +} + +.mini-link-box select { + min-width: 170px; + margin: 0; + padding: 7px 8px; + font-size: 12px; +} + +.mini-link-box button { + margin: 0; + padding: 7px 8px; + font-size: 12px; +} + +@media (max-width: 640px) { + .mini-link-box { + grid-template-columns: 1fr; + } +} + + +.match-note { + margin: 6px 0; + padding: 7px 8px; + border-radius: 10px; + background: #ecfdf5; + border: 1px solid #bbf7d0; + color: #166534; + font-size: 12px; + line-height: 1.35; +} + +.match-note.muted { + background: #f8fafc; + border-color: #e5e7eb; + color: #4b5563; +} + +.match-note.success { + background: #ecfdf3; + border: 1px solid #bbf7d0; + color: #166534; +} + +/* ========================= + DATA PETA PENDUKUNG DI HALAMAN INDEX + ========================= */ +.map-support-panel { + max-height: none; +} + +.support-tabs button.active, +.dashboard-menu-btn.active { + background: #0b5ed7; + color: #ffffff; + box-shadow: inset 0 0 0 2px rgba(255,255,255,0.18); +} + +.support-header-row { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; + margin: 8px 0 10px; +} + +.support-header-row b { + color: #111827; + font-size: 14px; +} + +.support-header-row a { + background: #0d6efd; + color: #ffffff; + font-size: 12px; + padding: 7px 9px; +} + +.support-note { + margin: 0 0 10px; + font-size: 12px; + line-height: 1.45; + color: #4b5563; +} + +.support-table-wrap { + max-height: 240px; +} + +.support-table-wrap table { + min-width: 520px; +} + + +/* ========================================================= + FINAL LANDING MAP LAYOUT + Letakkan blok ini PALING BAWAH style.css. + Tujuan: header di atas, map tampil besar di tengah, footer di bawah. + ========================================================= */ + +html, +body { + width: 100% !important; + min-height: 100% !important; + height: auto !important; + margin: 0 !important; + padding: 0 !important; + overflow: auto !important; + background: #eef4ff !important; + font-family: Arial, sans-serif !important; +} + +.public-map-body { + background: #eef4ff !important; +} + +.public-page { + min-height: 100vh; + display: flex; + flex-direction: column; + background: + radial-gradient(circle at top left, rgba(37, 99, 235, 0.18), transparent 35%), + linear-gradient(180deg, #eff6ff 0%, #f8fafc 55%, #eaf1ff 100%); +} + +.public-header { + width: 100%; + padding: 18px 20px 14px; +} + +.public-header-inner { + width: 100%; + max-width: none; + margin: 0; + display: flex; + align-items: center; + justify-content: space-between; + gap: 22px; + background: linear-gradient(135deg, #1e3a8a, #2563eb); + color: #ffffff; + border-radius: 26px; + padding: 28px; + box-shadow: 0 20px 42px rgba(30, 64, 175, 0.28); +} + +.eyebrow { + margin: 0 0 8px; + letter-spacing: 0.08em; + text-transform: uppercase; + font-size: 12px; + font-weight: 800; + color: rgba(255, 255, 255, 0.8); +} + +.public-header h1 { + margin: 0; + font-size: clamp(28px, 4vw, 44px); + line-height: 1.08; +} + +.public-header .subtitle { + max-width: 760px; + margin: 12px 0 0; + color: rgba(255, 255, 255, 0.9); + font-size: 15px; + line-height: 1.6; +} + +.user-status { + display: inline-flex; + width: fit-content; + margin: 14px 0 0; + padding: 8px 12px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.15); + color: rgba(255, 255, 255, 0.96); + font-size: 13px; + font-weight: 700; +} + +.header-actions { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: flex-end; + gap: 10px; +} + +.header-actions a, +.header-actions button { + display: inline-flex; + align-items: center; + justify-content: center; + background: #ffffff; + color: #1d4ed8; + border: 0; + border-radius: 12px; + padding: 10px 14px; + font-size: 14px; + font-weight: 800; + text-decoration: none; + cursor: pointer; + white-space: nowrap; + box-shadow: 0 8px 20px rgba(15, 23, 42, 0.16); +} + +.public-main { + flex: 1; + width: 100%; + max-width: none; + margin: 0; + padding: 0 20px 20px; +} + +.map-card { + width: 100%; + background: rgba(255, 255, 255, 0.96); + border: 1px solid #dbeafe; + border-radius: 24px; + padding: 18px; + box-shadow: 0 18px 42px rgba(30, 64, 175, 0.16); +} + +.map-card-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 18px; + padding: 4px 4px 16px; +} + +.map-card-header h2 { + margin: 0 0 6px; + color: #1e3a8a; + font-size: 24px; + line-height: 1.2; +} + +.map-card-header p { + margin: 0; + color: #475569; + font-size: 14px; + line-height: 1.5; +} + +.map-card-header .mini-legend { + margin: 0; + width: fit-content; + min-width: 250px; + background: #eff6ff; + border: 1px solid #bfdbfe; + border-radius: 16px; + padding: 12px; +} + +.control-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + gap: 12px; + margin-bottom: 16px; +} + +.control-grid .mode-panel, +.control-grid .form-panel, +.control-grid .login-box, +.control-grid .dashboard-link-panel { + position: static !important; + width: 100% !important; + max-height: none !important; + overflow: visible !important; + background: #ffffff !important; + border: 1px solid #dbeafe !important; + border-radius: 18px !important; + box-shadow: 0 10px 28px rgba(15, 23, 42, 0.10) !important; + padding: 14px !important; +} + +.control-grid .mode-panel b, +.control-grid .form-panel h3, +.control-grid .login-box h3, +.control-grid .dashboard-link-panel b { + color: #1e3a8a !important; +} + +.control-grid .mode-panel select, +.control-grid .form-panel input, +.control-grid .form-panel select, +.control-grid .form-panel textarea, +.control-grid .login-box input { + width: 100% !important; + border-color: #cbd5e1 !important; + border-radius: 12px !important; +} + +.map-area { + position: relative !important; + display: block !important; + width: 100% !important; + height: 78vh !important; + min-height: 680px !important; + max-height: none !important; + padding: 0 !important; + margin: 0 !important; + overflow: hidden !important; + border: 1px solid #bfdbfe !important; + border-radius: 22px !important; + background: #dbeafe !important; + box-shadow: inset 0 0 0 1px rgba(255,255,255,0.45) !important; +} + +#map { + display: block !important; + position: relative !important; + width: 100% !important; + height: 100% !important; + min-height: 680px !important; + z-index: 1 !important; + background: #dbeafe !important; +} + +.leaflet-container { + width: 100% !important; + height: 100% !important; + min-height: 680px !important; + font-family: Arial, sans-serif !important; +} + +button, +.dashboard-link-panel a, +.download-grid a, +.dashboard-menu-btn, +.small-action { + background: #2563eb; +} + +button:hover, +.dashboard-link-panel a:hover, +.download-grid a:hover, +.dashboard-menu-btn:hover, +.small-action:hover { + background: #1d4ed8; + opacity: 1; +} + +.btn-secondary { + background: #64748b !important; +} + +.danger { + background: #dc2626 !important; +} + +.public-footer { + width: calc(100% - 40px); + max-width: none; + margin: 0 20px 22px; + display: flex; + align-items: center; + justify-content: space-between; + gap: 14px; + background: #ffffff; + border: 1px solid #dbeafe; + border-radius: 20px; + padding: 16px 20px; + color: #475569; + box-shadow: 0 10px 28px rgba(30, 64, 175, 0.10); +} + +.public-footer b { + color: #1e3a8a; +} + +.public-footer span { + font-size: 13px; + text-align: right; +} + +@media (max-width: 900px) { + .public-header { + padding: 14px 0 12px; + } + + .public-header-inner { + width: calc(100% - 20px); + flex-direction: column; + align-items: flex-start; + border-radius: 22px; + padding: 22px; + } + + .header-actions { + justify-content: flex-start; + } + + .public-main { + width: 100%; + padding: 0 10px 16px; + } + + .public-footer { + width: calc(100% - 20px); + margin: 0 10px 18px; + } + + .map-card-header { + flex-direction: column; + } + + .map-card-header .mini-legend { + width: 100%; + min-width: 0; + } + + .map-area, + #map, + .leaflet-container { + height: 70vh !important; + min-height: 520px !important; + max-height: none !important; + } + + .public-footer { + flex-direction: column; + align-items: flex-start; + } + + .public-footer span { + text-align: left; + } +} + +@media (max-width: 520px) { + .public-header h1 { + font-size: 27px; + } + + .map-card { + padding: 12px; + border-radius: 20px; + } + + .map-area, + #map, + .leaflet-container { + min-height: 460px !important; + } +} + +/* ========================================================= + FINAL OVERRIDE: MAP KIRI + MODE/FORM KANAN (3/4 : 1/4) + Header dan footer tetap. Logic map/form tidak diubah. + ========================================================= */ + +.public-header-inner { + padding: 30px 34px !important; +} + +.header-actions a, +.header-actions button { + min-width: 108px !important; + min-height: 48px !important; + padding: 13px 22px !important; + border-radius: 14px !important; + font-size: 16px !important; + font-weight: 900 !important; +} + +.map-card { + padding: 18px !important; +} + +.map-card-header { + padding: 4px 4px 16px !important; +} + +.map-layout-grid { + display: grid !important; + grid-template-columns: minmax(0, 3fr) minmax(300px, 1fr) !important; + gap: 16px !important; + align-items: stretch !important; + width: 100% !important; +} + +.map-layout-grid .map-area { + width: 100% !important; + height: 78vh !important; + min-height: 680px !important; + margin: 0 !important; + border-radius: 22px !important; +} + +.map-layout-grid #map, +.map-layout-grid .leaflet-container { + width: 100% !important; + height: 100% !important; + min-height: 680px !important; +} + +.side-control-panel { + width: 100% !important; + height: 78vh !important; + min-height: 680px !important; + overflow-y: auto !important; + overflow-x: hidden !important; + display: flex !important; + flex-direction: column !important; + gap: 14px !important; + padding: 14px !important; + background: #f8fbff !important; + border: 1px solid #bfdbfe !important; + border-radius: 22px !important; + box-shadow: inset 0 0 0 1px rgba(255,255,255,0.55) !important; +} + +.side-control-panel .mode-panel, +.side-control-panel .form-panel, +.side-control-panel .login-box, +.side-control-panel .dashboard-link-panel { + position: static !important; + width: 100% !important; + max-height: none !important; + overflow: visible !important; + margin: 0 !important; + background: #ffffff !important; + border: 1px solid #dbeafe !important; + border-radius: 18px !important; + box-shadow: 0 10px 24px rgba(15, 23, 42, 0.08) !important; + padding: 15px !important; +} + +.side-control-panel .mode-panel b, +.side-control-panel .form-panel h3, +.side-control-panel .login-box h3, +.side-control-panel .dashboard-link-panel b { + color: #1e3a8a !important; + font-size: 16px !important; +} + +.side-control-panel .mode-panel small, +.side-control-panel .dashboard-link-panel p { + color: #475569 !important; + font-size: 12px !important; + line-height: 1.5 !important; +} + +.side-control-panel .mode-panel select, +.side-control-panel .form-panel input, +.side-control-panel .form-panel select, +.side-control-panel .form-panel textarea, +.side-control-panel .login-box input { + width: 100% !important; + border-color: #cbd5e1 !important; + border-radius: 12px !important; +} + +.side-control-panel .form-panel textarea { + min-height: 90px !important; +} + +.side-control-panel .btn-group { + display: flex !important; + flex-wrap: wrap !important; + gap: 8px !important; +} + +.side-control-panel button, +.side-control-panel .dashboard-link-panel a { + padding: 10px 13px !important; + border-radius: 11px !important; + font-size: 13px !important; + font-weight: 800 !important; +} + +@media (max-width: 1100px) { + .map-layout-grid { + grid-template-columns: 1fr !important; + } + + .side-control-panel { + height: auto !important; + min-height: 0 !important; + overflow: visible !important; + } + + .map-layout-grid .map-area, + .map-layout-grid #map, + .map-layout-grid .leaflet-container { + height: 70vh !important; + min-height: 560px !important; + } +} + +@media (max-width: 640px) { + .header-actions a, + .header-actions button { + min-width: 96px !important; + min-height: 44px !important; + padding: 11px 18px !important; + font-size: 15px !important; + } + + .map-layout-grid .map-area, + .map-layout-grid #map, + .map-layout-grid .leaflet-container { + min-height: 480px !important; + } +} + + +.public-header { + padding: 10px 20px 8px !important; +} + +.public-header-inner { + padding: 16px 24px !important; + border-radius: 20px !important; + gap: 16px !important; + box-shadow: 0 12px 28px rgba(30, 64, 175, 0.22) !important; +} + +.eyebrow { + margin: 0 0 5px !important; + font-size: 10px !important; + letter-spacing: 0.08em !important; +} + +.public-header h1 { + font-size: clamp(26px, 3vw, 34px) !important; + line-height: 1.1 !important; + margin: 0 !important; +} + +.public-header .subtitle { + margin: 7px 0 0 !important; + font-size: 13px !important; + line-height: 1.4 !important; + max-width: 760px !important; +} + +.user-status { + margin: 9px 0 0 !important; + padding: 6px 10px !important; + font-size: 12px !important; +} + +/* Tombol Login tetap agak besar, tapi tidak terlalu kebesaran */ +.header-actions a, +.header-actions button { + min-width: 100px !important; + min-height: 42px !important; + padding: 10px 18px !important; + border-radius: 12px !important; + font-size: 15px !important; + font-weight: 900 !important; +} + +/* Jarak bawah header ke card map dibuat lebih rapat */ +.public-main { + padding-top: 4px !important; +} + +/* Responsive */ +@media (max-width: 900px) { + .public-header { + padding: 8px 10px 8px !important; + } + + .public-header-inner { + padding: 15px 18px !important; + border-radius: 18px !important; + } + + .public-header h1 { + font-size: 26px !important; + } + + .public-header .subtitle { + font-size: 12px !important; + } + + .header-actions a, + .header-actions button { + min-width: 92px !important; + min-height: 40px !important; + padding: 9px 15px !important; + font-size: 14px !important; + } +} \ No newline at end of file diff --git a/CARA_PAKAI_ENV_DAN_GITIGNORE.md b/CARA_PAKAI_ENV_DAN_GITIGNORE.md new file mode 100644 index 0000000..468ec97 --- /dev/null +++ b/CARA_PAKAI_ENV_DAN_GITIGNORE.md @@ -0,0 +1,86 @@ +# Cara Pakai File Environment dan Git Ignore + +## 1. File yang perlu diletakkan di folder project utama + +Letakkan file berikut di folder utama repo: + +- `.gitignore` +- `.env.example` + +File `.env.example` boleh dipush ke Git karena tidak berisi password asli. + +## 2. Buat file `.env` untuk lokal + +Copy file `.env.example`, lalu rename menjadi: + +```text +.env +``` + +Isi sesuai database lokal kamu, misalnya: + +```env +DB_HOST=127.0.0.1 +DB_USER=root +DB_PASS=password_mysql_lokal_kamu +DB_NAME=sig +DB_PORT=3306 +``` + +File `.env` jangan dipush ke Git karena sudah masuk `.gitignore`. + +## 3. Untuk Coolify + +Di Coolify, isi Environment Variables: + +```env +DB_HOST=host_database_dari_coolify +DB_USER=user_database_dari_coolify +DB_PASS=password_database_dari_coolify +DB_NAME=nama_database_dari_coolify +DB_PORT=3306 +``` + +## 4. Kalau PHP kamu belum otomatis membaca `.env` + +Tambahkan file `env.php` ke folder `3_PovertyMapping/`. + +Lalu di bagian paling atas `index.php`, sebelum koneksi database, tambahkan: + +```php +require_once __DIR__ . '/env.php'; + +$host = env('DB_HOST', '127.0.0.1'); +$user = env('DB_USER', 'root'); +$pass = env('DB_PASS', ''); +$db = env('DB_NAME', 'sig'); +$port = (int) env('DB_PORT', 3306); + +$conn = new mysqli($host, $user, $pass, $db, $port); + +if ($conn->connect_error) { + die("Koneksi database gagal."); +} + +$conn->set_charset("utf8mb4"); +``` + +Lalu hapus koneksi lama yang masih berisi password hardcode. + +## 5. Yang aman dipush + +Boleh dipush: + +- `.gitignore` +- `.env.example` +- `README.md` +- folder project +- SQL final jika tidak berisi password + +Jangan dipush: + +- `.env` +- ZIP +- `__MACOSX` +- `.DS_Store` +- file yang berisi password asli diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4564687 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM php:8.2-apache + +RUN apt-get update \ + && apt-get install -y default-mysql-client \ + && docker-php-ext-install mysqli \ + && a2enmod rewrite \ + && rm -rf /var/lib/apt/lists/* + +COPY . /var/www/html/ + +RUN chown -R www-data:www-data /var/www/html + +EXPOSE 80 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..69616aa --- /dev/null +++ b/README.md @@ -0,0 +1,410 @@ +# WebGIS Poverty Mapping Kota Pontianak + +## Informasi Proyek + +| Keterangan | Detail | +|---|---| +| Nama Proyek | WebGIS Poverty Mapping Kota Pontianak | +| Jenis Sistem | Sistem Informasi Geografis berbasis Web | +| Mata Kuliah | Sistem Informasi Geografis (SIG) | +| Program Studi | Informatika, Fakultas Teknik, Universitas Tanjungpura | +| Pengembang | Talitha Syakirah Artanti | +| NIM | D1041231013 | +| Dosen Pengampu | Dr. Ir. Yus Sholva, ST., MT., CPro. | + +## Deskripsi Singkat + +WebGIS Poverty Mapping Kota Pontianak adalah aplikasi Sistem Informasi Geografis berbasis web yang digunakan untuk memetakan data masyarakat prasejahtera, laporan cepat masyarakat, histori bantuan, serta data rumah ibadah sebagai potensi pendukung penyaluran bantuan sosial. + +Sistem ini dikembangkan menggunakan PHP native, MySQL, JavaScript, Leaflet.js, dan OpenStreetMap. Fokus utama aplikasi adalah membantu visualisasi persebaran masyarakat prasejahtera di Kota Pontianak, memantau laporan masyarakat, mencatat histori bantuan, serta menampilkan rumah ibadah dalam bentuk titik lokasi dan radius jangkauan. + +## Tujuan Sistem + +Tujuan dari sistem ini adalah: + +1. Menampilkan persebaran masyarakat prasejahtera pada peta digital. +2. Menyediakan fitur laporan cepat dari masyarakat umum. +3. Membantu admin dalam memvalidasi dan mengelola laporan masyarakat. +4. Mencatat histori bantuan yang diterima masyarakat prasejahtera. +5. Menampilkan rumah ibadah sebagai potensi pemberi atau pendukung bantuan. +6. Menyediakan dashboard ringkasan bagi admin, wali kota, dan dinas terkait. +7. Menyediakan fitur unduh data dalam format CSV untuk kebutuhan monitoring. + +## Struktur Folder + +```text +UAS_SIG_Talitha/ +├── 1_Pemetaan_SPBU/ +├── 2_Jalan_ParsilTanah_dan_Layer/ +├── 3_PovertyMapping/ +├── env.php +├── .env.example +├── .gitignore +└── README.md +``` + +Keterangan: + +- `1_Pemetaan_SPBU/` berisi pengembangan awal WebGIS untuk pemetaan SPBU. +- `2_Jalan_ParsilTanah_dan_Layer/` berisi pengembangan awal WebGIS untuk data jalan, parsil tanah, dan layer peta. +- `3_PovertyMapping/` merupakan aplikasi utama/final yang digunakan untuk sistem WebGIS Poverty Mapping Kota Pontianak. +- `env.php` digunakan untuk membaca konfigurasi database dari environment variable. +- `.env.example` berisi contoh konfigurasi environment. +- `.gitignore` digunakan untuk mencegah file sensitif dan file tidak diperlukan masuk ke repository. +- `README.md` berisi dokumentasi proyek. + +## Fokus Aplikasi Final + +Aplikasi final berada pada folder: + +```text +3_PovertyMapping/ +``` + +Aplikasi ini tidak lagi menampilkan data SPBU, jalan, dan parsil tanah sebagai fitur utama. Folder SPBU dan jalan/parsil tetap disertakan sebagai bagian dari riwayat pengembangan tugas, tetapi sistem final yang digunakan untuk penilaian adalah Poverty Mapping. + +## Fitur Utama + +### 1. Peta Digital + +Sistem menampilkan peta digital Kota Pontianak menggunakan Leaflet.js dan OpenStreetMap sebagai basemap. Peta digunakan untuk menampilkan titik masyarakat prasejahtera, titik laporan masyarakat, dan titik rumah ibadah. + +### 2. Data Masyarakat Prasejahtera + +Admin dapat mengelola data masyarakat prasejahtera, meliputi: + +- nama kepala keluarga; +- NIK; +- tanggal lahir; +- pendidikan; +- riwayat penyakit; +- jumlah KK; +- alamat; +- kecamatan; +- kelurahan; +- status bantuan; +- latitude dan longitude. + +Data masyarakat prasejahtera ditampilkan dalam bentuk marker pada peta dan tabel pada dashboard. + +### 3. Laporan Cepat Masyarakat + +Masyarakat umum dapat mengirim laporan tanpa login melalui peta. Data laporan meliputi data pelapor, kategori laporan, tujuan laporan, deskripsi, data warga yang dilaporkan, serta titik lokasi. + +Status laporan terdiri dari: + +- `Masuk` +- `Ditinjau` +- `Diproses` +- `Selesai` +- `Dijadikan Data Masyarakat` +- `Ditolak` + +Laporan hanya dapat dijadikan data masyarakat prasejahtera setelah statusnya menjadi `Selesai`. + +### 4. Auto Terhubung NIK/Nama + +Sistem memiliki logika pencocokan otomatis berdasarkan NIK atau nama kepala keluarga. Jika laporan masyarakat memiliki NIK atau nama yang sama dengan data masyarakat prasejahtera yang sudah ada, sistem dapat menghubungkan laporan tersebut ke data lama agar tidak terjadi data ganda. + +### 5. Histori Bantuan + +Sistem mencatat histori bantuan yang diterima masyarakat prasejahtera. Data histori bantuan meliputi: + +- penerima bantuan; +- jenis bantuan; +- tanggal bantuan; +- nominal bantuan; +- sumber bantuan; +- keterangan. + +Histori bantuan dapat ditambahkan lebih dari satu kali untuk satu masyarakat prasejahtera, sehingga riwayat bantuan dapat dipantau secara berkala. + +### 6. Rumah Ibadah + +Sistem menampilkan data rumah ibadah sebagai titik lokasi dan radius jangkauan. Rumah ibadah dapat berupa: + +- Masjid; +- Gereja; +- Vihara; +- Kelenteng; +- Pura. + +Data rumah ibadah digunakan sebagai indikator potensi pendukung bantuan sosial. Radius rumah ibadah tidak otomatis berarti masyarakat menerima bantuan, tetapi menjadi acuan spasial untuk melihat potensi jangkauan bantuan. + +### 7. Relasi Bantuan dengan Rumah Ibadah + +Dalam pengembangan terbaru, histori bantuan dapat dikembangkan agar memiliki relasi dengan rumah ibadah tertentu melalui kolom `masjid_id`. Dengan relasi ini, sistem dapat mencatat bahwa suatu masyarakat prasejahtera menerima bantuan dari rumah ibadah tertentu. + +Konsep relasinya adalah: + +```text +penduduk_id = masyarakat penerima bantuan +masjid_id = rumah ibadah pemberi bantuan +``` + +Jika bantuan berasal dari dinas atau sumber lain, maka `masjid_id` dapat dikosongkan. Jika bantuan berasal dari rumah ibadah, maka `masjid_id` diisi sesuai rumah ibadah pemberi bantuan. + +### 8. Dashboard + +Dashboard digunakan oleh pengguna yang memiliki akses login, yaitu admin, wali kota, dan dinas. Dashboard menampilkan: + +- ringkasan jumlah masyarakat prasejahtera; +- jumlah laporan masuk, diproses, selesai, dan dijadikan data masyarakat; +- jumlah histori bantuan; +- jumlah rumah ibadah; +- tabel laporan masyarakat; +- tabel histori bantuan; +- tabel masyarakat prasejahtera; +- tabel rumah ibadah; +- fitur download data CSV; +- fitur kelola akun untuk admin. + +### 9. Download Data + +Sistem menyediakan fitur unduh data dalam format CSV untuk data utama, yaitu: + +- laporan masyarakat; +- histori bantuan; +- masyarakat prasejahtera; +- rumah ibadah. + +## Hak Akses Pengguna + +| Role | Hak Akses | +|---|---| +| Masyarakat Umum | Mengirim laporan cepat tanpa login | +| Admin | Mengelola data masyarakat, laporan, histori bantuan, rumah ibadah, akun pengguna, dashboard, dan download data | +| Wali Kota | Melihat dashboard dan mengunduh data | +| Dinas Sosial | Melihat laporan sesuai instansi dan menambahkan histori bantuan sosial | +| Dinas Kesehatan | Melihat laporan sesuai instansi dan menambahkan histori bantuan terkait kesehatan | + +## Alur Sistem + +### Alur Laporan Masyarakat + +1. Masyarakat membuka halaman peta. +2. Masyarakat memilih lokasi pada peta. +3. Masyarakat mengisi form laporan cepat. +4. Sistem menyimpan laporan dengan status awal `Masuk`. +5. Admin meninjau laporan. +6. Status laporan dapat diubah menjadi `Ditinjau`, `Diproses`, atau `Selesai`. +7. Setelah status `Selesai`, laporan dapat dihubungkan ke data masyarakat lama atau dijadikan data masyarakat baru. +8. Data yang sudah valid masuk ke data masyarakat prasejahtera dan dapat digunakan untuk monitoring bantuan. + +### Alur Histori Bantuan + +1. Admin atau dinas memilih data masyarakat prasejahtera. +2. Admin atau dinas mengisi jenis bantuan, tanggal, nominal, sumber bantuan, dan keterangan. +3. Sistem menyimpan bantuan ke tabel histori bantuan. +4. Data bantuan dapat dilihat pada dashboard dan diunduh dalam format CSV. +5. Jika bantuan berasal dari rumah ibadah, sistem dapat mencatat rumah ibadah pemberi bantuan melalui `masjid_id`. + +### Alur Rumah Ibadah + +1. Admin menambahkan data rumah ibadah pada peta. +2. Sistem menyimpan jenis, nama, PIC, alamat, koordinat, dan radius rumah ibadah. +3. Sistem menampilkan marker dan radius rumah ibadah. +4. Radius digunakan sebagai indikator potensi jangkauan bantuan. + +## Struktur Database Utama + +### Tabel `users` + +Menyimpan data akun pengguna sistem. + +| Kolom | Keterangan | +|---|---| +| id | ID pengguna | +| nama | Nama pengguna | +| username | Username login | +| password | Password terenkripsi | +| role | Role pengguna | +| instansi | Nama instansi untuk role dinas | +| created_at | Waktu data dibuat | + +### Tabel `penduduk_kemiskinan` + +Menyimpan data masyarakat prasejahtera. + +| Kolom | Keterangan | +|---|---| +| id | ID masyarakat | +| nama_kepala_keluarga | Nama kepala keluarga | +| nik | Nomor Induk Kependudukan | +| tanggal_lahir | Tanggal lahir | +| pendidikan | Pendidikan terakhir | +| riwayat_penyakit | Riwayat penyakit | +| jumlah_kk | Jumlah anggota keluarga | +| alamat | Alamat lengkap | +| kecamatan | Kecamatan | +| kelurahan | Kelurahan | +| status_bantuan | Status bantuan | +| latitude | Koordinat latitude | +| longitude | Koordinat longitude | +| created_at | Waktu data dibuat | + +### Tabel `laporan_masyarakat` + +Menyimpan laporan cepat dari masyarakat umum. + +| Kolom | Keterangan | +|---|---| +| id | ID laporan | +| penduduk_id | Relasi ke data masyarakat jika sudah terhubung | +| nama_pelapor | Nama pelapor | +| no_hp | Nomor HP pelapor | +| kategori_laporan | Kategori laporan | +| deskripsi | Deskripsi laporan | +| aktor_tujuan | Tujuan laporan | +| status_laporan | Status laporan | +| data_nama_kepala_keluarga | Nama warga yang dilaporkan | +| data_nik | NIK warga yang dilaporkan | +| data_tanggal_lahir | Tanggal lahir warga | +| data_pendidikan | Pendidikan warga | +| data_riwayat_penyakit | Riwayat penyakit warga | +| data_jumlah_kk | Jumlah anggota keluarga | +| data_alamat | Alamat warga | +| data_kecamatan | Kecamatan | +| data_kelurahan | Kelurahan | +| data_status_bantuan | Status bantuan awal | +| latitude | Koordinat latitude | +| longitude | Koordinat longitude | +| created_at | Waktu laporan dibuat | + +### Tabel `histori_bantuan` + +Menyimpan riwayat bantuan yang diterima masyarakat prasejahtera. + +| Kolom | Keterangan | +|---|---| +| id | ID histori | +| penduduk_id | Relasi ke masyarakat penerima bantuan | +| masjid_id | Relasi ke rumah ibadah pemberi bantuan jika sumber bantuan berasal dari rumah ibadah | +| jenis_bantuan | Jenis bantuan | +| tanggal_bantuan | Tanggal bantuan | +| nominal | Nominal bantuan | +| sumber_bantuan | Sumber bantuan | +| keterangan | Keterangan tambahan | +| created_at | Waktu data dibuat | + +### Tabel `masjid` + +Menyimpan data rumah ibadah. Nama tabel tetap menggunakan `masjid` untuk menyesuaikan struktur kode, tetapi isi tabel dapat memuat berbagai jenis rumah ibadah. + +| Kolom | Keterangan | +|---|---| +| id | ID rumah ibadah | +| jenis_rumah_ibadah | Jenis rumah ibadah | +| nama_masjid | Nama rumah ibadah | +| pic_masjid | PIC atau penanggung jawab | +| alamat_masjid | Alamat rumah ibadah | +| latitude | Koordinat latitude | +| longitude | Koordinat longitude | +| radius_meter | Radius jangkauan | +| created_at | Waktu data dibuat | + +## Teknologi yang Digunakan + +| Teknologi | Fungsi | +|---|---| +| PHP Native | Backend dan pengolahan request | +| MySQL | Penyimpanan data | +| JavaScript | Interaksi antarmuka dan peta | +| Leaflet.js | Library peta interaktif | +| OpenStreetMap | Basemap | +| HTML | Struktur halaman | +| CSS | Tampilan antarmuka | +| Git | Version control | +| Coolify | Platform deployment aplikasi | + +## Konfigurasi Environment + +Project menggunakan file environment agar konfigurasi database tidak ditulis langsung di kode. + +Contoh isi `.env.example`: + +```env +DB_HOST=127.0.0.1 +DB_USER=root +DB_PASS= +DB_NAME=sig +DB_PORT=3306 +``` + +File `.env` digunakan untuk konfigurasi lokal dan tidak boleh diunggah ke repository Git. + +## File yang Tidak Diunggah ke Git + +File berikut tidak perlu diunggah ke repository: + +```text +.env +.env.* +!.env.example +.DS_Store +__MACOSX/ +*.zip +``` + +Tujuannya adalah agar password database, file sistem Mac, dan file arsip tidak masuk ke repository. + +## Cara Menjalankan di Localhost + +1. Letakkan folder project pada direktori web server, misalnya `htdocs`. +2. Buat database MySQL dengan nama `sig`. +3. Import file SQL database yang tersedia. +4. Salin `.env.example` menjadi `.env`. +5. Sesuaikan konfigurasi database pada file `.env`. +6. Jalankan Apache dan MySQL. +7. Akses aplikasi melalui browser. + +Contoh alamat akses: + +```text +http://localhost/UAS_SIG_Talitha/3_PovertyMapping/ +``` + +## Cara Deploy ke Coolify + +1. Push project ke repository Git. +2. Pastikan file `.env` tidak ikut terunggah. +3. Buat aplikasi baru di Coolify dari repository Git. +4. Arahkan deployment ke folder `3_PovertyMapping`. +5. Buat database MySQL pada Coolify. +6. Import file SQL database. +7. Isi Environment Variables pada Coolify: + +```env +DB_HOST=host_database +DB_USER=user_database +DB_PASS=password_database +DB_NAME=nama_database +DB_PORT=3306 +``` + +8. Jalankan deploy aplikasi. +9. Akses aplikasi melalui domain yang diberikan oleh Coolify. + +## Catatan Keamanan + +1. Password pengguna disimpan dalam bentuk hash. +2. File `.env` tidak diunggah ke repository. +3. Query database menggunakan prepared statement pada proses utama. +4. Hak akses dibedakan berdasarkan role pengguna. +5. Data masyarakat prasejahtera hanya digunakan untuk kebutuhan pemetaan dan monitoring bantuan. + +## Catatan Pengembangan + +Sistem ini dikembangkan untuk kebutuhan tugas mata kuliah Sistem Informasi Geografis. Aplikasi masih dapat dikembangkan lebih lanjut, seperti: + +- penambahan filter berdasarkan kecamatan atau kelurahan; +- integrasi laporan PDF; +- analisis spasial lebih lanjut; +- notifikasi tindak lanjut laporan; +- validasi data kependudukan yang lebih lengkap; +- visualisasi bantuan berdasarkan sumber bantuan; +- relasi histori bantuan dengan rumah ibadah secara penuh melalui `masjid_id`. + +## Kesimpulan + +WebGIS Poverty Mapping Kota Pontianak merupakan aplikasi pemetaan berbasis web yang membantu visualisasi data masyarakat prasejahtera, laporan masyarakat, histori bantuan, dan rumah ibadah. Sistem ini mendukung proses monitoring bantuan melalui peta digital, dashboard, role pengguna, dan data yang dapat diunduh. Dengan adanya fitur laporan cepat dan histori bantuan, sistem dapat menjadi media pendukung dalam pengelolaan data sosial masyarakat prasejahtera di Kota Pontianak. diff --git a/database/sig.sql b/database/sig.sql new file mode 100644 index 0000000..7ea8532 --- /dev/null +++ b/database/sig.sql @@ -0,0 +1,300 @@ +-- MySQL dump 10.13 Distrib 8.0.46, for macos15 (arm64) +-- +-- Host: localhost Database: sig +-- ------------------------------------------------------ +-- Server version 8.0.46 + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- +-- Table structure for table `histori_bantuan` +-- + +DROP TABLE IF EXISTS `histori_bantuan`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `histori_bantuan` ( + `id` int NOT NULL AUTO_INCREMENT, + `penduduk_id` int NOT NULL, + `masjid_id` int DEFAULT NULL, + `jenis_bantuan` varchar(150) NOT NULL, + `tanggal_bantuan` date NOT NULL, + `nominal` decimal(14,2) NOT NULL DEFAULT '0.00', + `sumber_bantuan` varchar(150) NOT NULL DEFAULT 'Pemkot Pontianak / Dinas / Rumah Ibadah / Donatur', + `keterangan` text, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `fk_histori_bantuan_penduduk` (`penduduk_id`), + KEY `fk_histori_bantuan_masjid` (`masjid_id`), + CONSTRAINT `fk_histori_bantuan_masjid` FOREIGN KEY (`masjid_id`) REFERENCES `masjid` (`id`) ON DELETE SET NULL ON UPDATE CASCADE, + CONSTRAINT `fk_histori_bantuan_penduduk` FOREIGN KEY (`penduduk_id`) REFERENCES `penduduk_kemiskinan` (`id`) ON DELETE CASCADE ON UPDATE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `histori_bantuan` +-- + +LOCK TABLES `histori_bantuan` WRITE; +/*!40000 ALTER TABLE `histori_bantuan` DISABLE KEYS */; +INSERT INTO `histori_bantuan` VALUES (1,1,1,'Sembako','2026-06-07',100000.00,'Pemkot Pontianak / Rumah Ibadah / Donatur','Bantuan sembako tahap pertama','2026-06-09 07:25:39','2026-06-09 07:25:39'),(2,1,1,'Sembako','2026-06-09',100000.00,'Pemkot Pontianak / Rumah Ibadah / Donatur','Bantuan sembako tahap kedua','2026-06-09 07:26:05','2026-06-09 07:26:05'); +/*!40000 ALTER TABLE `histori_bantuan` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `jalan` +-- + +DROP TABLE IF EXISTS `jalan`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `jalan` ( + `id` int NOT NULL AUTO_INCREMENT, + `nama_jalan` varchar(150) NOT NULL, + `status_jalan` enum('Jalan Nasional','Jalan Provinsi','Jalan Kabupaten') NOT NULL, + `panjang_meter` double NOT NULL DEFAULT '0', + `geojson` longtext NOT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `jalan` +-- + +LOCK TABLES `jalan` WRITE; +/*!40000 ALTER TABLE `jalan` DISABLE KEYS */; +INSERT INTO `jalan` VALUES (3,'JALAN Pontianak','Jalan Nasional',50952.09,'{\"type\":\"LineString\",\"coordinates\":[[109.409494,-0.1436],[109.408743,-0.142956],[109.407606,-0.142312],[109.407885,-0.141712],[109.407949,-0.138407],[109.407799,-0.134952],[109.40752,-0.133707],[109.406576,-0.132059],[109.404817,-0.129441],[109.403014,-0.127552],[109.401598,-0.125278],[109.399924,-0.123131],[109.397435,-0.120857],[109.395032,-0.118539],[109.393058,-0.116264],[109.391513,-0.112873],[109.390483,-0.110813],[109.389067,-0.10768],[109.387608,-0.105234],[109.385848,-0.102616],[109.38396,-0.100985],[109.380612,-0.098109],[109.373875,-0.091843],[109.371343,-0.08931],[109.369712,-0.087208],[109.368467,-0.083602],[109.36718,-0.079182],[109.366579,-0.078323],[109.366665,-0.077422],[109.364734,-0.073215],[109.359326,-0.067121],[109.355507,-0.06283],[109.3507,-0.057165],[109.350014,-0.056391],[109.349735,-0.055747],[109.349048,-0.05534],[109.34907,-0.054803],[109.346323,-0.051455],[109.342074,-0.046691],[109.344606,-0.041797],[109.347868,-0.039308],[109.35173,-0.036904],[109.354219,-0.035531],[109.359198,-0.032354],[109.360914,-0.030123],[109.362545,-0.025315],[109.362888,-0.020766],[109.362888,-0.015358],[109.359541,-0.015529],[109.355936,-0.016216],[109.353104,-0.017418],[109.3501,-0.018448],[109.346838,-0.018362],[109.344435,-0.01819],[109.342031,-0.017418],[109.340401,-0.015959],[109.334264,-0.009867],[109.328728,-0.003944],[109.324865,-0.001111],[109.323106,0.000306],[109.322462,0.001336],[109.320059,0.00125],[109.316626,0.001894],[109.314222,0.003095],[109.312291,0.004083],[109.311476,0.005113],[109.300404,0.007559],[109.295211,0.010177],[109.288173,0.012924],[109.283366,0.014684],[109.278603,0.017002],[109.275041,0.019062],[109.273839,0.020006],[109.268389,0.021981],[109.265299,0.023182],[109.261136,0.024771],[109.257703,0.026402],[109.254484,0.027904],[109.253712,0.028805],[109.251094,0.03417],[109.250493,0.034814],[109.244742,0.03696],[109.240837,0.038419],[109.237189,0.040179],[109.234056,0.041767],[109.231181,0.044171],[109.228048,0.04636],[109.225602,0.047476],[109.224057,0.048163],[109.221354,0.050266],[109.211783,0.057476],[109.206719,0.061168],[109.204144,0.063142],[109.203415,0.063442],[109.198051,0.067348],[109.19539,0.069408],[109.193072,0.070911],[109.192429,0.071597],[109.190969,0.074044],[109.186463,0.078765],[109.182215,0.082886],[109.180155,0.085203],[109.178352,0.087779],[109.170284,0.098509],[109.168911,0.100483],[109.167624,0.101771],[109.166164,0.103359],[109.165864,0.104389],[109.165864,0.106235],[109.16522,0.107437],[109.164619,0.108467],[109.156079,0.125034],[109.156036,0.133103],[109.156036,0.147868],[109.157453,0.149928],[109.158611,0.150658],[109.159598,0.150958],[109.160371,0.152203],[109.160028,0.153534]]}','2026-06-09 06:33:08','2026-06-09 06:33:08'),(4,'JALAN Adisucipto','Jalan Provinsi',28365.68,'{\"type\":\"LineString\",\"coordinates\":[[109.369411,-0.251746],[109.370098,-0.249941],[109.371085,-0.24831],[109.371901,-0.247451],[109.37366,-0.245348],[109.375076,-0.243159],[109.384603,-0.228352],[109.385376,-0.227321],[109.385548,-0.22539],[109.386964,-0.221527],[109.4034,-0.192641],[109.405804,-0.188263],[109.410782,-0.179551],[109.412627,-0.175816],[109.414473,-0.171868],[109.417648,-0.161567],[109.417434,-0.1553],[109.417477,-0.152138],[109.413786,-0.150164],[109.412413,-0.149048],[109.411082,-0.146644],[109.410439,-0.145357],[109.410396,-0.142996],[109.410009,-0.134026],[109.41031,-0.129047],[109.40855,-0.116128],[109.40855,-0.113595],[109.409108,-0.11072],[109.409838,-0.108273],[109.410095,-0.10617],[109.409151,-0.10411],[109.407477,-0.102393],[109.404001,-0.099431],[109.402714,-0.099303],[109.401212,-0.099346],[109.397693,-0.097715],[109.396491,-0.096856],[109.395804,-0.09574],[109.395032,-0.094581],[109.394431,-0.093122],[109.39383,-0.092049],[109.392715,-0.091105],[109.392457,-0.090118],[109.390612,-0.08604],[109.389539,-0.084237],[109.388208,-0.082649],[109.386234,-0.080932],[109.37439,-0.069902],[109.367352,-0.062991],[109.366579,-0.061446],[109.366407,-0.060416],[109.364219,-0.057884],[109.362845,-0.055437],[109.360228,-0.052089],[109.358125,-0.050373],[109.354949,-0.047754],[109.354177,-0.046467],[109.353018,-0.044664],[109.352202,-0.043806],[109.350572,-0.04269],[109.349241,-0.041359],[109.348254,-0.0399]]}','2026-06-09 06:35:23','2026-06-09 06:35:23'),(5,'Jl Pontianal','Jalan Kabupaten',7463.65,'{\"type\":\"LineString\",\"coordinates\":[[109.342117,-0.046739],[109.338512,-0.042361],[109.334135,-0.037081],[109.330788,-0.032317],[109.326839,-0.02545],[109.325552,-0.023647],[109.326625,-0.019012],[109.329114,-0.018368],[109.330316,-0.018282],[109.332633,-0.017338],[109.336796,-0.020685],[109.337997,-0.021587],[109.342546,-0.026265],[109.344435,-0.02987],[109.346366,-0.034163],[109.34701,-0.037811],[109.347825,-0.039356]]}','2026-06-09 06:46:41','2026-06-09 06:46:41'); +/*!40000 ALTER TABLE `jalan` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `laporan_masyarakat` +-- + +DROP TABLE IF EXISTS `laporan_masyarakat`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `laporan_masyarakat` ( + `id` int NOT NULL AUTO_INCREMENT, + `penduduk_id` int DEFAULT NULL, + `nama_pelapor` varchar(150) NOT NULL, + `no_hp` varchar(30) NOT NULL, + `kategori_laporan` enum('Data kemiskinan','Bantuan belum diterima','Kondisi kesehatan','Data tidak sesuai','Lainnya') NOT NULL DEFAULT 'Data kemiskinan', + `deskripsi` text NOT NULL, + `aktor_tujuan` enum('RT/RW','Kelurahan','Kecamatan','Dinas Sosial','Dinas Kesehatan','Wali Kota') NOT NULL DEFAULT 'Dinas Sosial', + `status_laporan` enum('Masuk','Ditinjau','Diproses','Selesai','Dijadikan Data Masyarakat','Ditolak') NOT NULL DEFAULT 'Masuk', + `data_nama_kepala_keluarga` varchar(150) DEFAULT NULL, + `data_nik` varchar(20) DEFAULT NULL, + `data_tanggal_lahir` date DEFAULT NULL, + `data_pendidikan` enum('Tidak sekolah','SD','SMP','SMA/SMK','Diploma','S1','S2','S3','Tidak diketahui') NOT NULL DEFAULT 'Tidak diketahui', + `data_riwayat_penyakit` text, + `data_jumlah_kk` int NOT NULL DEFAULT '1', + `data_alamat` text, + `data_kecamatan` varchar(100) DEFAULT NULL, + `data_kelurahan` varchar(100) DEFAULT NULL, + `data_status_bantuan` enum('Belum menerima','Sudah menerima','Perlu verifikasi') NOT NULL DEFAULT 'Belum menerima', + `latitude` decimal(12,9) NOT NULL, + `longitude` decimal(12,9) NOT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_laporan_penduduk_id` (`penduduk_id`), + KEY `idx_laporan_data_nik` (`data_nik`), + KEY `idx_laporan_data_nama` (`data_nama_kepala_keluarga`), + CONSTRAINT `fk_laporan_penduduk` FOREIGN KEY (`penduduk_id`) REFERENCES `penduduk_kemiskinan` (`id`) ON DELETE SET NULL ON UPDATE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `laporan_masyarakat` +-- + +LOCK TABLES `laporan_masyarakat` WRITE; +/*!40000 ALTER TABLE `laporan_masyarakat` DISABLE KEYS */; +INSERT INTO `laporan_masyarakat` VALUES (1,1,'DUMMY Rina Pelapor','081234567001','Data kemiskinan','Butuh bantuan','Dinas Sosial','Dijadikan Data Masyarakat','DUMMY Siti Aminah','6171010101010001','1978-04-12','SD','Diabetes',4,'Jl. Gajah Mada Gg. Mawar No. 12','Pontianak Selatan','Benua Melayu Darat','Belum menerima',-0.033941503,109.340894222,'2026-06-06 22:18:11','2026-06-06 22:34:46'),(2,1,'DUMMY Rina Pelapor','081234567001','Bantuan belum diterima','Sembako bulan ini belum di terima','Dinas Sosial','Selesai','DUMMY Siti Aminah','6171010101010001','1978-04-12','SD','Diabetes',4,'Jl. Gajah Mada Gg. Mawar No. 12','Pontianak Selatan','Benua Melayu Darat','Belum menerima',-0.033203467,109.340475798,'2026-06-06 22:40:20','2026-06-06 22:41:30'),(3,NULL,'DUMMY Andi Pelapor','081234567002','Kondisi kesehatan','Asma','Dinas Kesehatan','Masuk','DUMMY Budi Santoso','6171010202020002','1982-09-21','SMP','',1,'Jl. Ahmad Yani Gg. Kenanga No. 7','Pontianak Tenggara','Bansir Laut','Belum menerima',-0.058536749,109.350700455,'2026-06-06 22:49:11','2026-06-09 06:58:00'),(4,2,'DUMMY Wawan Pelapor','081234567004','Data kemiskinan','layak masuk sebagai masyarakat prasejahtera.','Dinas Sosial','Dijadikan Data Masyarakat','DUMMY Maimunah','6171010606060006','1975-03-22','SD','Lansia dan sakit sendi',3,'Jl. Kom Yos Sudarso Gg. Sejahtera No. 4','Pontianak Barat','Sungai Jawi Luar','Belum menerima',-0.017598041,109.331774712,'2026-06-06 22:51:47','2026-06-06 22:52:42'),(5,NULL,'DUMMY Sari Pelapor','081234567003','Data kemiskinan','Keluarga ini belum terdata dan membutuhkan bantuan kebutuhan pokok.','Dinas Sosial','Diproses','DUMMY Nurhayati','6171010505050005','1985-07-17','SD','Tidak ada',6,'Jl. Tanjungpura Gg. Anggrek No. 9','Pontianak Kota','Tengah','Belum menerima',-0.025534733,109.342546463,'2026-06-06 22:57:12','2026-06-07 15:22:43'); +/*!40000 ALTER TABLE `laporan_masyarakat` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `masjid` +-- + +DROP TABLE IF EXISTS `masjid`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `masjid` ( + `id` int NOT NULL AUTO_INCREMENT, + `jenis_rumah_ibadah` enum('Masjid','Gereja','Vihara','Kelenteng','Pura') NOT NULL DEFAULT 'Masjid', + `nama_masjid` varchar(150) NOT NULL, + `pic_masjid` varchar(150) NOT NULL, + `alamat_masjid` text NOT NULL, + `latitude` decimal(12,9) NOT NULL, + `longitude` decimal(12,9) NOT NULL, + `radius_meter` int NOT NULL DEFAULT '500', + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `masjid` +-- + +LOCK TABLES `masjid` WRITE; +/*!40000 ALTER TABLE `masjid` DISABLE KEYS */; +INSERT INTO `masjid` VALUES (1,'Masjid','DUMMY Masjid Al-Ikhlas','Pak Rahman','Jl. Gajah Mada, Pontianak',-0.034199201,109.341076612,700,'2026-06-06 22:31:24','2026-06-06 22:31:24'),(2,'Masjid','DUMMY Masjid Nur Fajar','Pak Yusuf','Jl. Imam Bonjol, Pontianak',-0.048442001,109.356252551,800,'2026-06-06 22:31:54','2026-06-06 22:31:54'),(3,'Gereja','DUMMY Gereja Kasih','Ibu Maria','Jl. Ahmad Yani, Pontianak',-0.059465140,109.353318214,600,'2026-06-06 22:32:35','2026-06-06 22:32:35'),(4,'Vihara','DUMMY Vihara Damai','Pak Hendra','Jl. Tanjungpura, Pontianak',-0.023626150,109.342106581,500,'2026-06-06 22:32:56','2026-06-06 22:33:14'),(5,'Kelenteng','Kelenteng Tri Darma Adipati Sia Ng Bio','Darma','Jl. H.Agus Salim No.104, Benua Melayu Darat, Kec. Pontianak Sel',-0.028300905,109.338428061,500,'2026-06-09 06:56:07','2026-06-09 06:56:07'),(6,'Pura','Pura Giripati Mulawarman','Warman','Jl. Adi Sucipto, Sungai Raya, Kec. Sungai Raya',-0.061771122,109.366432311,500,'2026-06-09 06:57:43','2026-06-09 06:57:43'); +/*!40000 ALTER TABLE `masjid` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `parsil_tanah` +-- + +DROP TABLE IF EXISTS `parsil_tanah`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `parsil_tanah` ( + `id` int NOT NULL AUTO_INCREMENT, + `nama_pemilik` varchar(150) NOT NULL, + `status_kepemilikan` enum('SHM','HGB','HGU','HP') NOT NULL, + `luas_meter` double NOT NULL DEFAULT '0', + `geojson` longtext NOT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `parsil_tanah` +-- + +LOCK TABLES `parsil_tanah` WRITE; +/*!40000 ALTER TABLE `parsil_tanah` DISABLE KEYS */; +INSERT INTO `parsil_tanah` VALUES (2,'B','HGB',45886.23,'{\"type\":\"Polygon\",\"coordinates\":[[[109.348093,-0.043441],[109.349627,-0.044568],[109.34952,-0.044739],[109.350035,-0.045179],[109.349241,-0.046209],[109.347235,-0.044578],[109.348093,-0.043441]]]}','2026-06-09 06:36:47','2026-06-09 06:36:47'),(7,'Ayani','HGU',16708.46,'{\"type\":\"Polygon\",\"coordinates\":[[[109.345186,-0.050855],[109.345615,-0.051177],[109.345851,-0.051596],[109.344982,-0.052401],[109.344156,-0.051725],[109.345186,-0.050855]]]}','2026-06-09 06:39:33','2026-06-09 06:39:33'),(8,'Ayani','HGU',3753.41,'{\"type\":\"Polygon\",\"coordinates\":[[[109.344553,-0.050018],[109.345154,-0.050705],[109.344875,-0.05092],[109.344317,-0.050244],[109.344553,-0.050018]]]}','2026-06-09 06:39:50','2026-06-09 06:39:50'),(9,'Ayani','HGU',4836.21,'{\"type\":\"Polygon\",\"coordinates\":[[[109.346012,-0.051735],[109.346226,-0.051961],[109.34539,-0.052712],[109.345154,-0.05239],[109.346012,-0.051735]]]}','2026-06-09 06:40:18','2026-06-09 06:40:18'),(10,'Ayani','HGU',3761.97,'{\"type\":\"Polygon\",\"coordinates\":[[[109.344199,-0.05034],[109.344778,-0.051016],[109.344478,-0.05122],[109.343952,-0.050587],[109.344199,-0.05034]]]}','2026-06-09 06:40:32','2026-06-09 06:40:32'),(11,'Ayani','HGU',1759.01,'{\"type\":\"Polygon\",\"coordinates\":[[[109.344167,-0.05107],[109.344403,-0.051327],[109.344048,-0.051596],[109.343855,-0.05136],[109.344167,-0.05107]]]}','2026-06-09 06:40:47','2026-06-09 06:40:47'),(12,'Ayani','HGU',2265.46,'{\"type\":\"Polygon\",\"coordinates\":[[[109.343866,-0.050684],[109.344081,-0.050952],[109.343684,-0.051295],[109.343448,-0.05107],[109.343866,-0.050684]]]}','2026-06-09 06:41:00','2026-06-09 06:41:00'),(13,'D','HP',4256.4,'{\"type\":\"Polygon\",\"coordinates\":[[[109.347342,-0.051134],[109.347911,-0.051553],[109.347632,-0.05196],[109.347053,-0.051478],[109.347342,-0.051134]]]}','2026-06-09 06:42:20','2026-06-09 06:50:49'),(17,'HHH','HP',10239.35,'{\"type\":\"Polygon\",\"coordinates\":[[[109.348925,-0.048736],[109.349638,-0.049192],[109.349086,-0.050018],[109.348388,-0.049503],[109.348925,-0.048736]]]}','2026-06-09 06:44:43','2026-06-09 06:50:38'),(19,'AAAAAA','SHM',25333.04,'{\"type\":\"Polygon\",\"coordinates\":[[[109.344016,-0.043398],[109.348029,-0.046607],[109.347782,-0.046918],[109.343802,-0.043742],[109.344016,-0.043398]]]}','2026-06-09 06:47:57','2026-06-09 06:47:57'),(20,'ZZZZZ','HGB',17154.86,'{\"type\":\"Polygon\",\"coordinates\":[[[109.345808,-0.045458],[109.347707,-0.047036],[109.347321,-0.047454],[109.345433,-0.045866],[109.345808,-0.045458]]]}','2026-06-09 06:48:27','2026-06-09 06:48:46'),(21,'QQQQ','HP',12997.14,'{\"type\":\"Polygon\",\"coordinates\":[[[109.348351,-0.046349],[109.348737,-0.046574],[109.34731,-0.048473],[109.346956,-0.048195],[109.348351,-0.046349]]]}','2026-06-09 06:49:10','2026-06-09 06:49:10'),(22,'RRRR','SHM',26329.53,'{\"type\":\"Polygon\",\"coordinates\":[[[109.351344,-0.047593],[109.352074,-0.048119],[109.352975,-0.048656],[109.352546,-0.049106],[109.351408,-0.048237],[109.350003,-0.050255],[109.349585,-0.050019],[109.351344,-0.047593]]]}','2026-06-09 06:50:32','2026-06-09 06:50:32'),(23,'TTTTT','HP',48479.09,'{\"type\":\"Polygon\",\"coordinates\":[[[109.342546,-0.047486],[109.34422,-0.049375],[109.342697,-0.050555],[109.341602,-0.04798],[109.342546,-0.047486]]]}','2026-06-09 06:51:58','2026-06-09 06:51:58'); +/*!40000 ALTER TABLE `parsil_tanah` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `penduduk_kemiskinan` +-- + +DROP TABLE IF EXISTS `penduduk_kemiskinan`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `penduduk_kemiskinan` ( + `id` int NOT NULL AUTO_INCREMENT, + `nama_kepala_keluarga` varchar(150) NOT NULL, + `nik` varchar(20) DEFAULT NULL, + `tanggal_lahir` date DEFAULT NULL, + `pendidikan` enum('Tidak sekolah','SD','SMP','SMA/SMK','Diploma','S1','S2','S3','Tidak diketahui') NOT NULL DEFAULT 'Tidak diketahui', + `riwayat_penyakit` text, + `jumlah_kk` int NOT NULL DEFAULT '1', + `alamat` text NOT NULL, + `kecamatan` varchar(100) DEFAULT NULL, + `kelurahan` varchar(100) DEFAULT NULL, + `status_bantuan` enum('Belum menerima','Sudah menerima','Perlu verifikasi') NOT NULL DEFAULT 'Belum menerima', + `latitude` decimal(12,9) NOT NULL, + `longitude` decimal(12,9) NOT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + KEY `idx_penduduk_nik` (`nik`), + KEY `idx_penduduk_nama` (`nama_kepala_keluarga`) +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `penduduk_kemiskinan` +-- + +LOCK TABLES `penduduk_kemiskinan` WRITE; +/*!40000 ALTER TABLE `penduduk_kemiskinan` DISABLE KEYS */; +INSERT INTO `penduduk_kemiskinan` VALUES (1,'DUMMY Siti Aminah','6171010101010001','1978-04-12','SD','Diabetes',4,'Jl. Gajah Mada Gg. Mawar No. 12','Pontianak Selatan','Benua Melayu Darat','Sudah menerima',-0.032830444,109.337782975,'2026-06-06 22:34:46','2026-06-09 06:05:01'),(2,'DUMMY Maimunah','6171010606060006','1975-03-22','SD','Lansia dan sakit sendi',3,'Jl. Kom Yos Sudarso Gg. Sejahtera No. 4','Pontianak Barat','Sungai Jawi Luar','Belum menerima',-0.017598041,109.331774712,'2026-06-06 22:52:42','2026-06-06 22:52:42'); +/*!40000 ALTER TABLE `penduduk_kemiskinan` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `spbu` +-- + +DROP TABLE IF EXISTS `spbu`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `spbu` ( + `id` int NOT NULL AUTO_INCREMENT, + `nama_spbu` varchar(150) NOT NULL, + `no_telepon` varchar(30) NOT NULL, + `buka_24_jam` tinyint(1) NOT NULL DEFAULT '0', + `latitude` decimal(10,7) NOT NULL, + `longitude` decimal(10,7) NOT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `spbu` +-- + +LOCK TABLES `spbu` WRITE; +/*!40000 ALTER TABLE `spbu` DISABLE KEYS */; +INSERT INTO `spbu` VALUES (5,'SPBU Paris 2','08123456789',0,-0.0648854,109.3563652,'2026-06-09 06:09:33','2026-06-09 06:51:26'),(6,'SPBU Paris 1','021135',1,-0.0554674,109.3626523,'2026-06-09 06:10:26','2026-06-09 06:10:33'),(7,'SPBU Imam Bonjol','08123456789',1,-0.0463543,109.3542945,'2026-06-09 06:11:48','2026-06-09 06:13:07'),(8,'SPBU Tanjung Raya 2','08123456789',0,-0.0489240,109.3687356,'2026-06-09 06:13:00','2026-06-09 06:13:00'),(9,'SPBU Panglima Aim','08123456789',0,-0.0291771,109.3681294,'2026-06-09 06:13:59','2026-06-09 06:13:59'),(10,'SPBU OSO MT Haryono','08123456789',0,-0.0449221,109.3367153,'2026-06-09 06:14:36','2026-06-09 06:14:36'),(11,'SPBU Bundaran Kota BAru ','08123456789',1,-0.0478097,109.3187499,'2026-06-09 06:15:48','2026-06-09 06:15:48'),(12,'SPBU Kota Baru Ujung ','08123456789',0,-0.0623463,109.3044698,'2026-06-09 06:17:38','2026-06-09 06:17:38'),(13,'SPBU Wahidin','08123456789',0,-0.0388818,109.3107516,'2026-06-09 06:18:48','2026-06-09 06:18:48'),(14,'SPBU Husein Hamzah','08123456789',0,-0.0280991,109.2976248,'2026-06-09 06:19:53','2026-06-09 06:19:53'),(15,'SPBU Tanjungpura','08123456789',0,-0.0312108,109.3451428,'2026-06-09 06:20:53','2026-06-09 06:20:53'),(16,'SPBU KH Ahmad Dahlan','08123456789',0,-0.0345266,109.3318713,'2026-06-09 06:22:14','2026-06-09 06:22:14'),(17,'SPBU Hasanudin','08123456789',0,-0.0179067,109.3313885,'2026-06-09 06:23:10','2026-06-09 06:23:10'),(18,'SPBU Hos Cokroaminoto','08123456789',0,-0.0272142,109.3331909,'2026-06-09 06:23:49','2026-06-09 06:23:49'),(19,'SPBU Gusti Hamzah','08123456789',0,-0.0282396,109.3204129,'2026-06-09 06:24:45','2026-06-09 06:24:45'),(20,'SPBU Martadinata','08123456789',0,-0.0117108,109.3139809,'2026-06-09 06:25:22','2026-06-09 06:25:22'),(21,'SPBU Siantan 1','08123456789',0,-0.0162492,109.3580604,'2026-06-09 06:26:05','2026-06-09 06:26:05'),(22,'SPBU Siantan','0561886446',1,-0.0114167,109.3353796,'2026-06-09 06:27:15','2026-06-09 06:27:15'); +/*!40000 ALTER TABLE `spbu` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `users` +-- + +DROP TABLE IF EXISTS `users`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `users` ( + `id` int NOT NULL AUTO_INCREMENT, + `nama` varchar(150) NOT NULL, + `username` varchar(50) NOT NULL, + `password` varchar(255) NOT NULL, + `role` enum('admin','walikota','dinas') NOT NULL DEFAULT 'admin', + `instansi` varchar(100) DEFAULT NULL, + `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `username` (`username`) +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `users` +-- + +LOCK TABLES `users` WRITE; +/*!40000 ALTER TABLE `users` DISABLE KEYS */; +INSERT INTO `users` VALUES (1,'Administrator Sistem','admin','$2y$12$QrkopzCKam0f.9T0zBtesOsIacS.Ra.4BGkG0oO6RVlb8m1dAjHyG','admin','Admin Pengelola','2026-06-06 22:16:21'),(2,'Wali Kota Pontianak','walikota','$2y$12$QrkopzCKam0f.9T0zBtesOsIacS.Ra.4BGkG0oO6RVlb8m1dAjHyG','walikota','Wali Kota','2026-06-06 22:16:21'),(3,'Dinas Sosial Kota Pontianak','dinsos','$2y$12$QrkopzCKam0f.9T0zBtesOsIacS.Ra.4BGkG0oO6RVlb8m1dAjHyG','dinas','Dinas Sosial','2026-06-06 22:16:21'),(4,'Dinas Kesehatan Kota Pontianak','dinkes','$2y$12$QrkopzCKam0f.9T0zBtesOsIacS.Ra.4BGkG0oO6RVlb8m1dAjHyG','dinas','Dinas Kesehatan','2026-06-06 22:16:21'); +/*!40000 ALTER TABLE `users` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + +-- Dump completed on 2026-06-09 14:53:59 diff --git a/env.php b/env.php new file mode 100644 index 0000000..ccf132a --- /dev/null +++ b/env.php @@ -0,0 +1,54 @@ + + + + + Landing Page WebGIS SIG + + + + + + +
+

WebGIS Poverty Mapping

+

Tugas Besar Sistem Informasi Geografis

+

Talitha Syakirah Artanti - D1041231013

+

Informatika FT Universitas Tanjungpura

+
+ +
+ +

Daftar Project SIG

+ +
+
+

1. Pemetaan SPBU

+

+ Project WebGIS untuk menampilkan lokasi SPBU di Kota Pontianak. +

+ Buka Project +
+ +
+

2. SPBU, Jalan, Parsil Tanah dan Layer

+

+ Project WebGIS dengan beberapa layer seperti SPBU, jalan, dan parsil tanah. +

+ Buka Project +
+ +
+

3. Poverty Mapping

+

+ Project utama untuk pemetaan masyarakat prasejahtera, rumah ibadah, + laporan masyarakat, dan histori bantuan. +

+ Buka Project +
+
+ +

Informasi Link

+ +
+ URL Landing Page:
+ isi dengan URL Coolify setelah deploy +

+ + Repository Gitea:
+ isi dengan link repo Gitea kamu +

+ + Catatan:
+ Landing page ini digunakan sebagai halaman utama yang mengarahkan pengguna ke seluruh project SIG. +
+ +

Akun Demo Poverty Mapping

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
RoleUsernamePasswordHak Akses
AdminadminpasswordMengelola data, akun dinas, laporan masyarakat, dan data WebGIS.
WalikotawalikotapasswordMelihat dan mengunduh seluruh data tanpa melakukan perubahan data.
DinasdinaspasswordMelihat dan mengunduh data sesuai kebutuhan instansi.
Masyarakat--Mengirim laporan cepat melalui fitur laporan masyarakat.
+
+ +
+ Perhatian:
+ Jika username di database kamu berbeda, bagian tabel akun demo ini tinggal disesuaikan dengan akun yang benar. +
+ +
+ + + + + \ No newline at end of file