add new featurs like realtime 2026-5-10-24
This commit is contained in:
102
Admin/v2/quality/blacklist_manager.php
Normal file
102
Admin/v2/quality/blacklist_manager.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
// Admin/v2/quality/blacklist_manager.php
|
||||
require_once __DIR__ . '/../../../connect.php';
|
||||
// require_once __DIR__ . '/../../../encrypt_decrypt.php';
|
||||
require_once __DIR__ . '/../security/audit_logs_helper.php'; // إذا كان متاحاً، وإلا سننفذ الإدخال مباشرة
|
||||
|
||||
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||
jsonError("Unauthorized", 403);
|
||||
}
|
||||
|
||||
$action_type = filterRequest('action_type') ?: 'get_all';
|
||||
|
||||
try {
|
||||
if ($action_type === 'get_all') {
|
||||
// جلب قائمة السائقين المحظورين
|
||||
$stmt_drivers = $con->prepare("
|
||||
SELECT id, driver_id, phone, reason, created_at, 'driver' as type
|
||||
FROM blacklist_driver
|
||||
ORDER BY created_at DESC
|
||||
");
|
||||
$stmt_drivers->execute();
|
||||
$blocked_drivers = $stmt_drivers->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// جلب قائمة الركاب المحظورين
|
||||
$stmt_passengers = $con->prepare("
|
||||
SELECT id, phone, phone_normalized, reason, expires_at, created_at, 'passenger' as type
|
||||
FROM passenger_blacklist
|
||||
ORDER BY created_at DESC
|
||||
");
|
||||
$stmt_passengers->execute();
|
||||
$blocked_passengers = $stmt_passengers->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
// فك التشفير عن الأرقام إذا كانت مشفرة
|
||||
foreach ($blocked_drivers as &$bd) {
|
||||
$decrypted_phone = $encryptionHelper->decryptData($bd['phone']);
|
||||
if ($decrypted_phone) $bd['phone'] = $decrypted_phone;
|
||||
}
|
||||
|
||||
foreach ($blocked_passengers as &$bp) {
|
||||
$decrypted_phone = $encryptionHelper->decryptData($bp['phone']);
|
||||
if ($decrypted_phone) $bp['phone'] = $decrypted_phone;
|
||||
}
|
||||
|
||||
jsonSuccess([
|
||||
'drivers' => $blocked_drivers,
|
||||
'passengers' => $blocked_passengers
|
||||
]);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action_type === 'unblock_driver') {
|
||||
$phone = filterRequest('phone');
|
||||
if (!$phone) jsonError("Phone is required");
|
||||
|
||||
$enc_phone = $encryptionHelper->encryptData($phone);
|
||||
|
||||
$stmt = $con->prepare("DELETE FROM blacklist_driver WHERE phone = ? OR phone = ?");
|
||||
$stmt->execute([$phone, $enc_phone]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
// تسجيل في الـ Audit Log
|
||||
$log_stmt = $con->prepare("INSERT INTO admin_audit_log (admin_id, admin_phone, action, table_name, entity_type, details) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
$log_stmt->execute([
|
||||
$user_id, 'Admin', 'unblock_driver', 'blacklist_driver', 'driver',
|
||||
json_encode(['phone' => $phone, 'action' => 'Unblocked driver'])
|
||||
]);
|
||||
|
||||
jsonSuccess(null, "Driver unblocked successfully");
|
||||
} else {
|
||||
jsonError("Driver not found in blacklist");
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action_type === 'unblock_passenger') {
|
||||
$phone_normalized = filterRequest('phone_normalized');
|
||||
if (!$phone_normalized) jsonError("Normalized Phone is required");
|
||||
|
||||
$stmt = $con->prepare("DELETE FROM passenger_blacklist WHERE phone_normalized = ?");
|
||||
$stmt->execute([$phone_normalized]);
|
||||
|
||||
if ($stmt->rowCount() > 0) {
|
||||
// تسجيل في الـ Audit Log
|
||||
$log_stmt = $con->prepare("INSERT INTO admin_audit_log (admin_id, admin_phone, action, table_name, entity_type, details) VALUES (?, ?, ?, ?, ?, ?)");
|
||||
$log_stmt->execute([
|
||||
$user_id, 'Admin', 'unblock_passenger', 'passenger_blacklist', 'passenger',
|
||||
json_encode(['phone_normalized' => $phone_normalized, 'action' => 'Unblocked passenger'])
|
||||
]);
|
||||
|
||||
jsonSuccess(null, "Passenger unblocked successfully");
|
||||
} else {
|
||||
jsonError("Passenger not found in blacklist");
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
jsonError("Invalid action_type", 400);
|
||||
|
||||
} catch (Exception $e) {
|
||||
jsonError("Blacklist action failed: " . $e->getMessage(), 500);
|
||||
}
|
||||
?>
|
||||
105
Admin/v2/quality/driver_scorecard.php
Normal file
105
Admin/v2/quality/driver_scorecard.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
// Admin/v2/quality/driver_scorecard.php
|
||||
require_once __DIR__ . '/../../../connect.php';
|
||||
// require_once __DIR__ . '/../../../encrypt_decrypt.php';
|
||||
|
||||
// التحقق من الصلاحيات
|
||||
if ($role !== 'admin' && $role !== 'super_admin') {
|
||||
jsonError("Unauthorized", 403);
|
||||
}
|
||||
|
||||
$driver_id = filterRequest('driver_id');
|
||||
if (!$driver_id) {
|
||||
jsonError("Missing driver_id", 400);
|
||||
}
|
||||
|
||||
try {
|
||||
$scorecard = [];
|
||||
|
||||
// 1. البيانات الأساسية للسائق
|
||||
$stmt = $con->prepare("
|
||||
SELECT id, first_name, last_name, phone, status, created_at, expiry_date
|
||||
FROM driver
|
||||
WHERE id = ?
|
||||
");
|
||||
$stmt->execute([$driver_id]);
|
||||
$driver = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$driver) {
|
||||
jsonError("Driver not found", 404);
|
||||
}
|
||||
|
||||
// فك التشفير للبيانات الأساسية
|
||||
if (!empty($driver['first_name'])) $driver['first_name'] = $encryptionHelper->decryptData($driver['first_name']) ?: $driver['first_name'];
|
||||
if (!empty($driver['last_name'])) $driver['last_name'] = $encryptionHelper->decryptData($driver['last_name']) ?: $driver['last_name'];
|
||||
if (!empty($driver['phone'])) $driver['phone'] = $encryptionHelper->decryptData($driver['phone']) ?: $driver['phone'];
|
||||
|
||||
$scorecard['basic_info'] = $driver;
|
||||
|
||||
// 2. إحصائيات الرحلات (نسبة الإنجاز والإلغاء)
|
||||
$stmt = $con->prepare("
|
||||
SELECT
|
||||
COUNT(*) as total_rides,
|
||||
SUM(CASE WHEN status = 'Finished' THEN 1 ELSE 0 END) as completed_rides,
|
||||
SUM(CASE WHEN status = 'cancel' AND cancel_by = 'driver' THEN 1 ELSE 0 END) as driver_cancellations,
|
||||
SUM(CASE WHEN status = 'cancel' AND cancel_by = 'passenger' THEN 1 ELSE 0 END) as passenger_cancellations
|
||||
FROM ride
|
||||
WHERE driver_id = ?
|
||||
");
|
||||
$stmt->execute([$driver_id]);
|
||||
$rides = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// حساب نسبة الإنجاز
|
||||
$total = (int)$rides['total_rides'];
|
||||
$completed = (int)$rides['completed_rides'];
|
||||
$rides['completion_rate'] = $total > 0 ? round(($completed / $total) * 100, 2) : 0;
|
||||
|
||||
$scorecard['rides_stats'] = $rides;
|
||||
|
||||
// 3. التقييمات
|
||||
$stmt = $con->prepare("SELECT IFNULL(AVG(rating_driver), 0) as avg_rating FROM ride WHERE driver_id = ? AND rating_driver > 0");
|
||||
$stmt->execute([$driver_id]);
|
||||
$scorecard['rating'] = round($stmt->fetchColumn(), 2);
|
||||
|
||||
// 4. تحليل السلوك (Behavior)
|
||||
// نستخدم جدول driver_behavior لجمع المتوسطات
|
||||
$stmt = $con->prepare("
|
||||
SELECT
|
||||
IFNULL(AVG(behavior_score), 100) as avg_behavior_score,
|
||||
IFNULL(AVG(max_speed), 0) as avg_max_speed,
|
||||
IFNULL(SUM(hard_brakes), 0) as total_hard_brakes,
|
||||
IFNULL(SUM(rapid_accelerations), 0) as total_rapid_accel
|
||||
FROM driver_behavior
|
||||
WHERE driver_id = ?
|
||||
");
|
||||
$stmt->execute([$driver_id]);
|
||||
$scorecard['behavior'] = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// 5. الشكاوى (Complaints)
|
||||
$stmt = $con->prepare("
|
||||
SELECT
|
||||
COUNT(*) as total_complaints,
|
||||
SUM(CASE WHEN statusComplaint = 'Open' THEN 1 ELSE 0 END) as open_complaints,
|
||||
SUM(CASE WHEN statusComplaint = 'Resolved' THEN 1 ELSE 0 END) as resolved_complaints
|
||||
FROM complaint
|
||||
WHERE driver_id = ?
|
||||
");
|
||||
$stmt->execute([$driver_id]);
|
||||
$scorecard['complaints'] = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
// 6. تقييم شامل (Overall Score) من 100
|
||||
// وزن التقييم: 40% إنجاز رحلات، 30% تقييم ركاب (محول لـ 100)، 30% سلوك قيادة، وخصم للشكاوى
|
||||
$completion_score = $rides['completion_rate'] * 0.4;
|
||||
$rating_score = ($scorecard['rating'] / 5) * 100 * 0.3;
|
||||
$behavior_score = $scorecard['behavior']['avg_behavior_score'] * 0.3;
|
||||
$complaint_penalty = $scorecard['complaints']['total_complaints'] * 5; // خصم 5 نقاط عن كل شكوى
|
||||
|
||||
$overall = $completion_score + $rating_score + $behavior_score - $complaint_penalty;
|
||||
$scorecard['overall_score'] = max(0, min(100, round($overall, 1)));
|
||||
|
||||
jsonSuccess($scorecard);
|
||||
|
||||
} catch (Exception $e) {
|
||||
jsonError("Failed to fetch scorecard: " . $e->getMessage(), 500);
|
||||
}
|
||||
?>
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/core/bootstrap.php';
|
||||
|
||||
// ننشئ الاتصال يدوياً لتجاوز connect.php الذي يطلب Token
|
||||
try {
|
||||
$con = Database::get('main');
|
||||
} catch (Exception $e) {
|
||||
die("Database Connection Error: " . $e->getMessage());
|
||||
}
|
||||
|
||||
// لتعطيل الفحص الأمني مؤقتاً لأغراض الفحص من المتصفح
|
||||
// لا تقم برفع هذا الملف إلى السيرفر الحي إلا للفحص ثم حذفه
|
||||
|
||||
ini_set('display_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
|
||||
echo "<h3>فحص نظام السجلات (Audit Log Test)</h3>";
|
||||
|
||||
try {
|
||||
$stmt = $con->prepare("
|
||||
INSERT INTO `admin_audit_log` (`admin_id`, `action`, `table_name`, `record_id`, `details`)
|
||||
VALUES (:admin_id, :action, :table_name, :record_id, :details)
|
||||
");
|
||||
$result = $stmt->execute([
|
||||
':admin_id' => 'test_admin_01',
|
||||
':action' => 'فحص النظام',
|
||||
':table_name' => 'test_table',
|
||||
':record_id' => '999',
|
||||
':details' => json_encode(['status' => 'test'], JSON_UNESCAPED_UNICODE)
|
||||
]);
|
||||
|
||||
if ($result) {
|
||||
echo "<p style='color: green;'>✅ نجاح: تم إضافة سجل اختباري بنجاح إلى قاعدة البيانات.</p>";
|
||||
} else {
|
||||
echo "<p style='color: orange;'>⚠️ فشل الإضافة ولكن لم يظهر خطأ!</p>";
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo "<p style='color: red;'>❌ خطأ في قاعدة البيانات: " . $e->getMessage() . "</p>";
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user