feat: 启动/停止合并为切换按钮 + 设置参数改为中文

This commit is contained in:
2026-04-17 13:01:12 +08:00
parent 2f0f287c0f
commit 975ca5e894
3 changed files with 106 additions and 68 deletions
+55 -37
View File
@@ -73,27 +73,17 @@ function loadStatus() {
} }
function updateUI(data) { function updateUI(data) {
var startBtn = document.getElementById('start-btn'); // 更新切换按钮状态
var stopBtn = document.getElementById('stop-btn'); updateToggleButton(data.scheduler.running);
if (data.scheduler.running) { document.getElementById('capture-count').textContent = '拍照次数: ' + data.scheduler.capture_count;
startBtn.disabled = true;
stopBtn.disabled = false;
document.getElementById('scheduler-status').innerHTML = 'Status: Running';
} else {
startBtn.disabled = false;
stopBtn.disabled = true;
document.getElementById('scheduler-status').innerHTML = 'Status: Stopped';
}
document.getElementById('capture-count').textContent = 'Capture count: ' + data.scheduler.capture_count;
document.getElementById('total-images').textContent = data.stats.total_images; document.getElementById('total-images').textContent = data.stats.total_images;
document.getElementById('analyzed-images').textContent = data.stats.analyzed_images; document.getElementById('analyzed-images').textContent = data.stats.analyzed_images;
document.getElementById('total-events').textContent = data.stats.total_events; document.getElementById('total-events').textContent = data.stats.total_events;
// Event type filter // 事件类型筛选
var eventFilter = document.getElementById('event-filter'); var eventFilter = document.getElementById('event-filter');
eventFilter.innerHTML = '<option value="all">All types</option>'; eventFilter.innerHTML = '<option value="all">全部类型</option>';
data.stats.event_types.forEach(function(item) { data.stats.event_types.forEach(function(item) {
var opt = document.createElement('option'); var opt = document.createElement('option');
opt.value = item.type; opt.value = item.type;
@@ -103,30 +93,58 @@ function updateUI(data) {
} }
// Control // Control
function startScheduler() { function toggleScheduler() {
fetch(API_BASE + '/api/scheduler/start', {method: 'POST'}) var btn = document.getElementById('toggle-btn');
.then(function(res) { return res.json(); })
.then(function(data) { if (btn.classList.contains('stopped')) {
if (data.success) { // 当前已停止,启动
showToast('Started!', 1500); fetch(API_BASE + '/api/scheduler/start', {method: 'POST'})
refreshAll(); .then(function(res) { return res.json(); })
} else { .then(function(data) {
showToast('Failed: ' + data.error, 3000); if (data.success) {
} btn.classList.remove('stopped');
}) btn.classList.add('running');
.catch(function(e) { showToast('Error: ' + e.message, 3000); }); btn.innerHTML = '▶ 运行中';
btn.style.background = '#4CAF50';
showToast('已启动!', 1500);
refreshAll();
} else {
showToast('启动失败: ' + data.error, 3000);
}
})
.catch(function(e) { showToast('错误: ' + e.message, 3000); });
} else {
// 当前运行中,停止
fetch(API_BASE + '/api/scheduler/stop', {method: 'POST'})
.then(function(res) { return res.json(); })
.then(function(data) {
if (data.success) {
btn.classList.remove('running');
btn.classList.add('stopped');
btn.innerHTML = '⏹ 已停止';
btn.style.background = '#f44336';
showToast('已停止!', 1500);
refreshAll();
}
})
.catch(function(e) { showToast('错误: ' + e.message, 3000); });
}
} }
function stopScheduler() { function updateToggleButton(running) {
fetch(API_BASE + '/api/scheduler/stop', {method: 'POST'}) var btn = document.getElementById('toggle-btn');
.then(function(res) { return res.json(); })
.then(function(data) { if (running) {
if (data.success) { btn.classList.remove('stopped');
showToast('Stopped!', 1500); btn.classList.add('running');
refreshAll(); btn.innerHTML = '▶ 运行中';
} btn.style.background = '#4CAF50';
}) } else {
.catch(function(e) { showToast('Error: ' + e.message, 3000); }); btn.classList.remove('running');
btn.classList.add('stopped');
btn.innerHTML = '⏹ 已停止';
btn.style.background = '#f44336';
}
} }
function captureNow() { function captureNow() {
+38 -31
View File
@@ -23,8 +23,7 @@
<div class="panel-section"> <div class="panel-section">
<h3>📹 摄像头控制</h3> <h3>📹 摄像头控制</h3>
<div class="control-buttons"> <div class="control-buttons">
<button onclick="startScheduler()" id="start-btn" class="btn-primary">▶ 启动</button> <button onclick="toggleScheduler()" id="toggle-btn" class="btn-toggle stopped">⏹ 已停止</button>
<button onclick="stopScheduler()" id="stop-btn" class="btn-danger">⏹ 停止</button>
<button onclick="captureNow()" class="btn-secondary">📸 立即拍照</button> <button onclick="captureNow()" class="btn-secondary">📸 立即拍照</button>
</div> </div>
</div> </div>
@@ -102,108 +101,116 @@
<div class="modal" id="settings-modal" onclick="closeModalOnBackground(event, 'settings-modal')"> <div class="modal" id="settings-modal" onclick="closeModalOnBackground(event, 'settings-modal')">
<div class="modal-content settings-modal-content" onclick="event.stopPropagation()"> <div class="modal-content settings-modal-content" onclick="event.stopPropagation()">
<span class="modal-close" onclick="closeSettingsModal()">×</span> <span class="modal-close" onclick="closeSettingsModal()">×</span>
<h2>Settings</h2> <h2>⚙️ 参数设置</h2>
<div class="settings-section"> <div class="settings-section">
<h4>Save Settings</h4> <h4>💾 保存设置</h4>
<div class="setting-item"> <div class="setting-item">
<label>Save Dir:</label> <label>保存目录:</label>
<input type="text" id="setting-images-dir"> <input type="text" id="setting-images-dir">
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Interval (s):</label> <label>拍照间隔 ():</label>
<input type="number" id="setting-interval" value="60" min="10" max="3600"> <input type="number" id="setting-interval" value="60" min="10" max="3600">
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Display Limit:</label> <label>显示数量:</label>
<input type="number" id="setting-display-limit" value="20" min="5" max="100"> <input type="number" id="setting-display-limit" value="20" min="5" max="100">
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Refresh (s):</label> <label>刷新间隔 ():</label>
<input type="number" id="setting-refresh-interval" value="5" min="1" max="60"> <input type="number" id="setting-refresh-interval" value="5" min="1" max="60">
</div> </div>
</div> </div>
<div class="settings-section"> <div class="settings-section">
<h4>Person Detection (YOLO)</h4> <h4>👤 人体检测 (YOLO)</h4>
<div class="setting-item"> <div class="setting-item">
<label>Enable:</label> <label>启用 YOLO:</label>
<input type="checkbox" id="setting-use-yolo" checked> <input type="checkbox" id="setting-use-yolo" checked>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Min Conf:</label> <label>最小置信度:</label>
<input type="number" id="setting-yolo-confidence" value="0.3" min="0.1" max="1" step="0.1"> <input type="number" id="setting-yolo-confidence" value="0.3" min="0.1" max="1" step="0.1">
<span class="setting-desc">越小越敏感</span>
</div> </div>
</div> </div>
<div class="settings-section"> <div class="settings-section">
<h4>Person Identification</h4> <h4>🔍 人员识别</h4>
<div class="setting-item"> <div class="setting-item">
<label>Face Rec:</label> <label>人脸识别:</label>
<input type="checkbox" id="setting-use-face-rec" checked> <input type="checkbox" id="setting-use-face-rec" checked>
<span class="setting-desc">最准确</span>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>MediaPipe:</label> <label>MediaPipe:</label>
<input type="checkbox" id="setting-use-mediapipe" checked> <input type="checkbox" id="setting-use-mediapipe" checked>
<span class="setting-desc">人脸关键点</span>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Color Hist:</label> <label>颜色直方图:</label>
<input type="checkbox" id="setting-use-color-hist" checked> <input type="checkbox" id="setting-use-color-hist" checked>
<span class="setting-desc">备用方法</span>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Threshold:</label> <label>匹配阈值:</label>
<input type="number" id="setting-match-threshold" value="0.6" min="0.1" max="1" step="0.1"> <input type="number" id="setting-match-threshold" value="0.6" min="0.1" max="1" step="0.1">
<span class="setting-desc">越小越严格</span>
</div> </div>
</div> </div>
<div class="settings-section"> <div class="settings-section">
<h4>Confirmation</h4> <h4>✅ 连续性判断</h4>
<div class="setting-item"> <div class="setting-item">
<label>Confirm Frames:</label> <label>确认帧数:</label>
<input type="number" id="setting-confirm-frames" value="3" min="1" max="10"> <input type="number" id="setting-confirm-frames" value="3" min="1" max="10">
<span class="setting-desc">连续几帧确认变化</span>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Leave Frames:</label> <label>离开帧数:</label>
<input type="number" id="setting-leave-frames" value="2" min="1" max="10"> <input type="number" id="setting-leave-frames" value="2" min="1" max="10">
<span class="setting-desc">连续几帧确认离开</span>
</div> </div>
</div> </div>
<div class="settings-section"> <div class="settings-section">
<h4>AI Analysis</h4> <h4>🤖 AI 大模型分析</h4>
<div class="setting-item"> <div class="setting-item">
<label>Enable:</label> <label>启用大模型:</label>
<input type="checkbox" id="setting-use-vision-api"> <input type="checkbox" id="setting-use-vision-api">
<span class="setting-desc">调用 Vision API</span>
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Trigger:</label> <label>触发条件:</label>
<select id="setting-vision-trigger"> <select id="setting-vision-trigger">
<option value="person_change">Person Change</option> <option value="person_change">人员变化时</option>
<option value="motion">Motion</option> <option value="motion">运动检测时</option>
<option value="brightness">Brightness</option> <option value="brightness">亮度变化时</option>
<option value="always">Always</option> <option value="always">总是分析</option>
</select> </select>
</div> </div>
</div> </div>
<div class="settings-section"> <div class="settings-section">
<h4>API Config</h4> <h4>🔑 API 配置</h4>
<div class="setting-item"> <div class="setting-item">
<label>URL:</label> <label>API 地址:</label>
<input type="text" id="setting-api-url"> <input type="text" id="setting-api-url">
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Key:</label> <label>API Key:</label>
<input type="password" id="setting-api-key"> <input type="password" id="setting-api-key">
</div> </div>
<div class="setting-item"> <div class="setting-item">
<label>Model:</label> <label>模型名称:</label>
<input type="text" id="setting-model"> <input type="text" id="setting-model">
</div> </div>
</div> </div>
<div class="settings-actions"> <div class="settings-actions">
<button onclick="saveSettings()" class="btn-primary">Save</button> <button onclick="saveSettings()" class="btn-primary">保存设置</button>
<button onclick="closeSettingsModal()" class="btn-secondary">Cancel</button> <button onclick="closeSettingsModal()" class="btn-secondary">取消</button>
</div> </div>
</div> </div>
</div> </div>
+13
View File
@@ -128,6 +128,19 @@ button {
background: #f57c00; background: #f57c00;
} }
.btn-toggle {
min-width: 100px;
font-weight: bold;
}
.btn-toggle.stopped {
background: #f44336;
}
.btn-toggle.running {
background: #4CAF50;
}
/* 统计网格 */ /* 统计网格 */
.stats-grid { .stats-grid {
display: grid; display: grid;