feat(dashboard1): 支持摄像头画面原生全屏
This commit is contained in:
@@ -1372,6 +1372,36 @@ function closeMapPreview() {
|
||||
mapPreviewVisible.value = false;
|
||||
}
|
||||
|
||||
// 视频画面全屏:使用浏览器原生 Fullscreen API,进入浏览器顶层,避免被页面布局/包含块影响
|
||||
const whiteScreenRef = ref<HTMLElement | null>(null);
|
||||
const infraredScreenRef = ref<HTMLElement | null>(null);
|
||||
const videoScreenRefs: Record<CameraChannelKey, Ref<HTMLElement | null>> = {
|
||||
white: whiteScreenRef,
|
||||
infrared: infraredScreenRef,
|
||||
};
|
||||
// 当前处于全屏的摄像头通道,null 表示未全屏
|
||||
const videoFullscreenKey = ref<CameraChannelKey | null>(null);
|
||||
|
||||
// 进入/退出指定摄像头画面的全屏
|
||||
async function toggleVideoFullscreen(key: CameraChannelKey) {
|
||||
const element = videoScreenRefs[key].value;
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
if (document.fullscreenElement === element) {
|
||||
await document.exitFullscreen();
|
||||
return;
|
||||
}
|
||||
await element.requestFullscreen();
|
||||
}
|
||||
|
||||
// 同步原生全屏状态,用于切换按钮图标
|
||||
function handleVideoFullscreenChange() {
|
||||
const current = document.fullscreenElement;
|
||||
videoFullscreenKey.value =
|
||||
cameraChannelKeys.find((key) => videoScreenRefs[key].value === current) ?? null;
|
||||
}
|
||||
|
||||
// Esc 关闭预览
|
||||
function handleMapPreviewKeydown(event: KeyboardEvent) {
|
||||
if (event.key === "Escape" && mapPreviewVisible.value) {
|
||||
@@ -1386,6 +1416,7 @@ onMounted(() => {
|
||||
// startInspectionPolling();
|
||||
window.addEventListener("blur", stopContinuousControl);
|
||||
window.addEventListener("keydown", handleMapPreviewKeydown);
|
||||
document.addEventListener("fullscreenchange", handleVideoFullscreenChange);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -1395,6 +1426,7 @@ onBeforeUnmount(() => {
|
||||
closeControlSocket();
|
||||
window.removeEventListener("blur", stopContinuousControl);
|
||||
window.removeEventListener("keydown", handleMapPreviewKeydown);
|
||||
document.removeEventListener("fullscreenchange", handleVideoFullscreenChange);
|
||||
});
|
||||
|
||||
// 切换机器人或视频地址变化时,两路摄像头各自重新拉流
|
||||
@@ -1814,25 +1846,43 @@ function getStatusClass(status: DeviceItem["status"]) {
|
||||
</div>
|
||||
<div class="video-panel">
|
||||
<!-- 白光镜头:16:9 -->
|
||||
<div class="video-screen">
|
||||
<div ref="whiteScreenRef" class="video-screen">
|
||||
<video v-if="cameraUrls.white" ref="whiteVideoRef" :key="cameraUrls.white"
|
||||
class="monitor-video" autoplay muted playsinline></video>
|
||||
<div class="scan-line"></div>
|
||||
<div class="video-overlay top-left">实时视频流</div>
|
||||
<div class="video-overlay top-right">白光镜头</div>
|
||||
<div class="video-overlay bottom-left">{{ currentRobot.id }}</div>
|
||||
<!-- 全屏按钮:点击后进入/退出浏览器原生全屏 -->
|
||||
<button v-if="videoFullscreenKey !== 'white'" class="video-fullscreen-btn" type="button" title="全屏"
|
||||
aria-label="全屏" @click.stop="toggleVideoFullscreen('white')">
|
||||
<svg class="video-fullscreen-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M9 4H4v5M15 4h5v5M9 20H4v-5M15 20h5v-5" fill="none" stroke="currentColor"
|
||||
stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<button v-else class="video-fullscreen-close" type="button" title="退出全屏" aria-label="退出全屏"
|
||||
@click.stop="toggleVideoFullscreen('white')">✕</button>
|
||||
<div v-if="cameraLoading.white" class="video-empty">视频流连接中...</div>
|
||||
<div v-else-if="cameraError.white" class="video-empty">{{ cameraError.white }}</div>
|
||||
<div v-else-if="!cameraUrls.white" class="video-empty">当前机器人暂无白光视频地址</div>
|
||||
</div>
|
||||
<!-- 红外镜头:16:9 -->
|
||||
<div class="video-screen">
|
||||
<div ref="infraredScreenRef" class="video-screen">
|
||||
<video v-if="cameraUrls.infrared" ref="infraredVideoRef" :key="cameraUrls.infrared"
|
||||
class="monitor-video infrared" autoplay muted playsinline></video>
|
||||
<div class="scan-line"></div>
|
||||
<div class="video-overlay top-left">实时视频流</div>
|
||||
<div class="video-overlay top-right">红外镜头</div>
|
||||
<div class="video-overlay bottom-left">{{ currentRobot.id }}</div>
|
||||
<!-- 全屏按钮:点击后进入/退出浏览器原生全屏 -->
|
||||
<button v-if="videoFullscreenKey !== 'infrared'" class="video-fullscreen-btn" type="button" title="全屏"
|
||||
aria-label="全屏" @click.stop="toggleVideoFullscreen('infrared')">
|
||||
<svg class="video-fullscreen-icon" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M9 4H4v5M15 4h5v5M9 20H4v-5M15 20h5v-5" fill="none" stroke="currentColor"
|
||||
stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</button>
|
||||
<button v-else class="video-fullscreen-close" type="button" title="退出全屏" aria-label="退出全屏"
|
||||
@click.stop="toggleVideoFullscreen('infrared')">✕</button>
|
||||
<div v-if="cameraLoading.infrared" class="video-empty">视频流连接中...</div>
|
||||
<div v-else-if="cameraError.infrared" class="video-empty">{{ cameraError.infrared }}</div>
|
||||
<div v-else-if="!cameraUrls.infrared" class="video-empty">当前机器人暂无红外视频地址</div>
|
||||
|
||||
Reference in New Issue
Block a user