Spaces:
Running
Running
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Gestion Temps de Travail - Entrepôt</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| .gradient-bg { | |
| background: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%); | |
| } | |
| .pulse-animation { | |
| animation: pulse 2s infinite; | |
| } | |
| @keyframes pulse { | |
| 0% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.7); } | |
| 70% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0); } | |
| 100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); } | |
| } | |
| .slide-in { | |
| animation: slideIn 0.5s forwards; | |
| } | |
| @keyframes slideIn { | |
| from { transform: translateY(20px); opacity: 0; } | |
| to { transform: translateY(0); opacity: 1; } | |
| } | |
| </style> | |
| </head> | |
| <body class="bg-gray-100 font-sans"> | |
| <!-- Header --> | |
| <header class="gradient-bg text-white shadow-lg"> | |
| <div class="container mx-auto px-4 py-6"> | |
| <div class="flex justify-between items-center"> | |
| <div class="flex items-center space-x-3"> | |
| <i class="fas fa-warehouse text-3xl"></i> | |
| <h1 class="text-2xl font-bold">Gestion Temps de Travail</h1> | |
| </div> | |
| <div class="flex items-center space-x-4"> | |
| <span id="current-time" class="font-mono text-lg bg-blue-800 px-3 py-1 rounded"></span> | |
| <button class="bg-white text-blue-600 px-4 py-2 rounded-lg font-medium hover:bg-blue-50 transition"> | |
| <i class="fas fa-user mr-2"></i>Admin | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </header> | |
| <!-- Main Content --> | |
| <main class="container mx-auto px-4 py-8"> | |
| <!-- Mode Selection --> | |
| <div class="mb-12 text-center"> | |
| <h2 class="text-3xl font-bold text-gray-800 mb-6">Sélectionnez le mode de saisie</h2> | |
| <div class="flex justify-center space-x-8"> | |
| <div class="mode-card bg-white rounded-xl shadow-lg p-6 w-64 cursor-pointer hover:shadow-xl transition transform hover:-translate-y-1" data-mode="scan"> | |
| <div class="bg-blue-100 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-qrcode text-blue-600 text-3xl"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800 mb-2">Scan QR Code</h3> | |
| <p class="text-gray-600">Utilisez la scannette sur poste fixe</p> | |
| </div> | |
| <div class="mode-card bg-white rounded-xl shadow-lg p-6 w-64 cursor-pointer hover:shadow-xl transition transform hover:-translate-y-1" data-mode="form"> | |
| <div class="bg-green-100 w-16 h-16 rounded-full flex items-center justify-center mx-auto mb-4"> | |
| <i class="fas fa-mobile-alt text-green-600 text-3xl"></i> | |
| </div> | |
| <h3 class="text-xl font-semibold text-gray-800 mb-2">Formulaire Mobile</h3> | |
| <p class="text-gray-600">Accès via QR code sur smartphone</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Scan Mode (Hidden by default) --> | |
| <div id="scan-mode" class="hidden max-w-3xl mx-auto bg-white rounded-xl shadow-md overflow-hidden slide-in"> | |
| <div class="gradient-bg p-6 text-white"> | |
| <div class="flex justify-between items-center"> | |
| <h2 class="text-2xl font-bold"><i class="fas fa-qrcode mr-3"></i>Mode Scan</h2> | |
| <button class="back-btn bg-white text-blue-600 px-3 py-1 rounded-lg text-sm font-medium hover:bg-blue-50 transition"> | |
| <i class="fas fa-arrow-left mr-1"></i>Retour | |
| </button> | |
| </div> | |
| <p class="mt-2 opacity-90">Scannez votre badge puis le QR code de la tâche</p> | |
| </div> | |
| <div class="p-6"> | |
| <div class="flex flex-col md:flex-row gap-8"> | |
| <!-- Scan Area --> | |
| <div class="flex-1"> | |
| <div class="bg-gray-100 rounded-lg p-4 mb-6 text-center"> | |
| <div class="p-4 border-2 border-dashed border-gray-300 rounded-lg mb-4"> | |
| <i class="fas fa-barcode text-5xl text-gray-400 mb-3"></i> | |
| <p class="text-gray-600 font-medium">Zone de scan</p> | |
| </div> | |
| <button class="bg-blue-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-blue-700 transition flex items-center justify-center mx-auto"> | |
| <i class="fas fa-camera mr-2"></i>Activer la scannette | |
| </button> | |
| </div> | |
| <div class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-6"> | |
| <div class="flex"> | |
| <div class="flex-shrink-0"> | |
| <i class="fas fa-info-circle text-blue-500"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <p class="text-sm text-blue-700"> | |
| <span class="font-semibold">Instructions :</span> Scannez d'abord votre badge opérateur, puis scannez le QR code de la tâche. Le système détectera automatiquement s'il s'agit d'un début ou d'une fin de session. | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Current Session Info --> | |
| <div class="flex-1"> | |
| <h3 class="text-lg font-semibold text-gray-800 mb-4">Session en cours</h3> | |
| <div class="bg-gray-50 rounded-lg p-4 mb-4"> | |
| <div class="flex items-center mb-3"> | |
| <div class="bg-blue-100 p-2 rounded-full mr-3"> | |
| <i class="fas fa-user text-blue-600"></i> | |
| </div> | |
| <div> | |
| <p class="text-sm text-gray-500">Opérateur</p> | |
| <p class="font-medium" id="current-operator">Non identifié</p> | |
| </div> | |
| </div> | |
| <div class="flex items-center mb-3"> | |
| <div class="bg-green-100 p-2 rounded-full mr-3"> | |
| <i class="fas fa-tasks text-green-600"></i> | |
| </div> | |
| <div> | |
| <p class="text-sm text-gray-500">Tâche</p> | |
| <p class="font-medium" id="current-task">Aucune tâche en cours</p> | |
| </div> | |
| </div> | |
| <div class="flex items-center"> | |
| <div class="bg-purple-100 p-2 rounded-full mr-3"> | |
| <i class="fas fa-clock text-purple-600"></i> | |
| </div> | |
| <div> | |
| <p class="text-sm text-gray-500">Temps écoulé</p> | |
| <p class="font-mono font-medium" id="session-timer">00:00:00</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-yellow-50 border-l-4 border-yellow-400 p-4"> | |
| <div class="flex"> | |
| <div class="flex-shrink-0"> | |
| <i class="fas fa-exclamation-triangle text-yellow-500"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <p class="text-sm text-yellow-700"> | |
| <span class="font-semibold">Remarque :</span> Toutes les sessions seront automatiquement clôturées à 12h00 et 17h00. | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Form Mode (Hidden by default) --> | |
| <div id="form-mode" class="hidden max-w-3xl mx-auto bg-white rounded-xl shadow-md overflow-hidden slide-in"> | |
| <div class="gradient-bg p-6 text-white"> | |
| <div class="flex justify-between items-center"> | |
| <h2 class="text-2xl font-bold"><i class="fas fa-mobile-alt mr-3"></i>Mode Formulaire</h2> | |
| <button class="back-btn bg-white text-blue-600 px-3 py-1 rounded-lg text-sm font-medium hover:bg-blue-50 transition"> | |
| <i class="fas fa-arrow-left mr-1"></i>Retour | |
| </button> | |
| </div> | |
| <p class="mt-2 opacity-90">Accédez au formulaire via QR code mobile</p> | |
| </div> | |
| <div class="p-6"> | |
| <div class="flex flex-col md:flex-row gap-8"> | |
| <!-- QR Code Display --> | |
| <div class="flex-1"> | |
| <div class="bg-gray-100 rounded-lg p-6 mb-6 text-center"> | |
| <div class="p-4 mb-4"> | |
| <div class="bg-white p-4 rounded inline-block"> | |
| <div class="w-48 h-48 bg-gray-200 flex items-center justify-center mx-auto mb-3"> | |
| <i class="fas fa-qrcode text-5xl text-gray-400"></i> | |
| </div> | |
| <p class="text-gray-600 text-sm">Exemple de QR code pour la tâche</p> | |
| </div> | |
| </div> | |
| <p class="text-gray-700 mb-4">Scannez ce QR code avec votre appareil mobile pour accéder au formulaire de saisie</p> | |
| <button class="bg-green-600 text-white px-6 py-3 rounded-lg font-medium hover:bg-green-700 transition flex items-center justify-center mx-auto"> | |
| <i class="fas fa-sync-alt mr-2"></i>Générer un nouveau QR code | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Form Instructions --> | |
| <div class="flex-1"> | |
| <h3 class="text-lg font-semibold text-gray-800 mb-4">Instructions</h3> | |
| <div class="space-y-4 mb-6"> | |
| <div class="flex items-start"> | |
| <div class="bg-blue-100 p-2 rounded-full mr-3 mt-1"> | |
| <span class="text-blue-600 font-bold">1</span> | |
| </div> | |
| <div> | |
| <p class="font-medium text-gray-800">Scannez le QR code avec votre smartphone</p> | |
| <p class="text-sm text-gray-600">Utilisez l'appareil photo ou une application de scan de QR code</p> | |
| </div> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="bg-green-100 p-2 rounded-full mr-3 mt-1"> | |
| <span class="text-green-600 font-bold">2</span> | |
| </div> | |
| <div> | |
| <p class="font-medium text-gray-800">Remplissez le formulaire</p> | |
| <p class="text-sm text-gray-600">Sélectionnez votre nom et la tâche en cours</p> | |
| </div> | |
| </div> | |
| <div class="flex items-start"> | |
| <div class="bg-purple-100 p-2 rounded-full mr-3 mt-1"> | |
| <span class="text-purple-600 font-bold">3</span> | |
| </div> | |
| <div> | |
| <p class="font-medium text-gray-800">Soumettez pour enregistrer</p> | |
| <p class="text-sm text-gray-600">Le système détectera automatiquement début/fin de session</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-blue-50 border-l-4 border-blue-500 p-4"> | |
| <div class="flex"> | |
| <div class="flex-shrink-0"> | |
| <i class="fas fa-info-circle text-blue-500"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <p class="text-sm text-blue-700"> | |
| <span class="font-semibold">Conseil :</span> Des QR codes colorés sont affichés dans l'entrepôt pour chaque donneur d'ordre et type de tâche. | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Dashboard Preview --> | |
| <div class="mt-16 max-w-6xl mx-auto"> | |
| <h2 class="text-3xl font-bold text-gray-800 mb-6 text-center">Tableau de bord de suivi</h2> | |
| <div class="bg-white rounded-xl shadow-md overflow-hidden"> | |
| <div class="gradient-bg p-6 text-white"> | |
| <h3 class="text-xl font-bold"><i class="fas fa-chart-bar mr-3"></i>Aperçu des données</h3> | |
| </div> | |
| <div class="p-6"> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8"> | |
| <div class="bg-blue-50 p-4 rounded-lg border border-blue-100"> | |
| <div class="flex justify-between"> | |
| <div> | |
| <p class="text-sm text-blue-600 font-medium">Opérateurs actifs</p> | |
| <p class="text-2xl font-bold text-gray-800">24</p> | |
| </div> | |
| <div class="bg-blue-100 p-3 rounded-full"> | |
| <i class="fas fa-users text-blue-600"></i> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-green-50 p-4 rounded-lg border border-green-100"> | |
| <div class="flex justify-between"> | |
| <div> | |
| <p class="text-sm text-green-600 font-medium">Tâches en cours</p> | |
| <p class="text-2xl font-bold text-gray-800">18</p> | |
| </div> | |
| <div class="bg-green-100 p-3 rounded-full"> | |
| <i class="fas fa-tasks text-green-600"></i> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-purple-50 p-4 rounded-lg border border-purple-100"> | |
| <div class="flex justify-between"> | |
| <div> | |
| <p class="text-sm text-purple-600 font-medium">Heures travaillées</p> | |
| <p class="text-2xl font-bold text-gray-800">127.5</p> | |
| </div> | |
| <div class="bg-purple-100 p-3 rounded-full"> | |
| <i class="fas fa-clock text-purple-600"></i> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="min-w-full divide-y divide-gray-200"> | |
| <thead class="bg-gray-50"> | |
| <tr> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Opérateur</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tâche</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Donneur d'ordre</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Début</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Fin</th> | |
| <th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Durée</th> | |
| </tr> | |
| </thead> | |
| <tbody class="bg-white divide-y divide-gray-200"> | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap">Jean Dupont</td> | |
| <td class="px-6 py-4 whitespace-nowrap">Préparation commande</td> | |
| <td class="px-6 py-4 whitespace-nowrap">Client A</td> | |
| <td class="px-6 py-4 whitespace-nowrap">08:15</td> | |
| <td class="px-6 py-4 whitespace-nowrap">10:30</td> | |
| <td class="px-6 py-4 whitespace-nowrap font-medium">2h15</td> | |
| </tr> | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap">Marie Martin</td> | |
| <td class="px-6 py-4 whitespace-nowrap">Réception marchandises</td> | |
| <td class="px-6 py-4 whitespace-nowrap">Fournisseur B</td> | |
| <td class="px-6 py-4 whitespace-nowrap">09:00</td> | |
| <td class="px-6 py-4 whitespace-nowrap">12:00</td> | |
| <td class="px-6 py-4 whitespace-nowrap font-medium">3h00</td> | |
| </tr> | |
| <tr> | |
| <td class="px-6 py-4 whitespace-nowrap">Pierre Lambert</td> | |
| <td class="px-6 py-4 whitespace-nowrap">Inventaire</td> | |
| <td class="px-6 py-4 whitespace-nowrap">Interne</td> | |
| <td class="px-6 py-4 whitespace-nowrap">13:30</td> | |
| <td class="px-6 py-4 whitespace-nowrap">-</td> | |
| <td class="px-6 py-4 whitespace-nowrap font-medium text-blue-600">En cours</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <!-- Footer --> | |
| <footer class="bg-gray-800 text-white py-8 mt-12"> | |
| <div class="container mx-auto px-4"> | |
| <div class="flex flex-col md:flex-row justify-between"> | |
| <div class="mb-6 md:mb-0"> | |
| <h3 class="text-lg font-bold mb-4">Gestion Temps de Travail</h3> | |
| <p class="text-gray-400">Solution de suivi des opérateurs en entrepôt</p> | |
| </div> | |
| <div class="grid grid-cols-2 gap-8 md:grid-cols-3"> | |
| <div> | |
| <h4 class="text-sm font-semibold uppercase tracking-wider mb-4">Navigation</h4> | |
| <ul class="space-y-2"> | |
| <li><a href="#" class="text-gray-400 hover:text-white transition">Accueil</a></li> | |
| <li><a href="#" class="text-gray-400 hover:text-white transition">Tableau de bord</a></li> | |
| <li><a href="#" class="text-gray-400 hover:text-white transition">Rapports</a></li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h4 class="text-sm font-semibold uppercase tracking-wider mb-4">Support</h4> | |
| <ul class="space-y-2"> | |
| <li><a href="#" class="text-gray-400 hover:text-white transition">Documentation</a></li> | |
| <li><a href="#" class="text-gray-400 hover:text-white transition">FAQ</a></li> | |
| <li><a href="#" class="text-gray-400 hover:text-white transition">Contact</a></li> | |
| </ul> | |
| </div> | |
| <div> | |
| <h4 class="text-sm font-semibold uppercase tracking-wider mb-4">Légal</h4> | |
| <ul class="space-y-2"> | |
| <li><a href="#" class="text-gray-400 hover:text-white transition">Confidentialité</a></li> | |
| <li><a href="#" class="text-gray-400 hover:text-white transition">Conditions</a></li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="border-t border-gray-700 mt-8 pt-8 text-center text-gray-400 text-sm"> | |
| <p>© 2023 Gestion Temps de Travail. Tous droits réservés.</p> | |
| </div> | |
| </div> | |
| </footer> | |
| <script> | |
| // Update current time | |
| function updateTime() { | |
| const now = new Date(); | |
| const timeString = now.toLocaleTimeString('fr-FR', { hour: '2-digit', minute: '2-digit', second: '2-digit' }); | |
| document.getElementById('current-time').textContent = timeString; | |
| // Check for auto-closing times (12:00 and 17:00) | |
| const hours = now.getHours(); | |
| const minutes = now.getMinutes(); | |
| if ((hours === 12 && minutes === 0) || (hours === 17 && minutes === 0)) { | |
| showAutoCloseNotification(); | |
| } | |
| } | |
| setInterval(updateTime, 1000); | |
| updateTime(); | |
| // Mode selection | |
| const modeCards = document.querySelectorAll('.mode-card'); | |
| const scanMode = document.getElementById('scan-mode'); | |
| const formMode = document.getElementById('form-mode'); | |
| const backButtons = document.querySelectorAll('.back-btn'); | |
| modeCards.forEach(card => { | |
| card.addEventListener('click', () => { | |
| const mode = card.getAttribute('data-mode'); | |
| // Hide all content | |
| document.querySelector('main > div:not(.hidden)').classList.add('hidden'); | |
| // Show selected mode | |
| if (mode === 'scan') { | |
| scanMode.classList.remove('hidden'); | |
| startSessionTimer(); | |
| } else { | |
| formMode.classList.remove('hidden'); | |
| } | |
| }); | |
| }); | |
| backButtons.forEach(button => { | |
| button.addEventListener('click', () => { | |
| scanMode.classList.add('hidden'); | |
| formMode.classList.add('hidden'); | |
| stopSessionTimer(); | |
| }); | |
| }); | |
| // Session timer simulation | |
| let timerInterval; | |
| let seconds = 0; | |
| function startSessionTimer() { | |
| // Simulate scanning an operator badge | |
| document.getElementById('current-operator').textContent = "Jean Dupont (ID: 45678)"; | |
| document.getElementById('current-task').textContent = "Préparation commande - Client A"; | |
| // Start timer | |
| seconds = 0; | |
| updateTimerDisplay(); | |
| timerInterval = setInterval(() => { | |
| seconds++; | |
| updateTimerDisplay(); | |
| }, 1000); | |
| } | |
| function stopSessionTimer() { | |
| clearInterval(timerInterval); | |
| document.getElementById('current-operator').textContent = "Non identifié"; | |
| document.getElementById('current-task').textContent = "Aucune tâche en cours"; | |
| document.getElementById('session-timer').textContent = "00:00:00"; | |
| } | |
| function updateTimerDisplay() { | |
| const hours = Math.floor(seconds / 3600); | |
| const minutes = Math.floor((seconds % 3600) / 60); | |
| const secs = seconds % 60; | |
| document.getElementById('session-timer').textContent = | |
| `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; | |
| } | |
| // Auto-close notification | |
| function showAutoCloseNotification() { | |
| const notification = document.createElement('div'); | |
| notification.className = 'fixed bottom-4 right-4 bg-white shadow-xl rounded-lg p-4 max-w-sm border-l-4 border-red-500 z-50 slide-in'; | |
| notification.innerHTML = ` | |
| <div class="flex"> | |
| <div class="flex-shrink-0"> | |
| <i class="fas fa-clock text-red-500 text-xl mt-1"></i> | |
| </div> | |
| <div class="ml-3"> | |
| <h3 class="text-lg font-medium text-gray-900">Session automatiquement clôturée</h3> | |
| <p class="mt-1 text-sm text-gray-600">Toutes les sessions en cours ont été clôturées comme prévu à ${new Date().getHours()}h00.</p> | |
| <button class="mt-2 text-sm text-blue-600 font-medium hover:text-blue-500 focus:outline-none"> | |
| Fermer | |
| </button> | |
| </div> | |
| </div> | |
| `; | |
| document.body.appendChild(notification); | |
| notification.querySelector('button').addEventListener('click', () => { | |
| notification.classList.remove('slide-in'); | |
| notification.classList.add('slide-out'); | |
| setTimeout(() => notification.remove(), 500); | |
| }); | |
| // Auto-remove after 10 seconds | |
| setTimeout(() => { | |
| if (document.body.contains(notification)) { | |
| notification.classList.remove('slide-in'); | |
| notification.classList.add('slide-out'); | |
| setTimeout(() => notification.remove(), 500); | |
| } | |
| }, 10000); | |
| } | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=supportATP/gestiontemps" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
| </html> |