// 视觉记录系统前端逻辑 const API_BASE = ''; let currentImageId = null; // ============== 初始化 ============== document.addEventListener('DOMContentLoaded', () => { refreshAll(); setInterval(refreshAll, 5000); // 每5秒刷新 }); function refreshAll() { loadStatus(); loadImages(); loadEvents(); loadStats(); } // ============== 状态相关 ============== async function loadStatus() { try { const res = await fetch(`${API_BASE}/api/status`); const data = await res.json(); updateStatusBar(data.scheduler); updateStats(data.stats); // 更新按钮状态 const startBtn = document.getElementById('start-btn'); const stopBtn = document.getElementById('stop-btn'); if (data.scheduler.running) { startBtn.disabled = true; stopBtn.disabled = false; document.getElementById('scheduler-status').innerHTML = `状态: ✓ 运行中`; } else { startBtn.disabled = false; stopBtn.disabled = true; document.getElementById('scheduler-status').innerHTML = `状态: ⏹ 已停止`; } document.getElementById('capture-count').textContent = `拍照次数: ${data.scheduler.capture_count}`; // 更新输入框 document.getElementById('interval-input').value = data.scheduler.interval; document.getElementById('auto-analyze').checked = data.scheduler.auto_analyze; } catch (e) { console.error('加载状态失败:', e); } } function updateStatusBar(status) { // 已在 loadStatus 中处理 } function updateStats(stats) { document.getElementById('total-images').textContent = stats.total_images; document.getElementById('analyzed-images').textContent = stats.analyzed_images; document.getElementById('total-events').textContent = stats.total_events; // 更新事件类型筛选 const eventFilter = document.getElementById('event-filter'); const currentValue = eventFilter.value; // 清空并重建选项 eventFilter.innerHTML = ''; stats.event_types.forEach(item => { const opt = document.createElement('option'); opt.value = item.type; opt.textContent = `${item.type} (${item.count})`; eventFilter.appendChild(opt); }); eventFilter.value = currentValue; } // ============== 控制相关 ============== async function startScheduler() { const interval = parseInt(document.getElementById('interval-input').value); const autoAnalyze = document.getElementById('auto-analyze').checked; try { const res = await fetch(`${API_BASE}/api/scheduler/start?interval=${interval}&auto_analyze=${autoAnalyze}`, { method: 'POST' }); const data = await res.json(); if (data.success) { alert('启动成功!'); refreshAll(); } else { alert('启动失败: ' + data.error); } } catch (e) { alert('请求失败: ' + e.message); } } async function stopScheduler() { try { const res = await fetch(`${API_BASE}/api/scheduler/stop`, { method: 'POST' }); const data = await res.json(); if (data.success) { alert('已停止!'); refreshAll(); } } catch (e) { alert('请求失败: ' + e.message); } } async function setInterval() { const interval = parseInt(document.getElementById('interval-input').value); if (interval < 10) { alert('间隔不能小于10秒'); return; } try { const res = await fetch(`${API_BASE}/api/scheduler/interval?interval=${interval}`, { method: 'POST' }); const data = await res.json(); if (data.success) { alert('间隔已更新为 ' + interval + ' 秒'); refreshAll(); } } catch (e) { alert('请求失败: ' + e.message); } } async function captureNow() { try { const res = await fetch(`${API_BASE}/api/capture`, { method: 'POST' }); const data = await res.json(); if (data.success) { alert('拍照成功!图片ID: ' + data.image_id); refreshAll(); } else { alert('拍照失败: ' + data.error); } } catch (e) { alert('请求失败: ' + e.message); } } async function analyzeUnanalyzed() { try { const res = await fetch(`${API_BASE}/api/analyze/unanalyzed`, { method: 'POST' }); const data = await res.json(); alert(`分析了 ${data.results.length} 张图片`); refreshAll(); } catch (e) { alert('请求失败: ' + e.message); } } // ============== 图片相关 ============== async function loadImages() { const filter = document.getElementById('image-filter').value; const analyzedOnly = filter === 'analyzed'; try { const res = await fetch(`${API_BASE}/api/images?limit=50&analyzed_only=${analyzedOnly}`); const data = await res.json(); renderImages(data.images); } catch (e) { console.error('加载图片失败:', e); } } function renderImages(images) { const grid = document.getElementById('images-grid'); grid.innerHTML = ''; if (images.length === 0) { grid.innerHTML = '

