视频记录

This commit is contained in:
2026-01-08 16:03:39 +08:00
parent 69be82f892
commit 69d093fcb9
18 changed files with 550 additions and 13 deletions

View File

@@ -4,15 +4,22 @@
<meta charset="utf-8">
<title>环视系统</title>
<link rel="stylesheet" href="/static/layui/css/layui.css">
<link href="https://vjs.zencdn.net/8.23.3/video-js.css" rel="stylesheet" />
<style>
html, body { margin: 0; padding: 0; height: 100%; overflow: hidden; }
#app { display: flex; height: 100vh; }
#sidebar { width: 200px; background: #393D49; color: white; padding: 20px 0; }
#main { flex: 1; position: relative; background: black; }
#video { width: 100%; height: 100%; object-fit: contain; }
#video-player { width: 100%; height: 100%; display: none; }
.menu-item { padding: 12px 20px; cursor: pointer; }
.menu-item:hover { background: #4B515D; }
.active { background: #009688 !important; }
.disk-info { padding: 10px; background: #4B515D; margin: 10px; border-radius: 5px; font-size: 12px; }
.disk-bar { width: 100%; height: 6px; background: #5a5e6a; border-radius: 3px; margin: 5px 0; overflow: hidden; }
.disk-fill { height: 100%; background: #009688; transition: width 0.3s; }
.control-panel { position: absolute; top: 10px; right: 10px; background: rgba(0,0,0,0.7); padding: 10px; border-radius: 5px; color: white; }
.playback-panel { position: absolute; top: 10px; left: 220px; background: rgba(0,0,0,0.7); padding: 10px; border-radius: 5px; color: white; display: none; }
</style>
</head>
<body>
@@ -24,26 +31,192 @@
<div class="menu-item" data-view="left">左视</div>
<div class="menu-item" data-view="right">右视</div>
<hr style="border-color:#5a5e6a;margin:15px 10px">
<div class="menu-item" id="live-view">实时监控</div>
<div class="menu-item" id="playback-view">视频回放</div>
<hr style="border-color:#5a5e6a;margin:15px 10px">
<div class="disk-info">
<div>硬盘使用率</div>
<div class="disk-bar"><div class="disk-fill" id="disk-fill" style="width: 0%"></div></div>
<div id="disk-text">0%</div>
</div>
<hr style="border-color:#5a5e6a;margin:15px 10px">
<div class="menu-item" onclick="logout()">退出登录</div>
</div>
<div id="main">
<img id="video" src="/video_feed" />
<video id="video-player" class="video-js vjs-default-skin" controls preload="auto" data-setup="{}">
<p class="vjs-no-js">
要查看此视频请启用JavaScript并考虑升级到支持HTML5视频的浏览器
<a href="https://videojs.com.cn/html5-video-support/" target="_blank">支持HTML5视频</a>
</p>
</video>
<div class="control-panel">
<div>当前模式:<span id="mode-text">实时监控</span></div>
</div>
<div class="playback-panel" id="playback-panel">
<div style="margin-bottom: 10px">
<label>选择日期:</label>
<input type="date" id="date-picker" style="padding: 5px; border-radius: 3px; border: 1px solid #ccc;">
<button onclick="loadVideos()" style="padding: 5px 10px; background: #009688; color: white; border: none; border-radius: 3px; cursor: pointer;">加载</button>
</div>
<div>
<label>选择视频:</label>
<select id="video-select" style="padding: 5px; border-radius: 3px; border: 1px solid #ccc; width: 200px;">
<option value="">请选择视频</option>
</select>
</div>
</div>
</div>
</div>
<script src="https://vjs.zencdn.net/8.23.3/video.min.js"></script>
<script src="/static/layui/layui.js"></script>
<script>
// 切换视图(可选:后续通过 WebSocket 或 REST API 控制后端 current_view
document.querySelectorAll('.menu-item[data-view]').forEach(item => {
item.addEventListener('click', function() {
document.querySelector('.active').classList.remove('active');
this.classList.add('active');
const view = this.getAttribute('data-view');
// TODO: 发送 AJAX 请求通知后端切换 current_view
// fetch('/api/set_view?view=' + view);
});
// 初始化日期选择器为当前日期
document.getElementById('date-picker').value = new Date().toISOString().split('T')[0];
// 实时监控和回放模式切换
document.getElementById('live-view').addEventListener('click', function() {
setMode('live');
});
document.getElementById('playback-view').addEventListener('click', function() {
setMode('playback');
});
function setMode(mode) {
const liveViewBtn = document.getElementById('live-view');
const playbackViewBtn = document.getElementById('playback-view');
const videoImg = document.getElementById('video');
const videoPlayer = document.getElementById('video-player');
const playbackPanel = document.getElementById('playback-panel');
const modeText = document.getElementById('mode-text');
if (mode === 'live') {
liveViewBtn.classList.add('active');
playbackViewBtn.classList.remove('active');
videoImg.style.display = 'block';
videoPlayer.style.display = 'none';
playbackPanel.style.display = 'none';
modeText.textContent = '实时监控';
} else if (mode === 'playback') {
liveViewBtn.classList.remove('active');
playbackViewBtn.classList.add('active');
videoImg.style.display = 'none';
videoPlayer.style.display = 'block';
playbackPanel.style.display = 'block';
modeText.textContent = '视频回放';
loadVideos(); // 加载当天视频
}
}
// 加载指定日期的视频列表
function loadVideos() {
const datePicker = document.getElementById('date-picker');
const videoSelect = document.getElementById('video-select');
const selectedDate = datePicker.value;
if (!selectedDate) {
alert('请选择日期');
return;
}
// 清空视频选择器
videoSelect.innerHTML = '<option value="">请选择视频</option>';
// 请求视频列表
fetch('/api/videos')
.then(response => response.json())
.then(data => {
if (data.error) {
alert('获取视频列表失败:' + data.error);
return;
}
// 筛选指定日期的视频
const filteredVideos = data.videos.filter(video => video.date === selectedDate);
if (filteredVideos.length === 0) {
videoSelect.innerHTML += '<option value="">当天没有视频</option>';
return;
}
// 添加视频选项
filteredVideos.forEach(video => {
const option = document.createElement('option');
option.value = video.path;
option.textContent = video.time + ' (' + video.size + 'MB)';
videoSelect.appendChild(option);
});
// 监听选择变化,播放视频
videoSelect.addEventListener('change', function() {
const selectedPath = this.value;
if (selectedPath) {
playVideo(selectedPath);
}
});
})
.catch(error => {
console.error('获取视频列表出错:', error);
alert('获取视频列表失败');
});
}
// 播放选定的视频
function playVideo(videoPath) {
const videoElement = document.getElementById('video-player');
const player = videojs(videoElement);
// 根据文件扩展名设置视频类型
const videoType = videoPath.endsWith('.avi') ? 'video/x-msvideo' : 'video/mp4';
// 设置视频源
player.src({
src: '/api/video/' + videoPath,
type: videoType
});
// 播放视频
player.play();
}
// 更新磁盘使用率信息
function updateDiskUsage() {
fetch('/api/disk_usage')
.then(response => response.json())
.then(data => {
if (data.error) {
console.error('获取磁盘使用率失败:', data.error);
return;
}
const diskFill = document.getElementById('disk-fill');
const diskText = document.getElementById('disk-text');
const usagePercent = data.usage_percent;
diskFill.style.width = usagePercent + '%';
diskText.textContent = usagePercent + '% (' + data.used + 'GB / ' + data.total + 'GB)';
// 根据使用率设置不同颜色
if (usagePercent > 80) {
diskFill.style.background = '#FF5722'; // 红色
} else if (usagePercent > 60) {
diskFill.style.background = '#FFC107'; // 黄色
} else {
diskFill.style.background = '#009688'; // 绿色
}
})
.catch(error => {
console.error('获取磁盘使用率出错:', error);
});
}
// 初始化并定期更新磁盘使用率
updateDiskUsage();
setInterval(updateDiskUsage, 60000); // 每分钟更新一次
// 退出登录
function logout() {
if (confirm('确定退出?')) {
window.location.href = '/logout';