API réception alertes chute (SmartEye/YOLO), analyse IA (Gemini 2.5 Flash), gestion alertes avec escalade (watchdog), notifications Firebase, dashboard web, documentation MkDocs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
495 lines
44 KiB
PHP
495 lines
44 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SmartEye — Checklist Installation</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<style>
|
|
body { background: #0a0e1a; }
|
|
.badge-smarteye { background: #f59e0b22; color: #fbbf24; border: 1px solid #f59e0b44; }
|
|
.badge-lucas { background: #10b98122; color: #34d399; border: 1px solid #10b98144; }
|
|
.badge-ava { background: #6366f122; color: #818cf8; border: 1px solid #6366f144; }
|
|
.check-done:checked { accent-color: #10b981; }
|
|
.check-tested:checked { accent-color: #3b82f6; }
|
|
.phase-bar-smarteye { border-left: 3px solid #f59e0b; }
|
|
.phase-bar-lucas { border-left: 3px solid #10b981; }
|
|
.phase-bar-ava { border-left: 3px solid #6366f1; }
|
|
.phase-bar-all { border-left: 3px solid #8b5cf6; }
|
|
.row-done { opacity: 0.5; }
|
|
.row-done td { text-decoration: line-through; text-decoration-color: #475569; }
|
|
.row-done .no-strike { text-decoration: none; }
|
|
@keyframes pulse-border { 0%,100% { border-color: #ef444488; } 50% { border-color: #ef4444; } }
|
|
.pending-critical { animation: pulse-border 2s infinite; }
|
|
.progress-fill { transition: width 0.5s ease; }
|
|
</style>
|
|
</head>
|
|
<body class="min-h-screen text-slate-200">
|
|
|
|
<!-- HEADER -->
|
|
<nav class="bg-slate-900/80 backdrop-blur border-b border-slate-800 px-6 py-4 sticky top-0 z-50">
|
|
<div class="max-w-6xl mx-auto flex justify-between items-center">
|
|
<div class="flex items-center gap-4">
|
|
<div class="w-3 h-3 rounded-full bg-emerald-500"></div>
|
|
<span class="font-bold text-xl tracking-wider text-white">CHECKLIST <span class="text-slate-500 text-sm font-normal">INSTALLATION</span></span>
|
|
</div>
|
|
<div class="flex items-center gap-4">
|
|
<div class="flex gap-2 text-xs">
|
|
<span class="badge-smarteye px-2 py-1 rounded font-bold">SmartEye</span>
|
|
<span class="badge-lucas px-2 py-1 rounded font-bold">Lucas</span>
|
|
<span class="badge-ava px-2 py-1 rounded font-bold">AVA</span>
|
|
</div>
|
|
<select id="client-select" onchange="loadClient()" class="bg-slate-800 border border-slate-700 text-white text-sm rounded px-3 py-2">
|
|
<option value="">-- Client --</option>
|
|
<?php
|
|
$db = json_decode(file_get_contents('database.json'), true);
|
|
foreach ($db['clients'] as $id => $c) {
|
|
echo '<option value="' . htmlspecialchars($id) . '">' . htmlspecialchars($c['name']) . '</option>';
|
|
}
|
|
?>
|
|
</select>
|
|
<a href="admin.php" class="text-slate-400 hover:text-white text-sm border border-slate-700 px-3 py-2 rounded transition">Admin</a>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- PROGRESS BAR -->
|
|
<div class="max-w-6xl mx-auto px-6 mt-6">
|
|
<div class="bg-slate-900 rounded-xl border border-slate-800 p-4">
|
|
<div class="flex justify-between items-center mb-2">
|
|
<span class="text-sm text-slate-400">Progression globale</span>
|
|
<span id="progress-text" class="text-sm font-bold text-emerald-400">0 / 0</span>
|
|
</div>
|
|
<div class="w-full bg-slate-800 rounded-full h-3 overflow-hidden">
|
|
<div id="progress-bar" class="progress-fill bg-gradient-to-r from-emerald-600 to-emerald-400 h-full rounded-full" style="width: 0%"></div>
|
|
</div>
|
|
<div class="flex justify-between mt-2 text-xs text-slate-600">
|
|
<span>Bureau</span>
|
|
<span>Sur place</span>
|
|
<span>Config App</span>
|
|
<span>Tunnels</span>
|
|
<span>Tests</span>
|
|
<span>Production</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- CHECKLIST -->
|
|
<div class="max-w-6xl mx-auto px-6 py-6 space-y-6">
|
|
|
|
<!-- PHASE 1 : BUREAU -->
|
|
<div class="bg-slate-900 rounded-xl border border-slate-800 overflow-hidden">
|
|
<div class="px-5 py-3 bg-slate-800/50 flex items-center gap-3">
|
|
<span class="text-lg">🏢</span>
|
|
<h2 class="font-bold text-white text-sm uppercase tracking-wider">Phase 1 — Au Bureau</h2>
|
|
<span class="text-xs text-slate-500 ml-auto">Avant le déplacement</span>
|
|
</div>
|
|
<table class="w-full text-sm">
|
|
<thead class="text-xs text-slate-500 uppercase bg-slate-950/50">
|
|
<tr>
|
|
<th class="px-5 py-2 text-left w-8">Fait</th>
|
|
<th class="px-2 py-2 text-left w-8">Test</th>
|
|
<th class="px-3 py-2 text-left">Action</th>
|
|
<th class="px-3 py-2 text-left w-24">Qui</th>
|
|
<th class="px-3 py-2 text-left w-48">Notes</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-800/50">
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="bureau-1">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-lucas pl-5">Créer le dossier client dans <span class="text-emerald-400 font-mono text-xs">admin.php</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold">Lucas</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="bureau-2">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-lucas pl-5">Générer le mot de passe LucasApp <span class="text-slate-600 text-xs">(admin/generate_password.php)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold">Lucas</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="bureau-3">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-lucas pl-5">Remplir infos senior (nom, adresse, date naissance)</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold">Lucas</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="bureau-4">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-lucas pl-5">Ajouter contacts famille (noms, tél, OS)</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold">Lucas</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="bureau-5">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Préparer le Jetson <span class="text-slate-600 text-xs">(flash SSD, OS, drivers)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="bureau-5b">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Pré-configurer WiFi hotspot <span class="font-mono text-xs text-amber-400">SmartEye-Setup</span> <span class="text-slate-600 text-xs">(connexion sans écran)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="SSID: SmartEye-Setup / MDP: smarteye2026" onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="bureau-5c">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Préparer clé USB auto-config WiFi <span class="text-slate-600 text-xs">(script + wifi.conf du client)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="SSID + MDP du client" onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="bureau-6">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Vérifier que SmartEye tourne <span class="text-slate-600 text-xs">(service actif, YOLO chargé)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="bureau-7">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Préparer les caméras <span class="text-slate-600 text-xs">(reset usine, config 2 flux RTSP)</span> <a href="doc_camera.php" target="_blank" class="text-amber-400 hover:text-amber-300 text-xs ml-1">[guide]</a></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- PHASE 2 : SUR PLACE - HARDWARE -->
|
|
<div class="bg-slate-900 rounded-xl border border-slate-800 overflow-hidden">
|
|
<div class="px-5 py-3 bg-slate-800/50 flex items-center gap-3">
|
|
<span class="text-lg">🏠</span>
|
|
<h2 class="font-bold text-white text-sm uppercase tracking-wider">Phase 2 — Sur Place : Matériel</h2>
|
|
<span class="text-xs text-slate-500 ml-auto">Installation physique</span>
|
|
</div>
|
|
<table class="w-full text-sm">
|
|
<thead class="text-xs text-slate-500 uppercase bg-slate-950/50">
|
|
<tr><th class="px-5 py-2 text-left w-8">Fait</th><th class="px-2 py-2 text-left w-8">Test</th><th class="px-3 py-2 text-left">Action</th><th class="px-3 py-2 text-left w-24">Qui</th><th class="px-3 py-2 text-left w-48">Notes</th></tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-800/50">
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="place-1">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Alimenter le Jetson + connecter au réseau <span class="text-slate-600 text-xs">(hotspot OU clé USB OU Ethernet)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="Méthode utilisée : ..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="place-1b">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">SSH sur le Jetson → configurer WiFi client <span class="font-mono text-xs text-slate-600">nmcli dev wifi connect "SSID" password "***"</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="IP obtenue : ..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="place-2">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Installer et positionner les caméras</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="Nb caméras : ..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="place-3">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-lucas pl-5">Renseigner IP Jetson + IPs caméras + ports tunnel dans <span class="text-emerald-400 font-mono text-xs">admin.php</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold">Lucas</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="Ports : 8560, 8561..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="place-4">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Vérifier que SmartEye détecte les caméras (YOLO actif)</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- PHASE 3 : CONFIG APP AVA -->
|
|
<div class="bg-slate-900 rounded-xl border border-slate-800 overflow-hidden">
|
|
<div class="px-5 py-3 bg-slate-800/50 flex items-center gap-3">
|
|
<span class="text-lg">📱</span>
|
|
<h2 class="font-bold text-white text-sm uppercase tracking-wider">Phase 3 — Configuration App AVA</h2>
|
|
<span class="text-xs text-slate-500 ml-auto">Sur le téléphone famille</span>
|
|
</div>
|
|
<table class="w-full text-sm">
|
|
<thead class="text-xs text-slate-500 uppercase bg-slate-950/50">
|
|
<tr><th class="px-5 py-2 text-left w-8">Fait</th><th class="px-2 py-2 text-left w-8">Test</th><th class="px-3 py-2 text-left">Action</th><th class="px-3 py-2 text-left w-24">Qui</th><th class="px-3 py-2 text-left w-48">Notes</th></tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-800/50">
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="app-1">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-ava pl-5">Saisir identifiant + mot de passe dans AVA</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="app-2">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-all pl-5">Vérifier réception <span class="font-mono text-xs text-indigo-400">smarteye_token</span> + <span class="font-mono text-xs text-indigo-400">jetson_ip</span> + <span class="font-mono text-xs text-indigo-400">cameras</span></td>
|
|
<td class="px-3 py-3 no-strike">
|
|
<span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span>
|
|
<span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold ml-1">Lucas</span>
|
|
</td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="app-3">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-ava pl-5">Scanner caméras via Jetson <span class="text-slate-600 text-xs">(WiFi local : http://jetson_ip:8080)</span></td>
|
|
<td class="px-3 py-3 no-strike">
|
|
<span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span>
|
|
<span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold ml-1">SmartEye</span>
|
|
</td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="app-4">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-ava pl-5">Vérifier affichage caméra en local (WiFi)</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- PHASE 4 : TUNNELS SSH -->
|
|
<div class="bg-slate-900 rounded-xl border border-slate-800 overflow-hidden">
|
|
<div class="px-5 py-3 bg-slate-800/50 flex items-center gap-3">
|
|
<span class="text-lg">🔗</span>
|
|
<h2 class="font-bold text-white text-sm uppercase tracking-wider">Phase 4 — Tunnels SSH (accès distant)</h2>
|
|
<span class="text-xs text-slate-500 ml-auto">Jetson → OVH</span>
|
|
</div>
|
|
<table class="w-full text-sm">
|
|
<thead class="text-xs text-slate-500 uppercase bg-slate-950/50">
|
|
<tr><th class="px-5 py-2 text-left w-8">Fait</th><th class="px-2 py-2 text-left w-8">Test</th><th class="px-3 py-2 text-left">Action</th><th class="px-3 py-2 text-left w-24">Qui</th><th class="px-3 py-2 text-left w-48">Notes</th></tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-800/50">
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="tunnel-1">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-lucas pl-5">Clé SSH du Jetson ajoutée dans <span class="font-mono text-xs text-emerald-400">authorized_keys</span> sur OVH</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold">Lucas</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="tunnel-2">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Lancer <span class="font-mono text-xs text-amber-400">autossh</span> sur le Jetson avec les ports caméras</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="-R 8560:ip:554 ..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="tunnel-3">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-lucas pl-5">Vérifier ports actifs sur OVH <span class="text-slate-600 text-xs">(ss -tlnp)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold">Lucas</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="tunnel-4">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Configurer autossh en service (redémarrage auto)</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="systemd service" onchange="saveState()"></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- PHASE 5 : TESTS COMPLETS -->
|
|
<div class="bg-slate-900 rounded-xl border border-slate-800 overflow-hidden">
|
|
<div class="px-5 py-3 bg-slate-800/50 flex items-center gap-3">
|
|
<span class="text-lg">🧪</span>
|
|
<h2 class="font-bold text-white text-sm uppercase tracking-wider">Phase 5 — Tests Complets</h2>
|
|
<span class="text-xs text-slate-500 ml-auto">Couper WiFi, tester en 4G</span>
|
|
</div>
|
|
<table class="w-full text-sm">
|
|
<thead class="text-xs text-slate-500 uppercase bg-slate-950/50">
|
|
<tr><th class="px-5 py-2 text-left w-8">Fait</th><th class="px-2 py-2 text-left w-8">Test</th><th class="px-3 py-2 text-left">Action</th><th class="px-3 py-2 text-left w-24">Qui</th><th class="px-3 py-2 text-left w-48">Notes</th></tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-800/50">
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="test-1">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-ava pl-5">Caméra live à distance <span class="text-slate-600 text-xs">(rtsp://57.128.74.87:port)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="test-2">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-smarteye pl-5">Simuler une chute (passer devant caméra, se coucher)</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="test-3">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-lucas pl-5">Vérifier réception image + analyse Gemini <span class="text-slate-600 text-xs">(api.php → analyze.py)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold">Lucas</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="test-4">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-ava pl-5">Réception notification push Firebase</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="test-5">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-ava pl-5">Consulter photos capturées <span class="text-slate-600 text-xs">(photos.php)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="test-6">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-ava pl-5">Acquitter l'alerte <span class="text-slate-600 text-xs">(acknowledge.php)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="test-7">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-ava pl-5">Résoudre / reset l'alerte <span class="text-slate-600 text-xs">(reset.php)</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- PHASE 6 : MISE EN PRODUCTION -->
|
|
<div class="bg-slate-900 rounded-xl border border-slate-800 overflow-hidden">
|
|
<div class="px-5 py-3 bg-slate-800/50 flex items-center gap-3">
|
|
<span class="text-lg">🚀</span>
|
|
<h2 class="font-bold text-white text-sm uppercase tracking-wider">Phase 6 — Mise en Production</h2>
|
|
<span class="text-xs text-slate-500 ml-auto">Validation finale</span>
|
|
</div>
|
|
<table class="w-full text-sm">
|
|
<thead class="text-xs text-slate-500 uppercase bg-slate-950/50">
|
|
<tr><th class="px-5 py-2 text-left w-8">Fait</th><th class="px-2 py-2 text-left w-8">Test</th><th class="px-3 py-2 text-left">Action</th><th class="px-3 py-2 text-left w-24">Qui</th><th class="px-3 py-2 text-left w-48">Notes</th></tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-800/50">
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="prod-1">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-lucas pl-5">Passer <span class="font-mono text-xs text-emerald-400">site_status</span> à <span class="text-emerald-400 font-bold">"active"</span></td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold">Lucas</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="prod-2">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-all pl-5">Former la famille à l'utilisation de AVA</td>
|
|
<td class="px-3 py-3 no-strike"><span class="badge-ava px-2 py-0.5 rounded text-xs font-bold">AVA</span></td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
<tr class="task-row hover:bg-slate-800/30" data-task="prod-3">
|
|
<td class="px-5 py-3 no-strike"><input type="checkbox" class="check-done w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-2 py-3 no-strike"><input type="checkbox" class="check-tested w-4 h-4" onchange="saveState()"></td>
|
|
<td class="px-3 py-3 phase-bar-all pl-5">PV de recette signé par la famille</td>
|
|
<td class="px-3 py-3 no-strike">
|
|
<span class="badge-smarteye px-2 py-0.5 rounded text-xs font-bold">SmartEye</span>
|
|
<span class="badge-lucas px-2 py-0.5 rounded text-xs font-bold ml-1">Lucas</span>
|
|
<span class="badge-ava px-2 py-0.5 rounded text-xs font-bold ml-1">AVA</span>
|
|
</td>
|
|
<td class="px-3 py-3 no-strike"><input type="text" class="note-input w-full bg-transparent border-b border-slate-700 text-xs text-slate-400 px-1 py-0.5 focus:border-slate-500 outline-none" placeholder="..." onchange="saveState()"></td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- RESET -->
|
|
<div class="text-center py-4">
|
|
<button onclick="if(confirm('Remettre toute la checklist à zéro ?')){localStorage.removeItem(getStorageKey());location.reload();}" class="text-xs text-slate-600 hover:text-red-400 transition border border-slate-800 px-4 py-2 rounded">Remettre à zéro</button>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function getStorageKey() {
|
|
const client = document.getElementById('client-select').value || '_default';
|
|
return 'checklist_' + client;
|
|
}
|
|
|
|
function saveState() {
|
|
const state = {};
|
|
document.querySelectorAll('.task-row').forEach(row => {
|
|
const task = row.dataset.task;
|
|
const done = row.querySelector('.check-done').checked;
|
|
const tested = row.querySelector('.check-tested').checked;
|
|
const note = row.querySelector('.note-input').value;
|
|
state[task] = { done, tested, note };
|
|
|
|
if (done && tested) {
|
|
row.classList.add('row-done');
|
|
} else {
|
|
row.classList.remove('row-done');
|
|
}
|
|
});
|
|
localStorage.setItem(getStorageKey(), JSON.stringify(state));
|
|
updateProgress();
|
|
}
|
|
|
|
function loadState() {
|
|
const saved = localStorage.getItem(getStorageKey());
|
|
if (!saved) return;
|
|
const state = JSON.parse(saved);
|
|
document.querySelectorAll('.task-row').forEach(row => {
|
|
const task = row.dataset.task;
|
|
if (state[task]) {
|
|
row.querySelector('.check-done').checked = state[task].done;
|
|
row.querySelector('.check-tested').checked = state[task].tested;
|
|
row.querySelector('.note-input').value = state[task].note || '';
|
|
if (state[task].done && state[task].tested) {
|
|
row.classList.add('row-done');
|
|
}
|
|
}
|
|
});
|
|
updateProgress();
|
|
}
|
|
|
|
function loadClient() {
|
|
// Reset all checkboxes and notes
|
|
document.querySelectorAll('.task-row').forEach(row => {
|
|
row.querySelector('.check-done').checked = false;
|
|
row.querySelector('.check-tested').checked = false;
|
|
row.querySelector('.note-input').value = '';
|
|
row.classList.remove('row-done');
|
|
});
|
|
loadState();
|
|
}
|
|
|
|
function updateProgress() {
|
|
const rows = document.querySelectorAll('.task-row');
|
|
const total = rows.length;
|
|
let completed = 0;
|
|
rows.forEach(row => {
|
|
if (row.querySelector('.check-done').checked && row.querySelector('.check-tested').checked) {
|
|
completed++;
|
|
}
|
|
});
|
|
const pct = total > 0 ? Math.round((completed / total) * 100) : 0;
|
|
document.getElementById('progress-bar').style.width = pct + '%';
|
|
document.getElementById('progress-text').textContent = completed + ' / ' + total + ' (' + pct + '%)';
|
|
}
|
|
|
|
// Init
|
|
loadState();
|
|
</script>
|
|
</body>
|
|
</html>
|