Spaces:
Sleeping
Sleeping
| <html lang="fr"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>NEXUS - Centre de Commandement</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800&display=swap" rel="stylesheet"> | |
| <style> | |
| body { font-family: 'Inter', sans-serif; background-color: #0f172a; color: #f8fafc; } | |
| .glass-panel { background: rgba(30, 41, 59, 0.7); backdrop-filter: blur(10px); border: 1px solid rgba(255,255,255,0.1); } | |
| </style> | |
| </head> | |
| <body class="min-h-screen p-6"> | |
| <header class="flex justify-between items-center mb-8 border-b border-slate-700 pb-4"> | |
| <div> | |
| <h1 class="text-3xl font-extrabold text-blue-400 tracking-tight">NEXUS PRIME</h1> | |
| <p class="text-slate-400 text-sm">Centre de Commandement & Dispatching</p> | |
| </div> | |
| <div class="flex items-center gap-3"> | |
| <div class="h-3 w-3 bg-green-500 rounded-full animate-pulse"></div> | |
| <span class="text-sm font-semibold text-slate-300">Système En Ligne</span> | |
| </div> | |
| </header> | |
| <main> | |
| <div class="glass-panel rounded-xl overflow-hidden shadow-2xl"> | |
| <div class="p-4 bg-slate-800 border-b border-slate-700"> | |
| <h2 class="text-lg font-semibold flex items-center gap-2"> | |
| 📡 File d'attente des urgences en direct | |
| </h2> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="w-full text-left text-sm"> | |
| <thead class="bg-slate-900 text-slate-400"> | |
| <tr> | |
| <th class="p-4 font-semibold">Heure</th> | |
| <th class="p-4 font-semibold">Téléphone</th> | |
| <th class="p-4 font-semibold w-1/3">Message du Citoyen</th> | |
| <th class="p-4 font-semibold">Analyse IA</th> | |
| <th class="p-4 font-semibold">Action / Dispatch</th> | |
| </tr> | |
| </thead> | |
| <tbody id="tickets-body" class="divide-y divide-slate-700/50"> | |
| <!-- Les tickets apparaitront ici --> | |
| <tr> | |
| <td colspan="5" class="p-8 text-center text-slate-500 italic">En attente de signalements WhatsApp...</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </main> | |
| <script> | |
| // Correction : L'adresse IP GCP unifiée pour tout le projet | |
| const API_BASE_URL = "http://35.199.168.248:7860"; | |
| async function fetchTickets() { | |
| try { | |
| const response = await fetch(`${API_BASE_URL}/api/tickets`); | |
| const tickets = await response.json(); | |
| renderTickets(tickets); | |
| } catch (error) { | |
| console.error("Erreur de connexion au serveur NEXUS:", error); | |
| } | |
| } | |
| function renderTickets(tickets) { | |
| const tbody = document.getElementById('tickets-body'); | |
| if (tickets.length === 0) return; | |
| tbody.innerHTML = ''; | |
| tickets.forEach(ticket => { | |
| const tr = document.createElement('tr'); | |
| tr.className = "hover:bg-slate-800/50 transition-colors"; | |
| let iaColor = "text-slate-400"; | |
| if(ticket.domaine_ia === "POLICE") iaColor = "text-blue-400 font-bold"; | |
| if(ticket.domaine_ia === "POMPIERS") iaColor = "text-red-400 font-bold"; | |
| if(ticket.domaine_ia === "SAMU") iaColor = "text-emerald-400 font-bold"; | |
| const isTransferred = ticket.status.includes("TRANSFÉRÉ"); | |
| tr.innerHTML = ` | |
| <td class="p-4 text-slate-300 font-mono">${ticket.heure}</td> | |
| <td class="p-4 font-semibold text-slate-200">${ticket.telephone}</td> | |
| <td class="p-4 text-slate-300">${ticket.message}</td> | |
| <td class="p-4 ${iaColor}"> | |
| ${ticket.domaine_ia} | |
| ${ticket.score > 0 ? `<span class="bg-slate-700 text-xs px-2 py-1 rounded ml-2">Score: ${ticket.score}/10</span>` : ''} | |
| </td> | |
| <td class="p-4"> | |
| ${isTransferred ? | |
| `<span class="text-green-400 font-semibold text-xs border border-green-500/30 bg-green-500/10 px-3 py-1.5 rounded-full">${ticket.status}</span>` | |
| : | |
| `<div class="flex gap-2"> | |
| <button onclick="dispatchTicket(${ticket.id}, 'POLICE')" class="bg-blue-600 hover:bg-blue-500 text-white text-xs font-bold py-1.5 px-3 rounded shadow transition-all">POLICE</button> | |
| <button onclick="dispatchTicket(${ticket.id}, 'POMPIERS')" class="bg-red-600 hover:bg-red-500 text-white text-xs font-bold py-1.5 px-3 rounded shadow transition-all">POMPIERS</button> | |
| <button onclick="dispatchTicket(${ticket.id}, 'SAMU')" class="bg-emerald-600 hover:bg-emerald-500 text-white text-xs font-bold py-1.5 px-3 rounded shadow transition-all">SAMU</button> | |
| </div>` | |
| } | |
| </td> | |
| `; | |
| tbody.appendChild(tr); | |
| }); | |
| } | |
| async function dispatchTicket(ticketId, serviceName) { | |
| try { | |
| await fetch(`${API_BASE_URL}/api/tickets/${ticketId}/dispatch`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ service: serviceName }) | |
| }); | |
| fetchTickets(); | |
| } catch (error) { | |
| alert("Erreur lors de la transmission aux services."); | |
| } | |
| } | |
| setInterval(fetchTickets, 2000); | |
| fetchTickets(); | |
| </script> | |
| </body> | |
| </html> |