218 lines
8.3 KiB
PHP
218 lines
8.3 KiB
PHP
<?php
|
|
// api/stats/index.php — Dashboard Statistics
|
|
declare(strict_types=1);
|
|
require_once __DIR__ . '/../../config/bootstrap.php';
|
|
|
|
requireAuth();
|
|
$pdo = Database::get();
|
|
$action = $_GET['action'] ?? 'overview';
|
|
|
|
switch ($action) {
|
|
|
|
case 'overview': {
|
|
$centers = (int)$pdo->query("SELECT COUNT(*) FROM religious_centers WHERE is_active = 1")->fetchColumn();
|
|
$households = (int)$pdo->query("SELECT COUNT(*) FROM households WHERE is_active = 1")->fetchColumn();
|
|
|
|
// Total population (head + members)
|
|
$members = (int)$pdo->query("SELECT COUNT(*) FROM household_members")->fetchColumn();
|
|
$population = $households + $members;
|
|
|
|
// Aid received (based on aid_history)
|
|
$aidReceived = (int)$pdo->query("SELECT COUNT(DISTINCT household_id) FROM aid_history")->fetchColumn();
|
|
|
|
// Open emergency reports
|
|
$openReports = 0;
|
|
try {
|
|
$openReports = (int)$pdo->query("SELECT COUNT(*) FROM emergency_reports WHERE status IN ('open', 'in_progress')")->fetchColumn();
|
|
} catch (\Throwable) {}
|
|
|
|
// Pending public reports
|
|
$pendingPublic = 0;
|
|
try {
|
|
$pendingPublic = (int)$pdo->query("SELECT COUNT(*) FROM public_reports WHERE status = 'pending'")->fetchColumn();
|
|
} catch (\Throwable) {}
|
|
|
|
// Poverty breakdown
|
|
$povertyBreakdown = $pdo->query("
|
|
SELECT poverty_status, COUNT(*) AS cnt
|
|
FROM households WHERE is_active = 1
|
|
GROUP BY poverty_status
|
|
")->fetchAll(\PDO::FETCH_KEY_PAIR);
|
|
|
|
// Condition breakdown
|
|
$conditionBreakdown = $pdo->query("
|
|
SELECT house_condition, COUNT(*) AS cnt
|
|
FROM households WHERE is_active = 1
|
|
GROUP BY house_condition
|
|
")->fetchAll(\PDO::FETCH_KEY_PAIR);
|
|
|
|
Response::success([
|
|
'centers' => $centers,
|
|
'households' => $households,
|
|
'population' => $population,
|
|
'aid_received' => $aidReceived,
|
|
'aid_not_yet' => max(0, $households - $aidReceived),
|
|
'open_reports' => $openReports,
|
|
'pending_public' => $pendingPublic,
|
|
'poverty_breakdown' => [
|
|
'sangat_miskin' => (int)($povertyBreakdown['sangat_miskin'] ?? 0),
|
|
'miskin' => (int)($povertyBreakdown['miskin'] ?? 0),
|
|
'rentan_miskin' => (int)($povertyBreakdown['rentan_miskin'] ?? 0),
|
|
'terdata' => (int)($povertyBreakdown['terdata'] ?? 0),
|
|
],
|
|
'condition_breakdown' => [
|
|
'layak' => (int)($conditionBreakdown['layak'] ?? 0),
|
|
'tidak_layak' => (int)($conditionBreakdown['tidak_layak'] ?? 0),
|
|
],
|
|
]);
|
|
break;
|
|
}
|
|
|
|
case 'trend': {
|
|
$rows = $pdo->query("
|
|
SELECT
|
|
DATE_FORMAT(created_at, '%Y-%m') AS month,
|
|
COUNT(*) AS new_households,
|
|
SUM(CASE WHEN aid_status = 'received' THEN 1 ELSE 0 END) AS aided,
|
|
ROUND(AVG(poverty_score), 1) AS avg_score
|
|
FROM households
|
|
WHERE is_active = 1
|
|
AND created_at >= DATE_SUB(NOW(), INTERVAL 12 MONTH)
|
|
GROUP BY month
|
|
ORDER BY month
|
|
")->fetchAll();
|
|
|
|
foreach ($rows as &$r) {
|
|
$r['new_households'] = (int)$r['new_households'];
|
|
$r['aided'] = (int)$r['aided'];
|
|
$r['avg_score'] = (float)$r['avg_score'];
|
|
}
|
|
unset($r);
|
|
|
|
Response::success(['trend' => $rows]);
|
|
break;
|
|
}
|
|
|
|
case 'poverty_chart': {
|
|
$breakdown = $pdo->query("
|
|
SELECT poverty_status, COUNT(*) AS count,
|
|
ROUND(AVG(poverty_score), 1) AS avg_score
|
|
FROM households WHERE is_active = 1
|
|
GROUP BY poverty_status
|
|
ORDER BY FIELD(poverty_status, 'sangat_miskin', 'miskin', 'rentan_miskin', 'terdata')
|
|
")->fetchAll();
|
|
|
|
Response::success(['breakdown' => $breakdown]);
|
|
break;
|
|
}
|
|
|
|
case 'aid_chart': {
|
|
$byType = $pdo->query("
|
|
SELECT aid_type, COUNT(*) AS cnt, COALESCE(SUM(amount), 0) AS total_amount
|
|
FROM aid_history
|
|
GROUP BY aid_type
|
|
ORDER BY cnt DESC
|
|
")->fetchAll();
|
|
|
|
$total = (int)$pdo->query("SELECT COUNT(*) FROM aid_history")->fetchColumn();
|
|
|
|
Response::success([
|
|
'by_type' => $byType,
|
|
'summary' => ['total_distributions' => $total],
|
|
]);
|
|
break;
|
|
}
|
|
|
|
case 'age_distribution': {
|
|
$headQuery = "
|
|
SELECT
|
|
CASE
|
|
WHEN TIMESTAMPDIFF(YEAR, head_date_of_birth, CURDATE()) < 12 THEN 'anak'
|
|
WHEN TIMESTAMPDIFF(YEAR, head_date_of_birth, CURDATE()) BETWEEN 12 AND 17 THEN 'remaja'
|
|
WHEN TIMESTAMPDIFF(YEAR, head_date_of_birth, CURDATE()) BETWEEN 18 AND 30 THEN 'pemuda'
|
|
WHEN TIMESTAMPDIFF(YEAR, head_date_of_birth, CURDATE()) BETWEEN 31 AND 59 THEN 'dewasa'
|
|
WHEN TIMESTAMPDIFF(YEAR, head_date_of_birth, CURDATE()) >= 60 THEN 'lansia'
|
|
ELSE NULL
|
|
END AS age_group
|
|
FROM households
|
|
WHERE is_active = 1 AND head_date_of_birth IS NOT NULL
|
|
";
|
|
|
|
$memberQuery = "
|
|
SELECT
|
|
CASE
|
|
WHEN TIMESTAMPDIFF(YEAR, hm.date_of_birth, CURDATE()) < 12 THEN 'anak'
|
|
WHEN TIMESTAMPDIFF(YEAR, hm.date_of_birth, CURDATE()) BETWEEN 12 AND 17 THEN 'remaja'
|
|
WHEN TIMESTAMPDIFF(YEAR, hm.date_of_birth, CURDATE()) BETWEEN 18 AND 30 THEN 'pemuda'
|
|
WHEN TIMESTAMPDIFF(YEAR, hm.date_of_birth, CURDATE()) BETWEEN 31 AND 59 THEN 'dewasa'
|
|
WHEN TIMESTAMPDIFF(YEAR, hm.date_of_birth, CURDATE()) >= 60 THEN 'lansia'
|
|
ELSE NULL
|
|
END AS age_group
|
|
FROM household_members hm
|
|
INNER JOIN households h ON h.id = hm.household_id
|
|
WHERE h.is_active = 1 AND hm.date_of_birth IS NOT NULL
|
|
";
|
|
|
|
$combinedQuery = "
|
|
SELECT age_group, COUNT(*) as total
|
|
FROM (
|
|
$headQuery
|
|
UNION ALL
|
|
$memberQuery
|
|
) AS all_persons
|
|
WHERE age_group IS NOT NULL
|
|
GROUP BY age_group
|
|
";
|
|
|
|
$result = $pdo->query($combinedQuery);
|
|
$rows = $result->fetchAll(\PDO::FETCH_ASSOC);
|
|
|
|
// Inisialisasi array dengan nilai default 0
|
|
$distribution = [
|
|
'anak' => 0, // < 12 tahun
|
|
'remaja' => 0, // 12-17 tahun
|
|
'pemuda' => 0, // 18-30 tahun
|
|
'dewasa' => 0, // 31-59 tahun
|
|
'lansia' => 0, // >= 60 tahun
|
|
'unknown' => 0, // data tanggal lahir tidak tersedia
|
|
];
|
|
|
|
// Hitung jumlah orang tanpa tanggal lahir
|
|
$unknownCount = 0;
|
|
|
|
// Hitung kepala keluarga tanpa tanggal lahir
|
|
$stmt = $pdo->query("SELECT COUNT(*) FROM households WHERE is_active = 1 AND head_date_of_birth IS NULL");
|
|
$unknownCount += (int)$stmt->fetchColumn();
|
|
|
|
// Hitung anggota keluarga tanpa tanggal lahir
|
|
$stmt = $pdo->query("
|
|
SELECT COUNT(*) FROM household_members hm
|
|
INNER JOIN households h ON h.id = hm.household_id
|
|
WHERE h.is_active = 1 AND hm.date_of_birth IS NULL
|
|
");
|
|
$unknownCount += (int)$stmt->fetchColumn();
|
|
$distribution['unknown'] = $unknownCount;
|
|
|
|
// Isi hasil query ke array distribution
|
|
foreach ($rows as $row) {
|
|
if (isset($distribution[$row['age_group']])) {
|
|
$distribution[$row['age_group']] = (int)$row['total'];
|
|
}
|
|
}
|
|
|
|
// Hitung total keseluruhan untuk debugging (opsional)
|
|
$totalPeople = array_sum($distribution) - $distribution['unknown'];
|
|
|
|
Response::success([
|
|
'age_distribution' => $distribution,
|
|
'total_people' => $totalPeople,
|
|
'includes_members' => true // Indikator bahwa sudah termasuk anggota keluarga
|
|
]);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
Response::error('Unknown stats action.', 400);
|
|
}
|
|
|