mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-17 16:36:03 +08:00
1.代码更新
This commit is contained in:
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user