let currentTab = 'dashboard'; document.querySelectorAll('.tab-btn').forEach(btn => { btn.addEventListener('click', () => { document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); btn.classList.add('active'); document.getElementById(btn.dataset.tab).classList.add('active'); currentTab = btn.dataset.tab; if (btn.dataset.tab === 'dashboard') loadDashboard(); if (btn.dataset.tab === 'alerts') loadAlerts(); if (btn.dataset.tab === 'ams') loadAms(); if (btn.dataset.tab === 'edges') loadEdges(); if (btn.dataset.tab === 'simulate') loadSimulate(); }); }); async function api(url) { const r = await fetch(url); if (!r.ok) throw new Error(r.status); return r.json(); } async function loadStats() { try { const stats = await api('/api/stats'); document.getElementById('statAlerts').textContent = stats.alerts_today; document.getElementById('statOnline').textContent = `${stats.online_ams}/${stats.total_ams}`; document.getElementById('statEdges').textContent = `${stats.online_edges}/${stats.total_edges}`; } catch (e) { console.error('Stats error:', e); } } async function loadDashboard() { await loadStats(); await loadAmsMap(); await loadRecentAlerts(); await loadStatsChart(); } async function loadAmsMap() { try { const amsList = await api('/api/ams'); const container = document.getElementById('amsMap'); if (!amsList.length) { container.innerHTML = '
Нет АМС. Добавьте на вкладке АМС.
'; return; } container.style.position = 'relative'; container.innerHTML = amsList.map((a, i) => { const x = 10 + (i % 3) * 35; const y = 20 + Math.floor(i / 3) * 25; return ``; }).join(''); } catch (e) { console.error('Map error:', e); } } async function loadRecentAlerts() { try { const alerts = await api('/api/alerts'); const container = document.getElementById('recentAlerts'); if (!alerts.length) { container.innerHTML = 'Тревог нет
'; return; } container.innerHTML = alerts.slice(0, 5).map(a => `Нет данных
'; return; } container.innerHTML = `| ID | АМС | Камера | Тип | Время | Статус | Действия |
|---|---|---|---|---|---|---|
| ${a.id} | ${a.amc_name || 'АМС #' + a.amc_id} | ${a.camera_role} | ${a.event_type} | ${new Date(a.created_at).toLocaleString('kk-KZ')} | ${a.status} | ${a.status === 'new' ? `` : ''} ${a.status !== 'closed' ? `` : ''} |
Нет АМС. Добавьте первую!
'; return; } container.innerHTML = `| ID | Название | Адрес | Регион | Статус | Наряд |
|---|---|---|---|---|---|
| ${a.id} | ${a.name} | ${a.address || '-'} | ${a.region || '-'} | ${a.status} | ${a.has_permit ? '✅' : '❌'} |
Edge-устройств нет. Запустите симуляцию.
'; return; } container.innerHTML = `| Edge ID | АМС | Статус | Последний heartbeat |
|---|---|---|---|
${e.edge_id} |
${e.amc_name || 'АМС #' + e.amc_id} | ${e.status} | ${new Date(e.last_heartbeat).toLocaleString('kk-KZ')} |
Сначала добавьте АМС на вкладке "АМС"
'; return; } select.innerHTML = amsList.map(a => ``).join(''); } catch (e) { console.error('Simulate load error:', e); } } document.getElementById('simulateForm').addEventListener('submit', async (e) => { e.preventDefault(); const resultBox = document.getElementById('simulateResult'); try { const amsSelect = document.getElementById('simAms'); const amsName = amsSelect.options[amsSelect.selectedIndex].dataset.name; const amsId = parseInt(amsSelect.value); const event = { event_id: 'evt-' + Date.now(), amc_id: amsId, amc_name: amsName, camera_id: document.getElementById('simCamera').value, camera_role: document.getElementById('simCamera').value === 'ladder' ? 'ladder' : 'perimeter', event_type: document.getElementById('simEventType').value, confidence: 0.75 + Math.random() * 0.2, detected_at: new Date().toISOString(), snapshot_url: null, clip_url: null }; const hasPermit = document.getElementById('simPermit').value === 'true'; if (hasPermit) { const data = await fetch('/api/ams').then(r => r.json()); const ams = data.find(a => a.id === amsId); if (ams) { ams.has_permit = true; await fetch('/api/ams', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: ams }); } } const r = await fetch('/api/events', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(event) }); const result = await r.json(); resultBox.className = 'result-box success'; resultBox.innerHTML = ` ✅ Событие отправлено!