prepare($sql); $stmt->execute($params); $rows = $stmt->fetchAll(); // Hitung prioritas untuk setiap penduduk foreach ($rows as &$r) { $belumDibantu = (int)$r['jumlah_bantuan_diterima'] === 0; $r['prioritas_bantuan'] = hitungPrioritasBantuan($r['status_ekonomi'], $r['kondisi_kesehatan'], $belumDibantu); } unset($r); jsonResponse(true, 'OK', ['data' => $rows, 'total' => count($rows)]); } if ($action === 'detail') { $nik = sanitizeStr($_GET['nik'] ?? ''); if (!validateNIK($nik)) jsonResponse(false, 'NIK tidak valid.', [], 400); $stmt = $pdo->prepare(" SELECT p.*, k.no_kk, k.nama_kk, ri.nama AS nama_ri FROM penduduk p LEFT JOIN keluarga k ON k.id = p.id_keluarga LEFT JOIN rumah_ibadah ri ON ri.id = k.rumah_ibadah_id WHERE p.nik = :nik "); $stmt->execute([':nik' => $nik]); $penduduk = $stmt->fetch(); if (!$penduduk) jsonResponse(false, 'Data tidak ditemukan.', [], 404); // Histori bantuan $stmtHB = $pdo->prepare(" SELECT hb.*, jb.nama AS nama_bantuan, jb.kategori, ri.nama AS nama_ri FROM histori_bantuan hb JOIN jenis_bantuan jb ON jb.id = hb.id_jenis_bantuan LEFT JOIN rumah_ibadah ri ON ri.id = hb.rumah_ibadah_id WHERE hb.nik = :nik ORDER BY hb.tanggal DESC "); $stmtHB->execute([':nik' => $nik]); $histori = $stmtHB->fetchAll(); // Pelatihan $stmtPl = $pdo->prepare("SELECT * FROM riwayat_pelatihan WHERE nik = :nik ORDER BY tanggal_mulai DESC"); $stmtPl->execute([':nik' => $nik]); $pelatihan = $stmtPl->fetchAll(); // Validasi pendidikan $validasi = validasiPendidikanUmur( (int)$penduduk['umur'], $penduduk['pendidikan_terakhir'], $penduduk['status_pendidikan'] ); $belumDibantu = empty($histori); $penduduk['prioritas_bantuan'] = hitungPrioritasBantuan($penduduk['status_ekonomi'], $penduduk['kondisi_kesehatan'], $belumDibantu); jsonResponse(true, 'OK', [ 'data' => $penduduk, 'histori' => $histori, 'pelatihan' => $pelatihan, 'validasi' => $validasi, ]); } if ($action === 'geojson') { // Untuk layer Leaflet $stmt = $pdo->query(" SELECT p.nik, p.nama_lengkap, p.status_ekonomi, p.kondisi_kesehatan, p.latitude, p.longitude, k.nama_kk, (SELECT COUNT(*) FROM histori_bantuan hb WHERE hb.nik=p.nik AND hb.status_penyaluran='disalurkan') AS jml_bantuan FROM penduduk p LEFT JOIN keluarga k ON k.id = p.id_keluarga WHERE p.latitude IS NOT NULL AND p.longitude IS NOT NULL AND p.status_hidup = 'hidup' "); $rows = $stmt->fetchAll(); $features = []; foreach ($rows as $r) { $color = match($r['status_ekonomi']) { 'miskin' => '#ef4444', 'rentan' => '#f59e0b', default => '#22c55e' }; $features[] = [ 'type' => 'Feature', 'geometry' => [ 'type' => 'Point', 'coordinates' => [(float)$r['longitude'], (float)$r['latitude']] ], 'properties' => array_merge($r, ['color' => $color]) ]; } header('Content-Type: application/json'); echo json_encode(['type' => 'FeatureCollection', 'features' => $features], JSON_UNESCAPED_UNICODE); exit; } jsonResponse(false, 'Action tidak dikenal.', [], 400); } // ============================================================ // POST - Create // ============================================================ if ($method === 'POST') { if (!canEdit($currentUser)) jsonResponse(false, 'Akses ditolak.', [], 403); $body = json_decode(file_get_contents('php://input'), true) ?? $_POST; $nik = sanitizeStr($body['nik'] ?? ''); $nama = sanitizeStr($body['nama_lengkap'] ?? ''); $jk = sanitizeStr($body['jenis_kelamin'] ?? ''); $tgl = sanitizeStr($body['tanggal_lahir'] ?? ''); $idKk = !empty($body['id_keluarga']) ? (int)$body['id_keluarga'] : null; if (!validateNIK($nik)) jsonResponse(false, 'Format NIK harus 16 digit angka.', [], 400); if (strlen($nama) < 3) jsonResponse(false, 'Nama terlalu pendek.', [], 400); if (!in_array($jk, ['L','P'])) jsonResponse(false, 'Jenis kelamin tidak valid.', [], 400); if (!strtotime($tgl)) jsonResponse(false, 'Format tanggal lahir tidak valid.', [], 400); // Cek duplikat NIK $cek = $pdo->prepare("SELECT nik FROM penduduk WHERE nik = :nik"); $cek->execute([':nik' => $nik]); if ($cek->fetch()) jsonResponse(false, 'NIK sudah terdaftar.', [], 409); // Hitung umur untuk validasi pendidikan $umur = (int)(new DateTime())->diff(new DateTime($tgl))->y; $statusPendidikan = sanitizeStr($body['status_pendidikan'] ?? 'tidak_sekolah'); $pendidikan = sanitizeStr($body['pendidikan_terakhir'] ?? 'tidak_sekolah'); $validasi = validasiPendidikanUmur($umur, $pendidikan, $statusPendidikan); $lat = !empty($body['latitude']) ? (float)$body['latitude'] : null; $lng = !empty($body['longitude']) ? (float)$body['longitude'] : null; if ($lat !== null && !validateCoord((string)$lat, 'lat')) jsonResponse(false, 'Latitude tidak valid.', [], 400); if ($lng !== null && !validateCoord((string)$lng, 'lng')) jsonResponse(false, 'Longitude tidak valid.', [], 400); $stmt = $pdo->prepare(" INSERT INTO penduduk (nik, id_keluarga, nama_lengkap, jenis_kelamin, tanggal_lahir, status_keluarga, status_perkawinan, status_hidup, pendidikan_terakhir, status_pendidikan, pekerjaan, penghasilan, status_ekonomi, kondisi_kesehatan, catatan_kesehatan, no_telp, alamat, latitude, longitude) VALUES (:nik,:kk,:nama,:jk,:tgl, :sk,:sp,:sh, :ptk,:spd, :pkr,:pgn,:se, :kkh,:ckkh, :tlp,:almt,:lat,:lng) "); $stmt->execute([ ':nik' => $nik, ':kk' => $idKk, ':nama' => $nama, ':jk' => $jk, ':tgl' => $tgl, ':sk' => sanitizeStr($body['status_keluarga'] ?? 'anggota_lain'), ':sp' => sanitizeStr($body['status_perkawinan'] ?? 'belum_kawin'), ':sh' => sanitizeStr($body['status_hidup'] ?? 'hidup'), ':ptk' => $pendidikan, ':spd' => $statusPendidikan, ':pkr' => sanitizeStr($body['pekerjaan'] ?? '') ?: null, ':pgn' => !empty($body['penghasilan']) ? (float)$body['penghasilan'] : 0, ':se' => sanitizeStr($body['status_ekonomi'] ?? 'rentan'), ':kkh' => sanitizeStr($body['kondisi_kesehatan'] ?? 'sehat'), ':ckkh' => sanitizeStr($body['catatan_kesehatan'] ?? '') ?: null, ':tlp' => sanitizeStr($body['no_telp'] ?? '') ?: null, ':almt' => sanitizeStr($body['alamat'] ?? '') ?: null, ':lat' => $lat, ':lng' => $lng, ]); logAktivitas($pdo, $currentUser['id'] ?? null, 'CREATE', 'penduduk', $nik, null, $body); jsonResponse(true, 'Penduduk berhasil ditambahkan.', [ 'nik' => $nik, 'validasi' => $validasi ], 201); } // ============================================================ // PUT - Update // ============================================================ if ($method === 'PUT') { if (!canEdit($currentUser)) jsonResponse(false, 'Akses ditolak.', [], 403); $nik = sanitizeStr($_GET['nik'] ?? ''); if (!validateNIK($nik)) jsonResponse(false, 'NIK tidak valid.', [], 400); $body = json_decode(file_get_contents('php://input'), true) ?? []; // Ambil data lama $old = $pdo->prepare("SELECT * FROM penduduk WHERE nik = :nik"); $old->execute([':nik' => $nik]); $dataLama = $old->fetch(); if (!$dataLama) jsonResponse(false, 'Data tidak ditemukan.', [], 404); $sets = []; $params = [':nik' => $nik]; $fieldMap = [ 'id_keluarga' => ':kk', 'nama_lengkap' => ':nama', 'jenis_kelamin' => ':jk', 'tanggal_lahir' => ':tgl', 'status_keluarga' => ':sk', 'status_perkawinan' => ':sp', 'status_hidup' => ':sh', 'pendidikan_terakhir' => ':ptk', 'status_pendidikan' => ':spd', 'pekerjaan' => ':pkr', 'penghasilan' => ':pgn', 'status_ekonomi' => ':se', 'kondisi_kesehatan' => ':kkh', 'catatan_kesehatan' => ':ckkh', 'no_telp' => ':tlp', 'alamat' => ':almt', 'latitude' => ':lat', 'longitude' => ':lng', ]; foreach ($fieldMap as $field => $param) { if (array_key_exists($field, $body)) { $sets[] = "$field = $param"; $params[$param] = $body[$field] === '' ? null : $body[$field]; } } if (empty($sets)) jsonResponse(false, 'Tidak ada data yang diubah.', [], 400); $sql = "UPDATE penduduk SET " . implode(', ', $sets) . " WHERE nik = :nik"; $pdo->prepare($sql)->execute($params); logAktivitas($pdo, $currentUser['id'] ?? null, 'UPDATE', 'penduduk', $nik, $dataLama, $body); jsonResponse(true, 'Data penduduk berhasil diperbarui.', ['nik' => $nik]); } // ============================================================ // DELETE // ============================================================ if ($method === 'DELETE') { if (!isAdmin($currentUser)) jsonResponse(false, 'Hanya admin yang bisa menghapus data.', [], 403); $nik = sanitizeStr($_GET['nik'] ?? ''); if (!validateNIK($nik)) jsonResponse(false, 'NIK tidak valid.', [], 400); $old = $pdo->prepare("SELECT * FROM penduduk WHERE nik = :nik"); $old->execute([':nik' => $nik]); $dataLama = $old->fetch(); if (!$dataLama) jsonResponse(false, 'Data tidak ditemukan.', [], 404); $pdo->prepare("DELETE FROM penduduk WHERE nik = :nik")->execute([':nik' => $nik]); logAktivitas($pdo, $currentUser['id'] ?? null, 'DELETE', 'penduduk', $nik, $dataLama, null); jsonResponse(true, 'Data penduduk dihapus.'); } jsonResponse(false, 'Method tidak didukung.', [], 405);