1.代码更新

This commit is contained in:
zhuangpeng.li
2024-07-11 15:40:30 +08:00
parent ee78bf6efc
commit c74ea3df6a
17 changed files with 642 additions and 1066 deletions

View File

@@ -1,183 +0,0 @@
<template>
<div id="DeviceTree" style="width: 100%; height: 100%; background-color: #ffffff; overflow: auto">
<div style="line-height: 3vh;margin-bottom: 10px;font-size: 17px;">设备列表</div>
<el-tree ref="tree" :props="defaultProps" :current-node-key="selectchannelId" :default-expanded-keys="expandIds"
:highlight-current="true" @node-click="handleNodeClick" :load="loadNode" lazy node-key="id"
style="min-width: 100%; display: inline-block !important">
<span class="custom-tree-node" slot-scope="{ node, data }" style="width: 100%">
<span v-if="node.data.type === 0 && node.data.online" title="在线设备"
class="device-online iconfont icon-jiedianleizhukongzhongxin2"></span>
<span v-if="node.data.type === 0 && !node.data.online" title="离线设备"
class="device-offline iconfont icon-jiedianleizhukongzhongxin2"></span>
<span v-if="node.data.type === 3 && node.data.online" title="在线通道"
class="device-online iconfont icon-shebeileijiankongdian"></span>
<span v-if="node.data.type === 3 && !node.data.online" title="离线通道"
class="device-offline iconfont icon-shebeileijiankongdian"></span>
<span v-if="node.data.type === 4 && node.data.online" title="在线通道-球机"
class="device-online iconfont icon-shebeileiqiuji"></span>
<span v-if="node.data.type === 4 && !node.data.online" title="离线通道-球机"
class="device-offline iconfont icon-shebeileiqiuji"></span>
<span v-if="node.data.type === 5 && node.data.online" title="在线通道-半球"
class="device-online iconfont icon-shebeileibanqiu"></span>
<span v-if="node.data.type === 5 && !node.data.online" title="离线通道-半球"
class="device-offline iconfont icon-shebeileibanqiu"></span>
<span v-if="node.data.type === 6 && node.data.online" title="在线通道-枪机"
class="device-online iconfont icon-shebeileiqiangjitongdao"></span>
<span v-if="node.data.type === 6 && !node.data.online" title="离线通道-枪机"
class="device-offline iconfont icon-shebeileiqiangjitongdao"></span>
<span v-if="node.data.online" style="padding-left: 1px" class="device-online">{{ node.label }}</span>
<span v-if="!node.data.online" style="padding-left: 1px" class="device-offline">{{ node.label }}</span>
</span>
</el-tree>
</div>
</template>
<script>
import { listSipDeviceChannel } from '@/api/iot/sipdevice';
import { listDeviceShort } from '@/api/iot/device';
export default {
name: 'DeviceTree',
data() {
return {
// 总条数
total: 0,
// 监控设备通道信息表格数据
channelList: [],
DeviceData: [],
expandIds: [],
selectData: {},
selectchannelId: '',
defaultProps: {
children: 'children',
label: 'name',
isLeaf: 'isLeaf',
},
queryParams: {
pageNum: 1,
pageSize: 100,
status: 3,
deviceType: 3,
},
};
},
props: ['onlyCatalog', 'clickEvent'],
mounted() {
this.selectchannelId = '';
this.expandIds = ['0'];
},
methods: {
handleNodeClick(data, node, element) {
this.selectData = node.data;
this.selectchannelId = node.data.value;
if (node.level !== 0) {
let deviceNode = this.$refs.tree.getNode(data.userData.channelSipId);
if (typeof this.clickEvent == 'function' && node.level > 1) {
this.clickEvent(deviceNode.data.userData);
}
}
},
loadNode: function (node, resolve) {
if (node.level === 0) {
listDeviceShort(this.queryParams).then((response) => {
const data = response.rows;
if (data.length > 0) {
let nodeList = [];
for (let i = 0; i < data.length; i++) {
let node = {
name: data[i].deviceName,
isLeaf: false,
id: data[i].serialNumber,
type: 0,
online: data[i].status === 3,
userData: data[i],
};
nodeList.push(node);
}
resolve(nodeList);
} else {
resolve([]);
}
});
} else {
let channelArray = [];
listSipDeviceChannel(node.data.userData.serialNumber).then((res) => {
if (res.data != null) {
channelArray = channelArray.concat(res.data);
this.channelDataHandler(channelArray, resolve);
} else {
resolve([]);
}
});
}
},
channelDataHandler: function (data, resolve) {
if (data.length > 0) {
let nodeList = [];
for (let i = 0; i < data.length; i++) {
let item = data[i];
let channelType = item.id.substring(10, 13);
console.log('channelType: ' + channelType);
let type = 3;
if (item.id.length <= 10) {
type = 2;
} else {
if (item.id.length > 14) {
let channelType = item.id.substring(10, 13);
// 111-DVR编码;112-视频服务器编码;118-网络视频录像机(NVR)编码;131-摄像机编码;132-网络摄像机(IPC)编码
if (channelType !== '111' && channelType !== '112' && channelType !== '118' && channelType !== '131' && channelType !== '132') {
type = -1;
// 1-球机;2-半球;3-固定枪机;4-遥控枪机
} else if (item.basicData.ptztype === 1) {
type = 4;
} else if (item.basicData.ptztype === 2) {
type = 5;
} else if (item.basicData.ptztype === 3 || item.basicData.ptztype === 4) {
type = 6;
}
} else {
if (item.basicData.subCount > 0 || item.basicData.parental === 1) {
type = 2;
}
}
}
let node = {
name: item.name || item.id,
isLeaf: true,
id: item.id,
deviceId: item.deviceId,
type: type,
online: item.status === 2,
userData: item.basicData,
};
if (channelType === '111' || channelType === '112' || channelType === '118' || channelType === '131' || channelType === '132') {
nodeList.push(node);
}
}
resolve(nodeList);
} else {
resolve([]);
}
},
reset: function () {
this.$forceUpdate();
},
},
destroyed() { },
};
</script>
<style>
.device-tree-main-box {
text-align: left;
}
.device-online {
color: #252525;
}
.device-offline {
color: #727272;
}
</style>

