patrol-control-system / map-view.html
secutorpro's picture
point de contrôle avec geolocalisation pointeaux nfc
9838dd8 verified
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Carte des Points de Contrôle - Contrôle de Patrouille</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
</head>
<body class="bg-gray-50 min-h-screen">
<!-- Sidebar -->
<custom-sidebar></custom-sidebar>
<!-- Header -->
<custom-header></custom-header>
<!-- Main Content -->
<main class="ml-64 mt-16 p-6">
<div class="flex justify-between items-center mb-6">
<div>
<h1 class="text-2xl font-bold text-gray-800">Carte des Points de Contrôle</h1>
<p class="text-gray-600">Visualisation géographique de tous les points de contrôle</p>
</div>
<div class="flex space-x-2">
<button class="bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg flex items-center">
<i data-feather="filter" class="mr-2 w-4 h-4"></i>
Filtres
</button>
<button class="bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-4 rounded-lg flex items-center" id="locateBtn">
<i data-feather="crosshair" class="mr-2 w-4 h-4"></i>
Ma position
</button>
</div>
</div>
<!-- Map Container -->
<div class="bg-white rounded-xl shadow-sm overflow-hidden">
<div class="p-4 border-b border-gray-200">
<div class="flex flex-wrap gap-4">
<div class="flex items-center">
<div class="w-4 h-4 bg-green-500 rounded-full mr-2"></div>
<span class="text-sm text-gray-700">Actif (${activePoints})</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-gray-500 rounded-full mr-2"></div>
<span class="text-sm text-gray-700">Inactif (${inactivePoints})</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-yellow-500 rounded-full mr-2"></div>
<span class="text-sm text-gray-700">Maintenance (${maintenancePoints})</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-blue-500 rounded-full mr-2"></div>
<span class="text-sm text-gray-700">NFC</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-purple-500 rounded-full mr-2"></div>
<span class="text-sm text-gray-700">QR Code</span>
</div>
<div class="flex items-center">
<div class="w-4 h-4 bg-gray-400 rounded-full mr-2"></div>
<span class="text-sm text-gray-700">Manuel</span>
</div>
</div>
</div>
<div id="map" style="height: calc(100vh - 200px);"></div>
</div>
<!-- Point Details Sidebar (Hidden by default) -->
<div id="pointSidebar" class="fixed right-0 top-16 bottom-0 w-80 bg-white shadow-lg transform translate-x-full transition-transform duration-300 z-40">
<div class="p-6 border-b border-gray-200">
<div class="flex justify-between items-center">
<h3 class="text-lg font-semibold text-gray-800" id="sidebarTitle">Détails du Point</h3>
<button id="closeSidebar" class="text-gray-400 hover:text-gray-600">
<i data-feather="x" class="w-5 h-5"></i>
</button>
</div>
</div>
<div class="p-6" id="sidebarContent">
<!-- Content will be populated dynamically -->
</div>
</div>
</main>
<script src="components/sidebar.js"></script>
<script src="components/header.js"></script>
<script src="script.js"></script>
<script>
feather.replace();
// Control points data
const controlPoints = [
{
id: 'NFC-001',
name: 'Entrée Principale',
location: 'Bâtiment A - Rez-de-chaussée',
type: 'NFC',
status: 'active',
latitude: 48.8566,
longitude: 2.3522,
icon: 'green'
},
{
id: 'QR-002',
name: 'Salle des Serveurs',
location: 'Bâtiment B - 3ème étage',
type: 'QR',
status: 'maintenance',
latitude: 48.8584,
longitude: 2.3545,
icon: 'yellow'
},
{
id: 'MAN-003',
name: 'Parking',
location: 'Extérieur - Côté Sud',
type: 'Manual',
status: 'active',
latitude: 48.8575,
longitude: 2.3518,
icon: 'green'
},
{
id: 'NFC-004',
name: 'Porte Arrière',
location: 'Bâtiment A - Arrière',
type: 'NFC',
status: 'inactive',
latitude: 48.8569,
longitude: 2.3515,
icon: 'gray'
},
{
id: 'QR-005',
name: 'Réception',
location: 'Hall d\'accueil - Bâtiment A',
type: 'QR',
status: 'active',
latitude: 48.8563,
longitude: 2.3528,
icon: 'green'
},
{
id: 'MAN-006',
name: 'Sortie d\'Urgence',
location: 'Bâtiment C - Aile Est',
type: 'Manual',
status: 'active',
latitude: 48.8590,
longitude: 2.3550,
icon: 'green'
},
{
id: 'NFC-007',
name: 'Entrepôt',
location: 'Zone de stockage - Aile Nord',
type: 'NFC',
status: 'active',
latitude: 48.8578,
longitude: 2.3505,
icon: 'green'
},
{
id: 'QR-008',
name: 'Salle de Conférence',
location: 'Bâtiment B - 2ème étage',
type: 'QR',
status: 'maintenance',
latitude: 48.8581,
longitude: 2.3540,
icon: 'yellow'
},
{
id: 'MAN-009',
name: 'Quai de Chargement',
location: 'Entrée de Service',
type: 'Manual',
status: 'active',
latitude: 48.8572,
longitude: 2.3498,
icon: 'green'
}
];
// Count points by status
const activePoints = controlPoints.filter(p => p.status === 'active').length;
const inactivePoints = controlPoints.filter(p => p.status === 'inactive').length;
const maintenancePoints = controlPoints.filter(p => p.status === 'maintenance').length;
// Initialize map
let map;
let markers = [];
function initMap() {
map = L.map('map').setView([48.8566, 2.3522], 15);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap contributors'
}).addTo(map);
// Add markers for each control point
controlPoints.forEach(point => {
const marker = createMarker(point);
markers.push(marker);
});
}
function createMarker(point) {
const iconColor = getIconColor(point.status, point.type);
const customIcon = L.divIcon({
className: 'custom-marker',
html: `<div style="background-color: ${iconColor}; width: 20px; height: 20px; border-radius: 50%; border: 2px solid white; box-shadow: 0 2px 4px rgba(0,0,0,0.3);"></div>`,
iconSize: [20, 20],
iconAnchor: [10, 10]
});
const marker = L.marker([point.latitude, point.longitude], { icon: customIcon })
.addTo(map)
.bindPopup(createPopupContent(point));
marker.on('click', () => showPointDetails(point));
return marker;
}
function getIconColor(status, type) {
if (status === 'active') {
return type === 'NFC' ? '#059669' : type === 'QR' ? '#7c3aed' : '#6b7280';
} else if (status === 'inactive') {
return '#6b7280';
} else {
return '#d97706';
}
}
function createPopupContent(point) {
const statusColor = point.status === 'active' ? 'green' : point.status === 'inactive' ? 'gray' : 'yellow';
const typeColor = point.type === 'NFC' ? 'blue' : point.type === 'QR' ? 'purple' : 'gray';
return `
<div class="p-2">
<h4 class="font-semibold text-sm">${point.name}</h4>
<p class="text-xs text-gray-600 mb-2">${point.location}</p>
<div class="flex gap-2">
<span class="px-2 py-1 bg-${statusColor}-100 text-${statusColor}-800 text-xs rounded">${point.status}</span>
<span class="px-2 py-1 bg-${typeColor}-100 text-${typeColor}-800 text-xs rounded">${point.type}</span>
</div>
</div>
`;
}
function showPointDetails(point) {
const sidebar = document.getElementById('pointSidebar');
const title = document.getElementById('sidebarTitle');
const content = document.getElementById('sidebarContent');
title.textContent = point.name;
content.innerHTML = `
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700">Localisation</label>
<p class="text-gray-900">${point.location}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Type</label>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
${point.type}
</span>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Statut</label>
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${point.status === 'active' ? 'bg-green-100 text-green-800' : point.status === 'inactive' ? 'bg-gray-100 text-gray-800' : 'bg-yellow-100 text-yellow-800'}">
${point.status === 'active' ? 'Actif' : point.status === 'inactive' ? 'Inactif' : 'Maintenance'}
</span>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">ID</label>
<p class="text-gray-900">${point.id}</p>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">Coordonnées</label>
<p class="text-gray-900">${point.latitude}, ${point.longitude}</p>
</div>
<div class="pt-4 space-y-2">
<button class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg flex items-center justify-center">
<i data-feather="edit-2" class="mr-2 w-4 h-4"></i>
Modifier
</button>
<button class="w-full bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-4 rounded-lg flex items-center justify-center">
<i data-feather="navigation" class="mr-2 w-4 h-4"></i>
Itinéraire
</button>
${point.type === 'NFC' ? `
<button class="w-full bg-purple-600 hover:bg-purple-700 text-white font-medium py-2 px-4 rounded-lg flex items-center justify-center">
<i data-feather="credit-card" class="mr-2 w-4 h-4"></i>
Scanner NFC
</button>
` : ''}
</div>
</div>
`;
sidebar.classList.remove('translate-x-full');
feather.replace();
}
// Close sidebar
document.getElementById('closeSidebar').addEventListener('click', () => {
document.getElementById('pointSidebar').classList.add('translate-x-full');
});
// Locate user
document.getElementById('locateBtn').addEventListener('click', () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
const lat = position.coords.latitude;
const lng = position.coords.longitude;
map.setView([lat, lng], 16);
// Add user location marker
const userIcon = L.divIcon({
className: 'user-marker',
html: '<div style="background-color: #3b82f6; width: 12px; height: 12px; border-radius: 50%; border: 3px solid white; box-shadow: 0 2px 4px rgba(0,0,0,0.3);"></div>',
iconSize: [12, 12],
iconAnchor: [6, 6]
});
L.marker([lat, lng], { icon: userIcon })
.addTo(map)
.bindPopup('Votre position')
.openPopup();
});
} else {
alert('La géolocalisation n\'est pas supportée par ce navigateur.');
}
});
// Initialize map when page loads
document.addEventListener('DOMContentLoaded', initMap);
</script>
</body>
</html>