diff --git a/addons/mymach_fleet_intelligence/static/src/js/dashboard.js b/addons/mymach_fleet_intelligence/static/src/js/dashboard.js index c0defd4..f4d6a6b 100644 --- a/addons/mymach_fleet_intelligence/static/src/js/dashboard.js +++ b/addons/mymach_fleet_intelligence/static/src/js/dashboard.js @@ -6,413 +6,387 @@ document.addEventListener("DOMContentLoaded", function() { var logsData = JSON.parse(telemetryEl.getAttribute('data-logs') || '[]'); var googleMapsApiKey = telemetryEl.getAttribute('data-gmaps-key') || ''; - var map; - var activePolylines = []; - var activeMarkers = []; + // Arka planda sunucudan JSON rotasını çek + fetch('/mymach_fleet_intelligence/static/src/data/history.json?t=' + new Date().getTime()) + .then(function(res) { + if (!res.ok) throw new Error('History not found'); + return res.json(); + }) + .then(function(historyData) { + initDashboard(historyData); + }) + .catch(function(e) { + // Dosya yoksa veya hata varsa boş rotayla başlat + initDashboard([]); + }); - var isGoogleLoaded = false; - if (googleMapsApiKey) { - if (typeof google !== 'undefined' && google.maps) { - isGoogleLoaded = true; - } - } + function initDashboard(serverHistory) { + var map; + var activePolylines = []; + var activeMarkers = []; - if (isGoogleLoaded) { - map = new google.maps.Map(document.getElementById('map'), { - center: {lat: 41.0766, lng: 29.0124}, - zoom: 12, - mapTypeId: 'hybrid', // Google Uydu + Yol Haritası - zoomControl: true, - zoomControlOptions: { position: google.maps.ControlPosition.RIGHT_BOTTOM }, - mapTypeControl: false - }); - } else { - map = L.map('map', { zoomControl: false }).setView([41.0766, 29.0124], 12); - L.control.zoom({ position: 'bottomright' }).addTo(map); - - // Yüksek Detaylı Esri World Imagery Uydu Haritası Katmanı - L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { - attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community', - maxZoom: 19 - }).addTo(map); - - // Şehir ve Yol Etiketleri Katmanı (Uydu üzerine) - L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}{r}.png', { - subdomains: 'abcd', - maxZoom: 19 - }).addTo(map); - } - - // Mavi Başlangıç İğnesi (Google Maps Stilinde) - function createBlueStartIcon() { - return L.divIcon({ - className: 'custom-blue-start-marker', - html: '
' + - '
' + - '
' + - '
', - iconSize: [26, 26], - iconAnchor: [13, 26] - }); - } - - // Kırmızı Bitiş Hedef İğnesi (Google Maps Stilinde) - function createRedEndIcon() { - return L.divIcon({ - className: 'custom-red-end-marker', - html: '
' + - '
' + - '
' + - '
', - iconSize: [26, 26], - iconAnchor: [13, 26] - }); - } - - // Yol Üzeri Türkçe Çağrı Kutucuğu (Callout Badge) - function createCalloutIcon(text, bgHex) { - var bg = bgHex || '#2563eb'; - return L.divIcon({ - className: 'custom-callout-marker', - html: '
' + text + '
', - iconSize: [130, 26], - iconAnchor: [65, 13] - }); - } - - var vehicleAnimationTimer = null; - - // Canlı Hareket Eden Araç İkonu (SVG 🚘 + Anlık Hız Göstergeli) - function createLiveCarIcon(driverTag, speedText) { - return L.divIcon({ - className: 'custom-live-car-marker', - html: '
' + - '
' + - '🚘 ' + (driverTag || 'Sürücü') + ' • ' + (speedText || '55 km/s') + '' + - '
' + - '
' + - '🚗' + - '
' + - '
', - iconSize: [140, 55], - iconAnchor: [70, 52] - }); - } - - function animateMovingVehicle(routePoints, vehicle) { - if (vehicleAnimationTimer) { - clearInterval(vehicleAnimationTimer); - vehicleAnimationTimer = null; - } - if (!routePoints || routePoints.length === 0) return; - - // Canlı Takip Modu: Arabayı her zaman rotanın EN SON (en güncel) noktasına koy. - var lastPoint = routePoints[routePoints.length - 1]; - var speedStr = vehicle.gps_speed ? vehicle.gps_speed + " km/s" : "0 km/s"; - - var staticCar = L.marker(lastPoint, { - icon: createLiveCarIcon(vehicle.driver_tag, speedStr) - }).addTo(map); - activeMarkers.push(staticCar); - - // Haritayı doğrudan bu son noktaya odakla (Zoom) - map.setView(lastPoint, 16); - } - - function selectDriver(vehicle) { - if (vehicleAnimationTimer) { - clearInterval(vehicleAnimationTimer); - vehicleAnimationTimer = null; + var isGoogleLoaded = false; + if (googleMapsApiKey) { + if (typeof google !== 'undefined' && google.maps) { + isGoogleLoaded = true; + } } if (isGoogleLoaded) { - activePolylines.forEach(function(p) { p.setMap(null); }); - activeMarkers.forEach(function(m) { m.setMap(null); }); + map = new google.maps.Map(document.getElementById('map'), { + center: {lat: 41.0766, lng: 29.0124}, + zoom: 12, + mapTypeId: 'hybrid', // Google Uydu + Yol Haritası + zoomControl: true, + zoomControlOptions: { position: google.maps.ControlPosition.RIGHT_BOTTOM }, + mapTypeControl: false + }); } else { - activePolylines.forEach(function(p) { map.removeLayer(p); }); - activeMarkers.forEach(function(m) { map.removeLayer(m); }); + map = L.map('map', { zoomControl: false }).setView([41.0766, 29.0124], 12); + L.control.zoom({ position: 'bottomright' }).addTo(map); + + // Yüksek Detaylı Esri World Imagery Uydu Haritası Katmanı + L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { + attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community', + maxZoom: 19 + }).addTo(map); + + // Şehir ve Yol Etiketleri Katmanı (Uydu üzerine) + L.tileLayer('https://{s}.basemaps.cartocdn.com/rastertiles/voyager_only_labels/{z}/{x}/{y}{r}.png', { + subdomains: 'abcd', + maxZoom: 19 + }).addTo(map); } - activePolylines = []; - activeMarkers = []; - var greenPts = vehicle.green_route || []; - var redPts = vehicle.red_route || []; - var alt1Pts = vehicle.alt1 || []; - var alt2Pts = vehicle.alt2 || []; - - if (isGoogleLoaded) { - if (greenPts.length > 0) { - var polyGreen = new google.maps.Polyline({ - path: greenPts.map(function(p) { return {lat: p[0], lng: p[1]}; }), - strokeColor: '#10b981', - strokeOpacity: 0.95, - strokeWeight: 7, - map: map - }); - activePolylines.push(polyGreen); - } - if (redPts.length > 0) { - var polyRed = new google.maps.Polyline({ - path: redPts.map(function(p) { return {lat: p[0], lng: p[1]}; }), - strokeColor: '#ef4444', - strokeOpacity: 0.95, - strokeWeight: 7, - map: map - }); - activePolylines.push(polyRed); - } - var polyAlt1 = new google.maps.Polyline({ - path: alt1Pts.map(function(p) { return {lat: p[0], lng: p[1]}; }), - strokeColor: '#64748b', - strokeOpacity: 0.55, - strokeWeight: 4, - map: map + // Yol Üzeri Türkçe Çağrı Kutucuğu (Callout Badge) + function createCalloutIcon(text, bgHex) { + var bg = bgHex || '#2563eb'; + return L.divIcon({ + className: 'custom-callout-marker', + html: '
' + text + '
', + iconSize: [130, 26], + iconAnchor: [65, 13] }); - var polyAlt2 = new google.maps.Polyline({ - path: alt2Pts.map(function(p) { return {lat: p[0], lng: p[1]}; }), - strokeColor: '#64748b', - strokeOpacity: 0.55, - strokeWeight: 4, - map: map + } + + var vehicleAnimationTimer = null; + + // Canlı Hareket Eden Araç İkonu (SVG 🚘 + Anlık Hız Göstergeli) + function createLiveCarIcon(driverTag, speedText) { + return L.divIcon({ + className: 'custom-live-car-marker', + html: '
' + + '
' + + '🚘 ' + (driverTag || 'Sürücü') + ' • ' + (speedText || '55 km/s') + '' + + '
' + + '
' + + '🚗' + + '
' + + '
', + iconSize: [140, 55], + iconAnchor: [70, 52] }); - activePolylines.push(polyAlt1, polyAlt2); + } - var allPts = greenPts.concat(redPts).concat(alt1Pts).concat(alt2Pts); - if (allPts.length > 0) { - var startPt = greenPts[0] || allPts[0]; - var endPt = redPts.length > 0 ? redPts[redPts.length - 1] : (greenPts[greenPts.length - 1] || allPts[allPts.length - 1]); - var mStart = new google.maps.Marker({ position: {lat: startPt[0], lng: startPt[1]}, map: map, title: "Başlangıç Noktası" }); - var mEnd = new google.maps.Marker({ position: {lat: endPt[0], lng: endPt[1]}, map: map, title: vehicle.destination }); - activeMarkers.push(mStart, mEnd); - - var bounds = new google.maps.LatLngBounds(); - allPts.forEach(function(p) { bounds.extend({lat: p[0], lng: p[1]}); }); - map.fitBounds(bounds); + function animateMovingVehicle(routePoints, vehicle) { + if (vehicleAnimationTimer) { + clearInterval(vehicleAnimationTimer); + vehicleAnimationTimer = null; } + if (!routePoints || routePoints.length === 0) return; - } else { - // Leaflet.js Görsel Çizimler (Uydu Temalı) + // Canlı Takip Modu: Arabayı her zaman rotanın EN SON (en güncel) noktasına koy. + var lastPoint = routePoints[routePoints.length - 1]; + var speedStr = vehicle.gps_speed ? vehicle.gps_speed + " km/s" : "0 km/s"; - // 1. Alternatif Gri Yollar - var polyAlt1 = L.polyline(alt1Pts, { color: '#64748b', weight: 4, opacity: 0.6, dashArray: '8, 6' }).addTo(map); - var polyAlt2 = L.polyline(alt2Pts, { color: '#64748b', weight: 4, opacity: 0.6, dashArray: '8, 6' }).addTo(map); - activePolylines.push(polyAlt1, polyAlt2); + var staticCar = L.marker(lastPoint, { + icon: createLiveCarIcon(vehicle.driver_tag, speedStr) + }).addTo(map); + activeMarkers.push(staticCar); + + // Haritayı doğrudan bu son noktaya odakla (Zoom) + map.setView(lastPoint, 16); + } - // 2. Yeşil Ana Rota Çizgisi - if (greenPts.length > 0) { - var polyGreen = L.polyline(greenPts, { color: '#10b981', weight: 8, opacity: 0.95, lineCap: 'round', lineJoin: 'round' }).addTo(map); - activePolylines.push(polyGreen); + function selectDriver(vehicle) { + if (vehicleAnimationTimer) { + clearInterval(vehicleAnimationTimer); + vehicleAnimationTimer = null; } - // 3. Kırmızı 1 km+ Sapma Çizgisi - if (redPts.length > 0) { - var polyRed = L.polyline(redPts, { color: '#ef4444', weight: 8, opacity: 0.95, lineCap: 'round', lineJoin: 'round' }).addTo(map); - activePolylines.push(polyRed); + if (isGoogleLoaded) { + activePolylines.forEach(function(p) { p.setMap(null); }); + activeMarkers.forEach(function(m) { m.setMap(null); }); + } else { + activePolylines.forEach(function(p) { map.removeLayer(p); }); + activeMarkers.forEach(function(m) { map.removeLayer(m); }); } + activePolylines = []; + activeMarkers = []; - var allPts = greenPts.concat(redPts); - // Başlangıç ve Bitiş İğnelerini (Mavi/Kırmızı) Canlı Radarda Gizliyoruz (Sadece araba ve çizgi görünecek) - // Kırmızı Yol Üzerindeki "1.5 km Sapma" Çağrı Kutucuğu + var greenPts = vehicle.green_route || []; + var redPts = vehicle.red_route || []; + var alt1Pts = vehicle.alt1 || []; + var alt2Pts = vehicle.alt2 || []; + + if (isGoogleLoaded) { + if (greenPts.length > 0) { + var polyGreen = new google.maps.Polyline({ + path: greenPts.map(function(p) { return {lat: p[0], lng: p[1]}; }), + strokeColor: '#10b981', + strokeOpacity: 0.95, + strokeWeight: 7, + map: map + }); + activePolylines.push(polyGreen); + } if (redPts.length > 0) { - var midRedIdx = Math.floor(redPts.length / 2); - var mRedCallout = L.marker(redPts[midRedIdx], { icon: createCalloutIcon(vehicle.deviation_label, '#ef4444') }).addTo(map); - activeMarkers.push(mRedCallout); + var polyRed = new google.maps.Polyline({ + path: redPts.map(function(p) { return {lat: p[0], lng: p[1]}; }), + strokeColor: '#ef4444', + strokeOpacity: 0.95, + strokeWeight: 7, + map: map + }); + activePolylines.push(polyRed); + } + var polyAlt1 = new google.maps.Polyline({ + path: alt1Pts.map(function(p) { return {lat: p[0], lng: p[1]}; }), + strokeColor: '#64748b', + strokeOpacity: 0.55, + strokeWeight: 4, + map: map + }); + var polyAlt2 = new google.maps.Polyline({ + path: alt2Pts.map(function(p) { return {lat: p[0], lng: p[1]}; }), + strokeColor: '#64748b', + strokeOpacity: 0.55, + strokeWeight: 4, + map: map + }); + activePolylines.push(polyAlt1, polyAlt2); + + var allPts = greenPts.concat(redPts).concat(alt1Pts).concat(alt2Pts); + if (allPts.length > 0) { + var startPt = greenPts[0] || allPts[0]; + var endPt = redPts.length > 0 ? redPts[redPts.length - 1] : (greenPts[greenPts.length - 1] || allPts[allPts.length - 1]); + + var bounds = new google.maps.LatLngBounds(); + allPts.forEach(function(p) { bounds.extend({lat: p[0], lng: p[1]}); }); + map.fitBounds(bounds); } - // Rotada Gerçek Zamanlı Canlı Hareket Eden Araç Animasyonunu Başlat - animateMovingVehicle(allPts, vehicle); + } else { + // Leaflet.js Görsel Çizimler (Uydu Temalı) + + // 1. Alternatif Gri Yollar + var polyAlt1 = L.polyline(alt1Pts, { color: '#64748b', weight: 4, opacity: 0.6, dashArray: '8, 6' }).addTo(map); + var polyAlt2 = L.polyline(alt2Pts, { color: '#64748b', weight: 4, opacity: 0.6, dashArray: '8, 6' }).addTo(map); + activePolylines.push(polyAlt1, polyAlt2); - var group = new L.featureGroup([polyAlt1, polyAlt2].concat(activePolylines)); - map.fitBounds(group.getBounds(), { padding: [50, 50] }); + // 2. Yeşil Ana Rota Çizgisi + if (greenPts.length > 0) { + var polyGreen = L.polyline(greenPts, { color: '#10b981', weight: 8, opacity: 0.95, lineCap: 'round', lineJoin: 'round' }).addTo(map); + activePolylines.push(polyGreen); + } + + // 3. Kırmızı 1 km+ Sapma Çizgisi + if (redPts.length > 0) { + var polyRed = L.polyline(redPts, { color: '#ef4444', weight: 8, opacity: 0.95, lineCap: 'round', lineJoin: 'round' }).addTo(map); + activePolylines.push(polyRed); + } + + var allPts = greenPts.concat(redPts); + if (allPts.length > 0) { + var startPt = greenPts[0] || allPts[0]; + var endPt = redPts.length > 0 ? redPts[redPts.length - 1] : (greenPts[greenPts.length - 1] || allPts[allPts.length - 1]); + + // Başlangıç ve Bitiş İğnelerini (Mavi/Kırmızı) Canlı Radarda Gizliyoruz (Sadece araba ve çizgi görünecek) + // Kırmızı Yol Üzerindeki "1.5 km Sapma" Çağrı Kutucuğu + if (redPts.length > 0) { + var midRedIdx = Math.floor(redPts.length / 2); + var mRedCallout = L.marker(redPts[midRedIdx], { icon: createCalloutIcon(vehicle.deviation_label, '#ef4444') }).addTo(map); + activeMarkers.push(mRedCallout); + } + + // Rotada Gerçek Zamanlı Canlı Hareket Eden Araç Animasyonunu Başlat + animateMovingVehicle(allPts, vehicle); + + var group = new L.featureGroup([polyAlt1, polyAlt2].concat(activePolylines)); + map.fitBounds(group.getBounds(), { padding: [50, 50] }); + } + } + + // Yüzen Detay Kartını Güncelle + var overlayEl = document.getElementById('driver_info_overlay'); + if (overlayEl) { + var badgeBg = vehicle.is_violation ? 'rgba(239, 68, 68, 0.25)' : (vehicle.is_manager_approved ? 'rgba(56, 189, 248, 0.25)' : 'rgba(16, 185, 129, 0.25)'); + var badgeBorder = vehicle.is_violation ? '#ef4444' : (vehicle.is_manager_approved ? '#38bdf8' : '#10b981'); + var badgeText = vehicle.is_violation ? '#ef4444' : (vehicle.is_manager_approved ? '#38bdf8' : '#10b981'); + var badgeTitle = vehicle.is_violation + ? vehicle.badge_violation + : (vehicle.is_manager_approved ? vehicle.badge_approved : vehicle.badge_ok); + + overlayEl.style.display = 'block'; + overlayEl.innerHTML = + '
' + + '
' + + '