View File

@@ -1,291 +0,0 @@
<template>
<div style="display: block; width: 1000px">
<div style="display: flex">
<el-row>
<span style="margin-left: 10px" prop="channelName">通道</span>
<el-select v-model="channelId" placeholder="请选择" @change="changeChannel" style="width: 200px; margin-right: 10px" size="small">
<el-option v-for="option in channelList" :key="option.value" :label="option.label" :value="option.value"></el-option>
</el-select>
<span style="overflow: auto; margin-left: 10px">日期</span>
<el-date-picker v-model="queryDate" type="date" size="small" value-format="yyyy-MM-dd" clearable placeholder="选择日期" style="width: 180px; margin-right: 10px" />
<el-button-group style="margin: 0">
<el-button size="mini" type="success" title="查看录像" @click="loadDevRecord()" :disabled="channelId === '' || !queryDate">
<i class="el-icon-video-camera" />
查看
</el-button>
</el-button-group>
<span style="margin-left: 82px; overflow: auto">时间</span>
<el-button-group>
<el-time-picker
size="small"
is-range
align="left"
v-model="timeRange"
value-format="yyyy-MM-dd HH:mm:ss"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
placeholder="选择时间范围"
@change="timePickerChange"
style="width: 200px"
:disabled="channelId === '' || !queryDate"
></el-time-picker>
</el-button-group>
<el-button-group style="margin: 0 0 0 10px">
<el-button size="mini" type="primary" title="下载选定录像" @click="downloadRecord()" :disabled="channelId === '' || !timeRange">
<i class="el-icon-download" />
转存
</el-button>
</el-button-group>
</el-row>
</div>
<player ref="playbacker" :playerinfo="playinfo" class="components-container"></player>
</div>
</template>
<script>
import player from '@/views/components/player/player.vue';
import { listChannel, playback, closeStream, playbackSeek } from '@/api/iot/channel';
import { getDevRecord, startDownloadRecord } from '@/api/iot/record';
export default {
name: 'DeviceVideo',
components: {
player,
},
data() {
return {
deviceId: '',
channelId: '',
streamId: '',
ssrc: '',
playurl: '',
queryDate: '',
playing: false,
vodData: {},
hisData: [],
playinfo: {},
channelList: [],
playbackinfo: {},
timeRange: null,
startTime: null,
endTime: null,
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
deviceSipId: null,
channelSipId: null,
},
};
},
props: {
device: {
type: Object,
default: null,
},
},
watch: {
// 获取到父组件传递的device后
device: function (newVal, oldVal) {
this.deviceInfo = newVal;
if (this.deviceInfo && this.deviceInfo.deviceId !== 0) {
this.queryParams.deviceSipId = this.deviceInfo.serialNumber;
this.deviceId = this.device.serialNumber;
}
},
},
created() {
this.queryParams.deviceSipId = this.device.serialNumber;
this.deviceId = this.device.serialNumber;
this.getList();
this.playinfo = {
playtype: 'playback',
deviceId: this.device.serialNumber,
};
},
beforeDestroy() {},
destroyed() {
this.closeStream();
},
methods: {
/** 查询监控设备通道信息列表 */
getList() {
this.loading = true;
listChannel(this.queryParams).then((response) => {
this.channelList = response.rows.map((item) => {
return { value: item.channelSipId, label: item.channelName };
});
});
},
// 改变通道
changeChannel() {
this.playinfo.channelId = this.channelId;
},
initUrl(data) {
if (data) {
this.streamId = data.ssrc;
this.ssrc = data.ssrc;
this.playurl = data.playurl;
} else {
this.streamId = '';
this.ssrc = '';
this.playurl = '';
}
},
getBeijingTime(queryDate) {
// 计算与UTC的时区差对于北京时间来说是8小时
let offset = 8 * 60 * 60 * 1000;
// 加上时区差,得到北京时间
let beijingTime = new Date(new Date(queryDate).getTime() - offset);
return beijingTime.getTime();
},
// 录像控制
loadDevRecord() {
this.$refs.playbacker.registercallback('playbackSeek', this.seekPlay);
if (this.queryDate === '' || this.queryDate === null){
this.$message.error('请选择日期');
return;
}
if (this.deviceId && this.channelId) {
const date = this.getBeijingTime(this.queryDate);
const start = date / 1000;
const end = Math.floor((date + 24 * 60 * 60 * 1000 - 1) / 1000);
const query = {
start: start,
end: end,
};
this.vodData = {
start: start,
end: end,
base: start,
};
this.setTime(this.queryDate + ' 00:00:00', this.queryDate + ' 23:59:59');
getDevRecord(this.deviceId, this.channelId, query).then((res) => {
this.hisData = res.data.recordItems;
if (res.data.recordItems) {
const len = this.hisData.length;
if (len > 0) {
if (this.hisData[0].start < start) {
this.hisData[0].start = start;
this.vodData.start = start;
} else {
this.vodData.start = this.hisData[0].start;
}
if (this.hisData[0].end !== 0 &&this.hisData[0].end < end) {
this.vodData.end = this.hisData[0].end;
}
this.playback();
} else {
this.$message({
type: 'warning',
message: '请确认设备是否支持录像或者设备SD卡是否正确插入',
});
}
} else {
this.$message({
type: 'warning',
message: '请确认设备是否支持录像或者设备SD卡是否正确插入',
});
}
});
}
},
/**录像播放*/
playback() {
const query = {
start: this.vodData.start,
end: this.vodData.end,
};
if (this.ssrc) {
closeStream(this.deviceId, this.channelId, this.ssrc).then((res) => {
playback(this.deviceId, this.channelId, query)
.then((res) => {
this.initUrl(res.data);
})
.finally(() => {
this.triggerPlay(this.hisData);
});
});
} else {
playback(this.deviceId, this.channelId, query)
.then((res) => {
this.initUrl(res.data);
})
.finally(() => {
this.triggerPlay(this.hisData);
});
}
},
/**触发播放*/
triggerPlay(playTimes) {
this.$refs.playbacker.playback(this.playurl, playTimes);
this.playing = true;
},
/**录像播放*/
seekPlay(s) {
const curTime = this.vodData.base + s.hour * 3600 + s.min * 60 + s.second;
const seekRange = curTime - this.vodData.start;
if (this.ssrc) {
const query = {
seek: seekRange,
};
const _this = this;
playbackSeek(this.deviceId, this.channelId, this.streamId, query).then((res) => {
_this.$refs.playbacker.setPlaybackStartTime(curTime);
});
}
},
/**关闭播放流*/
closeStream() {
if (this.playing && this.streamId) {
closeStream(this.deviceId, this.channelId, this.streamId).then((res) => {
this.streamId = '';
this.ssrc = '';
this.playurl = '';
this.playing = false;
});
// this.$refs.playbacker.destroy();
}
},
/**销毁录像播放器*/
destroy() {
if (this.playing && this.streamId) {
this.$refs.playbacker.destroy();
}
},
closeDestroy() {
this.closeStream();
this.destroy();
},
/**设置时间*/
timePickerChange: function (val) {
this.setTime(val[0], val[1]);
},
setTime: function (startTime, endTime) {
this.startTime = startTime;
this.endTime = endTime;
this.timeRange = [startTime, endTime];
},
/**下载录像*/
downloadRecord: function () {
const start = new Date(this.startTime).getTime() / 1000;
const end = new Date(this.endTime).getTime() / 1000;
const query = {
startTime: start,
endTime: end,
speed: '4',
};
startDownloadRecord(this.deviceId, this.channelId, query).then((res) => {
console.log('开始转存到流服务器:' + this.deviceId + ' : ' + this.channelId);
if (res.code === 200 ) {
this.$message({
type: 'success',
message: '转存到流服务器,请前往视频中心->录像管理查看!',
});
}
});
},
},
};
</script>

