779 lines
28 KiB
HTML
779 lines
28 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>监控大屏 - 4路直播</title>
|
||
<link href="static/video-js.css" rel="stylesheet" />
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||
background: #000;
|
||
color: #fff;
|
||
overflow: hidden;
|
||
height: 100vh;
|
||
}
|
||
|
||
.header {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 60px;
|
||
background: linear-gradient(90deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 20px;
|
||
z-index: 1000;
|
||
border-bottom: 2px solid #00b4d8;
|
||
}
|
||
|
||
.header-title {
|
||
font-size: 24px;
|
||
font-weight: bold;
|
||
color: #00b4d8;
|
||
text-shadow: 0 0 10px rgba(0, 180, 216, 0.5);
|
||
}
|
||
|
||
.header-info {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 20px;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.time-display {
|
||
background: rgba(0, 180, 216, 0.1);
|
||
padding: 8px 16px;
|
||
border-radius: 20px;
|
||
border: 1px solid rgba(0, 180, 216, 0.3);
|
||
}
|
||
|
||
.monitor-container {
|
||
margin-top: 60px;
|
||
height: calc(100vh - 60px);
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
grid-template-rows: 1fr 1fr;
|
||
gap: 2px;
|
||
background: #000;
|
||
}
|
||
|
||
.monitor-screen {
|
||
background: #111;
|
||
position: relative;
|
||
overflow: hidden;
|
||
border: 1px solid #333;
|
||
}
|
||
|
||
.monitor-header {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 40px;
|
||
background: rgba(0, 0, 0, 0.8);
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 0 15px;
|
||
z-index: 100;
|
||
border-bottom: 1px solid #00b4d8;
|
||
}
|
||
|
||
.screen-title {
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
color: #00b4d8;
|
||
}
|
||
|
||
.screen-status {
|
||
margin-left: auto;
|
||
font-size: 12px;
|
||
color: #4ade80;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 5px;
|
||
}
|
||
|
||
.status-dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
background: #4ade80;
|
||
animation: pulse 2s infinite;
|
||
}
|
||
|
||
.video-container {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.video-js {
|
||
width: 100% !important;
|
||
height: 100% !important;
|
||
background: #000;
|
||
}
|
||
|
||
.loading-overlay {
|
||
position: absolute;
|
||
top: 40px;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(0, 0, 0, 0.8);
|
||
display: none; /* 默认隐藏 */
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
z-index: 50;
|
||
}
|
||
|
||
.loading-text {
|
||
color: #00b4d8;
|
||
font-size: 18px;
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.spinner {
|
||
width: 40px;
|
||
height: 40px;
|
||
border: 4px solid rgba(0, 180, 216, 0.3);
|
||
border-top: 4px solid #00b4d8;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
}
|
||
|
||
.error-overlay {
|
||
position: absolute;
|
||
top: 40px;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
background: rgba(139, 0, 0, 0.8);
|
||
display: none;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-direction: column;
|
||
z-index: 50;
|
||
}
|
||
|
||
.error-text {
|
||
color: #ff6b6b;
|
||
font-size: 16px;
|
||
margin-top: 15px;
|
||
text-align: center;
|
||
}
|
||
|
||
.refresh-btn {
|
||
margin-top: 10px;
|
||
padding: 8px 16px;
|
||
background: #ff6b6b;
|
||
color: white;
|
||
border: none;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.refresh-btn:hover {
|
||
background: #ff5252;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% { opacity: 1; }
|
||
50% { opacity: 0.5; }
|
||
}
|
||
|
||
/* 隐藏视频播放器的控制条 */
|
||
.video-js .vjs-control-bar {
|
||
display: none !important;
|
||
}
|
||
|
||
/* 隐藏播放器自带的错误显示 */
|
||
.video-js .vjs-error-display {
|
||
display: none !important;
|
||
}
|
||
|
||
/* 隐藏播放器自带的错误提示文字 */
|
||
.video-js .vjs-modal-dialog {
|
||
display: none !important;
|
||
}
|
||
|
||
/* 全屏模式下的样式调整 */
|
||
.monitor-screen.fullscreen {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100vw !important;
|
||
height: 100vh !important;
|
||
z-index: 2000;
|
||
border: none;
|
||
}
|
||
|
||
.fullscreen-btn {
|
||
position: absolute;
|
||
top: 10px;
|
||
right: 10px;
|
||
background: rgba(0, 0, 0, 0.7);
|
||
color: white;
|
||
border: none;
|
||
border-radius: 4px;
|
||
padding: 5px 10px;
|
||
cursor: pointer;
|
||
font-size: 12px;
|
||
z-index: 101;
|
||
}
|
||
|
||
.fullscreen-btn:hover {
|
||
background: rgba(0, 180, 216, 0.8);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="header">
|
||
<div class="header-title">智能监控大屏系统</div>
|
||
<div class="header-info">
|
||
<div class="time-display" id="currentTime">--:--:--</div>
|
||
<div>4路高清直播</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="monitor-container">
|
||
<!-- 屏幕1 -->
|
||
<div class="monitor-screen" id="screen1">
|
||
<div class="monitor-header">
|
||
<div class="screen-title">监控点 1 - 主入口</div>
|
||
<div class="screen-status">
|
||
<div class="status-dot"></div>
|
||
<span>直播中</span>
|
||
</div>
|
||
</div>
|
||
<div class="video-container">
|
||
<video
|
||
id="video1"
|
||
class="video-js vjs-default-skin"
|
||
controls
|
||
preload="auto">
|
||
<source src="" type="application/x-mpegURL">
|
||
</video>
|
||
<div class="loading-overlay" id="loading1">
|
||
<div class="spinner"></div>
|
||
<div class="loading-text">正在连接直播流...</div>
|
||
</div>
|
||
<div class="error-overlay" id="error1">
|
||
<div style="color: #ff6b6b; font-size: 24px;">⚠</div>
|
||
<div class="error-text">直播流连接失败</div>
|
||
<button class="refresh-btn" onclick="refreshStream(1)">重新连接</button>
|
||
</div>
|
||
</div>
|
||
<button class="fullscreen-btn" onclick="toggleFullscreen(1)">全屏</button>
|
||
</div>
|
||
|
||
<!-- 屏幕2 -->
|
||
<div class="monitor-screen" id="screen2">
|
||
<div class="monitor-header">
|
||
<div class="screen-title">监控点 2 - 走廊</div>
|
||
<div class="screen-status">
|
||
<div class="status-dot"></div>
|
||
<span>直播中</span>
|
||
</div>
|
||
</div>
|
||
<div class="video-container">
|
||
<video
|
||
id="video2"
|
||
class="video-js vjs-default-skin"
|
||
controls
|
||
preload="auto">
|
||
<source src="" type="application/x-mpegURL">
|
||
</video>
|
||
<div class="loading-overlay" id="loading2">
|
||
<div class="spinner"></div>
|
||
<div class="loading-text">正在连接直播流...</div>
|
||
</div>
|
||
<div class="error-overlay" id="error2">
|
||
<div style="color: #ff6b6b; font-size: 24px;">⚠</div>
|
||
<div class="error-text">直播流连接失败</div>
|
||
<button class="refresh-btn" onclick="refreshStream(2)">重新连接</button>
|
||
</div>
|
||
</div>
|
||
<button class="fullscreen-btn" onclick="toggleFullscreen(2)">全屏</button>
|
||
</div>
|
||
|
||
<!-- 屏幕3 -->
|
||
<div class="monitor-screen" id="screen3">
|
||
<div class="monitor-header">
|
||
<div class="screen-title">监控点 3 - 大厅</div>
|
||
<div class="screen-status">
|
||
<div class="status-dot"></div>
|
||
<span>直播中</span>
|
||
</div>
|
||
</div>
|
||
<div class="video-container">
|
||
<video
|
||
id="video3"
|
||
class="video-js vjs-default-skin"
|
||
controls
|
||
preload="auto">
|
||
<source src="" type="application/x-mpegURL">
|
||
</video>
|
||
<div class="loading-overlay" id="loading3">
|
||
<div class="spinner"></div>
|
||
<div class="loading-text">正在连接直播流...</div>
|
||
</div>
|
||
<div class="error-overlay" id="error3">
|
||
<div style="color: #ff6b6b; font-size: 24px;">⚠</div>
|
||
<div class="error-text">直播流连接失败</div>
|
||
<button class="refresh-btn" onclick="refreshStream(3)">重新连接</button>
|
||
</div>
|
||
</div>
|
||
<button class="fullscreen-btn" onclick="toggleFullscreen(3)">全屏</button>
|
||
</div>
|
||
|
||
<!-- 屏幕4 -->
|
||
<div class="monitor-screen" id="screen4">
|
||
<div class="monitor-header">
|
||
<div class="screen-title">监控点 4 - 出口</div>
|
||
<div class="screen-status">
|
||
<div class="status-dot"></div>
|
||
<span>直播中</span>
|
||
</div>
|
||
</div>
|
||
<div class="video-container">
|
||
<video
|
||
id="video4"
|
||
class="video-js vjs-default-skin"
|
||
controls
|
||
preload="auto">
|
||
<source src="" type="application/x-mpegURL">
|
||
</video>
|
||
<div class="loading-overlay" id="loading4">
|
||
<div class="spinner"></div>
|
||
<div class="loading-text">正在连接直播流...</div>
|
||
</div>
|
||
<div class="error-overlay" id="error4">
|
||
<div style="color: #ff6b6b; font-size: 24px;">⚠</div>
|
||
<div class="error-text">直播流连接失败</div>
|
||
<button class="refresh-btn" onclick="refreshStream(4)">重新连接</button>
|
||
</div>
|
||
</div>
|
||
<button class="fullscreen-btn" onclick="toggleFullscreen(4)">全屏</button>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="static/video.min.js"></script>
|
||
<script>
|
||
// 配置直播流地址 - 通过接口动态获取
|
||
const streamConfigs = {
|
||
1: {
|
||
url: '', // 将通过接口获取
|
||
title: '监控点 1 - 主入口',
|
||
videoId: 'cam001'
|
||
},
|
||
2: {
|
||
url: '', // 将通过接口获取
|
||
title: '监控点 2 - 走廊',
|
||
videoId: 'cam002'
|
||
},
|
||
3: {
|
||
url: '', // 将通过接口获取
|
||
title: '监控点 3 - 大厅',
|
||
videoId: 'cam003'
|
||
},
|
||
4: {
|
||
url: '', // 将通过接口获取
|
||
title: '监控点 4 - 出口',
|
||
videoId: 'cam004'
|
||
}
|
||
};
|
||
|
||
// 视频播放器实例
|
||
const players = {};
|
||
|
||
// 获取视频流URL的接口地址(通过Nginx代理)
|
||
const VIDEO_API_URL = '/api/v1/video-urls'; // 使用相对路径,通过Nginx代理到后端
|
||
|
||
// 获取视频流URL的接口
|
||
async function fetchVideoUrls() {
|
||
try {
|
||
const videoIds = Object.values(streamConfigs).map(config => config.videoId);
|
||
|
||
console.log('发送请求到:', VIDEO_API_URL);
|
||
console.log('请求体:', JSON.stringify({
|
||
"videoId": videoIds
|
||
}));
|
||
|
||
const response = await fetch(VIDEO_API_URL, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json',
|
||
},
|
||
body: JSON.stringify({
|
||
"videoId": videoIds
|
||
})
|
||
});
|
||
|
||
console.log('响应状态:', response.status, response.statusText);
|
||
|
||
if (!response.ok) {
|
||
let errorDetails = '';
|
||
try {
|
||
const errorData = await response.json();
|
||
errorDetails = JSON.stringify(errorData);
|
||
} catch (e) {
|
||
errorDetails = await response.text();
|
||
}
|
||
throw new Error(`HTTP error! status: ${response.status}, details: ${errorDetails}`);
|
||
}
|
||
|
||
const data = await response.json();
|
||
console.log('响应数据:', data);
|
||
|
||
// 更新streamConfigs中的URL
|
||
if (data.videoUrl && Array.isArray(data.videoUrl)) {
|
||
Object.keys(streamConfigs).forEach((screenId, index) => {
|
||
if (data.videoUrl[index]) {
|
||
streamConfigs[screenId].url = data.videoUrl[index];
|
||
console.log(`屏幕 ${screenId} 获取到URL: ${data.videoUrl[index]}`);
|
||
}
|
||
});
|
||
|
||
return true;
|
||
} else {
|
||
throw new Error('返回数据格式错误');
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error('获取视频流URL失败:', error);
|
||
|
||
// 在所有屏幕显示错误
|
||
for (let i = 1; i <= 4; i++) {
|
||
showError(i);
|
||
updateStatus(i, '获取流地址失败: ' + errorMessage);
|
||
}
|
||
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 初始化所有视频播放器
|
||
function initializePlayers() {
|
||
for (let i = 1; i <= 4; i++) {
|
||
const videoElement = document.getElementById(`video${i}`);
|
||
|
||
// 检查是否已经初始化
|
||
if (videojs.getPlayer(`video${i}`)) {
|
||
console.log(`播放器 ${i} 已经初始化,跳过`);
|
||
players[i] = videojs.getPlayer(`video${i}`);
|
||
continue;
|
||
}
|
||
|
||
const player = videojs(videoElement, {
|
||
liveui: true,
|
||
autoplay: 'any', // 使用更宽松的自动播放策略
|
||
muted: true, // 静音播放,避免多个视频同时播放声音
|
||
controls: false, // 隐藏控制条
|
||
fluid: true,
|
||
html5: {
|
||
hls: {
|
||
enableLowInitialPlaylist: true,
|
||
smoothQualityChange: true,
|
||
overrideNative: true
|
||
}
|
||
}
|
||
});
|
||
|
||
players[i] = player;
|
||
|
||
// 监听播放器事件
|
||
player.ready(() => {
|
||
console.log(`播放器 ${i} 准备就绪`);
|
||
// 显示初始状态
|
||
showLoading(i);
|
||
updateStatus(i, '正在连接...');
|
||
|
||
// 延迟加载流,确保播放器完全初始化
|
||
setTimeout(() => {
|
||
loadStream(i);
|
||
}, 100 * i); // 错开加载时间,避免同时请求
|
||
});
|
||
|
||
player.on('loadstart', () => {
|
||
console.log(`播放器 ${i} 开始加载`);
|
||
showLoading(i);
|
||
hideError(i);
|
||
updateStatus(i, '正在连接...');
|
||
});
|
||
|
||
player.on('loadedmetadata', () => {
|
||
console.log(`播放器 ${i} 元数据加载完成`);
|
||
updateStatus(i, '连接成功');
|
||
});
|
||
|
||
player.on('loadeddata', () => {
|
||
console.log(`播放器 ${i} 数据加载完成`);
|
||
hideLoading(i);
|
||
updateStatus(i, '直播中');
|
||
});
|
||
|
||
player.on('error', (e) => {
|
||
console.error(`播放器 ${i} 发生错误:`, player.error());
|
||
showError(i);
|
||
updateStatus(i, '连接失败');
|
||
});
|
||
|
||
player.on('waiting', () => {
|
||
console.log(`播放器 ${i} 等待数据`);
|
||
showLoading(i);
|
||
updateStatus(i, '缓冲中...');
|
||
});
|
||
|
||
player.on('playing', () => {
|
||
console.log(`播放器 ${i} 开始播放`);
|
||
hideLoading(i);
|
||
hideError(i);
|
||
updateStatus(i, '直播中');
|
||
});
|
||
|
||
player.on('canplay', () => {
|
||
console.log(`播放器 ${i} 可以播放`);
|
||
hideLoading(i);
|
||
});
|
||
}
|
||
}
|
||
|
||
// 加载直播流
|
||
function loadStream(screenId) {
|
||
const config = streamConfigs[screenId];
|
||
if (!config || !config.url) {
|
||
console.error(`屏幕 ${screenId} 未配置有效的直播流地址`);
|
||
showError(screenId);
|
||
updateStatus(screenId, '未配置');
|
||
return;
|
||
}
|
||
|
||
showLoading(screenId);
|
||
updateStatus(screenId, '正在连接...');
|
||
|
||
const player = players[screenId];
|
||
|
||
// 先设置源,然后尝试播放
|
||
player.src({
|
||
src: config.url,
|
||
type: 'application/x-mpegURL'
|
||
});
|
||
|
||
// 添加播放超时检测
|
||
const playTimeout = setTimeout(() => {
|
||
console.warn(`播放器 ${screenId} 播放超时`);
|
||
if (!player.hasStarted()) {
|
||
// 如果播放器没有开始播放,显示错误
|
||
showError(screenId);
|
||
updateStatus(screenId, '连接超时');
|
||
}
|
||
}, 10000); // 10秒超时
|
||
|
||
player.play().then(() => {
|
||
console.log(`播放器 ${screenId} 播放成功`);
|
||
clearTimeout(playTimeout);
|
||
}).catch(error => {
|
||
console.error(`播放器 ${screenId} 自动播放失败:`, error);
|
||
clearTimeout(playTimeout);
|
||
|
||
// 如果是自动播放策略限制,等待用户交互
|
||
if (error.name === 'NotAllowedError') {
|
||
console.log(`播放器 ${screenId} 等待用户交互`);
|
||
updateStatus(screenId, '点击播放');
|
||
|
||
// 添加点击播放功能
|
||
const videoElement = document.getElementById(`video${screenId}`);
|
||
const playHandler = () => {
|
||
player.play().then(() => {
|
||
console.log(`播放器 ${screenId} 用户交互后播放成功`);
|
||
videoElement.removeEventListener('click', playHandler);
|
||
}).catch(e => {
|
||
console.error(`播放器 ${screenId} 用户交互后仍然播放失败:`, e);
|
||
showError(screenId);
|
||
updateStatus(screenId, '播放失败');
|
||
});
|
||
};
|
||
videoElement.addEventListener('click', playHandler);
|
||
} else {
|
||
showError(screenId);
|
||
updateStatus(screenId, '播放失败');
|
||
}
|
||
});
|
||
}
|
||
|
||
// 显示加载状态
|
||
function showLoading(screenId) {
|
||
const loadingEl = document.getElementById(`loading${screenId}`);
|
||
if (loadingEl) loadingEl.style.display = 'flex';
|
||
}
|
||
|
||
// 隐藏加载状态
|
||
function hideLoading(screenId) {
|
||
const loadingEl = document.getElementById(`loading${screenId}`);
|
||
if (loadingEl) loadingEl.style.display = 'none';
|
||
}
|
||
|
||
// 显示错误状态
|
||
function showError(screenId) {
|
||
const errorEl = document.getElementById(`error${screenId}`);
|
||
if (errorEl) errorEl.style.display = 'flex';
|
||
}
|
||
|
||
// 隐藏错误状态
|
||
function hideError(screenId) {
|
||
const errorEl = document.getElementById(`error${screenId}`);
|
||
if (errorEl) errorEl.style.display = 'none';
|
||
}
|
||
|
||
// 更新状态显示
|
||
function updateStatus(screenId, status) {
|
||
const statusEl = document.querySelector(`#screen${screenId} .screen-status span`);
|
||
if (statusEl) {
|
||
statusEl.textContent = status;
|
||
|
||
// 根据状态改变颜色
|
||
if (status === '直播中') {
|
||
statusEl.style.color = '#4ade80';
|
||
document.querySelector(`#screen${screenId} .status-dot`).style.background = '#4ade80';
|
||
} else if (status === '连接失败') {
|
||
statusEl.style.color = '#ff6b6b';
|
||
document.querySelector(`#screen${screenId} .status-dot`).style.background = '#ff6b6b';
|
||
} else {
|
||
statusEl.style.color = '#fbbf24';
|
||
document.querySelector(`#screen${screenId} .status-dot`).style.background = '#fbbf24';
|
||
}
|
||
}
|
||
}
|
||
|
||
// 刷新直播流
|
||
function refreshStream(screenId) {
|
||
console.log(`刷新屏幕 ${screenId} 的直播流`);
|
||
hideError(screenId);
|
||
showLoading(screenId);
|
||
updateStatus(screenId, '重新连接中...');
|
||
|
||
// 重新加载流
|
||
loadStream(screenId);
|
||
}
|
||
|
||
// 全屏切换
|
||
function toggleFullscreen(screenId) {
|
||
const screen = document.getElementById(`screen${screenId}`);
|
||
const isFullscreen = screen.classList.contains('fullscreen');
|
||
|
||
if (isFullscreen) {
|
||
// 退出全屏
|
||
screen.classList.remove('fullscreen');
|
||
document.querySelector(`#screen${screenId} .fullscreen-btn`).textContent = '全屏';
|
||
} else {
|
||
// 进入全屏
|
||
screen.classList.add('fullscreen');
|
||
document.querySelector(`#screen${screenId} .fullscreen-btn`).textContent = '退出全屏';
|
||
}
|
||
}
|
||
|
||
// 更新当前时间
|
||
function updateTime() {
|
||
const now = new Date();
|
||
const timeString = now.toLocaleTimeString('zh-CN', {
|
||
hour12: false,
|
||
hour: '2-digit',
|
||
minute: '2-digit',
|
||
second: '2-digit'
|
||
});
|
||
document.getElementById('currentTime').textContent = timeString;
|
||
}
|
||
|
||
// 页面加载完成后初始化
|
||
document.addEventListener('DOMContentLoaded', async function() {
|
||
// 初始化视频播放器
|
||
initializePlayers();
|
||
|
||
// 启动时间更新
|
||
updateTime();
|
||
setInterval(updateTime, 1000);
|
||
|
||
// 首先获取视频流URL
|
||
console.log('开始获取视频流URL...');
|
||
|
||
// 显示加载状态
|
||
for (let i = 1; i <= 4; i++) {
|
||
showLoading(i);
|
||
updateStatus(i, '获取流地址中...');
|
||
}
|
||
|
||
// 调用接口获取视频URL
|
||
const success = await fetchVideoUrls();
|
||
|
||
if (success) {
|
||
console.log('视频流URL获取成功,开始加载直播流');
|
||
|
||
// 延迟300ms后开始加载所有直播流
|
||
setTimeout(() => {
|
||
console.log('开始加载所有直播流');
|
||
for (let i = 1; i <= 4; i++) {
|
||
const config = streamConfigs[i];
|
||
// 检查URL是否为空,只有配置了有效URL才重新加载
|
||
if (config && config.url) {
|
||
console.log(`加载屏幕 ${i} 的直播流`);
|
||
refreshStream(i);
|
||
} else {
|
||
console.log(`屏幕 ${i} 未获取到有效URL,跳过加载`);
|
||
showError(i);
|
||
updateStatus(i, '无可用流地址');
|
||
}
|
||
}
|
||
}, 300);
|
||
} else {
|
||
console.error('视频流URL获取失败,无法加载直播流');
|
||
}
|
||
|
||
// 添加键盘快捷键
|
||
document.addEventListener('keydown', function(e) {
|
||
// ESC键退出全屏
|
||
if (e.key === 'Escape') {
|
||
document.querySelectorAll('.monitor-screen').forEach(screen => {
|
||
screen.classList.remove('fullscreen');
|
||
screen.querySelector('.fullscreen-btn').textContent = '全屏';
|
||
});
|
||
}
|
||
|
||
// F1-F4键切换全屏
|
||
if (e.key >= 'F1' && e.key <= 'F4') {
|
||
const screenId = parseInt(e.key.substring(1));
|
||
toggleFullscreen(screenId);
|
||
}
|
||
});
|
||
|
||
console.log('监控大屏系统初始化完成');
|
||
});
|
||
|
||
// 页面卸载时清理资源
|
||
window.addEventListener('beforeunload', function() {
|
||
for (let i = 1; i <= 4; i++) {
|
||
if (players[i]) {
|
||
players[i].dispose();
|
||
}
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html> |