' + (vehicle.driver_tag_str || '') + ' - ' + vehicle.driver_name + '

' + + '' + vehicle.license_plate + ' (' + vehicle.name + ')' + + '
' + + '' + + vehicle.label_score + ' ' + vehicle.score + + '' + + '
' + + '
' + + badgeTitle + + '
' + + '
' + + '
' + + 'Personel Evi / Konaklama:' + + '' + (vehicle.driver_home_address || 'Bilinmiyor') + '' + + '
' + + '
' + + 'Başlangıç Noktası:' + + '' + (vehicle.start_location || 'Canlı GPS Konumu') + '' + + '
' + + '
' + + 'Ulaşım Hedefi:' + + '' + (vehicle.destination || 'Gerçek Zamanlı Aktif İzleme') + '' + + '
' + + '
' + + 'Planlanan / Gidilen Mesafe:' + + '' + vehicle.planned_km + ' KM / ' + vehicle.driven_km + ' KM' + + '
' + + '
' + + 'Rota Sapma Durumu:' + + '' + vehicle.deviation_label + '' + + '
' + + '
' + + 'Şirket Politikası:' + + '' + vehicle.policy_desc + '' + + '
' + + '
'; } } - // Yüzen Detay Kartını Güncelle - var overlayEl = document.getElementById('driver_info_overlay'); - if (overlayEl) { - var badgeBg = vehicle.is_violation ? 'rgba(239, 68, 68, 0.25)' : (vehicle.is_manager_approved ? 'rgba(56, 189, 248, 0.25)' : 'rgba(16, 185, 129, 0.25)'); - var badgeBorder = vehicle.is_violation ? '#ef4444' : (vehicle.is_manager_approved ? '#38bdf8' : '#10b981'); - var badgeText = vehicle.is_violation ? '#ef4444' : (vehicle.is_manager_approved ? '#38bdf8' : '#10b981'); - var badgeTitle = vehicle.is_violation - ? vehicle.badge_violation - : (vehicle.is_manager_approved ? vehicle.badge_approved : vehicle.badge_ok); + var tableBody = document.getElementById('vehicleTableBody'); + if (tableBody) { + tableBody.innerHTML = ''; + var movingCount = 0; + var parkedCount = 0; + var offlineCount = 0; - overlayEl.style.display = 'block'; - overlayEl.innerHTML = - '
' + - '
' + - '