View File

@@ -1,363 +0,0 @@
<template>
<div ref="container" @dblclick="fullscreenSwich"
style="width:100%;height:100%;background-color: #000000;margin:0 auto;">
<div class="buttons-box" id="buttonsBox">
<div class="buttons-box-left">
<i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick"></i>
<i v-if="playing" class="iconfont icon-pause jessibuca-btn" @click="pause"></i>
<i class="iconfont icon-stop jessibuca-btn" @click="destroy"></i>
<i v-if="isNotMute" class="iconfont icon-audio-high jessibuca-btn" @click="mute()"></i>
<i v-if="!isNotMute" class="iconfont icon-audio-mute jessibuca-btn" @click="cancelMute()"></i>
</div>
<div class="buttons-box-right">
<span class="jessibuca-btn">{{ kBps }} kb/s</span>
<i class="iconfont icon-camera1196054easyiconnet jessibuca-btn" @click="screenshot"
style="font-size: 1rem !important"></i>
<i class="iconfont icon-shuaxin11 jessibuca-btn" @click="playBtnClick"></i>
<i v-if="!fullscreen" class="iconfont icon-weibiaoti10 jessibuca-btn" @click="fullscreenSwich"></i>
<i v-if="fullscreen" class="iconfont icon-weibiaoti11 jessibuca-btn" @click="fullscreenSwich"></i>
</div>
</div>
</div>
</template>
<script>
let jessibucaPlayer = {};
export default {
name: 'jessibuca',
data() {
return {
playing: false,
isNotMute: false,
quieting: false,
fullscreen: false,
loaded: false, // mute
speed: 0,
performance: "", // 工作情况
kBps: 0,
btnDom: null,
videoInfo: null,
volume: 1,
rotate: 0,
vod: true, // 点播
forceNoOffscreen: false,
};
},
props: ['videoUrl', 'error', 'hasAudio', 'height'],
mounted() {
window.onerror = (msg) => {
// console.error(msg)
};
console.log(this._uid)
let paramUrl = decodeURIComponent(this.$route.params.url)
this.$nextTick(() => {
this.updatePlayerDomSize()
window.onresize = () => {
this.updatePlayerDomSize()
}
if (typeof (this.videoUrl) == "undefined") {
this.videoUrl = paramUrl;
}
this.btnDom = document.getElementById("buttonsBox");
console.log("初始化时的地址为: " + this.videoUrl)
this.play(this.videoUrl)
})
},
watch: {
videoUrl(newData, oldData) {
this.play(newData)
},
immediate: true
},
methods: {
updatePlayerDomSize() {
let dom = this.$refs.container;
let width = dom.parentNode.clientWidth
let height = (9 / 16) * width
const clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight)
if (height > clientHeight) {
height = clientHeight
width = (16 / 9) * height
}
dom.style.width = width + 'px';
dom.style.height = height + "px";
},
create() {
let options = {};
console.log("hasAudio " + this.hasAudio)
jessibucaPlayer[this._uid] = new window.JessibucaPro(Object.assign(
{
container: this.$refs.container,
autoWasm: true,
background: "",
controlAutoHide: false,
debug: false,
decoder: "/js/jessibuca-pro/decoder-pro.js",
forceNoOffscreen: true,
hasAudio: typeof (this.hasAudio) == "undefined" ? true : this.hasAudio,
hasVideo: true,
heartTimeout: 5,
heartTimeoutReplay: true,
heartTimeoutReplayTimes: 3,
hiddenAutoPause: false,
hotKey: false,
isFlv: false,
isFullResize: false,
isNotMute: this.isNotMute,
isResize: false,
keepScreenOn: false,
loadingText: "请稍等, 视频加载中......",
loadingTimeout: 10,
loadingTimeoutReplay: true,
loadingTimeoutReplayTimes: 3,
openWebglAlignment: false,
operateBtns: {
fullscreen: false,
screenshot: false,
play: false,
audio: false,
record: false
},
recordType: "webm",
rotate: 0,
showBandwidth: false,
supportDblclickFullscreen: false,
timeout: 10,
useMSE: location.hostname !== "localhost" && location.protocol !== "https:",
useOffscreen: false,
useWCS: location.hostname === "localhost" || location.protocol === "https",
useWebFullScreen: false,
videoBuffer: 0,
wasmDecodeAudioSyncVideo: true,
wasmDecodeErrorReplay: true,
wcsUseVideoRender: true
},
options
));
let jessibuca = jessibucaPlayer[this._uid];
let _this = this;
jessibuca.on("load", function () {
console.log("on load init");
});
jessibuca.on("log", function (msg) {
console.log("on log", msg);
});
jessibuca.on("record", function (msg) {
console.log("on record:", msg);
});
jessibuca.on("pause", function () {
_this.playing = false;
});
jessibuca.on("play", function () {
_this.playing = true;
});
jessibuca.on("fullscreen", function (msg) {
console.log("on fullscreen", msg);
_this.fullscreen = msg
});
jessibuca.on("mute", function (msg) {
console.log("on mute", msg);
_this.isNotMute = !msg;
});
jessibuca.on("audioInfo", function (msg) {
console.log("audioInfo", msg);
});
jessibuca.on("bps", function (bps) {
// console.log('bps', bps);
});
let _ts = 0;
jessibuca.on("timeUpdate", function (ts) {
// console.log('timeUpdate,old,new,timestamp', _ts, ts, ts - _ts);
_ts = ts;
});
jessibuca.on("videoInfo", function (info) {
console.log("videoInfo", info);
});
jessibuca.on("error", function (error) {
console.log("error", error);
});
jessibuca.on("timeout", function () {
console.log("timeout");
});
jessibuca.on('start', function () {
console.log('start');
})
jessibuca.on("performance", function (performance) {
let show = "卡顿";
if (performance === 2) {
show = "非常流畅";
} else if (performance === 1) {
show = "流畅";
}
_this.performance = show;
});
jessibuca.on('buffer', function (buffer) {
// console.log('buffer', buffer);
})
jessibuca.on('stats', function (stats) {
// console.log('stats', stats);
})
jessibuca.on('kBps', function (kBps) {
_this.kBps = Math.round(kBps);
});
// 显示时间戳 PTS
jessibuca.on('videoFrame', function () {
})
//
jessibuca.on('metadata', function () {
});
},
playBtnClick: function (event) {
this.play(this.videoUrl)
},
play: function (url) {
if (jessibucaPlayer[this._uid]) {
this.destroy().then(() => {
jessibucaPlayer[this._uid].on("play", () => {
this.playing = true;
this.loaded = true;
});
if (jessibucaPlayer[this._uid].hasLoaded()) {
jessibucaPlayer[this._uid].play(url);
} else {
jessibucaPlayer[this._uid].on("load", () => {
console.log("load 播放")
jessibucaPlayer[this._uid].play(url);
});
}
});
} else {
this.create();
jessibucaPlayer[this._uid].on("play", () => {
this.playing = true;
this.loaded = true;
});
if (jessibucaPlayer[this._uid].hasLoaded()) {
jessibucaPlayer[this._uid].play(url);
} else {
jessibucaPlayer[this._uid].on("load", () => {
console.log("load 播放")
jessibucaPlayer[this._uid].play(url);
});
}
}
},
pause: function () {
if (jessibucaPlayer[this._uid]) {
jessibucaPlayer[this._uid].pause();
}
this.playing = false;
this.err = "";
this.performance = "";
},
screenshot: function () {
if (jessibucaPlayer[this._uid]) {
jessibucaPlayer[this._uid].screenshot();
}
},
mute: function () {
if (jessibucaPlayer[this._uid]) {
jessibucaPlayer[this._uid].mute();
}
},
cancelMute: function () {
if (jessibucaPlayer[this._uid]) {
jessibucaPlayer[this._uid].cancelMute();
}
},
destroy: async function () {
if (jessibucaPlayer[this._uid]) {
await jessibucaPlayer[this._uid].destroy().then(() => {
this.create();
});
} else {
this.create();
}
if (document.getElementById("buttonsBox") == null) {
this.$refs.container.appendChild(this.btnDom)
}
jessibucaPlayer[this._uid] = null;
this.playing = false;
this.err = "";
this.performance = "";
},
eventcallbacK: function (type, message) {
// console.log("player 事件回调")
// console.log(type)
// console.log(message)
},
fullscreenSwich: function () {
let isFull = this.isFullscreen()
jessibucaPlayer[this._uid].setFullscreen(!isFull)
this.fullscreen = !isFull;
},
isFullscreen: function () {
return document.fullscreenElement ||
document.msFullscreenElement ||
document.mozFullScreenElement ||
document.webkitFullscreenElement || false;
}
},
destroyed() {
if (jessibucaPlayer[this._uid]) {
jessibucaPlayer[this._uid].destroy();
}
this.playing = false;
this.loaded = false;
this.performance = "";
},
}
</script>
<style>
@import '../css/iconfont.css';
.buttons-box {
width: 100%;
height: 28px;
background-color: rgba(43, 51, 63, 0.7);
position: absolute;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
left: 0;
bottom: 0;
user-select: none;
z-index: 10;
}
.jessibuca-btn {
width: 20px;
color: rgb(255, 255, 255);
line-height: 27px;
margin: 0px 10px;
padding: 0px 2px;
cursor: pointer;
text-align: center;
font-size: 0.8rem !important;
}
.buttons-box-right {
position: absolute;
right: 0;
}
</style>

