نسخة كاملة من مستودع سيرو عند ecfe7568 لتكون أساس تطبيق «انطلق». نُسخ المتعقَّب في git فقط (12,509 ملفاً / 302 م.ب) بـ git archive، لا `cp -r` — فاستُثنيت تلقائياً مخلفات البناء (build · node_modules · .dart_tool · .gradle · Pods ≈ 10.7 غ.ب) وكل ما يستثنيه .gitignore. هذا الكوميت **بلا أي تعديل عمداً** حتى يكون كل ما يليه فرقاً مقروءاً مقابل سيرو الأصلي. سيرو نفسه لم يُمسّ. ⚠️ لا يبني بعد: `.env` و`lib/env/env.g.dart` غير متعقَّبين في سيرو (وهذا صحيح — أسرار لكل مستأجر). كل تطبيق فلاتر هنا يحتاج .env خاصاً بانطلق ثم توليد env.g.dart عبر build_runner. لا تُنسخ أسرار سيرو. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
2.9 KiB
PHP
73 lines
2.9 KiB
PHP
<?php
|
|
// Admin/transit/org/list.php — قائمة كل مؤسسات مواصلاتي (لفريق سيرو)
|
|
// GET/POST: country?, type?, contract_status?, search?, page?, per_page?
|
|
|
|
require_once __DIR__ . '/../../../connect.php';
|
|
|
|
if ($role !== 'admin' && $role !== 'super_admin') {
|
|
jsonError('Unauthorized: Admin access required', 403);
|
|
}
|
|
|
|
try { $transit_con = Database::get('transit'); }
|
|
catch (Exception $e) { jsonError('Transit service unavailable', 503); }
|
|
|
|
$country = filterRequest('country');
|
|
$type = filterRequest('type');
|
|
$contractStatus = filterRequest('contract_status');
|
|
$search = filterRequest('search');
|
|
$page = max(1, (int)(filterRequest('page', 'int') ?? 1));
|
|
$perPage = min(100, max(10, (int)(filterRequest('per_page', 'int') ?? 30)));
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$where = '1=1';
|
|
$params = [];
|
|
|
|
if ($country) { $where .= ' AND country = ?'; $params[] = strtoupper(substr($country, 0, 2)); }
|
|
if ($type) { $where .= ' AND type = ?'; $params[] = $type; }
|
|
if ($contractStatus) { $where .= ' AND contract_status = ?'; $params[] = $contractStatus; }
|
|
if ($search) { $where .= ' AND (name_ar LIKE ? OR name_en LIKE ?)'; $params[] = "%$search%"; $params[] = "%$search%"; }
|
|
|
|
$countSt = $transit_con->prepare("SELECT COUNT(*) FROM transit_orgs WHERE $where");
|
|
$countSt->execute($params);
|
|
$total = (int)$countSt->fetchColumn();
|
|
|
|
$params[] = $perPage;
|
|
$params[] = $offset;
|
|
$st = $transit_con->prepare(
|
|
"SELECT id, type, country, city, name_ar, name_en, logo_url,
|
|
contract_status, trial_ends_at, created_at
|
|
FROM transit_orgs
|
|
WHERE $where
|
|
ORDER BY created_at DESC
|
|
LIMIT ? OFFSET ?"
|
|
);
|
|
$st->execute($params);
|
|
$orgs = $st->fetchAll();
|
|
|
|
if ($orgs) {
|
|
$ids = implode(',', array_map('intval', array_column($orgs, 'id')));
|
|
|
|
$drivers = $transit_con->query("SELECT org_id, COUNT(*) c FROM transit_drivers WHERE org_id IN ($ids) GROUP BY org_id")
|
|
->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
$vehicles = $transit_con->query("SELECT org_id, COUNT(*) c FROM transit_vehicles WHERE org_id IN ($ids) GROUP BY org_id")
|
|
->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
$routes = $transit_con->query("SELECT org_id, COUNT(*) c FROM transit_routes WHERE org_id IN ($ids) AND status='active' GROUP BY org_id")
|
|
->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
$enrollments = $transit_con->query("SELECT org_id, COUNT(*) c FROM transit_enrollments WHERE org_id IN ($ids) AND status='active' GROUP BY org_id")
|
|
->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
|
|
foreach ($orgs as &$o) {
|
|
$id = $o['id'];
|
|
$o['drivers_count'] = (int)($drivers[$id] ?? 0);
|
|
$o['vehicles_count'] = (int)($vehicles[$id] ?? 0);
|
|
$o['active_routes'] = (int)($routes[$id] ?? 0);
|
|
$o['active_enrollments'] = (int)($enrollments[$id] ?? 0);
|
|
}
|
|
unset($o);
|
|
}
|
|
|
|
jsonSuccess([
|
|
'orgs' => $orgs,
|
|
'pagination' => ['total' => $total, 'page' => $page, 'per_page' => $perPage],
|
|
]);
|