暂无图片

'; return; } images.forEach(img => { const card = document.createElement('div'); card.className = 'image-card'; card.onclick = () => openImageModal(img.id); const imgEl = document.createElement('img'); imgEl.src = `/images/${img.path.split('/').pop()}`; imgEl.alt = `图片 ${img.id}`; const info = document.createElement('div'); info.className = 'image-card-info'; const time = new Date(img.timestamp).toLocaleString('zh-CN'); info.innerHTML = `
${time}
${img.analyzed ? '✓ 已分析' : '○ 未分析'}
`; card.appendChild(imgEl); card.appendChild(info); grid.appendChild(card); }); } async function openImageModal(imageId) { currentImageId = imageId; try { const res = await fetch(`${API_BASE}/api/images/${imageId}`); const data = await res.json(); const modal = document.getElementById('image-modal'); const modalImg = document.getElementById('modal-image'); const modalTitle = document.getElementById('modal-title'); const modalTime = document.getElementById('modal-time'); const modalEvents = document.getElementById('modal-events'); modalImg.src = `/images/${data.path.split('/').pop()}`; modalTitle.textContent = `图片 #${data.id}`; modalTime.textContent = `时间: ${new Date(data.timestamp).toLocaleString('zh-CN')}`; modalEvents.innerHTML = ''; if (data.events && data.events.length > 0) { data.events.forEach(event => { const eventDiv = document.createElement('div'); eventDiv.className = 'modal-event'; eventDiv.innerHTML = ` ${event.event_type} ${event.confidence}
${event.description}
`; modalEvents.appendChild(eventDiv); }); } else { modalEvents.innerHTML = '

暂无事件记录

'; } modal.classList.add('active'); } catch (e) { console.error('加载图片详情失败:', e); } } function closeModal() { document.getElementById('image-modal').classList.remove('active'); currentImageId = null; } async function analyzeCurrentImage() { if (!currentImageId) return; try { const res = await fetch(`${API_BASE}/api/analyze/${currentImageId}`, { method: 'POST' }); const data = await res.json(); if (data.success) { alert('分析完成!'); openImageModal(currentImageId); // 刷新详情 refreshAll(); } else { alert('分析失败: ' + data.error); } } catch (e) { alert('请求失败: ' + e.message); } } async function deleteCurrentImage() { if (!currentImageId) return; if (!confirm('确定删除此图片?')) return; try { const res = await fetch(`${API_BASE}/api/images/${currentImageId}`, { method: 'DELETE' }); const data = await res.json(); if (data.success) { closeModal(); refreshAll(); } } catch (e) { alert('请求失败: ' + e.message); } } // ============== 事件相关 ============== async function loadEvents() { const filter = document.getElementById('event-filter').value; const eventType = filter === 'all' ? '' : filter; try { let url = `${API_BASE}/api/events?limit=50`; if (eventType) { url += `&event_type=${encodeURIComponent(eventType)}`; } const res = await fetch(url); const data = await res.json(); renderEvents(data.events); } catch (e) { console.error('加载事件失败:', e); } } function renderEvents(events) { const list = document.getElementById('events-list'); list.innerHTML = ''; if (events.length === 0) { list.innerHTML = '

暂无事件

'; return; } events.forEach(event => { const card = document.createElement('div'); card.className = `event-card type-${event.event_type}`; const time = new Date(event.timestamp).toLocaleString('zh-CN'); card.innerHTML = `
${event.event_type} ${time}
${event.description}
${event.confidence}
`; card.onclick = () => openImageModal(event.image_id); list.appendChild(card); }); } // 筛选变化监听 document.getElementById('image-filter').addEventListener('change', loadImages); document.getElementById('event-filter').addEventListener('change', loadEvents);