首页点播布局功能初版

This commit is contained in:
龚皓 2024-10-18 14:40:53 +08:00
parent 91bf81b2a1
commit 484e36b964
1 changed files with 206 additions and 6 deletions

View File

@ -1,7 +1,207 @@
<template>
<div>
<h1>
首页
</h1>
</div>
</template>
<div class="camera-container">
<!-- 左侧摄像头列表 -->
<div class="camera-list">
<el-card v-for="camera in cameras" :key="camera.id" class="camera-item" @click="selectCamera(camera)">
<div class="camera-header">
<span>ID: {{ camera.id }}</span>
<span class="status" :class="{'online': camera.status === 'online', 'offline': camera.status !== 'online'}">
{{ camera.status === 'online' ? '在线' : '离线' }}
</span>
</div>
<div class="camera-content">
<img :src="camera.snapshot" alt="camera-preview" class="camera-thumbnail" />
<p class="camera-name">{{ camera.name }}</p>
</div>
</el-card>
</div>
<!-- 右侧摄像头详情和播放控制 -->
<div class="camera-details" v-if="selectedCamera">
<el-card>
<p>{{ selectedCamera.name }}</p>
<canvas ref="canvasRef" class="camera-large"></canvas>
<p>摄像头状态:
<span :class="{'online': selectedCamera.status === 'online', 'offline': selectedCamera.status !== 'online'}">
{{ selectedCamera.status === 'online' ? '在线' : '离线' }}
</span>
</p>
<!-- 播放控制按钮 -->
<div class="stream-control">
<el-button v-if="!playing" type="primary" @click="handleStartStream">开始点播</el-button>
<el-button v-if="playing" type="danger" @click="handleStopStream">停止点播</el-button>
</div>
</el-card>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { BoxApi } from '@/utils/boxApi.ts';
// import Jsmpeg from '../../public/static/jsmpeg-master/jsmpeg.min.js';
// console.log(">>>>>>>>>>>>>>>>>"+Jsmpeg);
const cameras = ref([]);
const selectedCamera = ref(null);
const playing = ref(false);
const streamPort = ref(null);
const canvasRef = ref(null);
const playerRef = ref(null);
const apiInstance = new BoxApi();
//
const fetchCameras = async () => {
try {
const token = localStorage.getItem('alertToken');
const cameraData = await apiInstance.getMinCameras(token); // getMinCameras
cameras.value = cameraData; //
} catch (error) {
console.error('Error fetching cameras:', error);
}
};
//
const selectCamera = (camera) => {
selectedCamera.value = camera; //
playing.value = false; //
streamPort.value = null; //
};
//
const handleStartStream = async () => {
if (!selectedCamera.value || !canvasRef.value) {
return;
}
const token = localStorage.getItem('alertToken');
try {
// API
const response = await apiInstance.startCameraStream(token, selectedCamera.value.id);
streamPort.value = response.port;
playing.value = true;
//
const url = `ws://192.168.28.33:${streamPort.value}/`; // URL
console.log('WebSocket URL>>>>>>>>>>>>>:', url);
// 使 window.JSMpeg
if (playerRef.value) {
playerRef.value.destroy(); //
}
if (window.JSMpeg) {
playerRef.value = new window.JSMpeg.Player(url, {
canvas: canvasRef.value, // canvas
autoplay: true,
videoBufferSize: 15 * 1024 * 1024, //
audioBufferSize: 5 * 1024 * 1024, //
});
} else {
console.error('JSMpeg is not available on window object.');
}
} catch (error) {
console.error('Error starting stream:', error);
}
};
//
const handleStopStream = async () => {
if (!selectedCamera.value) {
return;
}
const token = localStorage.getItem('alertToken');
try {
await apiInstance.stopCameraStream(token, selectedCamera.value.id);
playing.value = false;
//
if (playerRef.value) {
playerRef.value.destroy();
playerRef.value = null;
}
} catch (error) {
console.error('Error stopping stream:', error);
}
};
//
onBeforeUnmount(() => {
if (playerRef.value) {
playerRef.value.destroy();
playerRef.value = null;
}
});
onMounted(() => {
fetchCameras(); //
});
</script>
<style scoped>
.camera-container {
display: flex;
}
.camera-list {
width: 20%;
max-height: 90vh; /* 限制高度为一屏 */
overflow-y: auto; /* 超出时滚动 */
box-sizing: border-box;
}
.camera-item {
margin-bottom: 5px;
cursor: pointer;
padding: 10px;
}
.camera-header {
display: flex;
justify-content: space-between;
font-size: 14px;
}
.status {
margin-left: 5px;
}
.camera-content {
display: flex;
align-items: center;
}
.camera-thumbnail {
width: 60px;
height: 40px;
margin-right: 10px;
}
.camera-name {
flex: 1;
word-break: break-word; /* 文本超出时换行 */
}
.camera-details {
width: 80%;
padding: 10px;
}
.camera-large {
width: 100%;
height: 68vh;
}
.online {
color: green;
}
.offline {
color: red;
}
.stream-control {
margin-top: 20px;
text-align: center;
}
</style>