支持通过网页增加、删除、修改摄像头配置信息

支持摄像头配置信息中句柄的设置,并实测有效
This commit is contained in:
2025-12-28 08:07:55 +08:00
parent 3718465463
commit 2ee25a4f7c
25 changed files with 2298 additions and 75 deletions

View File

@@ -0,0 +1,148 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>SHH 视频网关 - 控制底座</title>
<script src="https://cdn.staticfile.org/axios/1.5.0/axios.min.js"></script>
<link href="https://cdn.staticfile.org/twitter-bootstrap/5.3.0/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.staticfile.org/bootstrap-icons/1.10.0/font/bootstrap-icons.min.css" rel="stylesheet">
<style>
body, html { margin: 0; padding: 0; height: 100vh; overflow: hidden; background: #f4f6f9; }
.app-shell { display: flex; height: 100vh; }
.sidebar-container { width: 320px; border-right: 1px solid #ddd; background: #fff; flex-shrink: 0; }
.main-workarea { flex: 1; display: flex; flex-direction: column; overflow: hidden; }
.top-container { height: 110px; padding: 15px 15px 0 15px; flex-shrink: 0; }
.editor-container { flex: 1; padding: 15px; overflow: hidden; position: relative; }
.log-panel { height: 45px; border-top: 1px solid #333; transition: height 0.3s; background: #1e1e1e; }
.modal-body iframe { border: none; width: 100%; }
#frame-editor { width: 100%; height: 100%; border: none; background: #fff; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); }
</style>
</head>
<body>
<div class="app-shell">
<div class="sidebar-container">
<iframe id="frame-list" src="List.html" style="width:100%; height:100%; border:none;" name="list"></iframe>
</div>
<div class="main-workarea">
<div class="top-container">
<iframe id="frame-top" src="EditorTop.html" style="width:100%; height:100%; border:none;" name="top"></iframe>
</div>
<div class="editor-container">
<iframe id="frame-editor" src="Editor.html" name="editor"></iframe>
</div>
<div id="diag-wrapper" class="log-panel">
<iframe id="frame-diag" src="Diagnostic.html" style="width:100%; height:100%; border:none;" name="diag"></iframe>
</div>
</div>
</div>
<div class="modal fade" id="subModal" tabindex="-1"><div class="modal-dialog modal-lg modal-dialog-centered"><div class="modal-content shadow-lg"><div class="modal-body p-0"><iframe id="frame-sub" src="Subscription.html" style="height: 650px;" name="sub"></iframe></div></div></div></div>
<div class="modal fade" id="preModal" tabindex="-1"><div class="modal-dialog modal-md modal-dialog-centered"><div class="modal-content shadow-lg"><div class="modal-body p-0"><iframe id="frame-pre" src="Preprocessing.html" style="height: 580px;" name="pre"></iframe></div></div></div></div>
<div class="modal fade" id="ctrlModal" tabindex="-1"><div class="modal-dialog modal-dialog-centered"><div class="modal-content shadow-lg"><div class="modal-body p-0"><iframe id="frame-ctrl" src="CameraControl.html" style="height: 480px;" name="ctrl"></iframe></div></div></div></div>
<script src="https://cdn.staticfile.org/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
<script>
const API_BASE = "http://localhost:5000";
let currentDeviceId = 0;
window.addEventListener('message', (event) => {
const msg = event.data;
if (!msg || !msg.type) return;
const frames = {
list: document.getElementById('frame-list').contentWindow,
top: document.getElementById('frame-top').contentWindow,
editor: document.getElementById('frame-editor').contentWindow,
diag: document.getElementById('frame-diag').contentWindow,
sub: document.getElementById('frame-sub').contentWindow,
pre: document.getElementById('frame-pre').contentWindow,
ctrl: document.getElementById('frame-ctrl').contentWindow
};
const editorIframe = document.getElementById('frame-editor');
const switchToDetail = () => {
editorIframe.src = "Editor.html";
editorIframe.onload = () => {
setTimeout(() => {
if(currentDeviceId) editorIframe.contentWindow.postMessage({ type: 'LOAD_DEVICE', deviceId: currentDeviceId }, '*');
}, 100);
};
};
switch(msg.type) {
case 'DEVICE_SELECTED':
currentDeviceId = msg.data.id;
// 如果当前不是Editor页面切回
if (!editorIframe.src.includes('Editor.html')) {
switchToDetail();
} else {
if(frames.top) frames.top.postMessage({ type: 'UPDATE_TOP_INFO', data: msg.data }, '*');
if(frames.editor) frames.editor.postMessage({ type: 'LOAD_DEVICE', deviceId: msg.data.id }, '*');
}
break;
case 'DEVICE_CONTROL':
const controlUrl = `${API_BASE}/api/Cameras/${msg.deviceId}/power?enabled=${msg.action === 'start'}`;
axios.post(controlUrl).then(() => {
frames.list.postMessage({ type: 'REFRESH_LIST' }, '*');
frames.diag.postMessage({ type: 'PUSH_LOG', log: { method: 'POST', url: controlUrl, status: 200, msg: `Device ${msg.action}` } }, '*');
}).catch(e => console.error(e));
break;
case 'API_LOG':
if(frames.diag) frames.diag.postMessage({ type: 'PUSH_LOG', log: msg.log }, '*');
break;
case 'UI_RESIZE_DIAG':
const diagEl = document.getElementById('diag-wrapper');
if(diagEl) diagEl.style.height = msg.expanded ? '350px' : '45px';
break;
// 弹窗逻辑
case 'OPEN_SUBSCRIPTION':
new bootstrap.Modal(document.getElementById('subModal')).show();
setTimeout(() => frames.sub.postMessage({ type: 'LOAD_SUBS_DATA', deviceId: msg.id }, '*'), 400);
break;
case 'OPEN_PREPROCESS':
editorIframe.src = "Preprocessing.html";
editorIframe.onload = () => {
editorIframe.contentWindow.postMessage({ type: 'LOAD_PREPROCESS_DATA', deviceId: msg.id, apiBase: API_BASE }, '*');
};
break;
case 'OPEN_CAMERA_CONTROL':
new bootstrap.Modal(document.getElementById('ctrlModal')).show();
setTimeout(() => frames.ctrl.postMessage({ type: 'LOAD_CTRL_DATA', deviceId: msg.id, apiBase: API_BASE }, '*'), 400);
break;
// --- 统一使用 CameraEdit.html ---
case 'OPEN_CAMERA_EDIT':
editorIframe.src = "CameraEdit.html";
editorIframe.onload = () => {
editorIframe.contentWindow.postMessage({ type: 'LOAD_EDIT_DATA', deviceId: msg.id, apiBase: API_BASE }, '*');
};
break;
case 'OPEN_CAMERA_ADD': // 新增也指向同一个文件
editorIframe.src = "CameraEdit.html";
editorIframe.onload = () => {
editorIframe.contentWindow.postMessage({ type: 'INIT_ADD_PAGE', apiBase: API_BASE }, '*');
};
break;
// 统一关闭逻辑
case 'CLOSE_EDIT_MODE':
case 'CLOSE_PREPROCESS_MODE':
case 'CLOSE_ADD_MODE':
switchToDetail();
if(msg.needRefresh) frames.list.postMessage({ type: 'REFRESH_LIST' }, '*');
break;
}
});
</script>
</body>
</html>