复现步骤:
1、到苹果商店下载 “ 智能云服务平台 ” App
2、点击进入app,输入账号密码(账号:video 密码:123456)
3、点击底部导航栏 “ 工作台 ” => " 视频监控 " => 选中要操作的视频 => 点击全屏按钮
提供的设备页面代码如下:
<view class="page">
<u-loading-page :loading="loading"></u-loading-page>
<!-- <u-navbar placeholder title="视频监控" @leftClick="leftClick" :autoBack="false"></u-navbar> -->
<view class="camera-list">
<view class="video-item-wrap" v-for="(item, index) in playList" :key="index">
<video
:id="index"
:play-strategy="2"
:class="['video-item', current === index ? 'active' : '']"
object-fit="fill"
:show-play-btn="false"
:autoplay="true"
:src="item.url"
:controls="false"
@error="onPlayError(item)"
>
<cover-view v-if="item.status !== 1" class="video-item mask" @click="clickItem(item, index)">
<cover-view @click.stop="clickItem(item, index)" class="msg">无信号或设备不在线</cover-view>
</cover-view>
<cover-view v-else :class="['video-item', item.live ? '' : 'mask']" @click="clickItem(item, index)">
<cover-view @click.stop="clickItem(item, index)" class="msg" v-if="!item.live">{{ item.msg || '' }}</cover-view>
</cover-view>
</video>
</view>
</view>
<view class="grid-list" v-if="playList.length > 0">
<view class="grid-item" @click="preview">
<image class="icon" src="@/static/images/common/icon_lx.png" mode=""></image>
<text class="text">预览</text>
</view>
<view class="grid-item" @click="playback">
<image class="icon" src="@/static/images/common/icon_hf.png" mode=""></image>
<text class="text">回放</text>
</view>
<view class="grid-item" @click="fullScreen">
<image class="icon" src="@/static/images/common/icon_qp.png" mode=""></image>
<text class="text">全屏</text>
</view>
</view>
<view class="select-wrap" v-if="!loading">
<view class="row-item" @click="chooseLibrary">
<text class="text">分馆</text>
<view class="right">
<text class="value" v-if="libraryName">{{ libraryName }}</text>
<text class="label" v-else>请选择</text>
<image class="icon" src="@/static/images/common/icon_arrow_right.png" mode=""></image>
</view>
</view>
<view class="row-item" @click="chooseLibraryDevice">
<text class="text">设备</text>
<view class="right">
<text class="value" v-if="deviceName">{{ deviceName }}</text>
<text class="label" v-else>请选择</text>
<image class="icon" src="@/static/images/common/icon_arrow_right.png" mode=""></image>
</view>
</view>
<scroll-view :enable-flex="true" class="scroll-x" :scroll-x="true">
<view class="scroll-list">
<view class="scroll-item" v-for="(item, index) in cameraList" :key="item.live_id" @click="clickCamera(item, index)">
<camera-item :item="item" :checked="cameraIndex === index"></camera-item>
</view>
</view>
</scroll-view>
</view>
<tki-tree ref="tkitree" :selectParent="true" :range="libraryList" rangeKey="name" confirmColor="#4e8af7" @cancel="cancelLibrary" @confirm="onLibraryConfirm" />
<u-picker
:show="showDevice"
keyName="name"
:columns="[deviceList]"
closeOnClickOverlay
@cancel="showDevice = false"
@close="showDevice = false"
@confirm="onDeviceConfirm"
></u-picker>
<!-- 选择时间 -->
<u-datetime-picker
title="回放开始时间"
:show="showTime"
v-model="curChooseTime"
mode="datetime"
@confirm="confirmTime"
closeOnClickOverlay
@close="showTime = false"
@cancel="showTime = false"
></u-datetime-picker>
<u-datetime-picker
title="回放结束时间"
:show="showEndTime"
v-model="curChooseTime"
mode="datetime"
@confirm="confirmEndTime"
closeOnClickOverlay
@close="showEndTime = false"
@cancel="showEndTime = false"
></u-datetime-picker>
</view>
</template>
<script>
import MntDeviceApi from '@/model/mnt-device.js';
import MntCameraApi from '@/model/mnt-camera.js';
import LibraryApi from '@/model/library.js';
import CameraItem from '@/components/camera/camera-item.vue';
import tkiTree from '@/components/tki-tree/tki-tree.vue';
export default {
components: {
CameraItem,
tkiTree
},
data() {
return {
loading: true,
curGridIndex: 0,
showDevice: false,
showTime: false,
showEndTime: false,
curChooseTime: Number(new Date()),
libraryList: [],
deviceList: [],
current: 0,
columns: [],
columnData: [],
params: {
channel_no: null,
expire_time: null,
protocol: 3,
id: null,
quality: 1,
start_time: null,
stop_time: null,
support_h265: null,
type: 1
},
cameraIndex: null,
deviceSerial: null,
deviceName: '',
libraryName: '',
libraryId: null,
libraryVO: {},
liveAddrList: [0],
cameraList: [],
tkitree: null,
playList: [],
timer: [null, null, null, null],
timerOut: null,
curLive: null
};
},
onLoad() {},
onUnload() {
this.leftClick();
},
onReady() {
this.getLibrary();
},
computed: {
deviceId() {
return uni.$u.sys().deviceId;
}
},
methods: {
async leftClick() {
if (this.playList.length > 0) {
uni.showLoading({
title: '正在退出...'
});
clearTimeout(this.timerOut);
this.timerOut = null;
this.clearInterval();
const liveIds = this.playList.map(item => {
return item.live_id
});
await MntDeviceApi.multiLiveRelease({
live_ids: liveIds,
library_id: this.playList[0].library_id
});
/* uni.$u.sleep(1000).then(() => {
uni.hideLoading();
uni.navigateBack({
delta: 1
});
});
*/
uni.hideLoading();
}
},
// 清除定时器
clearInterval() {
this.timer.map(item => {
clearInterval(item);
});
this.timer = [];
},
// 选择摄像头
async clickCamera(item, index) {
const list = this.playList.filter(i => item.id === i.id);
if (list.length > 0) {
this.$u.toast('当前摄像头已在播放窗口');
return false;
}
uni.showLoading({
title: '切换中...'
});
console.log(item);
if (this.playList[this.current].live) {
const params = {
liveId: this.playList[this.current].live_id,
libraryId: this.playList[this.current].library_id
};
// 释放通道
await MntDeviceApi.liveRelease(params);
}
this.playList.splice(this.current, 1, uni.$u.deepClone(item));
this.cameraIndex = index;
this.liveHeartbeat(
{
liveId: item.live_id,
libraryId: item.library_id,
deviceId: this.deviceId
},
this.current
);
this.timerOut = setTimeout(() => {
this.intervalLiveHeartbeat();
}, 3000);
uni.hideLoading();
},
// 选择视频
clickItem(item, index) {
this.current = index;
this.curLive = item;
},
// 全屏
fullScreen() {
if (!this.curLive.live) {
uni.$u.toast(this.curLive.msg);
return false;
}
const video = uni.createVideoContext(this.current + '', this);
video.requestFullScreen();
},
// 回放模式
playback() {
if (!this.curLive.live) {
uni.$u.toast(this.curLive.msg);
return false;
}
this.params.type = 2;
this.showTime = true;
},
// 预览模式
async preview() {
if (!this.curLive.live) {
uni.$u.toast(this.curLive.msg);
return false;
}
this.cameraList.map(item => {
if (item.channel_no === this.playList[this.current].channel_no) {
this.$set(this.playList[this.current], 'url', item.url);
}
});
},
// 确认选择开始时间
confirmTime(e) {
this.showTime = false;
this.params.start_time = uni.$u.timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss');
this.showEndTime = true;
},
// 确认选择结束时间
async confirmEndTime(e) {
this.showEndTime = false;
this.params.stop_time = uni.$u.timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss');
this.params.channel_no = this.curLive.channel_no;
const res = await this.listLiveAddress();
const url = res[0].url;
this.$set(this.playList[this.current], 'url', url);
this.params.type = 1;
this.params.channel_no = null;
},
onPlayError(e) {
console.log(e);
},
// 确认选择分馆
onLibraryConfirm(e) {
console.log(e);
this.libraryId = e[0].id;
this.libraryName = e[0].name;
this.cameraList = [];
this.getDeviceList();
},
// 确认选择设备
async onDeviceConfirm(e) {
this.params.channel_no = null;
this.params.id = e.value[0].id;
this.deviceName = e.value[0].name;
this.showDevice = false;
this.getCameraList();
},
// 获取设备信息
async getDeviceList() {
const res = await MntDeviceApi.getList({
libraryId: this.libraryId
});
this.deviceList = res.map(item => item.device);
if (this.deviceList.length > 0) {
this.params.id = this.deviceList[0].id;
this.deviceName = this.deviceList[0].name;
this.deviceSerial = this.deviceList[0].device_serial;
this.getCameraList();
} else {
this.params.id = null;
this.deviceName = '';
this.liveAddrList = [];
uni.$u.toast('当前分馆暂无设备信息,请联系管理员添加', 3000);
this.loading = false;
}
},
// 获取摄像头列表
async getCameraList() {
if (this.playList.length > 0) {
uni.showLoading({
title: '正在释放通道,请稍后'
});
this.clearInterval();
for (let i = 0; i < this.playList.length; i++) {
if (this.playList[i].live) {
await this.liveRelease({
liveId: this.playList[i].live_id,
libraryId: this.playList[i].library_id
});
}
}
uni.hideLoading();
}
this.cameraIndex = null;
this.current = 0;
this.cameraList = await MntDeviceApi.listLiveAddress(this.params);
console.log(this.cameraList);
this.loading = false;
if (this.cameraList.length > 0) {
this.playList = uni.$u.deepClone(
this.cameraList
.filter((item, index) => index < 4)
.map((item, index) => {
item.live = false;
if (item.status === 1) {
this.liveHeartbeat(
{
liveId: item.live_id,
libraryId: item.library_id,
deviceId: this.deviceId
},
index
);
}
return item;
})
);
this.curLive = this.playList[0];
this.timerOut = setTimeout(() => {
this.intervalLiveHeartbeat();
}, 3000);
}
},
// 获取设备播放地址
async listLiveAddress() {
const res = await MntDeviceApi.listLiveAddress(this.params);
console.log('获取设备播放地址', res);
return res.map(item => {
item.live = true;
return item;
});
},
// 定时发送心跳
intervalLiveHeartbeat() {
let obj = {};
this.clearInterval();
this.playList.map((item, index) => {
if (!obj[item.live_id]) {
if (item.live && item.status === 1) {
const timer = setInterval(async () => {
const res = await MntDeviceApi.liveHeartbeat(
{
liveId: item.live_id,
libraryId: item.library_id,
deviceId: this.deviceId
},
index
);
}, uni.$u.random(2500, 3500));
this.timer.push(timer);
}
obj[item.live_id] = true;
}
});
console.log(obj);
},
// 心跳
async liveHeartbeat(params, index) {
const res = await MntDeviceApi.liveHeartbeat(params);
console.log('播放Id', params.liveId, '是否可播放', res.live, uni.$u.timeFormat(Number(new Date()), 'yyyy年mm月dd日 hh时MM分ss秒'));
this.playList[index].live = res.live;
this.playList[index].msg = res.msg;
},
// 释放通道
async liveRelease(params) {
console.log('释放通道', params);
return await MntDeviceApi.liveRelease(params);
},
// 获取分馆列表
async getLibrary() {
let arr = [];
const res = await LibraryApi.chainDown();
this.libraryList = res.map(item => this.mapTree(item));
this.libraryVO = this.libraryList[0];
this.libraryId = this.libraryVO.id;
this.libraryName = this.libraryVO.name;
this.getDeviceList();
},
mapTree(org) {
const haveChildren = Array.isArray(org.librarys) && org.librarys.length > 0;
return {
name: org.name,
id: org.id,
children: haveChildren ? org.librarys.map(i => this.mapTree(i)) : []
};
},
// 扁平化树形
flatten(data) {
//{id, title, pid, children = []},这段代码利用了对象的展开语法
return data.reduce(
(arr, { id, name, librarys = [] }) =>
arr.concat(
[
{
id,
name
}
],
this.flatten(librarys || [])
),
[]
);
},
// 选择分馆
chooseLibrary() {
this.$refs.tkitree._show();
},
// 取消选择图书馆
cancelLibrary() {
console.log('取消选择图书馆');
},
chooseLibraryDevice() {
if (this.deviceList.length === 0) {
uni.$u.toast('当前馆未添加设备,请联系管理员添加');
return false;
}
this.showDevice = true;
}
}
};
</script> ```
DCloud_iOS_LZY
新的版本设置了:controls="false"就会隐藏原生的状态栏,需要实现自定义状态栏。
2023-05-05 16:34