diff --git a/PANDUAN_FITUR.md b/PANDUAN_FITUR.md
index ff1229e..2cafb6e 100644
--- a/PANDUAN_FITUR.md
+++ b/PANDUAN_FITUR.md
@@ -366,14 +366,27 @@ web-gis/
├── create_tables.php ← Init database
├── db_config.php ← Database config
│
-├── api/
-│ ├── save_rumah_ibadah.php
+├── rancangan_sistem/ ← API & UI untuk rumah ibadah + penduduk miskin
│ ├── get_rumah_ibadah.php
+│ ├── save_rumah_ibadah.php
+│ ├── update_rumah_ibadah.php
│ ├── delete_rumah_ibadah.php
-│ ├── save_penduduk_miskin.php
│ ├── get_penduduk_miskin.php
+│ ├── save_penduduk_miskin.php
+│ ├── update_penduduk_miskin.php
│ └── delete_penduduk_miskin.php
│
+├── fitur_jalan_parsel/ ← API & UI untuk jalan rusak, polyline/polygon
+│ ├── get_jalan_rusak.php
+│ ├── save_jalan_rusak.php
+│ └── delete_jalan_rusak.php
+│
+├── layer_groups_choropleth/← API & UI untuk spatial features + choropleth
+│ ├── get_features.php
+│ ├── save_feature.php
+│ ├── update_feature.php
+│ └── delete_feature.php
+│
└── data/
├── pontianak-kecamatan.geojson ← Choropleth data
└── Export_Output_2.json ← Road network data
diff --git a/create_tables.php b/create_tables.php
index c6851e0..de69f10 100644
--- a/create_tables.php
+++ b/create_tables.php
@@ -37,6 +37,57 @@ $statements = [
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_penduduk_coords (latitude, longitude),
INDEX idx_penduduk_rumah_ibadah (rumah_ibadah_id)
+)",
+ "CREATE TABLE IF NOT EXISTS verifikasi_lapangan (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ jenis_target VARCHAR(50) NOT NULL DEFAULT 'penduduk_miskin',
+ target_nama VARCHAR(255) DEFAULT NULL,
+ petugas_nama VARCHAR(255) NOT NULL,
+ status_verifikasi VARCHAR(30) NOT NULL DEFAULT 'menunggu',
+ hasil_temuan TEXT,
+ tindak_lanjut TEXT,
+ foto VARCHAR(255) DEFAULT NULL,
+ latitude DECIMAL(10, 8) NOT NULL,
+ longitude DECIMAL(11, 8) NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ INDEX idx_verifikasi_coords (latitude, longitude),
+ INDEX idx_verifikasi_target (jenis_target, target_nama)
+)",
+ "CREATE TABLE IF NOT EXISTS aduan_warga (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ kategori VARCHAR(100) NOT NULL,
+ pelapor_nama VARCHAR(255) NOT NULL,
+ kontak_pelapor VARCHAR(100) DEFAULT NULL,
+ deskripsi TEXT NOT NULL,
+ status_tindak_lanjut VARCHAR(30) NOT NULL DEFAULT 'baru',
+ tindak_lanjut TEXT,
+ foto VARCHAR(255) DEFAULT NULL,
+ latitude DECIMAL(10, 8) NOT NULL,
+ longitude DECIMAL(11, 8) NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ INDEX idx_aduan_coords (latitude, longitude),
+ INDEX idx_aduan_status (status_tindak_lanjut)
+)",
+ "CREATE TABLE IF NOT EXISTS locations (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ nama VARCHAR(255) NOT NULL,
+ nomor VARCHAR(100) NOT NULL,
+ buka_24jam VARCHAR(10) NOT NULL DEFAULT 'tidak',
+ latitude DECIMAL(10, 8) NOT NULL,
+ longitude DECIMAL(11, 8) NOT NULL,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ INDEX idx_locations_coords (latitude, longitude)
+)",
+ "CREATE TABLE IF NOT EXISTS spatial_features (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ nama_objek VARCHAR(255) NOT NULL,
+ kategori VARCHAR(100) NOT NULL,
+ status_objek VARCHAR(100) NOT NULL,
+ type VARCHAR(50) NOT NULL,
+ geometry_data LONGTEXT NOT NULL,
+ nilai_ukur DECIMAL(15, 2) NOT NULL DEFAULT 0.00,
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ INDEX idx_features_kategori (kategori)
)"
];
@@ -55,7 +106,11 @@ $alterStatements = [
];
foreach ($alterStatements as $alterSql) {
- $conn->query($alterSql);
+ try {
+ @$conn->query($alterSql);
+ } catch (Exception $e) {
+ // Abaikan jika kolom sudah ada
+ }
}
echo json_encode(['status' => 'success', 'message' => 'Tabel berhasil dibuat atau sudah ada']);
diff --git a/delete_aduan_warga.php b/delete_aduan_warga.php
new file mode 100644
index 0000000..9a95f44
--- /dev/null
+++ b/delete_aduan_warga.php
@@ -0,0 +1,38 @@
+ 'error', 'message' => 'ID aduan tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare('DELETE FROM aduan_warga WHERE id = ?');
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param('i', $id);
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Aduan warga berhasil dihapus']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
\ No newline at end of file
diff --git a/delete_verifikasi_lapangan.php b/delete_verifikasi_lapangan.php
new file mode 100644
index 0000000..4af316d
--- /dev/null
+++ b/delete_verifikasi_lapangan.php
@@ -0,0 +1,38 @@
+ 'error', 'message' => 'ID verifikasi tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare('DELETE FROM verifikasi_lapangan WHERE id = ?');
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param('i', $id);
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Verifikasi lapangan berhasil dihapus']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
\ No newline at end of file
diff --git a/fitur_bantuan/api/delete_penduduk_miskin.php b/fitur_bantuan/api/delete_penduduk_miskin.php
new file mode 100644
index 0000000..ead1310
--- /dev/null
+++ b/fitur_bantuan/api/delete_penduduk_miskin.php
@@ -0,0 +1,26 @@
+ 'error', 'message' => 'ID tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("DELETE FROM penduduk_miskin WHERE id = ?");
+ $stmt->bind_param("i", $id);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Data penduduk miskin dihapus']);
+ } else {
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/delete_rumah_ibadah.php b/fitur_bantuan/api/delete_rumah_ibadah.php
new file mode 100644
index 0000000..468db6b
--- /dev/null
+++ b/fitur_bantuan/api/delete_rumah_ibadah.php
@@ -0,0 +1,26 @@
+ 'error', 'message' => 'ID tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("DELETE FROM rumah_ibadah WHERE id = ?");
+ $stmt->bind_param("i", $id);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Rumah ibadah berhasil dihapus']);
+ } else {
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/delete_verifikasi_lapangan.php b/fitur_bantuan/api/delete_verifikasi_lapangan.php
new file mode 100644
index 0000000..2a7230e
--- /dev/null
+++ b/fitur_bantuan/api/delete_verifikasi_lapangan.php
@@ -0,0 +1,38 @@
+ 'error', 'message' => 'ID verifikasi tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare('DELETE FROM verifikasi_lapangan WHERE id = ?');
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param('i', $id);
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Verifikasi lapangan berhasil dihapus']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/get_penduduk_miskin.php b/fitur_bantuan/api/get_penduduk_miskin.php
new file mode 100644
index 0000000..aff4290
--- /dev/null
+++ b/fitur_bantuan/api/get_penduduk_miskin.php
@@ -0,0 +1,34 @@
+query($sql);
+$data = [];
+
+if (!$result) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]);
+ $conn->close();
+ exit;
+}
+
+if ($result->num_rows > 0) {
+ while ($row = $result->fetch_assoc()) {
+ $row['latitude'] = (float)$row['latitude'];
+ $row['longitude'] = (float)$row['longitude'];
+ $row['jumlah_anggota'] = (int)$row['jumlah_anggota'];
+ $row['rumah_ibadah_id'] = $row['rumah_ibadah_id'] !== null ? (int)$row['rumah_ibadah_id'] : null;
+ $row['jarak_ke_rumah_ibadah_m'] = $row['jarak_ke_rumah_ibadah_m'] !== null ? (float)$row['jarak_ke_rumah_ibadah_m'] : null;
+ $row['bantuan_status'] = $row['bantuan_status'] ?: 'belum';
+ $row['bantuan_catatan'] = $row['bantuan_catatan'] ?? '';
+ $data[] = $row;
+ }
+}
+
+echo json_encode($data);
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/get_rumah_ibadah.php b/fitur_bantuan/api/get_rumah_ibadah.php
new file mode 100644
index 0000000..9bcdeb1
--- /dev/null
+++ b/fitur_bantuan/api/get_rumah_ibadah.php
@@ -0,0 +1,30 @@
+query($sql);
+$data = [];
+
+if (!$result) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]);
+ $conn->close();
+ exit;
+}
+
+if ($result->num_rows > 0) {
+ while ($row = $result->fetch_assoc()) {
+ $row['latitude'] = (float)$row['latitude'];
+ $row['longitude'] = (float)$row['longitude'];
+ $row['radius_m'] = (int)$row['radius_m'];
+ $data[] = $row;
+ }
+}
+
+echo json_encode($data);
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/get_verifikasi_lapangan.php b/fitur_bantuan/api/get_verifikasi_lapangan.php
new file mode 100644
index 0000000..dc983a7
--- /dev/null
+++ b/fitur_bantuan/api/get_verifikasi_lapangan.php
@@ -0,0 +1,24 @@
+query($sql);
+
+if (!$result) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]);
+ $conn->close();
+ exit;
+}
+
+$data = [];
+while ($row = $result->fetch_assoc()) {
+ $row['latitude'] = (float)$row['latitude'];
+ $row['longitude'] = (float)$row['longitude'];
+ $data[] = $row;
+}
+
+echo json_encode($data);
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/save_penduduk_miskin.php b/fitur_bantuan/api/save_penduduk_miskin.php
new file mode 100644
index 0000000..f195285
--- /dev/null
+++ b/fitur_bantuan/api/save_penduduk_miskin.php
@@ -0,0 +1,77 @@
+query("SELECT id, nama, latitude, longitude FROM rumah_ibadah ORDER BY created_at DESC");
+ if (!$result || $result->num_rows === 0) {
+ return null;
+ }
+
+ $nearest = null;
+ while ($row = $result->fetch_assoc()) {
+ $distance = distanceMeters($lat, $lng, (float)$row['latitude'], (float)$row['longitude']);
+ if ($nearest === null || $distance < $nearest['distance']) {
+ $nearest = [
+ 'id' => (int)$row['id'],
+ 'nama' => $row['nama'],
+ 'distance' => $distance
+ ];
+ }
+ }
+
+ return $nearest;
+}
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $namaKetuaKk = trim($_POST['nama_ketua_kk'] ?? '');
+ $jumlahAnggota = (int)($_POST['jumlah_anggota'] ?? 0);
+ $lat = $_POST['latitude'] ?? null;
+ $lng = $_POST['longitude'] ?? null;
+
+ if ($namaKetuaKk === '' || $jumlahAnggota <= 0 || $lat === null || $lng === null) {
+ echo json_encode(['status' => 'error', 'message' => 'Data penduduk miskin tidak lengkap']);
+ $conn->close();
+ exit;
+ }
+
+ $lat = (float)$lat;
+ $lng = (float)$lng;
+ $nearest = findNearestRumahIbadah($conn, $lat, $lng);
+
+ if (!$nearest) {
+ echo json_encode(['status' => 'error', 'message' => 'Tambahkan rumah ibadah terlebih dahulu']);
+ $conn->close();
+ exit;
+ }
+
+ $jarak = $nearest['distance'];
+ $rumahIbadahId = $nearest['id'];
+ $rumahIbadahNama = $nearest['nama'];
+
+ $stmt = $conn->prepare("INSERT INTO penduduk_miskin (nama_ketua_kk, jumlah_anggota, latitude, longitude, rumah_ibadah_id, rumah_ibadah_nama, jarak_ke_rumah_ibadah_m) VALUES (?, ?, ?, ?, ?, ?, ?)");
+ $stmt->bind_param("siddisd", $namaKetuaKk, $jumlahAnggota, $lat, $lng, $rumahIbadahId, $rumahIbadahNama, $jarak);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Penduduk miskin berhasil disimpan']);
+ } else {
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/save_rumah_ibadah.php b/fitur_bantuan/api/save_rumah_ibadah.php
new file mode 100644
index 0000000..e47b3c2
--- /dev/null
+++ b/fitur_bantuan/api/save_rumah_ibadah.php
@@ -0,0 +1,35 @@
+ 'error', 'message' => 'Data rumah ibadah tidak lengkap']);
+ $conn->close();
+ exit;
+ }
+
+ $lat = (float)$lat;
+ $lng = (float)$lng;
+ $radius = max(50, (int)$radius);
+
+ $stmt = $conn->prepare("INSERT INTO rumah_ibadah (nama, alamat, pic, latitude, longitude, radius_m) VALUES (?, ?, ?, ?, ?, ?)");
+ $stmt->bind_param("sssddi", $nama, $alamat, $pic, $lat, $lng, $radius);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Rumah ibadah berhasil disimpan']);
+ } else {
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/save_verifikasi_lapangan.php b/fitur_bantuan/api/save_verifikasi_lapangan.php
new file mode 100644
index 0000000..8a6ed64
--- /dev/null
+++ b/fitur_bantuan/api/save_verifikasi_lapangan.php
@@ -0,0 +1,76 @@
+ 'error', 'message' => 'Nama petugas dan koordinat wajib diisi']);
+ $conn->close();
+ exit;
+ }
+
+ $foto = null;
+ if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) {
+ $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+ $filename = $_FILES['foto']['name'];
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+
+ if (!in_array($ext, $allowed, true)) {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Format foto hanya JPG, PNG, GIF, WEBP']);
+ $conn->close();
+ exit;
+ }
+
+ // Folder is in root
+ if (!is_dir(__DIR__ . '/../../uploads')) {
+ mkdir(__DIR__ . '/../../uploads', 0755, true);
+ }
+
+ $foto = 'uploads/' . time() . '_' . basename($filename);
+ if (!move_uploaded_file($_FILES['foto']['tmp_name'], __DIR__ . '/../../' . $foto)) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Gagal upload foto']);
+ $conn->close();
+ exit;
+ }
+ }
+
+ $stmt = $conn->prepare('INSERT INTO verifikasi_lapangan (jenis_target, target_nama, petugas_nama, status_verifikasi, hasil_temuan, tindak_lanjut, foto, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $latitude = (float)$latitude;
+ $longitude = (float)$longitude;
+ $stmt->bind_param('sssssssdd', $jenisTarget, $targetNama, $petugasNama, $statusVerifikasi, $hasilTemuan, $tindakLanjut, $foto, $latitude, $longitude);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Verifikasi lapangan berhasil disimpan', 'id' => $stmt->insert_id]);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/update_bantuan_penduduk.php b/fitur_bantuan/api/update_bantuan_penduduk.php
new file mode 100644
index 0000000..7ccb17f
--- /dev/null
+++ b/fitur_bantuan/api/update_bantuan_penduduk.php
@@ -0,0 +1,48 @@
+ 'error', 'message' => 'Metode tidak diizinkan']);
+ $conn->close();
+ exit;
+}
+
+$id = (int)($_POST['id'] ?? 0);
+$status = strtolower(trim($_POST['bantuan_status'] ?? 'belum'));
+$catatan = trim($_POST['bantuan_catatan'] ?? '');
+
+if ($id <= 0) {
+ echo json_encode(['status' => 'error', 'message' => 'ID tidak valid']);
+ $conn->close();
+ exit;
+}
+
+if (!in_array($status, ['belum', 'proses', 'sudah'], true)) {
+ $status = 'belum';
+}
+
+$stmt = $conn->prepare("UPDATE penduduk_miskin SET bantuan_status = ?, bantuan_catatan = ?, bantuan_updated_at = CURRENT_TIMESTAMP WHERE id = ?");
+$stmt->bind_param("ssi", $status, $catatan, $id);
+
+if ($stmt->execute()) {
+ $updatedAtResult = $conn->query("SELECT bantuan_updated_at FROM penduduk_miskin WHERE id = " . (int)$id . " LIMIT 1");
+ $updatedAt = null;
+ if ($updatedAtResult && $updatedAtResult->num_rows > 0) {
+ $row = $updatedAtResult->fetch_assoc();
+ $updatedAt = $row['bantuan_updated_at'] ?? null;
+ }
+
+ echo json_encode([
+ 'status' => 'success',
+ 'message' => 'Status bantuan berhasil diperbarui',
+ 'bantuan_updated_at' => $updatedAt
+ ]);
+} else {
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+}
+
+$stmt->close();
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/update_penduduk_miskin.php b/fitur_bantuan/api/update_penduduk_miskin.php
new file mode 100644
index 0000000..170f67d
--- /dev/null
+++ b/fitur_bantuan/api/update_penduduk_miskin.php
@@ -0,0 +1,79 @@
+query("SELECT id, nama, latitude, longitude FROM rumah_ibadah ORDER BY created_at DESC");
+ if (!$result || $result->num_rows === 0) {
+ return null;
+ }
+
+ $nearest = null;
+ while ($row = $result->fetch_assoc()) {
+ $distance = distanceMeters($lat, $lng, (float)$row['latitude'], (float)$row['longitude']);
+ if ($nearest === null || $distance < $nearest['distance']) {
+ $nearest = [
+ 'id' => (int)$row['id'],
+ 'nama' => $row['nama'],
+ 'distance' => $distance
+ ];
+ }
+ }
+
+ return $nearest;
+}
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $id = (int)($_POST['id'] ?? 0);
+ $namaKetuaKk = trim($_POST['nama_ketua_kk'] ?? '');
+ $jumlahAnggota = (int)($_POST['jumlah_anggota'] ?? 0);
+ $lat = $_POST['latitude'] ?? null;
+ $lng = $_POST['longitude'] ?? null;
+
+ if ($id <= 0 || $namaKetuaKk === '' || $jumlahAnggota <= 0 || $lat === null || $lng === null) {
+ echo json_encode(['status' => 'error', 'message' => 'Data penduduk miskin tidak lengkap']);
+ $conn->close();
+ exit;
+ }
+
+ $lat = (float)$lat;
+ $lng = (float)$lng;
+ $nearest = findNearestRumahIbadah($conn, $lat, $lng);
+
+ if (!$nearest) {
+ echo json_encode(['status' => 'error', 'message' => 'Tambahkan rumah ibadah terlebih dahulu']);
+ $conn->close();
+ exit;
+ }
+
+ $jarak = $nearest['distance'];
+ $rumahIbadahId = $nearest['id'];
+ $rumahIbadahNama = $nearest['nama'];
+
+ $stmt = $conn->prepare("UPDATE penduduk_miskin SET nama_ketua_kk = ?, jumlah_anggota = ?, latitude = ?, longitude = ?, rumah_ibadah_id = ?, rumah_ibadah_nama = ?, jarak_ke_rumah_ibadah_m = ? WHERE id = ?");
+ $stmt->bind_param("siddisdi", $namaKetuaKk, $jumlahAnggota, $lat, $lng, $rumahIbadahId, $rumahIbadahNama, $jarak, $id);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Data penduduk miskin berhasil diperbarui']);
+ } else {
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/update_rumah_ibadah.php b/fitur_bantuan/api/update_rumah_ibadah.php
new file mode 100644
index 0000000..db600ce
--- /dev/null
+++ b/fitur_bantuan/api/update_rumah_ibadah.php
@@ -0,0 +1,36 @@
+ 'error', 'message' => 'Data rumah ibadah tidak lengkap']);
+ $conn->close();
+ exit;
+ }
+
+ $lat = (float)$lat;
+ $lng = (float)$lng;
+ $radius = max(50, (int)$radius);
+
+ $stmt = $conn->prepare("UPDATE rumah_ibadah SET nama = ?, alamat = ?, pic = ?, latitude = ?, longitude = ?, radius_m = ? WHERE id = ?");
+ $stmt->bind_param("sssddii", $nama, $alamat, $pic, $lat, $lng, $radius, $id);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Rumah ibadah berhasil diperbarui']);
+ } else {
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+$conn->close();
+?>
diff --git a/fitur_bantuan/api/update_verifikasi_lapangan.php b/fitur_bantuan/api/update_verifikasi_lapangan.php
new file mode 100644
index 0000000..119ccce
--- /dev/null
+++ b/fitur_bantuan/api/update_verifikasi_lapangan.php
@@ -0,0 +1,84 @@
+ 'error', 'message' => 'Data verifikasi tidak lengkap']);
+ $conn->close();
+ exit;
+ }
+
+ $fotoSql = '';
+ $foto = null;
+ if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) {
+ $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+ $filename = $_FILES['foto']['name'];
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+
+ if (!in_array($ext, $allowed, true)) {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Format foto hanya JPG, PNG, GIF, WEBP']);
+ $conn->close();
+ exit;
+ }
+
+ if (!is_dir(__DIR__ . '/../../uploads')) {
+ mkdir(__DIR__ . '/../../uploads', 0755, true);
+ }
+
+ $foto = 'uploads/' . time() . '_' . basename($filename);
+ if (!move_uploaded_file($_FILES['foto']['tmp_name'], __DIR__ . '/../../' . $foto)) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Gagal upload foto']);
+ $conn->close();
+ exit;
+ }
+
+ $fotoSql = ', foto = ?';
+ }
+
+ $sql = 'UPDATE verifikasi_lapangan SET jenis_target = ?, target_nama = ?, petugas_nama = ?, status_verifikasi = ?, hasil_temuan = ?, tindak_lanjut = ?, latitude = ?, longitude = ?' . $fotoSql . ' WHERE id = ?';
+ $stmt = $conn->prepare($sql);
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $latitude = (float)$latitude;
+ $longitude = (float)$longitude;
+ if ($foto !== null) {
+ $stmt->bind_param('sssssssddi', $jenisTarget, $targetNama, $petugasNama, $statusVerifikasi, $hasilTemuan, $tindakLanjut, $foto, $latitude, $longitude, $id);
+ } else {
+ $stmt->bind_param('ssssssddi', $jenisTarget, $targetNama, $petugasNama, $statusVerifikasi, $hasilTemuan, $tindakLanjut, $latitude, $longitude, $id);
+ }
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Verifikasi lapangan berhasil diperbarui']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_bantuan/index.html b/fitur_bantuan/index.html
new file mode 100644
index 0000000..9587fcf
--- /dev/null
+++ b/fitur_bantuan/index.html
@@ -0,0 +1,1275 @@
+
+
+
+
+
+ Sistem GIS — Manajemen Bantuan
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informatika UNTAN
+
+
+
Manajemen Bantuan
+
Penyaluran bantuan penduduk miskin berbasis wilayah tempat ibadah.
+
+
+
+
+
+ Rumah Ibadah
+
+
+ Penduduk Miskin
+
+
+ Status Bantuan
+
+
+ Verifikasi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pilih Rumah Ibadah Wilayah
+
+ Pilih rumah ibadah...
+
+
+
+ Status Bantuan
+
+ Semua Status
+ Belum Dibantu
+ Dalam Proses
+ Sudah Dibantu
+
+
+
+
+
Pilih rumah ibadah untuk memfilter penerima bantuan.
+
+
+
+
+
+
+
+
+
+
+ + Rumah Ibadah
+
+
+ + Keluarga Miskin
+
+
+ + Verifikasi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fitur_jalan/api/delete_feature.php b/fitur_jalan/api/delete_feature.php
new file mode 100644
index 0000000..9d1dd69
--- /dev/null
+++ b/fitur_jalan/api/delete_feature.php
@@ -0,0 +1,39 @@
+ 'error', 'message' => 'ID jalan tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("DELETE FROM spatial_features WHERE id = ?");
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param("i", $id);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Data jalan berhasil dihapus']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_jalan/api/delete_jalan_rusak.php b/fitur_jalan/api/delete_jalan_rusak.php
new file mode 100644
index 0000000..1f37e9e
--- /dev/null
+++ b/fitur_jalan/api/delete_jalan_rusak.php
@@ -0,0 +1,52 @@
+ 'error', 'message' => 'ID laporan tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ // Optional: Get file path and delete physical image file
+ $stmtSelect = $conn->prepare('SELECT gambar FROM jalan_rusak WHERE id = ?');
+ if ($stmtSelect) {
+ $stmtSelect->bind_param('i', $id);
+ $stmtSelect->execute();
+ $stmtSelect->bind_result($gambar);
+ if ($stmtSelect->fetch()) {
+ if ($gambar && file_exists(__DIR__ . '/../../' . $gambar)) {
+ @unlink(__DIR__ . '/../../' . $gambar);
+ }
+ }
+ $stmtSelect->close();
+ }
+
+ $stmt = $conn->prepare('DELETE FROM jalan_rusak WHERE id = ?');
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param('i', $id);
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Laporan jalan rusak berhasil dihapus']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/get_features.php b/fitur_jalan/api/get_features.php
similarity index 61%
rename from get_features.php
rename to fitur_jalan/api/get_features.php
index c210eb8..6703d66 100644
--- a/get_features.php
+++ b/fitur_jalan/api/get_features.php
@@ -1,14 +1,10 @@
query($sql);
@@ -23,19 +19,12 @@ if (!$result) {
if ($result && $result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
- // Mendecode data JSON koordinat agar bisa langsung digunakan oleh Leaflet di frontend
$row['geometry_data'] = json_decode($row['geometry_data']);
-
- // Memastikan nilai_ukur dikirim sebagai angka (float/double)
$row['nilai_ukur'] = (float)$row['nilai_ukur'];
-
$features[] = $row;
}
}
-// Mengirimkan data dalam format JSON
echo json_encode($features);
-
-// Menutup koneksi database
$conn->close();
-?>
\ No newline at end of file
+?>
diff --git a/fitur_jalan/api/get_jalan_rusak.php b/fitur_jalan/api/get_jalan_rusak.php
new file mode 100644
index 0000000..cf9aaf4
--- /dev/null
+++ b/fitur_jalan/api/get_jalan_rusak.php
@@ -0,0 +1,29 @@
+query($sql);
+$data = [];
+
+if (!$result) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]);
+ $conn->close();
+ exit;
+}
+
+if ($result && $result->num_rows > 0) {
+ while ($row = $result->fetch_assoc()) {
+ $row['latitude'] = (float)$row['latitude'];
+ $row['longitude'] = (float)$row['longitude'];
+ $data[] = $row;
+ }
+}
+
+echo json_encode($data);
+$conn->close();
+?>
diff --git a/fitur_jalan/api/save_feature.php b/fitur_jalan/api/save_feature.php
new file mode 100644
index 0000000..5a921f3
--- /dev/null
+++ b/fitur_jalan/api/save_feature.php
@@ -0,0 +1,45 @@
+ 'error', 'message' => 'Data jalan tidak lengkap']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("INSERT INTO spatial_features (nama_objek, kategori, status_objek, type, geometry_data, nilai_ukur) VALUES (?, ?, ?, ?, ?, ?)");
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param("sssssd", $nama, $kategori, $status, $type, $geometry, $nilai);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Data jalan berhasil disimpan']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_jalan/api/save_jalan_rusak.php b/fitur_jalan/api/save_jalan_rusak.php
new file mode 100644
index 0000000..15725a2
--- /dev/null
+++ b/fitur_jalan/api/save_jalan_rusak.php
@@ -0,0 +1,72 @@
+ 'error', 'message' => 'Latitude, longitude, dan jenis kerusakan wajib diisi']);
+ exit;
+ }
+
+ $gambar = null;
+
+ // Handle file upload
+ if (isset($_FILES['gambar']) && $_FILES['gambar']['error'] === UPLOAD_ERR_OK) {
+ $allowed = ['jpg', 'jpeg', 'png', 'gif'];
+ $filename = $_FILES['gambar']['name'];
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+
+ if (!in_array($ext, $allowed)) {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Format gambar hanya JPG, PNG, GIF']);
+ exit;
+ }
+
+ // Buat folder uploads di root jika belum ada
+ if (!is_dir(__DIR__ . '/../../uploads')) {
+ mkdir(__DIR__ . '/../../uploads', 0755, true);
+ }
+
+ // Generate nama file unik
+ $gambar = 'uploads/' . time() . '_' . basename($filename);
+
+ if (!move_uploaded_file($_FILES['gambar']['tmp_name'], __DIR__ . '/../../' . $gambar)) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Gagal upload gambar']);
+ exit;
+ }
+ }
+
+ $stmt = $conn->prepare("INSERT INTO jalan_rusak (latitude, longitude, jenis_kerusakan, deskripsi, severity, gambar) VALUES (?, ?, ?, ?, ?, ?)");
+
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ exit;
+ }
+
+ $stmt->bind_param("ddssss", $latitude, $longitude, $jenis_kerusakan, $deskripsi, $severity, $gambar);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Laporan jalan rusak berhasil disimpan', 'id' => $stmt->insert_id]);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_jalan/api/update_feature.php b/fitur_jalan/api/update_feature.php
new file mode 100644
index 0000000..c0e7083
--- /dev/null
+++ b/fitur_jalan/api/update_feature.php
@@ -0,0 +1,66 @@
+ 'error', 'message' => 'ID jalan tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ $isGeometryUpdate = isset($_POST['geometry']);
+
+ if ($isGeometryUpdate) {
+ $geometry = $_POST['geometry'] ?? '';
+ $nilai = (float)($_POST['nilai'] ?? 0);
+
+ if ($geometry === '') {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Data geometri kosong']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("UPDATE spatial_features SET geometry_data = ?, nilai_ukur = ? WHERE id = ?");
+ $stmt->bind_param("sdi", $geometry, $nilai, $id);
+ } else {
+ $nama = trim($_POST['nama'] ?? '');
+ $status = trim($_POST['status'] ?? '');
+
+ if ($nama === '' || $status === '') {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Nama atau status tidak boleh kosong']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("UPDATE spatial_features SET nama_objek = ?, status_objek = ? WHERE id = ?");
+ $stmt->bind_param("ssi", $nama, $status, $id);
+ }
+
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Data jalan berhasil diperbarui']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_jalan/index.html b/fitur_jalan/index.html
new file mode 100644
index 0000000..8115fd1
--- /dev/null
+++ b/fitur_jalan/index.html
@@ -0,0 +1,951 @@
+
+
+
+
+
+ Sistem GIS — Infrastruktur Jalan
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informatika UNTAN
+
+
+
Infrastruktur Jalan
+
Pemetaan jaringan jalan beserta pelaporan titik kerusakan jalan.
+
+
+
+
+
+ Jaringan Jalan
+
+
+ Laporan Kerusakan
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Memuat data jalan...
+
+
+
+
+
+
Memuat laporan kerusakan...
+
+
+
+
+
+
+
+ Gunakan tool Draw Polyline di sisi kanan peta untuk menambahkan ruas jalan baru dan menghitung panjangnya.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fitur_jalan_parsel/api.php b/fitur_jalan_parsel/api.php
new file mode 100644
index 0000000..2b86e94
--- /dev/null
+++ b/fitur_jalan_parsel/api.php
@@ -0,0 +1,3 @@
+true,'msg'=>'API placeholder untuk fitur jalan/parsel']);
diff --git a/delete_jalan_rusak.php b/fitur_jalan_parsel/delete_jalan_rusak.php
similarity index 86%
rename from delete_jalan_rusak.php
rename to fitur_jalan_parsel/delete_jalan_rusak.php
index 7a0e08d..728a14b 100644
--- a/delete_jalan_rusak.php
+++ b/fitur_jalan_parsel/delete_jalan_rusak.php
@@ -1,6 +1,6 @@
get_result();
$row = $result->fetch_assoc();
- if ($row && $row['gambar'] && file_exists($row['gambar'])) {
- unlink($row['gambar']);
+ if ($row && $row['gambar'] && file_exists(__DIR__ . '/../' . $row['gambar'])) {
+ unlink(__DIR__ . '/../' . $row['gambar']);
}
$stmt->close();
@@ -43,4 +43,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
http_response_code(405);
echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
$conn->close();
-?>
\ No newline at end of file
+?>
diff --git a/get_jalan_rusak.php b/fitur_jalan_parsel/get_jalan_rusak.php
similarity index 94%
rename from get_jalan_rusak.php
rename to fitur_jalan_parsel/get_jalan_rusak.php
index 8ad088a..742dac4 100644
--- a/get_jalan_rusak.php
+++ b/fitur_jalan_parsel/get_jalan_rusak.php
@@ -1,6 +1,6 @@
+
+
+
+
+ Fitur Jalan & Parsel
+
+
+
+
+
+
+ Tipe Jalan: Jalan Nasional Jalan Provinsi Jalan Kabupaten
+
+
+
+
+
+
+
+
diff --git a/save_jalan_rusak.php b/fitur_jalan_parsel/save_jalan_rusak.php
similarity index 90%
rename from save_jalan_rusak.php
rename to fitur_jalan_parsel/save_jalan_rusak.php
index 78ca41e..f2e168f 100644
--- a/save_jalan_rusak.php
+++ b/fitur_jalan_parsel/save_jalan_rusak.php
@@ -1,6 +1,6 @@
'error', 'message' => 'Gagal upload gambar']);
exit;
diff --git a/fitur_parsil_tanah/api/delete_feature.php b/fitur_parsil_tanah/api/delete_feature.php
new file mode 100644
index 0000000..9864228
--- /dev/null
+++ b/fitur_parsil_tanah/api/delete_feature.php
@@ -0,0 +1,39 @@
+ 'error', 'message' => 'ID parsel tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("DELETE FROM spatial_features WHERE id = ?");
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param("i", $id);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Parsil tanah berhasil dihapus']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_parsil_tanah/api/get_features.php b/fitur_parsil_tanah/api/get_features.php
new file mode 100644
index 0000000..8abe16a
--- /dev/null
+++ b/fitur_parsil_tanah/api/get_features.php
@@ -0,0 +1,30 @@
+query($sql);
+$features = [];
+
+if (!$result) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]);
+ $conn->close();
+ exit;
+}
+
+if ($result && $result->num_rows > 0) {
+ while($row = $result->fetch_assoc()) {
+ $row['geometry_data'] = json_decode($row['geometry_data']);
+ $row['nilai_ukur'] = (float)$row['nilai_ukur'];
+ $features[] = $row;
+ }
+}
+
+echo json_encode($features);
+$conn->close();
+?>
diff --git a/fitur_parsil_tanah/api/save_feature.php b/fitur_parsil_tanah/api/save_feature.php
new file mode 100644
index 0000000..d5bc6be
--- /dev/null
+++ b/fitur_parsil_tanah/api/save_feature.php
@@ -0,0 +1,45 @@
+ 'error', 'message' => 'Data parsel tidak lengkap']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("INSERT INTO spatial_features (nama_objek, kategori, status_objek, type, geometry_data, nilai_ukur) VALUES (?, ?, ?, ?, ?, ?)");
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param("sssssd", $nama, $kategori, $status, $type, $geometry, $nilai);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Parsil tanah berhasil disimpan']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_parsil_tanah/api/update_feature.php b/fitur_parsil_tanah/api/update_feature.php
new file mode 100644
index 0000000..103cf80
--- /dev/null
+++ b/fitur_parsil_tanah/api/update_feature.php
@@ -0,0 +1,67 @@
+ 'error', 'message' => 'ID parsel tidak valid']);
+ $conn->close();
+ exit;
+ }
+
+ // Check if it is a geometry update or attribute update
+ $isGeometryUpdate = isset($_POST['geometry']);
+
+ if ($isGeometryUpdate) {
+ $geometry = $_POST['geometry'] ?? '';
+ $nilai = (float)($_POST['nilai'] ?? 0);
+
+ if ($geometry === '') {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Data geometri kosong']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("UPDATE spatial_features SET geometry_data = ?, nilai_ukur = ? WHERE id = ?");
+ $stmt->bind_param("sdi", $geometry, $nilai, $id);
+ } else {
+ $nama = trim($_POST['nama'] ?? '');
+ $status = trim($_POST['status'] ?? '');
+
+ if ($nama === '' || $status === '') {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Nama atau status tidak boleh kosong']);
+ $conn->close();
+ exit;
+ }
+
+ $stmt = $conn->prepare("UPDATE spatial_features SET nama_objek = ?, status_objek = ? WHERE id = ?");
+ $stmt->bind_param("ssi", $nama, $status, $id);
+ }
+
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Parsil tanah berhasil diperbarui']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
diff --git a/fitur_parsil_tanah/index.html b/fitur_parsil_tanah/index.html
new file mode 100644
index 0000000..30d6779
--- /dev/null
+++ b/fitur_parsil_tanah/index.html
@@ -0,0 +1,651 @@
+
+
+
+
+
+ Sistem GIS — Parsil Tanah
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informatika UNTAN
+
+
+
Parsil Tanah
+
Kelola dan ukur luas parsel tanah (polygon) secara realtime.
+
+
+
+
+ Total Parsil
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Memuat data parsel...
+
+
+
+
+
+
+
+
+ Tips: Gunakan tombol gambar di peta (sisi kanan) untuk menggambar batas parsel tanah baru, lalu isi nama pemilik & status sertifikat.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fitur_spbu/api/delete_location.php b/fitur_spbu/api/delete_location.php
new file mode 100644
index 0000000..985cd1a
--- /dev/null
+++ b/fitur_spbu/api/delete_location.php
@@ -0,0 +1,33 @@
+ 'error', 'message' => 'ID tidak valid']);
+ exit;
+ }
+
+ $stmt = $conn->prepare("DELETE FROM locations WHERE id = ?");
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param("i", $id);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'SPBU berhasil dihapus']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+$conn->close();
+?>
diff --git a/fitur_spbu/api/get_location.php b/fitur_spbu/api/get_location.php
new file mode 100644
index 0000000..0e6cb99
--- /dev/null
+++ b/fitur_spbu/api/get_location.php
@@ -0,0 +1,25 @@
+query($sql);
+
+$locations = [];
+
+if (!$result) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]);
+ $conn->close();
+ exit;
+}
+
+if ($result->num_rows > 0) {
+ while($row = $result->fetch_assoc()) {
+ $locations[] = $row;
+ }
+}
+
+echo json_encode($locations);
+$conn->close();
+?>
diff --git a/fitur_spbu/api/save_location.php b/fitur_spbu/api/save_location.php
new file mode 100644
index 0000000..bf03477
--- /dev/null
+++ b/fitur_spbu/api/save_location.php
@@ -0,0 +1,39 @@
+ 'error', 'message' => 'Data tidak lengkap']);
+ exit;
+ }
+
+ $stmt = $conn->prepare("INSERT INTO locations (nama, nomor, buka_24jam, latitude, longitude) VALUES (?, ?, ?, ?, ?)");
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param("sssdd", $nama, $nomor, $status, $lat, $lng);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Data SPBU berhasil disimpan']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+$conn->close();
+?>
diff --git a/fitur_spbu/api/update_coords.php b/fitur_spbu/api/update_coords.php
new file mode 100644
index 0000000..b42af04
--- /dev/null
+++ b/fitur_spbu/api/update_coords.php
@@ -0,0 +1,36 @@
+ 'error', 'message' => 'Data tidak lengkap']);
+ exit;
+ }
+
+ $stmt = $conn->prepare("UPDATE locations SET latitude = ?, longitude = ? WHERE id = ?");
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param("ddi", $lat, $lng, $id);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Koordinat SPBU berhasil diperbarui']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+$conn->close();
+?>
diff --git a/fitur_spbu/api/update_details.php b/fitur_spbu/api/update_details.php
new file mode 100644
index 0000000..6b6ee78
--- /dev/null
+++ b/fitur_spbu/api/update_details.php
@@ -0,0 +1,37 @@
+ 'error', 'message' => 'Data tidak lengkap']);
+ exit;
+ }
+
+ $stmt = $conn->prepare("UPDATE locations SET nama = ?, nomor = ?, buka_24jam = ? WHERE id = ?");
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $stmt->bind_param("sssi", $nama, $nomor, $status, $id);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Detail SPBU berhasil diperbarui']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+}
+$conn->close();
+?>
diff --git a/fitur_spbu/index.html b/fitur_spbu/index.html
new file mode 100644
index 0000000..e4c4c31
--- /dev/null
+++ b/fitur_spbu/index.html
@@ -0,0 +1,600 @@
+
+
+
+
+
+ Sistem GIS — Lokasi SPBU
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Informatika UNTAN
+
+
+
Lokasi SPBU
+
Pemetaan Stasiun Pengisian Bahan Bakar Umum (SPBU) beserta jam operasional.
+
+
+
+
+
+ Total SPBU
+ 0
+
+
+ Buka 24 Jam
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Memuat data SPBU...
+
+
+
+
+
+
+
+
+ Cara Menambah SPBU: Klik tombol Tambah Titik di atas peta, lalu klik lokasi SPBU pada peta.
+
+
+
+
+
+
+
+
+
+
+
+
+ Tambah Titik SPBU
+
+
+
+
+
+ Notifikasi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/get_aduan_warga.php b/get_aduan_warga.php
new file mode 100644
index 0000000..748c588
--- /dev/null
+++ b/get_aduan_warga.php
@@ -0,0 +1,24 @@
+query($sql);
+
+if (!$result) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]);
+ $conn->close();
+ exit;
+}
+
+$data = [];
+while ($row = $result->fetch_assoc()) {
+ $row['latitude'] = (float)$row['latitude'];
+ $row['longitude'] = (float)$row['longitude'];
+ $data[] = $row;
+}
+
+echo json_encode($data);
+$conn->close();
+?>
\ No newline at end of file
diff --git a/get_verifikasi_lapangan.php b/get_verifikasi_lapangan.php
new file mode 100644
index 0000000..1fbc570
--- /dev/null
+++ b/get_verifikasi_lapangan.php
@@ -0,0 +1,24 @@
+query($sql);
+
+if (!$result) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]);
+ $conn->close();
+ exit;
+}
+
+$data = [];
+while ($row = $result->fetch_assoc()) {
+ $row['latitude'] = (float)$row['latitude'];
+ $row['longitude'] = (float)$row['longitude'];
+ $data[] = $row;
+}
+
+echo json_encode($data);
+$conn->close();
+?>
\ No newline at end of file
diff --git a/global/leaflet-loader.js b/global/leaflet-loader.js
new file mode 100644
index 0000000..b46fe29
--- /dev/null
+++ b/global/leaflet-loader.js
@@ -0,0 +1,17 @@
+// Simple loader to make Leaflet resources available globally to pages
+(function(){
+ if(window._leafletLoaderRan) return; window._leafletLoaderRan = true;
+ var link = document.createElement('link');
+ link.rel = 'stylesheet';
+ link.href = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.css';
+ document.head.appendChild(link);
+
+ var script = document.createElement('script');
+ script.src = 'https://unpkg.com/leaflet@1.9.4/dist/leaflet.js';
+ script.defer = false;
+ script.onload = function(){
+ console.log('Leaflet loaded');
+ var ev = document.createEvent('Event'); ev.initEvent('leaflet:loaded', true, true); window.dispatchEvent(ev);
+ };
+ document.head.appendChild(script);
+})();
diff --git a/index.html b/index.html
index 3885645..afa23cb 100644
--- a/index.html
+++ b/index.html
@@ -3,4059 +3,244 @@
- Sistem GIS
+ GIS Portal Program Studi Informatika Untan
-
-
-
+
+
+
+
-
+
-
-
-
-
+
+
+
+
-
-
Mengecek koneksi...
-
- SPBU
- 0
-
-
-
-
- Status
-
-
-
- Panjang / Luas
-
-
-
- Mulai
- Bersih
-
-
-
-
+
+
+
+ Akses visualisasi data spasial kota Pontianak, mulai dari sertifikasi parsel tanah, sebaran SPBU, jaringan jalan dan kondisi infrastruktur, hingga pengelolaan bantuan penduduk.
+
-
-
-
-
-
-
-
-
Registry
-
Filter dan pencarian data input.
-
-
-
-
-
-
-
- Tercatat
- 0
-
-
-
-
-
Cari Nama / Atribut
-
+
+
- Jenis
-
- Semua
- Poin
- Polyline
- Polygon
- Rumah Ibadah
- Penduduk Miskin
- Jalan Rusak
-
-
-
-
-
-
- Terapkan
- Reset
-
-
-
-
- Memuat data input...
+
Database
+
-
-
-
-
-
Manajemen Bantuan
-
Kelola bantuan untuk penduduk miskin per wilayah rumah ibadah.
-
-
-
-
-
-
-
-
- Rumah Ibadah Wilayah
-
- Pilih rumah ibadah...
-
-
-
- Status Bantuan
-
- Semua
- Belum Dibantu
- Sedang Diproses
- Sudah Dibantu
-
-
-
- Cari Ketua KK
-
-
-
-
-
- Prioritas
- 0
-
-
-
-
- Pilih rumah ibadah untuk melihat daftar penerima bantuan.
-
-
-
-
-
-
-
-
-
-
Choropleth Kecamatan Pontianak
-
Klik kecamatan untuk melihat jumlah penduduk.
-
-
Interaktif
-
-
-
-
Belum dipilih
-
-
-
Klik salah satu kecamatan di peta.
-
-
-
-
< 80.000 jiwa
-
80.000 - 100.000
-
100.000 - 120.000
-
> 120.000 jiwa
-
-
-
-
-
-
-
-
-
-
-
-
Edit Fitur Spasial
-
Ubah atribut atau simpan geometri yang sudah diedit di peta.
-
-
Tutup
-
-
-
-
- Nama Objek
-
-
-
- Kategori
-
-
-
- Tipe
-
-
-
- Status
-
-
-
- Panjang / Luas
-
-
-
-
- Simpan Atribut
- Edit Geometri
- Simpan Geometri
- Hapus
-
-
-
-
-
-
-
-
-
-
Input Fitur Baru
-
Isi nama setelah garis atau polygon selesai digambar.
-
-
Tutup
-
-
-
- Simpan
- Batal
-
-
-
-
-
-
-
-
-
-
Lapor Jalan Rusak
-
Dokumentasikan kondisi jalan dengan foto untuk membantu perbaikan.
-
-
Tutup
-
-
-
- Jenis Kerusakan
-
- Pilih jenis kerusakan
- Lubang
- Retak
- Ambles
- Bergelombang
- Lainnya
-
-
-
- Tingkat Kerusakan
-
- Ringan
- Sedang
- Berat
-
-
-
- Deskripsi
-
-
-
-
Foto Kondisi (Opsional)
-
-
-
-
-
-
- 📍 Koordinat: -
-
-
-
- Simpan Laporan
- Batal
-
-
-
-
-
-
-
-
-
Input Rumah Ibadah
-
Alamat diambil otomatis dari reverse geocode koordinat peta.
-
-
Tutup
-
-
-
-
- Nama Rumah Ibadah
-
-
-
- Alamat Otomatis
-
-
-
- PIC
-
-
-
-
Radius Pencarian
-
-
Radius: 1000 meter
-
-
- 📍 Koordinat: -
-
-
-
- Simpan
- Batal
-
-
-
-
-
-
-
-
-
Input Penduduk Miskin
-
Data akan ditautkan otomatis ke rumah ibadah terdekat.
-
-
Tutup
-
-
-
-
- Nama Ketua KK
-
-
-
- Jumlah Anggota Keluarga
-
-
-
- Rumah Ibadah Terdekat
-
-
-
- Jarak ke Rumah Ibadah
-
-
-
- 📍 Koordinat: -
-
-
-
- Simpan
- Batal
-
-
-
-
-
- polyline
- polygon
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/layer_groups_choropleth/api.php b/layer_groups_choropleth/api.php
new file mode 100644
index 0000000..57ffcc7
--- /dev/null
+++ b/layer_groups_choropleth/api.php
@@ -0,0 +1,3 @@
+true,'msg'=>'API placeholder untuk layer groups']);
diff --git a/delete_feature.php b/layer_groups_choropleth/delete_feature.php
similarity index 95%
rename from delete_feature.php
rename to layer_groups_choropleth/delete_feature.php
index 35148d7..dc6f240 100644
--- a/delete_feature.php
+++ b/layer_groups_choropleth/delete_feature.php
@@ -1,6 +1,6 @@
close();
-?>
\ No newline at end of file
+?>
diff --git a/layer_groups_choropleth/get_features.php b/layer_groups_choropleth/get_features.php
new file mode 100644
index 0000000..2831793
--- /dev/null
+++ b/layer_groups_choropleth/get_features.php
@@ -0,0 +1,29 @@
+query($sql);
+$features = [];
+
+if (!$result) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Query gagal: ' . $conn->error]);
+ $conn->close();
+ exit;
+}
+
+if ($result && $result->num_rows > 0) {
+ while($row = $result->fetch_assoc()) {
+ $row['geometry_data'] = json_decode($row['geometry_data']);
+ $row['nilai_ukur'] = (float)$row['nilai_ukur'];
+ $features[] = $row;
+ }
+}
+
+echo json_encode($features);
+$conn->close();
+?>
diff --git a/layer_groups_choropleth/index.html b/layer_groups_choropleth/index.html
new file mode 100644
index 0000000..18df4b4
--- /dev/null
+++ b/layer_groups_choropleth/index.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
Layer Groups & Choropleth
+
+
+
+
+
+
+
+
+
diff --git a/save_feature.php b/layer_groups_choropleth/save_feature.php
similarity index 93%
rename from save_feature.php
rename to layer_groups_choropleth/save_feature.php
index f94bcf2..28b7c1c 100644
--- a/save_feature.php
+++ b/layer_groups_choropleth/save_feature.php
@@ -2,7 +2,7 @@
header('Content-Type: application/json');
ini_set('display_errors', '0');
ini_set('html_errors', '0');
-include 'db_config.php';
+include __DIR__ . '/../db_config.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$nama = trim($_POST['nama'] ?? '');
@@ -13,7 +13,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$status = trim($_POST['status'] ?? '');
$type = trim($_POST['type'] ?? '');
$geometry = $_POST['geometry'] ?? '';
- $nilai = (float)($_POST['nilai'] ?? 0); // Nilai otomatis dari frontend
+ $nilai = (float)($_POST['nilai'] ?? 0);
if ($nama === '' || $kategori === '' || $status === '' || $type === '' || $geometry === '') {
http_response_code(400);
diff --git a/update_feature.php b/layer_groups_choropleth/update_feature.php
similarity index 97%
rename from update_feature.php
rename to layer_groups_choropleth/update_feature.php
index e8ed329..06a5ac5 100644
--- a/update_feature.php
+++ b/layer_groups_choropleth/update_feature.php
@@ -1,6 +1,6 @@
close();
-?>
\ No newline at end of file
+?>
diff --git a/rancangan_sistem/README.md b/rancangan_sistem/README.md
new file mode 100644
index 0000000..0af0866
--- /dev/null
+++ b/rancangan_sistem/README.md
@@ -0,0 +1,33 @@
+# Rancangan Sistem Geospasial untuk Kontribusi Pengentasan Kemiskinan
+
+Ringkasan singkat: rancangan ini menggabungkan data titik (SPBU, fasilitas), jaringan jalan (polyline), parsel tanah (polygon dengan luas otomatis), dan peta tematik (choropleth). Tujuan: menyediakan basis data spasial untuk analisis kebutuhan bantuan, akses layanan, dan prioritas intervensi.
+
+Komponen:
+
+- Data: sampel sensus, kemiskinan, infrastruktur, peta batas administrasi, penggunaan lahan, parsel tanah.
+- Backend: API PHP ringan untuk CRUD GeoJSON + penyimpanan file atau database spatial (PostGIS direkomendasikan).
+- Frontend: Leaflet + plugins (Draw, Turf.js) untuk editing, pengukuran, dan visualisasi layer groups.
+- Analitik: agregasi statistik per kelurahan/kecamatan untuk choropleth (tingkat kemiskinan, akses fasilitas).
+
+Alur kerja singkat:
+
+1. Kumpulkan & validasi data atribut (nama, id, status ekonomis, luas parsel).
+2. Masukkan ke sistem: titik/line/polygon.
+3. Hitung atribut turunan: luas parsel (m²), distance-to-nearest-facility, road-condition index.
+4. Hasilkan peta tematik & laporan untuk prioritisasi intervensi.
+
+Rekomendasi teknis singkat:
+
+- Gunakan PostGIS untuk query spasial yang efisien.
+- Simpan snapshot GeoJSON untuk interoperabilitas.
+- Bangun API otentikasi dan logging perubahan (audit trail) untuk kebijakan bantuan.
+
+Catatan: folder lain di repo ini berisi contoh starter untuk tiap fitur (uji_spbu, fitur_jalan_parsel, layer_groups_choropleth).
+
+Global Leaflet loader:
+
+- File: `global/leaflet-loader.js` — tambahkan tag berikut ke halaman HTML Anda untuk memuat Leaflet dari satu sumber global:
+
+
+
+Gunakan `rancangan_sistem/index.html` sebagai contoh integrasi: halaman akan memanggil `rancangan_sistem/get_rumah_ibadah.php` dan `rancangan_sistem/get_penduduk_miskin.php` (endpoints lokal di folder yang sama) dan menambahkan data ke peta.
diff --git a/delete_penduduk_miskin.php b/rancangan_sistem/delete_penduduk_miskin.php
similarity index 94%
rename from delete_penduduk_miskin.php
rename to rancangan_sistem/delete_penduduk_miskin.php
index cdd0b98..daf3487 100644
--- a/delete_penduduk_miskin.php
+++ b/rancangan_sistem/delete_penduduk_miskin.php
@@ -1,6 +1,6 @@
close();
}
$conn->close();
-?>
\ No newline at end of file
+?>
diff --git a/get_penduduk_miskin.php b/rancangan_sistem/get_penduduk_miskin.php
similarity index 96%
rename from get_penduduk_miskin.php
rename to rancangan_sistem/get_penduduk_miskin.php
index 0342fca..f68a54d 100644
--- a/get_penduduk_miskin.php
+++ b/rancangan_sistem/get_penduduk_miskin.php
@@ -1,6 +1,6 @@
num_rows > 0) {
echo json_encode($data);
$conn->close();
-?>
\ No newline at end of file
+?>
diff --git a/rancangan_sistem/get_penduduk_miskin_geojson.php b/rancangan_sistem/get_penduduk_miskin_geojson.php
new file mode 100644
index 0000000..2c6c0f9
--- /dev/null
+++ b/rancangan_sistem/get_penduduk_miskin_geojson.php
@@ -0,0 +1,24 @@
+query($sql);
+$features = [];
+
+if ($result && $result->num_rows > 0) {
+ while ($row = $result->fetch_assoc()) {
+ $lat = isset($row['latitude']) ? (float)$row['latitude'] : null;
+ $lng = isset($row['longitude']) ? (float)$row['longitude'] : null;
+ $props = $row;
+ unset($props['latitude'], $props['longitude']);
+ $features[] = [
+ 'type' => 'Feature',
+ 'geometry' => [ 'type' => 'Point', 'coordinates' => [$lng, $lat] ],
+ 'properties' => $props
+ ];
+ }
+}
+
+echo json_encode([ 'type' => 'FeatureCollection', 'features' => $features ]);
+$conn->close();
diff --git a/get_rumah_ibadah.php b/rancangan_sistem/get_rumah_ibadah.php
similarity index 94%
rename from get_rumah_ibadah.php
rename to rancangan_sistem/get_rumah_ibadah.php
index 7f016d8..43fab32 100644
--- a/get_rumah_ibadah.php
+++ b/rancangan_sistem/get_rumah_ibadah.php
@@ -1,6 +1,6 @@
num_rows > 0) {
echo json_encode($data);
$conn->close();
-?>
\ No newline at end of file
+?>
diff --git a/rancangan_sistem/get_rumah_ibadah_geojson.php b/rancangan_sistem/get_rumah_ibadah_geojson.php
new file mode 100644
index 0000000..d5f19b4
--- /dev/null
+++ b/rancangan_sistem/get_rumah_ibadah_geojson.php
@@ -0,0 +1,24 @@
+query($sql);
+$features = [];
+
+if ($result && $result->num_rows > 0) {
+ while ($row = $result->fetch_assoc()) {
+ $lat = isset($row['latitude']) ? (float)$row['latitude'] : null;
+ $lng = isset($row['longitude']) ? (float)$row['longitude'] : null;
+ $props = $row;
+ unset($props['latitude'], $props['longitude']);
+ $features[] = [
+ 'type' => 'Feature',
+ 'geometry' => [ 'type' => 'Point', 'coordinates' => [$lng, $lat] ],
+ 'properties' => $props
+ ];
+ }
+}
+
+echo json_encode([ 'type' => 'FeatureCollection', 'features' => $features ]);
+$conn->close();
diff --git a/rancangan_sistem/index.html b/rancangan_sistem/index.html
new file mode 100644
index 0000000..6e4207a
--- /dev/null
+++ b/rancangan_sistem/index.html
@@ -0,0 +1,57 @@
+
+
+
+
+
+
Rancangan Sistem — Integrasi Rumah Ibadah & Penduduk Miskin
+
+
+
+
+
Data: Rumah Ibadah & Penduduk Miskin (dari API)
+
+
+
+
+
diff --git a/save_penduduk_miskin.php b/rancangan_sistem/save_penduduk_miskin.php
similarity index 98%
rename from save_penduduk_miskin.php
rename to rancangan_sistem/save_penduduk_miskin.php
index 18b4c51..d64856b 100644
--- a/save_penduduk_miskin.php
+++ b/rancangan_sistem/save_penduduk_miskin.php
@@ -1,6 +1,6 @@
close();
}
$conn->close();
-?>
\ No newline at end of file
+?>
diff --git a/save_rumah_ibadah.php b/rancangan_sistem/save_rumah_ibadah.php
similarity index 96%
rename from save_rumah_ibadah.php
rename to rancangan_sistem/save_rumah_ibadah.php
index 0f2481f..b6e5d9d 100644
--- a/save_rumah_ibadah.php
+++ b/rancangan_sistem/save_rumah_ibadah.php
@@ -1,6 +1,6 @@
close();
}
$conn->close();
-?>
\ No newline at end of file
+?>
diff --git a/rancangan_sistem/update_bantuan_penduduk.php b/rancangan_sistem/update_bantuan_penduduk.php
new file mode 100644
index 0000000..8e87d48
--- /dev/null
+++ b/rancangan_sistem/update_bantuan_penduduk.php
@@ -0,0 +1,48 @@
+ 'error', 'message' => 'Metode tidak diizinkan']);
+ $conn->close();
+ exit;
+}
+
+$id = (int)($_POST['id'] ?? 0);
+$status = strtolower(trim($_POST['bantuan_status'] ?? 'belum'));
+$catatan = trim($_POST['bantuan_catatan'] ?? '');
+
+if ($id <= 0) {
+ echo json_encode(['status' => 'error', 'message' => 'ID tidak valid']);
+ $conn->close();
+ exit;
+}
+
+if (!in_array($status, ['belum', 'proses', 'sudah'], true)) {
+ $status = 'belum';
+}
+
+$stmt = $conn->prepare("UPDATE penduduk_miskin SET bantuan_status = ?, bantuan_catatan = ?, bantuan_updated_at = CURRENT_TIMESTAMP WHERE id = ?");
+$stmt->bind_param("ssi", $status, $catatan, $id);
+
+if ($stmt->execute()) {
+ $updatedAtResult = $conn->query("SELECT bantuan_updated_at FROM penduduk_miskin WHERE id = " . (int)$id . " LIMIT 1");
+ $updatedAt = null;
+ if ($updatedAtResult && $updatedAtResult->num_rows > 0) {
+ $row = $updatedAtResult->fetch_assoc();
+ $updatedAt = $row['bantuan_updated_at'] ?? null;
+ }
+
+ echo json_encode([
+ 'status' => 'success',
+ 'message' => 'Status bantuan berhasil diperbarui',
+ 'bantuan_updated_at' => $updatedAt
+ ]);
+} else {
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+}
+
+$stmt->close();
+$conn->close();
+?>
diff --git a/update_penduduk_miskin.php b/rancangan_sistem/update_penduduk_miskin.php
similarity index 98%
rename from update_penduduk_miskin.php
rename to rancangan_sistem/update_penduduk_miskin.php
index b92f2c9..5282085 100644
--- a/update_penduduk_miskin.php
+++ b/rancangan_sistem/update_penduduk_miskin.php
@@ -1,6 +1,6 @@
close();
}
$conn->close();
-?>
\ No newline at end of file
+?>
diff --git a/save_aduan_warga.php b/save_aduan_warga.php
new file mode 100644
index 0000000..01bade8
--- /dev/null
+++ b/save_aduan_warga.php
@@ -0,0 +1,75 @@
+ 'error', 'message' => 'Kategori, nama pelapor, deskripsi, dan koordinat wajib diisi']);
+ $conn->close();
+ exit;
+ }
+
+ $foto = null;
+ if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) {
+ $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+ $filename = $_FILES['foto']['name'];
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+
+ if (!in_array($ext, $allowed, true)) {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Format foto hanya JPG, PNG, GIF, WEBP']);
+ $conn->close();
+ exit;
+ }
+
+ if (!is_dir('uploads')) {
+ mkdir('uploads', 0755, true);
+ }
+
+ $foto = 'uploads/' . time() . '_' . basename($filename);
+ if (!move_uploaded_file($_FILES['foto']['tmp_name'], $foto)) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Gagal upload foto']);
+ $conn->close();
+ exit;
+ }
+ }
+
+ $stmt = $conn->prepare('INSERT INTO aduan_warga (kategori, pelapor_nama, kontak_pelapor, deskripsi, status_tindak_lanjut, tindak_lanjut, foto, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $latitude = (float)$latitude;
+ $longitude = (float)$longitude;
+ $stmt->bind_param('sssssssdd', $kategori, $pelaporNama, $kontakPelapor, $deskripsi, $statusTindakLanjut, $tindakLanjut, $foto, $latitude, $longitude);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Aduan warga berhasil disimpan', 'id' => $stmt->insert_id]);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
\ No newline at end of file
diff --git a/save_verifikasi_lapangan.php b/save_verifikasi_lapangan.php
new file mode 100644
index 0000000..4e29331
--- /dev/null
+++ b/save_verifikasi_lapangan.php
@@ -0,0 +1,75 @@
+ 'error', 'message' => 'Nama petugas dan koordinat wajib diisi']);
+ $conn->close();
+ exit;
+ }
+
+ $foto = null;
+ if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) {
+ $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+ $filename = $_FILES['foto']['name'];
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+
+ if (!in_array($ext, $allowed, true)) {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Format foto hanya JPG, PNG, GIF, WEBP']);
+ $conn->close();
+ exit;
+ }
+
+ if (!is_dir('uploads')) {
+ mkdir('uploads', 0755, true);
+ }
+
+ $foto = 'uploads/' . time() . '_' . basename($filename);
+ if (!move_uploaded_file($_FILES['foto']['tmp_name'], $foto)) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Gagal upload foto']);
+ $conn->close();
+ exit;
+ }
+ }
+
+ $stmt = $conn->prepare('INSERT INTO verifikasi_lapangan (jenis_target, target_nama, petugas_nama, status_verifikasi, hasil_temuan, tindak_lanjut, foto, latitude, longitude) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $latitude = (float)$latitude;
+ $longitude = (float)$longitude;
+ $stmt->bind_param('sssssssdd', $jenisTarget, $targetNama, $petugasNama, $statusVerifikasi, $hasilTemuan, $tindakLanjut, $foto, $latitude, $longitude);
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Verifikasi lapangan berhasil disimpan', 'id' => $stmt->insert_id]);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
\ No newline at end of file
diff --git a/test_features.html b/test_features.html
index ffc8094..f2e8ee5 100644
--- a/test_features.html
+++ b/test_features.html
@@ -41,19 +41,19 @@
Load Rumah Ibadah Data
-
GET /get_rumah_ibadah.php
+
GET /rancangan_sistem/get_rumah_ibadah.php
Load Penduduk Miskin Data
-
GET /get_penduduk_miskin.php
+
GET /rancangan_sistem/get_penduduk_miskin.php
Load Jalan Rusak Data
-
GET /get_jalan_rusak.php
+
GET /fitur_jalan_parsel/get_jalan_rusak.php
@@ -158,7 +158,7 @@ async function testDatabase() {
async function testLoadRumahIbadah() {
try {
- const response = await fetch('get_rumah_ibadah.php');
+ const response = await fetch('rancangan_sistem/get_rumah_ibadah.php');
const text = await response.text();
const data = JSON.parse(text);
@@ -171,7 +171,7 @@ async function testLoadRumahIbadah() {
async function testLoadPendudukMiskin() {
try {
- const response = await fetch('get_penduduk_miskin.php');
+ const response = await fetch('rancangan_sistem/get_penduduk_miskin.php');
const text = await response.text();
const data = JSON.parse(text);
@@ -184,7 +184,7 @@ async function testLoadPendudukMiskin() {
async function testLoadJalanRusak() {
try {
- const response = await fetch('get_jalan_rusak.php');
+ const response = await fetch('fitur_jalan_parsel/get_jalan_rusak.php');
const text = await response.text();
const data = JSON.parse(text);
@@ -205,7 +205,7 @@ async function testSaveRumahIbadah() {
formData.append('longitude', document.getElementById('lngRumah').value);
formData.append('radius_m', document.getElementById('radiusRumah').value);
- const response = await fetch('save_rumah_ibadah.php', {
+ const response = await fetch('rancangan_sistem/save_rumah_ibadah.php', {
method: 'POST',
body: formData
});
diff --git a/uji_spbu/api.php b/uji_spbu/api.php
new file mode 100644
index 0000000..900860b
--- /dev/null
+++ b/uji_spbu/api.php
@@ -0,0 +1,12 @@
+false,'msg'=>'no input']); exit; }
+if($input['action']==='update_status'){
+ // contoh sederhana: simpan ke file log (uji saja)
+ $log = ['time'=>date('c'),'id'=>$input['id'],'status'=>$input['status']];
+ file_put_contents(__DIR__.'/spbu_status.log',json_encode($log)."\n",FILE_APPEND);
+ echo json_encode(['success'=>true,'log'=>$log]);
+ exit;
+}
+echo json_encode(['success'=>false,'msg'=>'unknown action']);
diff --git a/uji_spbu/index.html b/uji_spbu/index.html
new file mode 100644
index 0000000..b17b04d
--- /dev/null
+++ b/uji_spbu/index.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
Uji CRUD SPBU — Open/Close
+
+
+
+
+
+
+
+
+
diff --git a/update_aduan_warga.php b/update_aduan_warga.php
new file mode 100644
index 0000000..1d9e357
--- /dev/null
+++ b/update_aduan_warga.php
@@ -0,0 +1,84 @@
+ 'error', 'message' => 'Data aduan tidak lengkap']);
+ $conn->close();
+ exit;
+ }
+
+ $fotoSql = '';
+ $foto = null;
+ if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) {
+ $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+ $filename = $_FILES['foto']['name'];
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+
+ if (!in_array($ext, $allowed, true)) {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Format foto hanya JPG, PNG, GIF, WEBP']);
+ $conn->close();
+ exit;
+ }
+
+ if (!is_dir('uploads')) {
+ mkdir('uploads', 0755, true);
+ }
+
+ $foto = 'uploads/' . time() . '_' . basename($filename);
+ if (!move_uploaded_file($_FILES['foto']['tmp_name'], $foto)) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Gagal upload foto']);
+ $conn->close();
+ exit;
+ }
+
+ $fotoSql = ', foto = ?';
+ }
+
+ $sql = 'UPDATE aduan_warga SET kategori = ?, pelapor_nama = ?, kontak_pelapor = ?, deskripsi = ?, status_tindak_lanjut = ?, tindak_lanjut = ?, latitude = ?, longitude = ?' . $fotoSql . ' WHERE id = ?';
+ $stmt = $conn->prepare($sql);
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $latitude = (float)$latitude;
+ $longitude = (float)$longitude;
+ if ($foto !== null) {
+ $stmt->bind_param('sssssssddi', $kategori, $pelaporNama, $kontakPelapor, $deskripsi, $statusTindakLanjut, $tindakLanjut, $foto, $latitude, $longitude, $id);
+ } else {
+ $stmt->bind_param('ssssssddi', $kategori, $pelaporNama, $kontakPelapor, $deskripsi, $statusTindakLanjut, $tindakLanjut, $latitude, $longitude, $id);
+ }
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Aduan warga berhasil diperbarui']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
\ No newline at end of file
diff --git a/update_verifikasi_lapangan.php b/update_verifikasi_lapangan.php
new file mode 100644
index 0000000..33b2b66
--- /dev/null
+++ b/update_verifikasi_lapangan.php
@@ -0,0 +1,84 @@
+ 'error', 'message' => 'Data verifikasi tidak lengkap']);
+ $conn->close();
+ exit;
+ }
+
+ $fotoSql = '';
+ $foto = null;
+ if (isset($_FILES['foto']) && $_FILES['foto']['error'] === UPLOAD_ERR_OK) {
+ $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+ $filename = $_FILES['foto']['name'];
+ $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+
+ if (!in_array($ext, $allowed, true)) {
+ http_response_code(400);
+ echo json_encode(['status' => 'error', 'message' => 'Format foto hanya JPG, PNG, GIF, WEBP']);
+ $conn->close();
+ exit;
+ }
+
+ if (!is_dir('uploads')) {
+ mkdir('uploads', 0755, true);
+ }
+
+ $foto = 'uploads/' . time() . '_' . basename($filename);
+ if (!move_uploaded_file($_FILES['foto']['tmp_name'], $foto)) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => 'Gagal upload foto']);
+ $conn->close();
+ exit;
+ }
+
+ $fotoSql = ', foto = ?';
+ }
+
+ $sql = 'UPDATE verifikasi_lapangan SET jenis_target = ?, target_nama = ?, petugas_nama = ?, status_verifikasi = ?, hasil_temuan = ?, tindak_lanjut = ?, latitude = ?, longitude = ?' . $fotoSql . ' WHERE id = ?';
+ $stmt = $conn->prepare($sql);
+ if (!$stmt) {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $conn->error]);
+ $conn->close();
+ exit;
+ }
+
+ $latitude = (float)$latitude;
+ $longitude = (float)$longitude;
+ if ($foto !== null) {
+ $stmt->bind_param('sssssssddi', $jenisTarget, $targetNama, $petugasNama, $statusVerifikasi, $hasilTemuan, $tindakLanjut, $foto, $latitude, $longitude, $id);
+ } else {
+ $stmt->bind_param('ssssssddi', $jenisTarget, $targetNama, $petugasNama, $statusVerifikasi, $hasilTemuan, $tindakLanjut, $latitude, $longitude, $id);
+ }
+
+ if ($stmt->execute()) {
+ echo json_encode(['status' => 'success', 'message' => 'Verifikasi lapangan berhasil diperbarui']);
+ } else {
+ http_response_code(500);
+ echo json_encode(['status' => 'error', 'message' => $stmt->error]);
+ }
+
+ $stmt->close();
+ $conn->close();
+ exit;
+}
+
+http_response_code(405);
+echo json_encode(['status' => 'error', 'message' => 'Method tidak diizinkan']);
+$conn->close();
+?>
\ No newline at end of file