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

支持摄像头配置信息中句柄的设置,并实测有效
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,133 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<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 { background: #1e1e1e; color: #d4d4d4; margin: 0; font-family: 'Consolas', monospace; font-size: 11px; height: 100vh; display: flex; flex-direction: column; overflow: hidden; }
/* 头部样式 */
.header { background: #2d2d2d; padding: 5px 15px; display: flex; justify-content: space-between; align-items: center; cursor: pointer; border-bottom: 2px solid #444; height: 40px; flex-shrink: 0; }
.search-box { background: #3c3c3c; border: 1px solid #555; color: #fff; padding: 2px 8px; border-radius: 4px; font-size: 11px; width: 220px; }
/* 日志区域 */
.body { flex: 1; overflow-y: auto; padding: 5px 10px; background: #1e1e1e; }
.log-row { display: flex; gap: 12px; border-bottom: 1px solid #2a2a2a; padding: 4px 0; align-items: center; white-space: nowrap; }
.log-row:hover { background: #2a2a2a; }
/* 文字颜色定义 */
.t-time { color: #888; min-width: 75px; }
.t-method { font-weight: bold; min-width: 50px; color: #569cd6; }
.t-url { color: #9cdcfe; flex: 1; overflow: hidden; text-overflow: ellipsis; cursor: help; }
.status-ok { color: #4ec9b0; }
.status-err { color: #f44747; }
/* 复制按钮样式 */
.btn-copy {
color: #6a9955; cursor: pointer; padding: 0 5px;
border: 1px solid transparent; border-radius: 3px;
transition: 0.2s; visibility: hidden; /* 默认隐藏,悬停显示 */
}
.log-row:hover .btn-copy { visibility: visible; }
.btn-copy:hover { border-color: #6a9955; background: rgba(106, 153, 85, 0.1); }
/* 滚动条 */
::-webkit-scrollbar { width: 6px; }
::-webkit-scrollbar-thumb { background: #444; border-radius: 3px; }
</style>
</head>
<body>
<div id="app" style="display: contents;">
<div class="header" @click="toggle">
<div>
<i class="bi bi-terminal-split me-2 text-warning"></i>
全路径诊断中控 ({{ filteredLogs.length }} 条)
</div>
<div class="d-flex align-items-center">
<input type="text" class="form-control form-control-sm search-box me-3"
v-model="searchText" @click.stop placeholder="检索 URL / 关键字...">
<span style="color:#ffca28; font-weight:bold; cursor:pointer" class="me-3">
{{ isExpanded ? '▼ 收起' : '▲ 展开' }}
</span>
<button class="btn btn-outline-danger btn-sm py-0 px-2" @click.stop="logs=[]">清空</button>
</div>
</div>
<div class="body" id="log-container">
<div v-for="log in filteredLogs" :key="log.id" class="log-row">
<span class="t-time">[{{ log.time }}]</span>
<span class="t-method">{{ log.method }}</span>
<span class="t-url" :title="log.url">{{ log.url }}</span>
<span :class="log.ok ? 'status-ok' : 'status-err'">{{ log.status }}</span>
<span class="btn-copy" @click.stop="copyLog(log.url)" title="复制完整URL">
<i class="bi bi-clipboard-plus"></i> 复制
</span>
</div>
<div v-if="filteredLogs.length === 0" class="text-center text-muted mt-5">
<i class="bi bi-activity d-block fs-3 mb-2"></i>
等待数据请求...
</div>
</div>
</div>
<script src="https://cdn.staticfile.org/vue/3.3.4/vue.global.prod.min.js"></script>
<script>
const { createApp, ref, computed, nextTick } = Vue;
createApp({
setup() {
const logs = ref([]);
const isExpanded = ref(false);
const searchText = ref("");
// 监听母座转发的日志
window.addEventListener('message', (e) => {
if (e.data.type === 'PUSH_LOG') {
logs.value.push({
id: Date.now() + Math.random(),
time: new Date().toLocaleTimeString(),
...e.data.log,
ok: e.data.log.status === 200 || e.data.log.status === 'OK' || e.data.log.status === 'SEND'
});
// 自动清理,防止内存溢出
if (logs.value.length > 200) logs.value.shift();
// 如果没在搜索,自动滚动到底部
if(!searchText.value) {
nextTick(() => {
const c = document.getElementById('log-container');
c.scrollTop = c.scrollHeight;
});
}
}
});
// 复制到剪贴板功能
const copyLog = (text) => {
navigator.clipboard.writeText(text).then(() => {
// 可以在这里加个简单的 Toast 提示,或者改变图标颜色
console.log('Copied:', text);
});
};
const toggle = () => {
isExpanded.value = !isExpanded.value;
window.parent.postMessage({ type: 'UI_RESIZE_DIAG', expanded: isExpanded.value }, '*');
};
const filteredLogs = computed(() => {
const kw = searchText.value.toLowerCase();
return logs.value.filter(l =>
l.url.toLowerCase().includes(kw) ||
(l.msg && l.msg.toLowerCase().includes(kw))
);
});
return { logs, isExpanded, searchText, filteredLogs, toggle, copyLog };
}
}).mount('#app');
</script>
</body>
</html>