2025-12-28 08:07:55 +08:00
|
|
|
<!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>
|
|
|
|
|
|
|
|
|
|
<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,
|
2025-12-28 13:14:40 +08:00
|
|
|
sub: document.getElementById('frame-sub').contentWindow
|
2025-12-28 08:07:55 +08:00
|
|
|
};
|
|
|
|
|
const editorIframe = document.getElementById('frame-editor');
|
|
|
|
|
|
2025-12-28 13:14:40 +08:00
|
|
|
// 辅助:切回详情页
|
2025-12-28 08:07:55 +08:00
|
|
|
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;
|
2025-12-28 13:14:40 +08:00
|
|
|
// 如果当前在深层页面(Edit/Add/Pre/Ctrl),强制切回详情页
|
2025-12-28 08:07:55 +08:00
|
|
|
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;
|
|
|
|
|
|
2025-12-28 13:14:40 +08:00
|
|
|
// --- 路由切换逻辑 ---
|
2025-12-28 08:07:55 +08:00
|
|
|
|
2025-12-28 13:14:40 +08:00
|
|
|
// 1. 编辑/新增
|
2025-12-28 08:07:55 +08:00
|
|
|
case 'OPEN_CAMERA_EDIT':
|
2025-12-28 13:14:40 +08:00
|
|
|
case 'OPEN_CAMERA_ADD':
|
2025-12-28 08:07:55 +08:00
|
|
|
editorIframe.src = "CameraEdit.html";
|
|
|
|
|
editorIframe.onload = () => {
|
2025-12-28 13:14:40 +08:00
|
|
|
const initType = msg.type === 'OPEN_CAMERA_ADD' ? 'INIT_ADD_PAGE' : 'LOAD_EDIT_DATA';
|
|
|
|
|
editorIframe.contentWindow.postMessage({ type: initType, deviceId: msg.id, apiBase: API_BASE }, '*');
|
2025-12-28 08:07:55 +08:00
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
|
2025-12-28 13:14:40 +08:00
|
|
|
// 2. 预处理
|
|
|
|
|
case 'OPEN_PREPROCESS':
|
|
|
|
|
editorIframe.src = "Preprocessing.html";
|
2025-12-28 08:07:55 +08:00
|
|
|
editorIframe.onload = () => {
|
2025-12-28 13:14:40 +08:00
|
|
|
editorIframe.contentWindow.postMessage({ type: 'LOAD_PREPROCESS_DATA', deviceId: msg.id, apiBase: API_BASE }, '*');
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// 3. 【修改】云台控制 (不弹窗,全屏)
|
|
|
|
|
case 'OPEN_CAMERA_CONTROL':
|
|
|
|
|
editorIframe.src = "CameraControl.html";
|
|
|
|
|
editorIframe.onload = () => {
|
|
|
|
|
editorIframe.contentWindow.postMessage({ type: 'LOAD_CTRL_DATA', deviceId: msg.id, apiBase: API_BASE }, '*');
|
2025-12-28 08:07:55 +08:00
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// 统一关闭逻辑
|
|
|
|
|
case 'CLOSE_EDIT_MODE':
|
|
|
|
|
case 'CLOSE_ADD_MODE':
|
2025-12-28 13:14:40 +08:00
|
|
|
case 'CLOSE_PREPROCESS_MODE':
|
|
|
|
|
case 'CLOSE_CONTROL_MODE': // 【新增】
|
2025-12-28 08:07:55 +08:00
|
|
|
switchToDetail();
|
|
|
|
|
if(msg.needRefresh) frames.list.postMessage({ type: 'REFRESH_LIST' }, '*');
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
</script>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|