' + (vehicle.driver_tag_str || '') + ' - ' + vehicle.driver_name + '

' + - '' + vehicle.license_plate + ' (' + vehicle.name + ')' + - '
' + - '' + - vehicle.label_score + ' ' + vehicle.score + - '' + - '
' + - '
' + - badgeTitle + - '
' + - '
' + - '
' + - 'Personel Evi / Konaklama:' + - '' + (vehicle.driver_home_address || 'Bilinmiyor') + '' + - '
' + - '
' + - 'Başlangıç Noktası:' + - '' + (vehicle.start_location || 'Canlı GPS Konumu') + '' + - '
' + - '
' + - 'Ulaşım Hedefi:' + - '' + (vehicle.destination || 'Gerçek Zamanlı Aktif İzleme') + '' + - '
' + - '
' + - 'Planlanan / Gidilen Mesafe:' + - '' + vehicle.planned_km + ' KM / ' + vehicle.driven_km + ' KM' + - '
' + - '
' + - 'Rota Sapma Durumu:' + - '' + vehicle.deviation_label + '' + - '
' + - '
' + - 'Şirket Politikası:' + - '' + vehicle.policy_desc + '' + - '
' + - '
'; - } - } + vehiclesData.forEach(function(v, idx) { + // Sunucudan (Odoo JSON dosyası) gelen rotayı ezici olarak kullan + if (serverHistory && serverHistory.length > 0) { + v.green_route = serverHistory; + } - var tableBody = document.getElementById('vehicleTableBody'); - if (tableBody) { - tableBody.innerHTML = ''; - var movingCount = 0; - var parkedCount = 0; - var offlineCount = 0; + // Basit bir kural: Hızı 0'dan büyük olanlar HAREKETLİ, 0 olanlar PARK, veri olmayanlar ÇEVRİMDIŞI. + var speedStr = "0 km/s"; + if (v.gps_speed !== undefined) { + if (v.gps_speed > 0) { + movingCount++; + speedStr = v.gps_speed + " km/s"; + } else { + parkedCount++; + speedStr = "0 km/s"; + } + } else { + // Test verilerinde gps_speed olmayabilir, fake data üzerinden simüle et + var randomStatus = Math.random(); + if (randomStatus > 0.4) { movingCount++; speedStr = Math.floor(Math.random() * 80 + 20) + " km/s"; } + else if (randomStatus > 0.1) { parkedCount++; speedStr = "0 km/s"; } + else { offlineCount++; speedStr = "Offline"; } + } - vehiclesData.forEach(function(v, idx) { - // === Tarayıcı Tabanlı Rota Çizgisi Geçmişi (Frontend History) === - var historyKey = 'mymach_route_' + v.id; - var history = []; - try { - history = JSON.parse(localStorage.getItem(historyKey) || '[]'); - } catch(e) {} + var tr = document.createElement('tr'); + tr.style.cursor = 'pointer'; + tr.style.transition = 'all 0.2s ease'; + tr.style.borderBottom = '1px solid rgba(255,255,255,0.05)'; + + var isRev = v.is_violation; + var badgeStyle = isRev + ? 'background: rgba(239, 68, 68, 0.2); color: #ef4444; border: 1px solid rgba(239, 68, 68, 0.4);' + : (v.is_manager_approved + ? 'background: rgba(56, 189, 248, 0.2); color: #38bdf8; border: 1px solid rgba(56, 189, 248, 0.4);' + : 'background: rgba(16, 185, 129, 0.2); color: #10b981; border: 1px solid rgba(16, 185, 129, 0.4);'); + var statusLabel = isRev ? (v.badge_violation) : (v.is_manager_approved ? v.badge_approved : v.badge_ok); + + tr.innerHTML = + '' + + '' + (v.driver_tag_str || '') + ' - ' + v.driver_name + '
' + + '' + v.license_plate + '' + + '' + + '' + + '' + speedStr + '' + + '' + + '' + + '' + + statusLabel + + '' + + ''; + + tr.addEventListener('click', function() { + var children = tableBody.children; + for (var i = 0; i < children.length; i++) { + children[i].style.background = 'transparent'; + } + tr.style.background = 'rgba(56, 189, 248, 0.2)'; + selectDriver(v); + }); + + tableBody.appendChild(tr); + + if (idx === 0) { + tr.style.background = 'rgba(56, 189, 248, 0.2)'; + setTimeout(function() { selectDriver(v); }, 300); + } + }); + + // Metrikleri DOM'a yaz + var mMoving = document.getElementById('metric_moving'); + if (mMoving) mMoving.textContent = movingCount; - if (v.green_route && v.green_route.length > 0) { - var currentLat = v.green_route[0][0]; - var currentLon = v.green_route[0][1]; - - var addPoint = true; - if (history.length > 0) { - var lastPt = history[history.length - 1]; - // Sadece BİREBİR aynı koordinatsa ekleme. (Hafif bir GPS oynamasını bile kaydetmek için) - if (lastPt[0] === currentLat && lastPt[1] === currentLon) { - addPoint = false; + var mParked = document.getElementById('metric_parked'); + if (mParked) mParked.textContent = parkedCount; + + var mOffline = document.getElementById('metric_offline'); + if (mOffline) mOffline.textContent = offlineCount; + } + + var miniChartEl = document.getElementById('miniChart'); + if (miniChartEl) { + var ctx = miniChartEl.getContext('2d'); + new Chart(ctx, { + type: 'line', + data: { + labels: ['Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz'], + datasets: [{ + label: 'KM Trend', + data: [2200, 2500, 2100, 2800, 3100, 2700], + borderColor: '#00f2fe', + backgroundColor: 'rgba(0, 242, 254, 0.05)', + borderWidth: 2, + tension: 0.4, + fill: true + }] + }, + options: { + responsive: true, + plugins: { legend: { display: false } }, + scales: { + x: { grid: { display: false }, ticks: { color: '#94a3b8' } }, + y: { grid: { color: 'rgba(255,255,255,0.05)' }, ticks: { color: '#94a3b8' } } } } - if (addPoint) { - history.push([currentLat, currentLon]); - if (history.length > 300) history = history.slice(-300); // 300 noktayı hafızada tut - localStorage.setItem(historyKey, JSON.stringify(history)); - } - v.green_route = history; - } - - // Basit bir kural: Hızı 0'dan büyük olanlar HAREKETLİ, 0 olanlar PARK, veri olmayanlar ÇEVRİMDIŞI. - var speedStr = "0 km/s"; - if (v.gps_speed !== undefined) { - if (v.gps_speed > 0) { - movingCount++; - speedStr = v.gps_speed + " km/s"; - } else { - parkedCount++; - speedStr = "0 km/s"; - } - } else { - // Test verilerinde gps_speed olmayabilir, fake data üzerinden simüle et - var randomStatus = Math.random(); - if (randomStatus > 0.4) { movingCount++; speedStr = Math.floor(Math.random() * 80 + 20) + " km/s"; } - else if (randomStatus > 0.1) { parkedCount++; speedStr = "0 km/s"; } - else { offlineCount++; speedStr = "Offline"; } - } - - var tr = document.createElement('tr'); - tr.style.cursor = 'pointer'; - tr.style.transition = 'all 0.2s ease'; - tr.style.borderBottom = '1px solid rgba(255,255,255,0.05)'; - - var isRev = v.is_violation; - var badgeStyle = isRev - ? 'background: rgba(239, 68, 68, 0.2); color: #ef4444; border: 1px solid rgba(239, 68, 68, 0.4);' - : (v.is_manager_approved - ? 'background: rgba(56, 189, 248, 0.2); color: #38bdf8; border: 1px solid rgba(56, 189, 248, 0.4);' - : 'background: rgba(16, 185, 129, 0.2); color: #10b981; border: 1px solid rgba(16, 185, 129, 0.4);'); - var statusLabel = isRev ? (v.badge_violation) : (v.is_manager_approved ? v.badge_approved : v.badge_ok); - - tr.innerHTML = - '' + - '' + (v.driver_tag_str || '') + ' - ' + v.driver_name + '
' + - '' + v.license_plate + '' + - '' + - '' + - '' + speedStr + '' + - '' + - '' + - '' + - statusLabel + - '' + - ''; - - tr.addEventListener('click', function() { - var children = tableBody.children; - for (var i = 0; i < children.length; i++) { - children[i].style.background = 'transparent'; - } - tr.style.background = 'rgba(56, 189, 248, 0.2)'; - selectDriver(v); }); - - tableBody.appendChild(tr); - - if (idx === 0) { - tr.style.background = 'rgba(56, 189, 248, 0.2)'; - setTimeout(function() { selectDriver(v); }, 300); - } - }); - - // Metrikleri DOM'a yaz - var mMoving = document.getElementById('metric_moving'); - if (mMoving) mMoving.textContent = movingCount; + } - var mParked = document.getElementById('metric_parked'); - if (mParked) mParked.textContent = parkedCount; - - var mOffline = document.getElementById('metric_offline'); - if (mOffline) mOffline.textContent = offlineCount; - } - - var miniChartEl = document.getElementById('miniChart'); - if (miniChartEl) { - var ctx = miniChartEl.getContext('2d'); - new Chart(ctx, { - type: 'line', - data: { - labels: ['Oca', 'Şub', 'Mar', 'Nis', 'May', 'Haz'], - datasets: [{ - label: 'KM Trend', - data: [2200, 2500, 2100, 2800, 3100, 2700], - borderColor: '#00f2fe', - backgroundColor: 'rgba(0, 242, 254, 0.05)', - borderWidth: 2, - tension: 0.4, - fill: true - }] - }, - options: { - responsive: true, - plugins: { legend: { display: false } }, - scales: { - x: { grid: { display: false }, ticks: { color: '#94a3b8' } }, - y: { grid: { color: 'rgba(255,255,255,0.05)' }, ticks: { color: '#94a3b8' } } - } - } - }); + // --- 10 Saniyede Bir Sayfayı Tam Ekran Yenileyerek Görüntüyü Güncelleyen Kod --- + setInterval(function() { + window.location.reload(); + }, 15000); } });