View File

@@ -70,7 +70,7 @@ export default {
initplayer() {
this.isPlaybackPause = false;
this.initconf();
jessibucaPlayer[this._uid] = new window.JessibucaPro({
jessibucaPlayer[this._uid] = new window.Jessibuca({
container: this.$refs.container,
decoder: '/js/jessibuca-pro/decoder-pro.js',
videoBuffer: Number(0.2), // 缓存时长

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -278,7 +278,6 @@ import { deviceSynchronization, getDevice, addDevice, updateDevice, generatorDev
import { getDeviceRunningStatus } from '@/api/iot/device';
import { cacheJsonThingsModel } from '@/api/iot/model';
import { getDeviceTemp } from '@/api/iot/temp';
import deviceVideo from '@/views/components/player/deviceVideo.vue';
import deviceLiveStream from '@/views/components/player/deviceLiveStream';
import sipid from '../sip/sipidGen.vue';
import player from '@/views/components/player/player.vue';
@@ -301,7 +300,6 @@ export default {
deviceTimer,
JsonViewer,
vueQr,
deviceVideo,
deviceLiveStream,
player,
channel,

View File

@@ -1,221 +0,0 @@
<template>
<div style="padding: 6px">
<el-card id="devicePosition" style="width: 100vw; height: 91vh" :body-style="{ padding: '0px' }">
<el-container v-loading="loading" style="height: 91vh; " element-loading-text="拼命加载中">
<el-aside width="250px" style="background-color: #ffffff;">
<DeviceTree :clickEvent="clickEvent"></DeviceTree>
</el-aside>
<el-main style="padding: 0">
<div height="5vh" style="text-align: left; font-size: 17px; line-height: 5vh;margin-bottom: 10px;">
分屏:
<el-button type="success" style="margin-left: 10px;" :class="{ active: spilt == 1 }" @click="spilt = 1"
plain icon='el-icon-full-screen' size="mini">单屏 </el-button>
<el-button type="info" style="margin-left: 10px;" :class="{ active: spilt == 4 }" @click="spilt = 4"
icon="el-icon-menu" plain size="mini">四屏</el-button>
<el-button type="warning" style="margin-left: 10px;" :class="{ active: spilt == 9 }" @click="spilt = 9"
plain icon="el-icon-s-grid" size="mini">九屏</el-button>
</div>
<div style="height: 85vh; display: flex; flex-wrap: wrap">
<div v-for="i in spilt" :key="i" class="play-box" :style="liveStyle"
:class="{ redborder: playerIdx == i - 1 }" @click="playerIdx = i - 1">
<div v-if="!videoUrl[i - 1]" style="color: #ffffff; font-size: 30px; font-weight: bold">{{ i }}</div>
<player ref="player" v-else :videoUrl="videoUrl[i - 1]" fluent autoplay @screenshot="shot"
@destroy="destroy" class="player-wrap" />
</div>
</div>
</el-main>
</el-container>
</el-card>
</div>
</template>
<script>
import player from '@/views/components/player/jessibuca.vue';
import DeviceTree from '@/views/components/player/DeviceTree.vue';
import { startPlay } from '@/api/iot/channel';
export default {
name: 'SplitView',
components: {
player,
DeviceTree,
},
data() {
return {
videoUrl: [''],
spilt: 1, //分屏
playerIdx: 0, //激活播放器
updateLooper: 0, //数据刷新轮训标志
count: 15,
total: 0,
loading: false,
};
},
mounted() { },
created() {
this.checkPlayByParam();
},
computed: {
liveStyle() {
let style = { width: '81%', height: '99%' };
switch (this.spilt) {
case 4:
style = { width: '40%', height: '49%' };
break;
case 9:
style = { width: '27%', height: '32%' };
break;
}
this.$nextTick(() => {
for (let i = 0; i < this.spilt; i++) {
const player = this.$refs.player;
player && player[i] && player[i].updatePlayerDomSize();
}
});
return style;
},
},
watch: {
spilt(newValue) {
console.log('切换画幅;' + newValue);
let that = this;
for (let i = 1; i <= newValue; i++) {
if (!that.$refs['player' + i]) {
continue;
}
this.$nextTick(() => {
if (that.$refs['player' + i] instanceof Array) {
that.$refs['player' + i][0].resize();
} else {
that.$refs['player' + i].resize();
}
});
}
window.localStorage.setItem('split', newValue);
},
'$route.fullPath': 'checkPlayByParam',
},
destroyed() {
clearTimeout(this.updateLooper);
},
methods: {
destroy(idx) {
console.log(idx);
this.clear(idx.substring(idx.length - 1));
},
clickEvent: function (data) {
if (data.channelSipId) {
this.sendDevicePush(data);
}
},
//通知设备上传媒体流
sendDevicePush: function (itemData) {
this.save(itemData);
let deviceId = itemData.deviceSipId;
let channelId = itemData.channelSipId;
console.log('通知设备推流1' + deviceId + ' : ' + channelId);
let idxTmp = this.playerIdx;
let that = this;
this.loading = true;
startPlay(deviceId, channelId)
.then((response) => {
console.log('开始播放:' + this.deviceId + ' : ' + this.channelId);
console.log('流媒体信息:' + response.data);
let res = response.data;
console.log('playurl' + res.playurl);
itemData.playUrl = res.playurl;
itemData.streamId = res.streamId;
that.setPlayUrl(itemData.playUrl, idxTmp);
})
.finally(() => {
that.loading = false;
});
},
setPlayUrl(url, idx) {
this.$set(this.videoUrl, idx, url);
let _this = this;
setTimeout(() => {
window.localStorage.setItem('videoUrl', JSON.stringify(_this.videoUrl));
}, 100);
},
checkPlayByParam() {
let { deviceId, channelId } = this.$route.query;
if (deviceId && channelId) {
this.sendDevicePush({ deviceId, channelId });
}
},
shot(e) {
var base64ToBlob = function (code) {
let parts = code.split(';base64,');
let contentType = parts[0].split(':')[1];
let raw = window.atob(parts[1]);
let rawLength = raw.length;
let uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {
type: contentType,
});
};
let aLink = document.createElement('a');
let blob = base64ToBlob(e); //new Blob([content]);
let evt = document.createEvent('HTMLEvents');
evt.initEvent('click', true, true); //initEvent 不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为
aLink.download = '截图';
aLink.href = URL.createObjectURL(blob);
aLink.click();
},
save(item) {
let dataStr = window.localStorage.getItem('playData') || '[]';
let data = JSON.parse(dataStr);
data[this.playerIdx] = item;
window.localStorage.setItem('playData', JSON.stringify(data));
},
clear(idx) {
let dataStr = window.localStorage.getItem('playData') || '[]';
let data = JSON.parse(dataStr);
data[idx - 1] = null;
console.log(data);
window.localStorage.setItem('playData', JSON.stringify(data));
},
},
};
</script>
<style>
.btn {
margin: 0 10px;
}
.btn:hover {
color: #409eff;
}
.btn.active {
color: #409eff;
}
.redborder {
border: 2px solid red !important;
}
.play-box {
background-color: #000000;
border: 1px solid #505050;
display: flex;
align-items: center;
justify-content: center;
margin-right: 10px;
position: relative;
border-radius: 5px;
}
.player-wrap {
position: absolute;
top: 0px;
height: 100% !important;
}
</style>