Files
Siro/knowledge/siro_admin_simulation.html
2026-06-21 02:07:00 +03:00

752 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Siro Admin محاكاة لوحة التحكم والعمليات</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Tajawal:wght@300;400;500;700;900&display=swap" rel="stylesheet">
<style>
:root {
--bg: #090a0f;
--surface: #11131c;
--surface-elevated: #1a1d2b;
--border: #23273c;
--primary: #4776e6;
--primary-glow: rgba(71, 118, 230, 0.3);
--accent: #8e2de2;
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
--info: #06b6d4;
--text-primary: #f3f4f6;
--text-secondary: #9ca3af;
--divider: #1f2937;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Tajawal', sans-serif;
background-color: var(--bg);
color: var(--text-primary);
min-height: 100vh;
overflow-x: hidden;
display: flex;
flex-direction: column;
}
/* Header styling with Glassmorphism */
header {
background: rgba(17, 19, 28, 0.85);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--border);
padding: 16px 24px;
position: sticky;
top: 0;
z-index: 100;
display: flex;
justify-content: space-between;
align-items: center;
}
.brand {
display: flex;
align-items: center;
gap: 12px;
}
.logo-container {
width: 40px;
height: 40px;
background: linear-gradient(135deg, var(--primary), var(--accent));
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
font-weight: 900;
color: #ffffff;
font-size: 20px;
box-shadow: 0 0 15px var(--primary-glow);
}
.brand h1 {
font-size: 20px;
font-weight: 700;
background: linear-gradient(to left, #ffffff, var(--text-secondary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.header-status {
display: flex;
align-items: center;
gap: 16px;
}
.status-badge {
background: rgba(16, 185, 129, 0.1);
border: 1px solid var(--success);
color: var(--success);
padding: 6px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
display: flex;
align-items: center;
gap: 6px;
}
.pulse {
width: 8px;
height: 8px;
background-color: var(--success);
border-radius: 50%;
animation: pulse-animation 2s infinite;
}
@keyframes pulse-animation {
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0.7); }
70% { transform: scale(1); box-shadow: 0 0 0 6px rgba(16, 185, 129, 0); }
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(16, 185, 129, 0); }
}
/* Main layout setup */
.dashboard-container {
display: grid;
grid-template-columns: 280px 1fr;
flex: 1;
height: calc(100vh - 73px);
}
/* Sidebar controls */
.sidebar {
background-color: var(--surface);
border-left: 1px solid var(--border);
padding: 24px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 20px;
}
.menu-section-title {
font-size: 12px;
font-weight: 700;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 1px;
margin-bottom: 8px;
}
.sidebar-btn {
width: 100%;
background: var(--surface-elevated);
border: 1px solid var(--border);
border-radius: 12px;
padding: 12px 16px;
color: var(--text-primary);
font-family: inherit;
font-size: 14px;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
gap: 12px;
transition: all 0.2s ease;
text-align: right;
}
.sidebar-btn:hover {
border-color: var(--primary);
background: rgba(71, 118, 230, 0.05);
transform: translateY(-1px);
}
.sidebar-btn.active {
border-color: var(--primary);
background: linear-gradient(135deg, var(--primary), var(--accent));
color: #ffffff;
box-shadow: 0 4px 15px var(--primary-glow);
}
/* Workspace Panel */
.workspace {
display: grid;
grid-template-rows: auto 1fr;
overflow: hidden;
}
/* Top stats row */
.stats-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
padding: 24px;
background-color: rgba(9, 10, 15, 0.5);
}
.stat-card {
background-color: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 20px;
display: flex;
flex-direction: column;
gap: 8px;
position: relative;
overflow: hidden;
}
.stat-card::after {
content: '';
position: absolute;
bottom: 0;
right: 0;
left: 0;
height: 3px;
background: linear-gradient(to left, var(--primary), var(--accent));
opacity: 0;
transition: opacity 0.3s;
}
.stat-card:hover::after {
opacity: 1;
}
.stat-header {
display: flex;
justify-content: space-between;
align-items: center;
color: var(--text-secondary);
font-size: 13px;
}
.stat-value {
font-size: 28px;
font-weight: 800;
color: #ffffff;
}
.stat-change {
font-size: 12px;
display: flex;
align-items: center;
gap: 4px;
}
.stat-change.up { color: var(--success); }
.stat-change.down { color: var(--danger); }
/* Action view area */
.action-view {
padding: 0 24px 24px 24px;
overflow-y: auto;
display: grid;
grid-template-columns: 2fr 1fr;
gap: 24px;
}
/* Card Panels */
.panel-card {
background-color: var(--surface);
border: 1px solid var(--border);
border-radius: 16px;
padding: 24px;
display: flex;
flex-direction: column;
gap: 16px;
}
.panel-title {
font-size: 18px;
font-weight: 700;
display: flex;
align-items: center;
gap: 10px;
border-bottom: 1px solid var(--border);
padding-bottom: 12px;
}
/* Simulation Canvas Map */
.map-panel {
position: relative;
height: 320px;
background-color: #0b0d19;
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--border);
}
canvas {
width: 100%;
height: 100%;
display: block;
}
.map-controls {
position: absolute;
bottom: 12px;
right: 12px;
display: flex;
gap: 8px;
}
.map-btn {
background: rgba(17, 19, 28, 0.9);
border: 1px solid var(--border);
color: #fff;
padding: 6px 12px;
border-radius: 8px;
font-size: 12px;
cursor: pointer;
font-family: inherit;
}
.map-btn:hover {
background: var(--primary);
}
/* Logs view */
.logs-container {
max-height: 280px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 8px;
}
.log-item {
padding: 10px 14px;
border-radius: 10px;
font-size: 13px;
line-height: 1.4;
background-color: var(--surface-elevated);
border-right: 3px solid var(--border);
}
.log-item.success { border-color: var(--success); }
.log-item.warning { border-color: var(--warning); }
.log-item.danger { border-color: var(--danger); }
.log-item.info { border-color: var(--info); }
/* Forms */
.form-group {
display: flex;
flex-direction: column;
gap: 6px;
}
label {
font-size: 13px;
color: var(--text-secondary);
font-weight: 500;
}
input, select {
background-color: var(--surface-elevated);
border: 1px solid var(--border);
border-radius: 10px;
padding: 12px;
color: #fff;
font-family: inherit;
font-size: 14px;
outline: none;
}
input:focus, select:focus {
border-color: var(--primary);
}
.submit-btn {
background: linear-gradient(135deg, var(--primary), var(--accent));
color: #fff;
border: none;
padding: 12px;
border-radius: 10px;
font-weight: 700;
cursor: pointer;
font-family: inherit;
transition: opacity 0.2s;
}
.submit-btn:hover {
opacity: 0.9;
}
/* List queues (Captains documents) */
.doc-item {
display: flex;
justify-content: space-between;
align-items: center;
background-color: var(--surface-elevated);
padding: 12px 16px;
border-radius: 12px;
border: 1px solid var(--border);
}
.doc-info {
display: flex;
flex-direction: column;
gap: 4px;
}
.doc-name { font-weight: 600; font-size: 14px; }
.doc-details { font-size: 12px; color: var(--text-secondary); }
.doc-actions {
display: flex;
gap: 8px;
}
.action-btn {
padding: 6px 12px;
border-radius: 8px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
border: none;
font-family: inherit;
}
.action-btn.approve { background-color: rgba(16, 185, 129, 0.15); color: var(--success); }
.action-btn.reject { background-color: rgba(239, 68, 68, 0.15); color: var(--danger); }
</style>
</head>
<body>
<!-- Header -->
<header>
<div class="brand">
<div class="logo-container">S</div>
<h1>Siro Admin — محاكاة المشرف والعمليات</h1>
</div>
<div class="header-status">
<div class="status-badge">
<span class="pulse"></span>
اتصال WebSocket نشط
</div>
</div>
</header>
<!-- Container -->
<div class="dashboard-container">
<!-- Sidebar -->
<div class="sidebar">
<div>
<div class="menu-section-title">إدارة لوحة التحكم</div>
<button class="sidebar-btn active" onclick="switchTab('dashboard', this)">
<span>📊</span> لوحة التحكم الرئيسية
</button>
</div>
<div>
<div class="menu-section-title">التشغيل المالي والأسعار</div>
<button class="sidebar-btn" onclick="switchTab('kazan', this)">
<span>💰</span> عمولة Kazan والأسعار
</button>
</div>
<div>
<div class="menu-section-title">التوثيق والجودة</div>
<button class="sidebar-btn" onclick="switchTab('docs', this)">
<span>📑</span> وثائق الكباتن الجديدة
</button>
</div>
<div>
<div class="menu-section-title">الأمن والخصوصية</div>
<button class="sidebar-btn" onclick="switchTab('fraud', this)">
<span>🛡️</span> رادار بصمة الجهاز (الاحتيال)
</button>
</div>
</div>
<!-- Workspace -->
<div class="workspace">
<!-- Stats Row -->
<div class="stats-row">
<div class="stat-card">
<div class="stat-header">
<span>إجمالي الركاب</span>
<span class="stat-change up">▲ 12%</span>
</div>
<div class="stat-value" id="countPassengers">18,240</div>
</div>
<div class="stat-card">
<div class="stat-header">
<span>إجمالي الكباتن</span>
<span class="stat-change up">▲ 8%</span>
</div>
<div class="stat-value" id="countDrivers">4,912</div>
</div>
<div class="stat-card">
<div class="stat-header">
<span>رحلات الشهر الحالي</span>
<span class="stat-change up">▲ 24%</span>
</div>
<div class="stat-value" id="countRides">32,490</div>
</div>
<div class="stat-card">
<div class="stat-header">
<span>محفظة النظام (عمولات)</span>
<span class="stat-change down">▼ 2%</span>
</div>
<div class="stat-value" id="walletBalance">145,200 SP</div>
</div>
</div>
<!-- Tab Content Area -->
<div class="action-view">
<!-- Tab 1: Dashboard -->
<div id="tab-dashboard" class="panel-card" style="grid-column: 1 / 3;">
<div class="panel-title">📡 مراقبة الرحلات المباشرة والعمليات</div>
<div class="map-panel">
<canvas id="liveMapCanvas"></canvas>
<div class="map-controls">
<button class="map-btn" onclick="triggerMockRide()">محاكاة رحلة جديدة</button>
<button class="map-btn" onclick="clearSimulation()">مسح الخريطة</button>
</div>
</div>
<div class="panel-title">📝 سجل الأحداث والعمليات الفورية</div>
<div class="logs-container" id="logsContainer">
<div class="log-item info">[النظام]: تم تشغيل محاكاة Siro Admin بنجاح.</div>
<div class="log-item success">[العمليات]: تم الاتصال بخادم الـ Websocket (rides.intaleq.xyz).</div>
</div>
</div>
<!-- Tab 2: Kazan pricing -->
<div id="tab-kazan" class="panel-card" style="display:none;">
<div class="panel-title">💰 تعديل عمولة Kazan ومعدلات التعرفة</div>
<div class="form-group">
<label>الدولة والمنطقة</label>
<select id="countrySelect">
<option value="Syria">سوريا (دمشق)</option>
<option value="Jordan">الأردن (عمان)</option>
<option value="Egypt">مصر (القاهرة)</option>
</select>
</div>
<div class="form-group">
<label>نسبة عمولة Kazan (%)</label>
<input type="number" id="commissionPct" value="15" min="5" max="30">
</div>
<div class="form-group">
<label>تعرفة الكيلومتر الأساسية (عملة محلية)</label>
<input type="number" id="baseKmPrice" value="1200">
</div>
<button class="submit-btn" onclick="updateKazanCommission()">حفظ وتحديث نظام التسعير</button>
</div>
<!-- Tab 3: Captin Documents (Azure OCR Simulation) -->
<div id="tab-docs" class="panel-card" style="display:none;">
<div class="panel-title">📑 وثائق الكباتن بانتظار التدقيق والتحقق</div>
<div style="display:flex; flex-direction:column; gap:12px;" id="docsQueue">
<div class="doc-item" id="doc-c1">
<div class="doc-info">
<span class="doc-name">الكابتن: محمد أحمد الحموي</span>
<span class="doc-details">رقم السيارة: دمشق - 482920 • نوع المستند: رخصة القيادة</span>
<span class="doc-details" style="color:var(--success);">[تحليل الذكاء الاصطناعي Azure OCR]: الاسم والتواريخ متطابقة بنسبة 98%</span>
</div>
<div class="doc-actions">
<button class="action-btn approve" onclick="verifyDocument('c1', true)">قبول</button>
<button class="action-btn reject" onclick="verifyDocument('c1', false)">رفض</button>
</div>
</div>
<div class="doc-item" id="doc-c2">
<div class="doc-info">
<span class="doc-name">الكابتن: رامي طارق المصري</span>
<span class="doc-details">رقم السيارة: ريف دمشق - 729221 • نوع المستند: تأمين المركبة</span>
<span class="doc-details" style="color:var(--warning);">[تحليل الذكاء الاصطناعي Azure OCR]: المستند ينتهي خلال 3 أيام</span>
</div>
<div class="doc-actions">
<button class="action-btn approve" onclick="verifyDocument('c2', true)">قبول</button>
<button class="action-btn reject" onclick="verifyDocument('c2', false)">رفض</button>
</div>
</div>
</div>
</div>
<!-- Tab 4: Fraud radar device fingerprints -->
<div id="tab-fraud" class="panel-card" style="display:none;">
<div class="panel-title">🛡️ رادار كشف الاحتيال وتكرار بصمات الأجهزة</div>
<div class="log-item danger" style="padding:14px;">
<strong>تنبيه أمني هام:</strong> تم اكتشاف بصمة جهاز مكررة مرتبطة بـ 3 كباتن مختلفين!
<br>Device FP: <code>SHA256:d89ef239fbc87a1d...</code>
</div>
<div style="display:flex; flex-direction:column; gap:10px;">
<div class="doc-item">
<div class="doc-info">
<span class="doc-name">كابتن 1: علي سليم (نشط)</span>
<span class="doc-details">رقم الهاتف: 963992019283</span>
</div>
<button class="action-btn reject" style="background-color:rgba(239,68,68,0.25)" onclick="blockCaptain('علي سليم')">حظر فوري</button>
</div>
<div class="doc-item">
<div class="doc-info">
<span class="doc-name">كابتن 2: سامر وحيد (نشط)</span>
<span class="doc-details">رقم الهاتف: 963942091922</span>
</div>
<button class="action-btn reject" style="background-color:rgba(239,68,68,0.25)" onclick="blockCaptain('سامر وحيد')">حظر فوري</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Tab switching logic
function switchTab(tabId, btn) {
document.getElementById('tab-dashboard').style.display = 'none';
document.getElementById('tab-kazan').style.display = 'none';
document.getElementById('tab-docs').style.display = 'none';
document.getElementById('tab-fraud').style.display = 'none';
document.getElementById('tab-' + tabId).style.display = 'flex';
const buttons = document.querySelectorAll('.sidebar-btn');
buttons.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
if (tabId === 'dashboard') {
initCanvas();
}
}
// Logging helpers
function log(message, type = 'info') {
const container = document.getElementById('logsContainer');
const time = new Date().toLocaleTimeString('ar-EG');
const div = document.createElement('div');
div.className = `log-item ${type}`;
div.innerText = `[${time}] ${message}`;
container.prepend(div);
}
// Kazan changes
function updateKazanCommission() {
const pct = document.getElementById('commissionPct').value;
const kmPrice = document.getElementById('baseKmPrice').value;
const country = document.getElementById('countrySelect').value;
// Update stats
document.getElementById('walletBalance').innerText = `${(pct * 10000).toLocaleString()} SP`;
log(`[نظام كازان]: تم تحديث العمولة لتصبح ${pct}% لـ ${country} مع سعر كم قدره ${kmPrice}.`, 'success');
}
// Document approvals
function verifyDocument(id, approved) {
const element = document.getElementById(`doc-${id}`);
if (element) {
element.remove();
log(`[المستندات]: تم ${approved ? 'قبول' : 'رفض'} الوثائق للكابتن بنجاح.`, approved ? 'success' : 'danger');
}
}
// Block captain
function blockCaptain(name) {
log(`[الأمان والخصوصية]: تم حظر الكابتن (${name}) وتجميد محفظته بسبب مطابقة البصمة الرقمية المكررة.`, 'danger');
}
// Canvas map rendering
let canvas, ctx, animId;
let particles = [];
function initCanvas() {
canvas = document.getElementById('liveMapCanvas');
if (!canvas) return;
ctx = canvas.getContext('2d');
// Resize canvas relative to its container client dimensions
canvas.width = canvas.parentElement.clientWidth;
canvas.height = canvas.parentElement.clientHeight || 320;
// Seed initial dummy drivers
particles = [
{ x: canvas.width * 0.3, y: canvas.height * 0.4, label: '🚗 Comfort', angle: 0.5, speed: 0.3 },
{ x: canvas.width * 0.6, y: canvas.height * 0.7, label: '🏍️ Bike', angle: 1.2, speed: 0.6 },
{ x: canvas.width * 0.7, y: canvas.height * 0.3, label: '🚗 Speed', angle: 2.3, speed: 0.4 }
];
if (animId) cancelAnimationFrame(animId);
draw();
}
function draw() {
ctx.fillStyle = '#0b0d19';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Grid background
ctx.strokeStyle = '#181b2e';
ctx.lineWidth = 1;
for (let x = 0; x < canvas.width; x += 40) {
ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, canvas.height); ctx.stroke();
}
for (let y = 0; y < canvas.height; y += 40) {
ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(canvas.width, y); ctx.stroke();
}
// Draw cars
particles.forEach(p => {
p.x += Math.cos(p.angle) * p.speed;
p.y += Math.sin(p.angle) * p.speed;
// Boundary checks
if (p.x < 0 || p.x > canvas.width) p.angle = Math.PI - p.angle;
if (p.y < 0 || p.y > canvas.height) p.angle = -p.angle;
// Draw car indicator
ctx.fillStyle = '#4776e6';
ctx.beginPath();
ctx.arc(p.x, p.y, 8, 0, Math.PI * 2);
ctx.fill();
// Label
ctx.fillStyle = '#9ca3af';
ctx.font = '10px Tajawal';
ctx.fillText(p.label, p.x + 12, p.y + 4);
});
animId = requestAnimationFrame(draw);
}
function triggerMockRide() {
const newCar = {
x: canvas.width * 0.1,
y: canvas.height * 0.1,
label: '🚗 Speed (Active Ride)',
angle: 0.8,
speed: 1.2
};
particles.push(newCar);
log('[رحلة جديدة]: تم بدء رحلة نشطة للراكب #3829 مع الكابتن #4928.', 'info');
}
function clearSimulation() {
particles = [];
log('[النظام]: تم إخلاء الخريطة وتصفية كافة المركبات.', 'warning');
}
// Run canvas on page load
window.onload = initCanvas;
</script>
</body>
</html>