You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
220 lines
6.9 KiB
Vue
220 lines
6.9 KiB
Vue
<template>
|
|
<view class="container">
|
|
<picker mode="selector" :range="cameras" range-key="name" @change="handleCameraChange">
|
|
<button>{{ currentCamera ? currentCamera.name : '选择相机' }}</button>
|
|
</picker>
|
|
<video id="myVideo" ref="videoPlayer" :src="streamUrl" autoplay muted controls style="width: 100%; height: 50%;"
|
|
@fullscreenchange="handleFullscreenChange"></video>
|
|
|
|
<!-- 云台控制面板 -->
|
|
<view class="ptz-control" :class="{ 'ptz-control-fullscreen': isFullscreen }">
|
|
<view class="direction-list">
|
|
<view class="operation-item">
|
|
<u-icon name="minus" :size="40" @touchstart="handleControl('zoomSub', 'start')"
|
|
@touchend="handleControl('zoomSub', 'stop')"
|
|
@touchcancel="handleControl('zoomSub', 'stop')"></u-icon>
|
|
</view>
|
|
<span>变倍</span>
|
|
<view class="operation-item">
|
|
<u-icon name="plus" :size="isFullscreen ? 40 : 40" @touchstart="handleControl('zoomAdd', 'start')"
|
|
@touchend="handleControl('zoomAdd', 'stop')"
|
|
@touchcancel="handleControl('zoomAdd', 'stop')"></u-icon>
|
|
</view>
|
|
<view class="operation-item">
|
|
<u-icon name="minus" :size="isFullscreen ? 40 : 40" @touchstart="handleControl('focusSub', 'start')"
|
|
@touchend="handleControl('focusSub', 'stop')"
|
|
@touchcancel="handleControl('focusSub', 'stop')"></u-icon>
|
|
</view>
|
|
<span>变焦</span>
|
|
<view class="operation-item">
|
|
<u-icon name="plus" :size="isFullscreen ? 40 : 40" @touchstart="handleControl('focusAdd', 'start')"
|
|
@touchend="handleControl('focusAdd', 'stop')"
|
|
@touchcancel="handleControl('focusAdd', 'stop')"></u-icon>
|
|
</view>
|
|
|
|
|
|
<view class="direction-item">
|
|
<image src="@/static/tabbar/icon/l_u.png"
|
|
:style="{ width: isFullscreen ? '40px' : '40px', height: isFullscreen ? '40px' : '40px', opacity: activeButton === 'leftUp' ? 0.7 : 1 }"
|
|
@touchstart="handleControl('leftUp', 'start')" @touchend="handleControl('leftUp', 'stop')"
|
|
@touchcancel="handleControl('leftUp', 'stop')"></image>
|
|
</view>
|
|
<view class="direction-item">
|
|
<u-icon name="arrow-up" :size="isFullscreen ? 40 : 40" @touchstart="handleControl('up', 'start')"
|
|
@touchend="handleControl('up', 'stop')" @touchcancel="handleControl('up', 'stop')"></u-icon>
|
|
</view>
|
|
<view class="direction-item">
|
|
<image src="@/static/tabbar/icon/r_u.png"
|
|
:style="{ width: isFullscreen ? '40px' : '40px', height: isFullscreen ? '40px' : '40px' }"
|
|
@touchstart="handleControl('rightUp', 'start')" @touchend="handleControl('rightUp', 'stop')"
|
|
@touchcancel="handleControl('rightUp', 'stop')"></image>
|
|
</view>
|
|
<view class="direction-item">
|
|
<u-icon name="arrow-left" :size="isFullscreen ? 40 : 40"
|
|
@touchstart="handleControl('left', 'start')" @touchend="handleControl('left', 'stop')"
|
|
@touchcancel="handleControl('left', 'stop')"></u-icon>
|
|
</view>
|
|
<view class="direction-item">
|
|
<u-icon :size="isFullscreen ? 40 : 40" @click="refresh"></u-icon>
|
|
</view>
|
|
<view class="direction-item">
|
|
<u-icon name="arrow-right" :size="isFullscreen ? 40 : 40"
|
|
@touchstart="handleControl('right', 'start')" @touchend="handleControl('right', 'stop')"
|
|
@touchcancel="handleControl('right', 'stop')"></u-icon>
|
|
</view>
|
|
<view class="direction-item">
|
|
<image src="@/static/tabbar/icon/l_d.png"
|
|
:style="{ width: isFullscreen ? '40px' : '40px', height: isFullscreen ? '40px' : '40px' }"
|
|
@touchstart="handleControl('leftDown', 'start')" @touchend="handleControl('leftDown', 'stop')"
|
|
@touchcancel="handleControl('leftDown', 'stop')"></image>
|
|
</view>
|
|
<view class="direction-item">
|
|
<u-icon name="arrow-down" :size="isFullscreen ? 40 : 40"
|
|
@touchstart="handleControl('down', 'start')" @touchend="handleControl('down', 'stop')"
|
|
@touchcancel="handleControl('down', 'stop')"></u-icon>
|
|
</view>
|
|
<view class="direction-item">
|
|
<image src="@/static/tabbar/icon/r_d.png"
|
|
:style="{ width: isFullscreen ? '40px' : '40px', height: isFullscreen ? '40px' : '40px' }"
|
|
@touchstart="handleControl('rightDown', 'start')" @touchend="handleControl('rightDown', 'stop')"
|
|
@touchcancel="handleControl('rightDown', 'stop')"></image>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
import request from '@/utils/request';
|
|
export default {
|
|
data() {
|
|
return {
|
|
streamUrl: '',
|
|
cameras: [{
|
|
name: '相机1',
|
|
id: 1,
|
|
streamName: 'stream123'
|
|
},
|
|
{
|
|
name: '相机2',
|
|
id: 2,
|
|
streamName: 'stream456'
|
|
}
|
|
],
|
|
currentCamera: {},
|
|
videoPlayer: null,
|
|
isFullscreen: false
|
|
}
|
|
},
|
|
async mounted() {
|
|
console.log(uni.getSystemInfoSync().platform)
|
|
this.videoPlayer = uni.createVideoContext('myVideo', this);
|
|
await this.fetchCameraList();
|
|
},
|
|
methods: {
|
|
async fetchCameraList() {
|
|
try {
|
|
const res = await request({
|
|
url: '/admin-api/logistics/camera/list'
|
|
});
|
|
console.log(res);
|
|
|
|
this.cameras = res.data.data;
|
|
this.currentCamera = this.cameras[0];
|
|
this.updateStreamUrl();
|
|
} catch (error) {
|
|
uni.showToast({
|
|
title: '加载相机列表失败',
|
|
icon: 'none'
|
|
});
|
|
}
|
|
},
|
|
updateStreamUrl() {
|
|
const ipAddres = uni.getStorageSync('IP_ADDRESS');
|
|
const isH5 = uni.getSystemInfoSync().platform === 'h5';
|
|
const protocol = isH5 ? 'http' : 'rtmp';
|
|
const ext = isH5 ? '.m3u8' : '';
|
|
this.streamUrl = `${protocol}://${ipAddres}/live/camera${this.currentCamera.id}${ext}`;
|
|
console.log(this.streamUrl)
|
|
this.$nextTick(() => {
|
|
this.videoPlayer.play();
|
|
});
|
|
},
|
|
handleCameraChange(e) {
|
|
this.videoPlayer.stop();
|
|
this.currentCamera = this.cameras[e.detail.value];
|
|
this.updateStreamUrl();
|
|
},
|
|
// 云台控制方法
|
|
async handleControl(action, state) {
|
|
console.log(`${action}-${state}`);
|
|
const data = {
|
|
id: this.currentCamera.id
|
|
};
|
|
const res = await request({
|
|
url: '/admin-api/camera/control/' + action + '/' + state,
|
|
method: 'POST',
|
|
data: {
|
|
id: this.currentCamera.id
|
|
|
|
}
|
|
});
|
|
},
|
|
// 刷新画面
|
|
refresh() {
|
|
this.videoPlayer.stop();
|
|
this.updateStreamUrl();
|
|
},
|
|
// 全屏状态变化
|
|
handleFullscreenChange(e) {
|
|
this.isFullscreen = e.detail.fullScreen;
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.container {
|
|
width: 100%;
|
|
height: 85vh;
|
|
}
|
|
|
|
/* 云台控制面板样式 */
|
|
.ptz-control {
|
|
margin-top: 10px;
|
|
background-color: rgba(255, 255, 255, 0.8);
|
|
border: 1px solid #ccc;
|
|
padding: 5px;
|
|
border-radius: 5px;
|
|
}
|
|
|
|
.ptz-control-fullscreen {
|
|
position: fixed;
|
|
bottom: 10px;
|
|
left: 50%;
|
|
transform: translateX(-50%);
|
|
width: 80%;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.direction-list {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 3px;
|
|
justify-items: center;
|
|
}
|
|
|
|
.operation-item,
|
|
.direction-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
margin: 3px;
|
|
}
|
|
|
|
.operation-item span,
|
|
.direction-item span {
|
|
font-size: 10px;
|
|
margin-top: 3px;
|
|
}
|
|
</style> |