Peta WebGIS Poverty Mapping
Pilih mode, klik titik pada peta, lalu isi form pada panel kanan sesuai kebutuhan data.
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(); ?>
Sistem Informasi Geografis
Pemetaan masyarakat prasejahtera, rumah ibadah, laporan cepat, dan histori bantuan berbasis lokasi.
= $loggedIn ? 'Login: ' . htmlspecialchars($_SESSION['user']['nama']) . ' (' . htmlspecialchars($roleLabel) . ($instansiLabel ? ' - ' . $instansiLabel : '') . ')' : 'Mode: Masyarakat Umum' ?>
Pilih mode, klik titik pada peta, lalu isi form pada panel kanan sesuai kebutuhan data.