190 lines
8.5 KiB
HTML
Executable File
190 lines
8.5 KiB
HTML
Executable File
<!DOCTYPE html>
|
|
<html lang="ar" dir="rtl">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>تتبع السائقين - Tripz</title>
|
|
|
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
|
|
|
<style>
|
|
body { margin: 0; padding: 0; font-family: 'Segoe UI', Tahoma, sans-serif; overflow: hidden; }
|
|
#map { height: 100vh; width: 100%; z-index: 1; }
|
|
|
|
/* تصميم لوحة التحكم */
|
|
.dashboard {
|
|
position: absolute; top: 20px; right: 20px; width: 280px;
|
|
background: rgba(255, 255, 255, 0.95); padding: 15px;
|
|
border-radius: 10px; box-shadow: 0 4px 15px rgba(0,0,0,0.15);
|
|
z-index: 1000; text-align: right; border: 1px solid #ddd;
|
|
}
|
|
.dashboard h2 { margin: 0 0 10px 0; font-size: 16px; color: #333; border-bottom: 2px solid #3498db; padding-bottom: 8px; }
|
|
|
|
/* أزرار التبديل */
|
|
.mode-switcher { display: flex; gap: 5px; margin-bottom: 15px; }
|
|
.mode-btn {
|
|
flex: 1; padding: 8px; border: 1px solid #3498db; background: white;
|
|
color: #3498db; cursor: pointer; border-radius: 4px; font-size: 12px; transition: 0.2s;
|
|
}
|
|
.mode-btn.active { background: #3498db; color: white; font-weight: bold; }
|
|
|
|
/* الإحصائيات */
|
|
.info-row { display: flex; justify-content: space-between; margin-bottom: 5px; font-size: 13px; }
|
|
.val-active { color: #27ae60; font-weight: bold; }
|
|
.update-time { font-size: 11px; color: #7f8c8d; text-align: center; margin-top: 10px; display: block; }
|
|
|
|
/* زر التحديث */
|
|
.refresh-btn {
|
|
width: 100%; margin-top: 8px; padding: 8px; background: #2c3e50;
|
|
color: white; border: none; border-radius: 4px; cursor: pointer;
|
|
}
|
|
.refresh-btn:hover { background: #34495e; }
|
|
|
|
/* أيقونة السيارة */
|
|
.car-wrapper { transition: transform 0.5s ease; }
|
|
.car-svg { width: 35px; height: 35px; filter: drop-shadow(0px 2px 2px rgba(0,0,0,0.3)); }
|
|
|
|
/* Popup */
|
|
.popup-content { text-align: right; font-size: 12px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<div id="map"></div>
|
|
|
|
<div class="dashboard">
|
|
<h2>نظام التتبع المباشر</h2>
|
|
|
|
<div class="mode-switcher">
|
|
<button class="mode-btn active" id="btnLive" onclick="setMode('live')">مباشر (20د)</button>
|
|
<button class="mode-btn" id="btnDay" onclick="setMode('day')">اليوم كامل</button>
|
|
</div>
|
|
|
|
<div class="info-row">
|
|
<span>الوضع:</span>
|
|
<span id="modeLabel" style="font-weight:bold; color:#2980b9;">مباشر</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span>السائقين:</span>
|
|
<span id="countVal" class="val-active">0</span>
|
|
</div>
|
|
|
|
<small id="statusMsg" class="update-time">جاري التحميل...</small>
|
|
<button class="refresh-btn" onclick="fetchData()">تحديث البيانات</button>
|
|
</div>
|
|
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
|
|
|
<script>
|
|
// ================= إعدادات النظام =================
|
|
const BASE_URL = "https://location.intaleq.xyz/intaleq/ride/";
|
|
let currentMode = 'live';
|
|
|
|
// إعداد الخريطة
|
|
const map = L.map('map').setView([33.513, 36.276], 10);
|
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
attribution: 'Tripz System'
|
|
}).addTo(map);
|
|
|
|
const markersGroup = L.layerGroup().addTo(map);
|
|
|
|
// ================= دوال التحكم =================
|
|
function setMode(mode) {
|
|
currentMode = mode;
|
|
// تحديث الأزرار
|
|
document.getElementById('btnLive').className = mode === 'live' ? 'mode-btn active' : 'mode-btn';
|
|
document.getElementById('btnDay').className = mode === 'day' ? 'mode-btn active' : 'mode-btn';
|
|
|
|
// تحديث البيانات
|
|
fetchData();
|
|
}
|
|
|
|
function fetchData() {
|
|
const statusElem = document.getElementById('statusMsg');
|
|
statusElem.innerText = "جاري الاتصال بالسيرفر...";
|
|
statusElem.style.color = "#7f8c8d";
|
|
|
|
// تحديد اسم الملف
|
|
const fileName = currentMode === 'day' ? 'locations_day.json' : 'locations_live.json';
|
|
const finalUrl = BASE_URL + fileName + '?t=' + Date.now(); // Cache busting
|
|
|
|
fetch(finalUrl)
|
|
.then(response => {
|
|
// التحقق من أن الملف موجود
|
|
if (!response.ok) {
|
|
throw new Error("الملف غير موجود (404)");
|
|
}
|
|
// التحقق من نوع المحتوى (لتجنب Hello World)
|
|
const contentType = response.headers.get("content-type");
|
|
if (contentType && contentType.indexOf("application/json") === -1) {
|
|
throw new Error("البيانات ليست JSON (الرجاء تشغيل ملف PHP أولاً)");
|
|
}
|
|
return response.json();
|
|
})
|
|
.then(data => {
|
|
renderMap(data);
|
|
statusElem.innerText = "آخر تحديث: " + (data.last_updated || "الآن");
|
|
})
|
|
.catch(err => {
|
|
console.error("Error:", err);
|
|
statusElem.innerText = "خطأ: " + err.message;
|
|
statusElem.style.color = "#e74c3c";
|
|
// لا نمسح الخريطة عند الخطأ للحفاظ على آخر عرض
|
|
});
|
|
}
|
|
|
|
function renderMap(json) {
|
|
markersGroup.clearLayers();
|
|
const drivers = json.drivers || [];
|
|
|
|
document.getElementById('countVal').innerText = json.count || drivers.length;
|
|
document.getElementById('modeLabel').innerText = json.title || (currentMode=='day'?'يومي':'مباشر');
|
|
|
|
let bounds = [];
|
|
|
|
drivers.forEach(d => {
|
|
// البحث الذكي عن الإحداثيات
|
|
let lat = parseFloat(d.lat || d.latitude || d.Lat || d.LAT);
|
|
let lon = parseFloat(d.lon || d.lng || d.longitude || d.long || d.Lon || d.LNG);
|
|
|
|
if (!isNaN(lat) && !isNaN(lon) && lat !== 0 && lon !== 0) {
|
|
bounds.push([lat, lon]);
|
|
|
|
const color = currentMode === 'live' ? '#27ae60' : '#2980b9'; // أخضر للمباشر، أزرق لليومي
|
|
const heading = d.heading || 0;
|
|
|
|
const iconHtml = `
|
|
<div class="car-wrapper" style="transform: rotate(${heading}deg);">
|
|
<svg class="car-svg" viewBox="0 0 24 24" fill="${color}">
|
|
<path d="M18.92 6.01C18.72 5.42 18.16 5 17.5 5h-11c-.66 0-1.21.42-1.42 1.01L3 12v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 16c-.83 0-1.5-.67-1.5-1.5S5.67 13 6.5 13s1.5.67 1.5 1.5S7.33 16 6.5 16zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 11l1.5-4.5h11L19 11H5z"/>
|
|
</svg>
|
|
</div>`;
|
|
|
|
const icon = L.divIcon({ className: '', html: iconHtml, iconSize: [35, 35], iconAnchor: [17.5, 17.5] });
|
|
|
|
L.marker([lat, lon], {icon: icon})
|
|
.bindPopup(`
|
|
<div class="popup-content">
|
|
<strong>ID:</strong> ${d.driver_id || d.id}<br>
|
|
<strong>السرعة:</strong> ${d.speed || 0}<br>
|
|
<strong>الوقت:</strong> ${d.updated_at}
|
|
</div>
|
|
`)
|
|
.addTo(markersGroup);
|
|
}
|
|
});
|
|
|
|
// توجيه الكاميرا تلقائياً (Auto Zoom)
|
|
if (bounds.length > 0) {
|
|
map.fitBounds(bounds, { padding: [50, 50] });
|
|
}
|
|
}
|
|
|
|
// بدء التشغيل
|
|
fetchData();
|
|
// تحديث تلقائي كل 15 ثانية
|
|
setInterval(fetchData, 15000);
|
|
|
|
</script>
|
|
</body>
|
|
</html> |