单路点播界面初步完场
This commit is contained in:
parent
26e326dd1d
commit
b81eaa24a9
|
@ -5,7 +5,7 @@
|
|||
<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'}">
|
||||
<span class="status" :class="{ 'online': camera.status === 'online', 'offline': camera.status !== 'online' }">
|
||||
{{ camera.status === 'online' ? '在线' : '离线' }}
|
||||
</span>
|
||||
</div>
|
||||
|
@ -19,27 +19,41 @@
|
|||
<!-- 右侧摄像头详情和播放控制 -->
|
||||
<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>
|
||||
<p>{{ selectedCamera.name }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 在未播放时显示播放按钮 -->
|
||||
<div class="play-button-container" @mouseenter="showButton = true" @mouseleave="showButton = false">
|
||||
<img v-show="!playing && selectedCamera.snapshot" :src="selectedCamera.snapshot" alt="camera snapshot"
|
||||
class="camera-snapshot" />
|
||||
<canvas v-show="playing" ref="canvasRef" class="camera-large"></canvas>
|
||||
|
||||
<!-- 播放按钮 -->
|
||||
<el-button
|
||||
v-show="!playing || showButton"
|
||||
class="play-button"
|
||||
type="primary"
|
||||
circle
|
||||
size="large"
|
||||
@click="handlePlayPause"
|
||||
>
|
||||
<el-icon>
|
||||
<VideoPlay v-if="!playing" />
|
||||
<VideoPause v-if="playing" />
|
||||
</el-icon>
|
||||
</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);
|
||||
import { VideoPlay, VideoPause } from '@element-plus/icons-vue';
|
||||
|
||||
const cameras = ref([]);
|
||||
const selectedCamera = ref(null);
|
||||
|
@ -47,6 +61,7 @@ const playing = ref(false);
|
|||
const streamPort = ref(null);
|
||||
const canvasRef = ref(null);
|
||||
const playerRef = ref(null);
|
||||
const showButton = ref(false); // 用于控制按钮的显示和隐藏
|
||||
|
||||
const apiInstance = new BoxApi();
|
||||
|
||||
|
@ -66,36 +81,45 @@ const selectCamera = (camera) => {
|
|||
selectedCamera.value = camera; // 将点击的摄像头设为选中的摄像头
|
||||
playing.value = false; // 重置播放状态
|
||||
streamPort.value = null; // 重置流端口
|
||||
showButton.value = true; // 重置按钮显示状态
|
||||
};
|
||||
|
||||
// 启动或暂停播放
|
||||
const handlePlayPause = async () => {
|
||||
if (playing.value) {
|
||||
handleStopStream();
|
||||
} else {
|
||||
handleStartStream();
|
||||
}
|
||||
};
|
||||
|
||||
// 启动流播放
|
||||
const handleStartStream = async () => {
|
||||
console.log('Button clicked and playing is:', playing.value);
|
||||
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);
|
||||
const url = `ws://192.168.28.33:${streamPort.value}/`;
|
||||
console.log('Playing set to true:', playing.value);
|
||||
|
||||
// 使用全局的 window.JSMpeg 对象
|
||||
if (playerRef.value) {
|
||||
playerRef.value.destroy(); // 销毁旧播放器
|
||||
}
|
||||
|
||||
|
||||
if (window.JSMpeg) {
|
||||
playerRef.value = new window.JSMpeg.Player(url, {
|
||||
canvas: canvasRef.value, // 指定 canvas 渲染
|
||||
canvas: canvasRef.value,
|
||||
autoplay: true,
|
||||
videoBufferSize: 15 * 1024 * 1024, // 设置视频缓冲区大小
|
||||
audioBufferSize: 5 * 1024 * 1024, // 设置音频缓冲区大小
|
||||
videoBufferSize: 15 * 1024 * 1024,
|
||||
audioBufferSize: 5 * 1024 * 1024,
|
||||
});
|
||||
} else {
|
||||
console.error('JSMpeg is not available on window object.');
|
||||
|
@ -138,6 +162,7 @@ onMounted(() => {
|
|||
fetchCameras(); // 页面加载时请求摄像头数据
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.camera-container {
|
||||
display: flex;
|
||||
|
@ -145,8 +170,10 @@ onMounted(() => {
|
|||
|
||||
.camera-list {
|
||||
width: 20%;
|
||||
max-height: 90vh; /* 限制高度为一屏 */
|
||||
overflow-y: auto; /* 超出时滚动 */
|
||||
max-height: 90vh;
|
||||
/* 限制高度为一屏 */
|
||||
overflow-y: auto;
|
||||
/* 超出时滚动 */
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
@ -179,7 +206,7 @@ onMounted(() => {
|
|||
|
||||
.camera-name {
|
||||
flex: 1;
|
||||
word-break: break-word; /* 文本超出时换行 */
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.camera-details {
|
||||
|
@ -187,6 +214,12 @@ onMounted(() => {
|
|||
padding: 10px;
|
||||
}
|
||||
|
||||
.camera-snapshot {
|
||||
width: 100%;
|
||||
height: 68vh;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.camera-large {
|
||||
width: 100%;
|
||||
height: 68vh;
|
||||
|
@ -201,7 +234,54 @@ onMounted(() => {
|
|||
}
|
||||
|
||||
.stream-control {
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
.stream-control p {
|
||||
margin-right: 20px;
|
||||
font-size: 15px;
|
||||
line-height: 5px;
|
||||
}
|
||||
|
||||
.stream-control el-button {
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
}
|
||||
|
||||
.play-button-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.play-button {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 10;
|
||||
opacity: 0.4;
|
||||
transition: opacity 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.play-button:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.camera-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
gap: 10px;
|
||||
width: 80%;
|
||||
height: 90vh;
|
||||
}
|
||||
|
||||
.camera-box {
|
||||
position: relative;
|
||||
background-color: #1a1a1a;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
Loading…
Reference in New Issue