Files
Siro/backend/Admin/v2/analytics/dashboard_data.php
T

120 lines
4.1 KiB
PHP

<?php
/**
* dashboard_data.php
* API موحّد للداشبورد التحليلي — يقرأ من ملفات JSON المؤرشفة + بيانات حيّة من Redis.
*
* Parameters:
* date (optional) — YYYY-MM-DD, default: today
* section (optional) — realtime|gap|heatmap|pricing|revenue|growth|market|complaints|funnel|hourly|weekly|zones|retention|all
* default: all
*/
require_once __DIR__ . '/../../../connect.php';
if ($role !== 'admin' && $role !== 'super_admin') {
http_response_code(403);
echo json_encode(['status' => 'error', 'message' => 'Unauthorized']);
exit;
}
$requestedDate = filterRequest('date') ?: date('Y-m-d');
$section = filterRequest('section') ?: 'all';
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $requestedDate)) {
http_response_code(400);
echo json_encode(['status' => 'error', 'message' => 'Invalid date format']);
exit;
}
$cacheBase = __DIR__ . '/../../../cache/analytics';
$dayDir = "$cacheBase/$requestedDate";
$response = [
'status' => 'success',
'date' => $requestedDate,
'section' => $section,
'data' => [],
];
function loadSnapshot(string $dir, string $name): ?array {
$path = "$dir/$name.json";
if (!file_exists($path)) return null;
$data = json_decode(file_get_contents($path), true);
return is_array($data) ? $data : null;
}
function loadLatestRealtime(string $dir): ?array {
$files = glob("$dir/realtime_*.json");
if (empty($files)) return null;
sort($files);
$latest = end($files);
$data = json_decode(file_get_contents($latest), true);
return is_array($data) ? $data : null;
}
$sectionMap = [
'realtime' => fn() => loadLatestRealtime($dayDir),
'gap' => fn() => loadSnapshot($dayDir, 'supply_demand_gap'),
'heatmap' => fn() => loadSnapshot($dayDir, 'heatmap'),
'pricing' => fn() => loadSnapshot($dayDir, 'pricing_grids'),
'demand' => fn() => loadSnapshot($dayDir, 'predictive_demand'),
'revenue' => fn() => loadSnapshot($dayDir, 'revenue_30d'),
'growth' => fn() => loadSnapshot($dayDir, 'growth_30d'),
'market' => fn() => loadSnapshot($dayDir, 'market_health'),
'complaints' => fn() => loadSnapshot($dayDir, 'complaints_open'),
'funnel' => fn() => loadSnapshot($dayDir, 'ride_funnel'),
'hourly' => fn() => loadSnapshot($dayDir, 'hourly_pattern'),
'weekly' => fn() => loadSnapshot($dayDir, 'weekly_comparison'),
'zones' => fn() => loadSnapshot($dayDir, 'top_zones'),
'retention' => fn() => loadSnapshot($dayDir, 'retention_cohort'),
'competitor' => fn() => loadSnapshot($dayDir, 'competitor_prices_24h'),
];
try {
if (!is_dir($dayDir)) {
$response['data'] = null;
$response['note'] = "No snapshot data for $requestedDate";
$indexPath = "$cacheBase/index.json";
if (file_exists($indexPath)) {
$idx = json_decode(file_get_contents($indexPath), true);
$response['available_dates'] = $idx['available_dates'] ?? [];
}
echo json_encode($response, JSON_UNESCAPED_UNICODE);
exit;
}
if ($section === 'all') {
foreach ($sectionMap as $key => $loader) {
$result = $loader();
if ($result !== null) {
$response['data'][$key] = $result;
}
}
} elseif (isset($sectionMap[$section])) {
$response['data'] = $sectionMap[$section]();
} else {
http_response_code(400);
echo json_encode([
'status' => 'error',
'message' => "Unknown section: $section",
'available' => array_keys($sectionMap),
]);
exit;
}
$indexPath = "$cacheBase/index.json";
if (file_exists($indexPath)) {
$idx = json_decode(file_get_contents($indexPath), true);
$response['available_dates'] = $idx['available_dates'] ?? [];
}
echo json_encode($response, JSON_UNESCAPED_UNICODE);
} catch (Exception $e) {
http_response_code(500);
error_log("[dashboard_data.php] " . $e->getMessage());
echo json_encode(['status' => 'error', 'message' => 'Internal error']);
}