提交: 视频管理-分屏展示 功能 *使用 livePlayer 播放器。
This commit is contained in:
parent
52b5d81481
commit
3d1e5a545b
|
@ -36,6 +36,7 @@
|
|||
"url": "https://github.com/histroniot/smart-power-ui.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@liveqing/liveplayer": "^2.7.0",
|
||||
"@riophae/vue-treeselect": "0.4.0",
|
||||
"axios": "0.21.0",
|
||||
"clipboard": "2.0.6",
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<cross-domain-policy>
|
||||
<allow-access-from domain="*"/>
|
||||
</cross-domain-policy>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 180 B |
Binary file not shown.
After Width: | Height: | Size: 183 B |
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
|
@ -11,7 +11,7 @@
|
|||
<link rel="stylesheet" href="//at.alicdn.com/t/font_2506643_9w119og75cs.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_2506643_ncb9eqoon2o.css">
|
||||
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_2506643_5jmnx3lcnpu.css">
|
||||
|
||||
<script type="text/javascript" src="http://webapi.amap.com/maps?v=1.4.15&key=4b483d227a9c7dd12e46faae5a8c8af8"></script>
|
||||
<script src="<%= BASE_URL %>js/config.js"></script>
|
||||
|
@ -20,6 +20,7 @@
|
|||
<script src="https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js"></script>
|
||||
<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=4b483d227a9c7dd12e46faae5a8c8af8&plugin=AMap.Geocoder"></script>
|
||||
<script type="text/javascript" src="<%= BASE_URL %>cdn/js/jessibuca/jessibuca.js"></script>
|
||||
<script src="<%= BASE_URL %>cdn/js/liveplayer/liveplayer-lib.min.js"></script>
|
||||
<title><%= webpackConfig.name %></title>
|
||||
<style>
|
||||
html,
|
||||
|
|
|
@ -80,3 +80,12 @@ export function screenshotList(query) {
|
|||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询未绑定 摄像头列表
|
||||
export function unbindVideoDev(query) {
|
||||
return request({
|
||||
url: '/monitor/video/unbindVideoList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import request from '@/utils/request'
|
||||
|
||||
// 查询视频回放列表
|
||||
export function listVideo(query) {
|
||||
return request({
|
||||
url: '/iot/replay/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询视频回放列表
|
||||
export function splitScreenTree(query) {
|
||||
return request({
|
||||
url: '/monitor/splitScreenDisplay/treeList',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import request from '@/utils/request'
|
||||
import { preventRepeatFu } from "@/utils/hciot";
|
||||
|
||||
// 查询站点监控列表
|
||||
export function listSite(query) {
|
||||
return request({
|
||||
url: '/iot/site/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
// 查询站点监控详细
|
||||
export function getSite(siteId) {
|
||||
return request({
|
||||
url: '/iot/site/detail/' + siteId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 新增站点监控
|
||||
export function addSite(data) {
|
||||
preventRepeatFu(true)
|
||||
return request({
|
||||
url: '/iot/site/add',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 修改站点监控
|
||||
export function updateSite(data) {
|
||||
preventRepeatFu(true)
|
||||
return request({
|
||||
url: '/iot/site/edit',
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
// 删除站点监控
|
||||
export function delSite(siteId) {
|
||||
return request({
|
||||
url: '/iot/site/del/' + siteId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 实时监控树形
|
||||
export function siteTree(data) {
|
||||
return request({
|
||||
url: '/iot/site/tree',
|
||||
method: 'get',
|
||||
params: data
|
||||
})
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
<svg t="1631782689827" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7221" width="128" height="128"><path d="M1024.2 480L861.9 710c-9.3 13.2-21.5 23.7-35.4 30.9-13.9 7.2-29.5 11.1-45.7 11.1-18.7 0-37-5.3-52.8-15.2L98.4 341.5C87.8 334.8 79.2 325.6 73.3 315c-5.9-10.7-9.1-22.8-9.1-35.3 0-15.3 4.8-30.3 13.8-42.8l117.6-163c9.3-12.9 21.4-23.1 35.1-30.1 13.7-7 29.1-10.8 45-10.8 18.4 0 36.4 5.1 52.1 14.8L1024.2 480zM754.1 768c-11.1 0-22-1.5-32.6-4.5-10.6-3-20.7-7.4-30.2-13.2l-611.8-373c-6.7-4.1-15.3 0.7-15.3 8.6v22.6c0 14.6 7.6 28.2 20 35.8l182.5 112.3C241.2 572 224.2 600 224.2 632c0 20.2 6.8 38.8 18.3 53.7a62.518 62.518 0 0 1-44.2 18.3H64.2v-46.8c0-29-19.5-54.4-47.6-61.9L0.2 591l-0.2 369 28.8-14.3c21.7-10.8 35.5-33 35.5-57.3V768h135.5c25.9 0 50.8-10.3 69.2-28.7l3.1-3.1c10.6-10.6 25-16.3 40-16.3h0.2c46.4 0 84.4-35.9 87.8-81.4L674.2 807.2c9.2 5.7 19.9 8.7 30.7 8.7 9.8 0 19.3-2.5 27.7-6.9 8.4-4.5 15.7-11 21.1-19.2l6.8-10.1c3.2-5-0.4-11.7-6.4-11.7zM312.2 656c-13.2 0-24-10.8-24-24s10.8-24 24-24 24 10.8 24 24-10.8 24-24 24z" p-id="7222"></path></svg>
|
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1 @@
|
|||
<svg t="1631782749568" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7516" width="128" height="128"><path d="M969.4 532.9c-16.2 10.3-26.8 27.3-29 46.4-22.6 197-205.2 350.6-427.6 350.6-221.6 0-403.7-152.7-427.3-349-2.3-18.7-12.7-35.6-28.5-45.8-2.2-1.4-4.4-2.8-6.5-4.3C20.1 510 1.9 475.5 1.4 438.6c-0.6-44.5 0.1-104.1 0.7-150 0.6-47.1 27.1-90.1 69-111.8 206.5-106.9 673-108.3 882.4-0.4 42.5 21.9 69.4 65.7 69.4 113.6v146.2c0 38.4-19.1 74.4-51.3 95.3-0.8 0.5-1.5 0.9-2.2 1.4z m-617 251.4c22 37.2 91.1 65.7 160.4 65.7s136.9-26.9 158.8-64l-0.7-210c-14.8-73-81.1-126.1-158.1-126.1s-145.7 53.7-160.4 126.8v207.6z m574.8-533.8C767 157.4 298 150.8 100 248.5c-10.8 5.3-17.6 16.3-17.8 28.3-0.3 32.8-0.9 92.2 1.5 115.6 151.5-95.3 703.3-93.9 859.4 0V278.1c0.1-11.4-6-21.9-15.9-27.6zM512.8 609.9c43.9 0 79.7 39.4 79.7 88.1 0 48.7-35.7 88.1-79.7 88.1s-79.7-39.4-79.7-88.1c-0.1-48.7 35.7-88.1 79.7-88.1z" p-id="7517"></path></svg>
|
After Width: | Height: | Size: 961 B |
|
@ -0,0 +1,190 @@
|
|||
<template>
|
||||
<div class="cloud-control-wrap">
|
||||
<div
|
||||
class="direction-new-wrap"
|
||||
:style="{
|
||||
width: width,
|
||||
height: width
|
||||
}">
|
||||
<div class="direction-new-item">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-caret-top"
|
||||
style="font-size: 35px;transform: rotate(-45deg);"
|
||||
:disabled="disabledState"
|
||||
@mousedown.native="handleCloudSend('left')"
|
||||
@mouseup.native="handleCloudSend('stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-new-item">
|
||||
<el-button
|
||||
type="text"
|
||||
style="font-size: 35px;transform: rotate(-45deg);"
|
||||
:disabled="disabledState"
|
||||
@mousedown.native="handleCloudSend('up')"
|
||||
@mouseup.native="handleCloudSend('stop')"
|
||||
icon="el-icon-caret-right"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-new-item">
|
||||
<el-button
|
||||
type="text"
|
||||
style="font-size: 35px;transform: rotate(-45deg);"
|
||||
:disabled="disabledState"
|
||||
@mousedown.native="handleCloudSend('down')"
|
||||
@mouseup.native="handleCloudSend('stop')"
|
||||
icon="el-icon-caret-left"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-new-item">
|
||||
<el-button
|
||||
type="text"
|
||||
style="font-size: 35px;transform: rotate(-45deg);"
|
||||
:disabled="disabledState"
|
||||
@mousedown.native="handleCloudSend('right')"
|
||||
@mouseup.native="handleCloudSend('stop')"
|
||||
icon="el-icon-caret-bottom"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- <div class="direction-wrap">
|
||||
<div class="direction-item">
|
||||
<el-button type="text" icon="" />
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-caret-right"
|
||||
style="font-size: 35px;transform: rotate(-45deg);"
|
||||
:disabled="disabledState"
|
||||
@mousedown.native="handleCloudSend('left')"
|
||||
@mouseup.native="handleCloudSend('stop')"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<el-button type="text" icon="" />
|
||||
</div>
|
||||
|
||||
<div class="direction-item">
|
||||
<el-button
|
||||
type="text"
|
||||
style="font-size: 35px;transform: rotate(-45deg);"
|
||||
:disabled="disabledState"
|
||||
@mousedown.native="handleCloudSend('up')"
|
||||
@mouseup.native="handleCloudSend('stop')"
|
||||
icon="el-icon-caret-left"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="direction-item">
|
||||
<el-button type="text" icon="" />
|
||||
</div>
|
||||
|
||||
<div class="direction-item">
|
||||
<el-button
|
||||
type="text"
|
||||
style="font-size: 35px;transform: rotate(-45deg);"
|
||||
:disabled="disabledState"
|
||||
@mousedown.native="handleCloudSend('down')"
|
||||
@mouseup.native="handleCloudSend('stop')"
|
||||
icon="el-icon-caret-right"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="direction-item">
|
||||
<el-button type="text" icon="" />
|
||||
</div>
|
||||
|
||||
<div class="direction-item">
|
||||
<el-button
|
||||
type="text"
|
||||
style="font-size: 35px;transform: rotate(-45deg);"
|
||||
:disabled="disabledState"
|
||||
@mousedown.native="handleCloudSend('right')"
|
||||
@mouseup.native="handleCloudSend('stop')"
|
||||
icon="el-icon-caret-bottom"
|
||||
/>
|
||||
</div>
|
||||
<div class="direction-item">
|
||||
<el-button type="text" icon="" />
|
||||
</div>
|
||||
</div>
|
||||
<div class=""></div> -->
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
name: "CloudControl",
|
||||
props: {
|
||||
disabledState: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '120px'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleCloudSend(type) {
|
||||
this.$emit("sendCloud", type);
|
||||
},
|
||||
handleClick() {},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.cloud-control-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 120px;
|
||||
min-width: 120px;
|
||||
}
|
||||
.direction-wrap {
|
||||
width: 180px;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
}
|
||||
.direction-item {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.direction-new-wrap {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 120px;
|
||||
min-width: 120px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background: url(~@/assets/images/cloudBg1.png?);
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
.direction-new-item {
|
||||
/* border: 1px solid #8d8d8d; */
|
||||
width: 50%;
|
||||
height: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.direction-new-item:hover {
|
||||
/* box-shadow: 1px 1px 1px 1px slategrey; */
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,7 @@
|
|||
import axios from 'axios'
|
||||
import { serviceApi } from '@/config/dvr.config'
|
||||
import { getPTZCmd, PTZ_TYPE } from './ptz-cmd.js'
|
||||
import axios from 'axios'
|
||||
|
||||
/**
|
||||
* 获取gbs 指令接口 api
|
||||
* @param {*} v 使用 m7s 版本
|
||||
|
@ -141,8 +142,8 @@ export const handleStopBye = (device, channel) => {
|
|||
axiosGet(url, params)
|
||||
}
|
||||
|
||||
export const handleSendDirect = (reqUrl, params, type, ) => {
|
||||
let url = `${reqUrl}control`
|
||||
export const handleSendDirect = (reqUrl, version, params, type ) => {
|
||||
let url = `${reqUrl}${getServiceApi(version)}control`
|
||||
axiosGet(url, Object.assign(params, {
|
||||
ptzcmd: getPTZCmd({
|
||||
type: PTZ_TYPE[type]
|
||||
|
|
|
@ -555,7 +555,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { listInfo, getInfo, delInfo, addInfo, updateInfo } from "@/api/video/camera";
|
||||
import { listInfo, getInfo, delInfo, addInfo, updateInfo, unbindVideoDev } from "@/api/video/camera";
|
||||
import { getUser } from "@/api/system/user";
|
||||
import { listSite } from "@/api/iot/site";
|
||||
import { initMap, gjzCode } from "@/utils/latlngFromAddress";
|
||||
|
@ -565,9 +565,9 @@ import SelectTableWrap from "@/components/SelectTable/index";
|
|||
import ShopLocation from "@/components/Amap/components/shopLocation/index";
|
||||
import SelectInput from "../profile/SelectInput/index";
|
||||
import { getToken } from "@/utils/auth";
|
||||
import {
|
||||
listDevice,
|
||||
} from "@/api/iot/device";
|
||||
// import {
|
||||
// listDevice,
|
||||
// } from "@/api/iot/device";
|
||||
|
||||
const joinTypeOpt = {
|
||||
CAMERA: "摄像头直连",
|
||||
|
@ -972,7 +972,7 @@ export default {
|
|||
},
|
||||
// 查詢 设备列表 接口
|
||||
getDeviceChildList(data) {
|
||||
listDevice(Object.assign(JSON.parse(JSON.stringify(data.page)), JSON.parse(JSON.stringify(data.param)))).then(res => {
|
||||
unbindVideoDev(Object.assign(JSON.parse(JSON.stringify(data.page)), JSON.parse(JSON.stringify(data.param)))).then(res => {
|
||||
this.tableSelectOption.tableList = res.rows;
|
||||
this.tableSelectOption.queryOpt.page.total = Number(res.total);
|
||||
})
|
||||
|
@ -1092,7 +1092,7 @@ export default {
|
|||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.getTenantList();
|
||||
// this.getTenantList();
|
||||
this.open = true;
|
||||
this.tempType = "create";
|
||||
this.title = "添加监控设备";
|
||||
|
@ -1101,7 +1101,7 @@ export default {
|
|||
handleUpdate(row) {
|
||||
this.tempType = "update";
|
||||
this.reset();
|
||||
this.getTenantList();
|
||||
// this.getTenantList();
|
||||
const recordId = row.recordId || this.ids;
|
||||
getInfo(recordId).then((response) => {
|
||||
this.form = response.data;
|
||||
|
|
|
@ -0,0 +1,588 @@
|
|||
<template>
|
||||
<div
|
||||
class="gbs-screen-view"
|
||||
style="background: #f4f4f4; height: calc(100vh - 85px); padding: 10px"
|
||||
>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="5" style="overflow: hidden">
|
||||
<div>
|
||||
<span
|
||||
style="
|
||||
display: block;
|
||||
height: 40px;
|
||||
width: 100%;
|
||||
background-color: #2b2f3a;
|
||||
color: #fff;
|
||||
line-height: 42px;
|
||||
padding-left: 12px;
|
||||
margin-bottom: 5px;
|
||||
"
|
||||
>监控资源</span
|
||||
>
|
||||
<el-tree
|
||||
style="
|
||||
height: 100%;
|
||||
padding-top: 10px;
|
||||
height: calc(100vh - 370px);
|
||||
overflow: auto;
|
||||
"
|
||||
class="zzjg-video-tree"
|
||||
:data="deptOptions"
|
||||
:props="defaultProps"
|
||||
node-key="treeId"
|
||||
:default-expanded-keys="expandedList"
|
||||
:expand-on-click-node="true"
|
||||
@node-expand="handleNodeExpand"
|
||||
@node-collapse="handleNodeCollapse"
|
||||
:filter-node-method="filterNode"
|
||||
ref="entityTreeRef"
|
||||
>
|
||||
<div
|
||||
class="custom-tree-node"
|
||||
style="display: flex; width: 100%; align-items: baseline"
|
||||
slot-scope="{ node, data }"
|
||||
>
|
||||
<i class="el-icon-folder-opened" v-if="node.level !== 3"></i>
|
||||
<svg-icon
|
||||
v-if="data.videoType === 'GUN_MACHINE'"
|
||||
icon-class="A_qjsxt"
|
||||
class="svg-icon"
|
||||
style="position: relative; top: 3px"
|
||||
/>
|
||||
<svg-icon
|
||||
v-else-if="data.videoType === 'BALL_MACHINE'"
|
||||
icon-class="A_yjsxt"
|
||||
class="svg-icon"
|
||||
style="position: relative; top: 3px"
|
||||
/>
|
||||
<span
|
||||
:title="data.playing ? '在线' : '离线'"
|
||||
class="palying-span"
|
||||
:style="computeIsPlaying(data) || data.playing ? 'background: #27e874;' : ''"
|
||||
v-if="node.level === 3"
|
||||
></span>
|
||||
<span
|
||||
style="font-size: 13px; margin-left: 5px; line-height: 18px"
|
||||
@click="handlePaly(node, data)"
|
||||
>{{ node.label }}</span
|
||||
>
|
||||
<el-button
|
||||
type="text"
|
||||
v-if="node.level === 3"
|
||||
@click="handlePaly(node, data)"
|
||||
>
|
||||
<i
|
||||
:class="
|
||||
computeIsPlaying(data) || node.data.playing
|
||||
? 'el-icon-video-camera-solid'
|
||||
: 'el-icon-video-play'
|
||||
"
|
||||
:style="
|
||||
computeIsPlaying(data) || node.data.playing
|
||||
? 'margin-left: 5px; color: #37dc11;'
|
||||
: 'margin-left: 5px; '
|
||||
"
|
||||
></i>
|
||||
<span v-if="!computeIsPlaying(data) && !data.playing"
|
||||
>播放</span
|
||||
>
|
||||
</el-button>
|
||||
</div>
|
||||
</el-tree>
|
||||
</div>
|
||||
<div class="video-right">
|
||||
<cloud-control
|
||||
:disabledState="false"
|
||||
width="200px"
|
||||
@sendCloud="sendCloud"
|
||||
></cloud-control>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="19" id="videoView">
|
||||
<div
|
||||
:class="
|
||||
fullscreen
|
||||
? 'third-party-right-view fullscreen'
|
||||
: 'third-party-right-view'
|
||||
"
|
||||
v-loading="splitScreenLoading"
|
||||
element-loading-text="拼命加载中"
|
||||
element-loading-spinner="el-icon-loading"
|
||||
element-loading-background="rgba(0, 0, 0, 0.8)"
|
||||
>
|
||||
<!-- <split-screen
|
||||
v-if="!splitScreenLoading && !isWebRTC"
|
||||
ref="splitScreen"
|
||||
:scale="scale"
|
||||
:serviceUrl="getServiceUrl()"
|
||||
:split="splitType"
|
||||
/> -->
|
||||
<e-other-screen
|
||||
v-if="!splitScreenLoading"
|
||||
ref="splitScreen"
|
||||
:scale="scale"
|
||||
:serviceUrl="getServiceUrl()"
|
||||
:split="splitType"
|
||||
@handleTreeNodes="handleTreeNodes"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="third-rarty-right-option"
|
||||
:style="isWebRTC ? 'justify-content: right' : ''"
|
||||
>
|
||||
<div
|
||||
class="ptz-attribute"
|
||||
v-show="!isWebRTC"
|
||||
style="
|
||||
padding-left: 5px;
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
width: 300px;
|
||||
align-items: center;
|
||||
"
|
||||
>
|
||||
<el-radio-group v-model="scale" size="mini" @change="scaleChange">
|
||||
<el-radio-button :label="0">拉伸填充</el-radio-button>
|
||||
<el-radio-button :label="1">等比缩放</el-radio-button>
|
||||
<el-radio-button :label="2">完全填充</el-radio-button>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<div>
|
||||
<!-- <el-button
|
||||
type="text"
|
||||
icon="el-icon-menu"
|
||||
size="medium"
|
||||
:style="splitType === 1 ? 'color: #1890ff' : ''"
|
||||
@click="radioScreenChange(1)"
|
||||
title="一宫格"
|
||||
></el-button> -->
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-menu"
|
||||
size="medium"
|
||||
:style="splitType === 4 ? 'color: #1890ff' : ''"
|
||||
@click="radioScreenChange(4)"
|
||||
title="四宫格"
|
||||
></el-button>
|
||||
<el-button
|
||||
:style="splitType === 9 ? 'color: #1890ff' : ''"
|
||||
type="text"
|
||||
icon="el-icon-s-grid"
|
||||
size="medium"
|
||||
@click="radioScreenChange(9)"
|
||||
title="九宫格"
|
||||
></el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
size="medium"
|
||||
@click="radioScreenChange(16)"
|
||||
title="十六宫格"
|
||||
>
|
||||
<img
|
||||
:src="
|
||||
splitType === 16 ? '/images/16gg_bc.png' : '/images/16gg.png'
|
||||
"
|
||||
style="width: 12px; margin-top: 1px"
|
||||
/>
|
||||
</el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-full-screen"
|
||||
@click="screen"
|
||||
size="medium"
|
||||
title="全屏"
|
||||
></el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import CloudControl from "@/components/JessibucaPlay/CloudControl";
|
||||
import {
|
||||
getServiceUrlWS,
|
||||
handleStartInviteLive,
|
||||
getServiceUrl,
|
||||
getServiceApi,
|
||||
} from "@/utils/gbsLive";
|
||||
import { splitScreenTree } from "@/api/video/playVideo";
|
||||
import {
|
||||
setRecordIdx,
|
||||
getType,
|
||||
setType,
|
||||
init,
|
||||
getScreenIsWebRTC,
|
||||
setScreenIsWebRTC,
|
||||
} from "./modules/screenRecord";
|
||||
import EOtherScreen from "./modules/EOtherScreen";
|
||||
export default {
|
||||
name: "GbsScreen",
|
||||
components: {
|
||||
CloudControl,
|
||||
EOtherScreen,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
splitType: 4,
|
||||
fullscreen: false,
|
||||
isWebRTC: true, // 是否 webRTC 模式 分屏展示,存入浏览器 cookies 默认 true
|
||||
splitOption: {
|
||||
alone: 1,
|
||||
four: 4,
|
||||
nine: 9,
|
||||
sixteen: 16,
|
||||
},
|
||||
defaultProps: {
|
||||
children: "children",
|
||||
label: "label",
|
||||
key: "key",
|
||||
},
|
||||
deptOptions: [],
|
||||
expandedList: [],
|
||||
queryVideo1: {
|
||||
siteId: "",
|
||||
},
|
||||
selectSite: {},
|
||||
eventSource: null,
|
||||
scale: 0,
|
||||
splitScreenLoading: false,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
let that = this;
|
||||
let isWebRTCStart = getScreenIsWebRTC();
|
||||
if (!isWebRTCStart) {
|
||||
setScreenIsWebRTC(true);
|
||||
this.isWebRTC = true;
|
||||
} else {
|
||||
this.isWebRTC = getScreenIsWebRTC() == "false" ? false : true;
|
||||
}
|
||||
window.onresize = function () {
|
||||
if (!that.checkFull()) {
|
||||
that.fullscreen = false;
|
||||
}
|
||||
};
|
||||
this.splitType = Number(getType());
|
||||
this.getTreeselect();
|
||||
this.$forceUpdate();
|
||||
},
|
||||
computed: {},
|
||||
methods: {
|
||||
handleNodeExpand(e) {
|
||||
this.expandedList.push(e.treeId);
|
||||
},
|
||||
handleNodeCollapse(e) {
|
||||
this.expandedList = this.expandedList.filter((v) => v !== e.treeId);
|
||||
},
|
||||
scaleChange(e) {
|
||||
this.scale = e;
|
||||
this.$forceUpdate();
|
||||
// this.jessibuca.setScaleMode(this.scale)
|
||||
},
|
||||
/** 查询部门下拉树结构 */
|
||||
getTreeselect() {
|
||||
this.deptOptions = [];
|
||||
this.splitScreenLoading = true;
|
||||
splitScreenTree({ serverType: "M7S" }).then((res) => {
|
||||
if (res.code === 200) {
|
||||
this.deptOptions = res.data;
|
||||
this.splitScreenLoading = init(this.deptOptions);
|
||||
}
|
||||
// 封锁 国标实时获取 设备状态
|
||||
// if (res.data && res.data.length > 0) {
|
||||
// this.eventResult({ val: res.data[0].id });
|
||||
// }
|
||||
});
|
||||
},
|
||||
checkFull() {
|
||||
var isFull =
|
||||
document.mozFullScreen ||
|
||||
document.fullScreen ||
|
||||
//谷歌浏览器及Webkit内核浏览器
|
||||
document.webkitIsFullScreen ||
|
||||
document.webkitRequestFullScreen ||
|
||||
document.mozRequestFullScreen ||
|
||||
document.msFullscreenEnabled;
|
||||
if (isFull === undefined) {
|
||||
isFull = false;
|
||||
}
|
||||
return isFull;
|
||||
},
|
||||
computeIsPlaying(e) {
|
||||
return this.$refs.splitScreen.getIsPlaying(e);
|
||||
},
|
||||
computeIsDisabled() {
|
||||
return this.$refs.splitScreen.getIsDisabled();
|
||||
},
|
||||
sendCloud(e) {
|
||||
this.$refs.splitScreen.sendCloud(e);
|
||||
},
|
||||
getServiceUrl() {
|
||||
return `${getServiceUrl(
|
||||
this.selectSite["https"] === true ? "https://" : "http://",
|
||||
this.selectSite.m7sHost,
|
||||
this.selectSite.m7sPort
|
||||
)}${getServiceApi(this.selectSite["m7sVersion"])}`;
|
||||
},
|
||||
// 筛选节点
|
||||
filterNode(value, data) {
|
||||
if (!value) return true;
|
||||
return data.label.indexOf(value) !== -1;
|
||||
},
|
||||
radioScreenChange(e) {
|
||||
if (this.$refs.splitScreen) {
|
||||
this.$refs.splitScreen.batchDestroyed();
|
||||
}
|
||||
setType(e);
|
||||
this.splitType = e;
|
||||
},
|
||||
/**
|
||||
* 2022-09-14 放弃 用 list 接口获取实时 状态
|
||||
initEventSource() {
|
||||
if (this.selectSite["serverType"] === "M7S") {
|
||||
let url = `${getServiceUrl(
|
||||
this.selectSite["https"] === true ? "https://" : "http://",
|
||||
this.selectSite.m7sHost,
|
||||
this.selectSite.m7sPort
|
||||
)}${getServiceApi(this.selectSite["m7sVersion"])}list`;
|
||||
if (this.eventSource) {
|
||||
this.eventSource.close();
|
||||
}
|
||||
this.eventSource = new EventSource(url);
|
||||
this.eventSource.onmessage = this.eventSourceMessage;
|
||||
}
|
||||
},
|
||||
*/
|
||||
/**
|
||||
* 2022-09-14 放弃 用 list 接口获取实时 状态
|
||||
eventResult(data) {
|
||||
if (data.val) {
|
||||
this.queryVideo1 = {
|
||||
siteId: data["val"],
|
||||
};
|
||||
getSite(this.queryVideo1.siteId).then((response) => {
|
||||
this.selectSite = response.data;
|
||||
this.initEventSource();
|
||||
});
|
||||
}
|
||||
},
|
||||
*/
|
||||
// 回调事件处理
|
||||
eventSourceMessage(event) {
|
||||
var _this = this;
|
||||
if (event.data !== "null" && _this.deptOptions) {
|
||||
var newList = [...JSON.parse(event.data)];
|
||||
var depTree = [..._this.deptOptions];
|
||||
newList.forEach((camera) => {
|
||||
if (camera["Channels"] && camera["Channels"].length > 0) {
|
||||
camera["Channels"].forEach((cameraItem) => {
|
||||
depTree.forEach((treeNode) => {
|
||||
if (treeNode["children"] && treeNode["children"].length > 0) {
|
||||
treeNode["children"].forEach((childNode) => {
|
||||
if (
|
||||
childNode.devChannel === cameraItem.DeviceID &&
|
||||
camera.ID === childNode.devId
|
||||
) {
|
||||
childNode = Object.assign(childNode, cameraItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
this.deptOptions = [...depTree];
|
||||
this.deptOptions = this.deptOptions.concat();
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
handleOpenInviteLive(node, data) {
|
||||
var _this = this;
|
||||
if (!this.computeIsPlaying(data)) {
|
||||
this.$confirm("连接设备,并且开始播放直播!", "提示", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning",
|
||||
}).then(function () {
|
||||
let selectIdx = _this.$refs.splitScreen.getSelectIdx();
|
||||
setRecordIdx(data, selectIdx);
|
||||
_this.$nextTick(() =>
|
||||
_this.$refs.splitScreen.handleOpenInviteLive(
|
||||
Object.assign(data, {
|
||||
devChannel: data["devChannel"] || data.devChannel,
|
||||
}),
|
||||
selectIdx
|
||||
)
|
||||
);
|
||||
_this.handleUpdatePlayStatus(node, data);
|
||||
});
|
||||
} else {
|
||||
this.$refs.splitScreen.setPlayingIdx(row.data);
|
||||
}
|
||||
},
|
||||
handleTreeNodes(data) {
|
||||
let { getNode } = this.$refs.entityTreeRef;
|
||||
if (this.$refs.entityTreeRef) {
|
||||
let node = getNode(data.treeId);
|
||||
if (node) {
|
||||
this.handleUpdatePlayStatus(node, data, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 热更新 播放摄像头 状态
|
||||
*/
|
||||
handleUpdatePlayStatus(node, data, status) {
|
||||
let { updateKeyChildren } = this.$refs.entityTreeRef;
|
||||
let parentId = node.parent.data.treeId;
|
||||
let parentChildNodes = node.parent.data.children || [];
|
||||
parentChildNodes = parentChildNodes.map((v) => {
|
||||
if (v["treeId"] === data["treeId"]) {
|
||||
v["playing"] = status;
|
||||
}
|
||||
return v;
|
||||
});
|
||||
updateKeyChildren(parentId, [...parentChildNodes]);
|
||||
},
|
||||
handlePaly(node, data) {
|
||||
if (node.level === 3) {
|
||||
if (!this.computeIsPlaying(node.data)) {
|
||||
if (data.LivePublisher) {
|
||||
this.onTreeSelect(node);
|
||||
} else {
|
||||
this.handleOpenInviteLive(node, data);
|
||||
}
|
||||
} else {
|
||||
this.$refs.splitScreen.setPlayingIdx(node.data);
|
||||
}
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
onTreeSelect(row) {
|
||||
this.treeSelectKey = row["key"];
|
||||
if (!row.data.LivePublisher) {
|
||||
let siteInfo = {
|
||||
https: row.data.https,
|
||||
devId: row.data.devId,
|
||||
m7sHost: row.data.siteM7sHost,
|
||||
m7sPort: row.data.siteM7sPort,
|
||||
m7sVersion: row.data.siteM7sVersion,
|
||||
};
|
||||
handleStartInviteLive(siteInfo, row.data);
|
||||
} else {
|
||||
const playUrl = `${getServiceUrlWS(
|
||||
row.data["https"] === true ? "https://" : "http://",
|
||||
row.data.siteM7sHost,
|
||||
row.data.siteM7sPort
|
||||
)}/jessica/${row.data.LivePublisher.StreamPath}`;
|
||||
setRecordIdx(row.data, this.$refs.splitScreen.getSelectIdx());
|
||||
this.$nextTick(() =>
|
||||
this.$refs.splitScreen.setPassagewayByIdx(row.data, playUrl)
|
||||
);
|
||||
}
|
||||
},
|
||||
// 视频模块全屏
|
||||
screen() {
|
||||
let element = document.getElementById("videoView");
|
||||
if (this.fullscreen) {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document.webkitCancelFullScreen) {
|
||||
document.webkitCancelFullScreen();
|
||||
} else if (document.mozCancelFullScreen) {
|
||||
document.mozCancelFullScreen();
|
||||
} else if (document.msExitFullscreen) {
|
||||
document.msExitFullscreen();
|
||||
}
|
||||
} else {
|
||||
if (element.requestFullscreen) {
|
||||
element.requestFullscreen();
|
||||
} else if (element.webkitRequestFullScreen) {
|
||||
element.webkitRequestFullScreen();
|
||||
} else if (element.mozRequestFullScreen) {
|
||||
element.mozRequestFullScreen();
|
||||
} else if (element.msRequestFullscreen) {
|
||||
// IE11
|
||||
element.msRequestFullscreen();
|
||||
}
|
||||
}
|
||||
this.fullscreen = !this.fullscreen;
|
||||
// this.changeLayout();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.gbs-screen-view {
|
||||
.zzjg-video-tree .el-tree-node__content:hover {
|
||||
background: #e2d170f1 !important;
|
||||
}
|
||||
.el-card__title {
|
||||
width: 100px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.el-card__ts {
|
||||
display: block;
|
||||
width: 5px;
|
||||
height: 19px;
|
||||
background-color: #0bb2d4;
|
||||
border-radius: 15px;
|
||||
}
|
||||
.el-card__t {
|
||||
font-weight: 600;
|
||||
margin-left: 7px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
.third-party-right-view {
|
||||
width: calc(100% - 0px);
|
||||
height: 100%;
|
||||
border: 1px solid rgb(121, 120, 120);
|
||||
height: calc(100vh - 140px);
|
||||
}
|
||||
.third-rarty-right-option {
|
||||
height: 35px;
|
||||
width: 100%;
|
||||
background-color: #2b2f3a;
|
||||
margin-top: 2px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-right: 10px;
|
||||
justify-content: space-between;
|
||||
.el-button--text {
|
||||
color: #f0f0f1;
|
||||
}
|
||||
}
|
||||
.video-right {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #e1e4e7;
|
||||
min-height: 220px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.palying-span {
|
||||
display: block;
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
left: -7px;
|
||||
top: 3px;
|
||||
}
|
||||
.fullscreen {
|
||||
height: calc(100vh - 37px);
|
||||
}
|
||||
.ptz-attribute .el-radio-button--mini .el-radio-button__inner {
|
||||
background: #1a1d23;
|
||||
color: #fff;
|
||||
}
|
||||
.ptz-attribute
|
||||
.el-radio-button__orig-radio:checked
|
||||
+ .el-radio-button__inner {
|
||||
background-color: #f56c6c;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,112 @@
|
|||
<template>
|
||||
<div class="e-live-player">
|
||||
<LivePlayer
|
||||
ref="livePlayerRef"
|
||||
aspect="fullscreen"
|
||||
alt="无信号"
|
||||
:autofocus="true"
|
||||
:stretch="true"
|
||||
:live="true"
|
||||
controls
|
||||
:autoplay="true"
|
||||
v-loading="bLoading"
|
||||
element-loading-text="加载中..."
|
||||
element-loading-background="#000"
|
||||
:loading.sync="bLoading"
|
||||
:hide-big-play-button="true"
|
||||
@error="EventError"
|
||||
@pause="videoPause"
|
||||
@ended="videoEnded"
|
||||
:videoUrl="LoadingNum <= LoadingMax ? videoUrl : ''"
|
||||
></LivePlayer>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import LivePlayer from "@liveqing/liveplayer";
|
||||
import { handleStartInviteLive } from "@/utils/gbsLive";
|
||||
export default {
|
||||
name: "ELivePlayer",
|
||||
props: {
|
||||
videoUrl: {
|
||||
type: String,
|
||||
require: true,
|
||||
default: () => {
|
||||
return "";
|
||||
},
|
||||
},
|
||||
videoItem: {
|
||||
type: Object,
|
||||
require: true,
|
||||
default: () => {
|
||||
return {};
|
||||
},
|
||||
},
|
||||
},
|
||||
components: {
|
||||
LivePlayer,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
bLoading: true,
|
||||
LoadingMax: 30,
|
||||
LoadingNum: 0,
|
||||
timeoutHeartbeat: 60,
|
||||
isHeartbeat: true,
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
videoUrl(val) {
|
||||
this.LoadingNum = 0;
|
||||
this.bLoading = true;
|
||||
},
|
||||
},
|
||||
// created() {
|
||||
// this.restartLive()
|
||||
// },
|
||||
methods: {
|
||||
// 重新 啓動 推流的操作
|
||||
restartLive() {
|
||||
this.$refs.livePlayerRef.play()
|
||||
let siteInfo = {
|
||||
https: this.videoItem.https,
|
||||
devId: this.videoItem.devId,
|
||||
m7sHost: this.videoItem.siteM7sHost,
|
||||
m7sPort: this.videoItem.siteM7sPort,
|
||||
m7sVersion: this.videoItem.siteM7sVersion,
|
||||
};
|
||||
var _this = this;
|
||||
if (this.isHeartbeat) {
|
||||
this.isHeartbeat = false
|
||||
handleStartInviteLive(siteInfo, this.videoItem);
|
||||
setTimeout(() => {
|
||||
_this.isHeartbeat = true;
|
||||
}, _this.timeoutHeartbeat * 1000);
|
||||
}
|
||||
},
|
||||
videoEnded(e) {
|
||||
console.log("video-videoEnded--:");
|
||||
this.restartLive();
|
||||
},
|
||||
videoPause(e) {
|
||||
console.log("video-pause--:");
|
||||
this.restartLive();
|
||||
},
|
||||
EventError(e) {
|
||||
if (this.LoadingNum <= this.LoadingMax - 1) {
|
||||
this.bLoading = true;
|
||||
}
|
||||
this.LoadingNum += 1;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" >
|
||||
.e-live-player {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
.el-loading-parent--relative {
|
||||
position: initial !important;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,301 @@
|
|||
<template>
|
||||
<div class="e-webrtc-screen">
|
||||
<div class="video-list">
|
||||
<div
|
||||
v-for="(item, index) in list"
|
||||
@click="videoViewClick(item, index)"
|
||||
:style="{
|
||||
height: compVideoWidth(),
|
||||
width: compVideoWidth(),
|
||||
margin: '1px',
|
||||
overflow: 'hidden',
|
||||
}"
|
||||
:class="selectionRow === index ? 'checked-video' : ''"
|
||||
:key="index"
|
||||
>
|
||||
<div
|
||||
class="item-option"
|
||||
:style="selectionRow === index ? 'display: flex;' : ''"
|
||||
ref="itemOption"
|
||||
>
|
||||
<el-button
|
||||
v-if="split === 1"
|
||||
type="text"
|
||||
icon="el-icon-full-screen"
|
||||
size="medium"
|
||||
title="全屏"
|
||||
@click="fullScreenVideo(index)"
|
||||
></el-button>
|
||||
<el-button
|
||||
type="text"
|
||||
icon="el-icon-circle-close"
|
||||
@click="closeVideo(index)"
|
||||
size="medium"
|
||||
title="关闭"
|
||||
></el-button>
|
||||
</div>
|
||||
<div
|
||||
v-if="index < split"
|
||||
ref="videoDiv"
|
||||
:class="
|
||||
selectionRow === index
|
||||
? 'item-video-div video-div-hover'
|
||||
: 'item-video-div '
|
||||
"
|
||||
>
|
||||
<!-- <e-webrtc-video
|
||||
v-if="item"
|
||||
:videoUrl="`webrtc://localhost:9527/${item.devId}/${item.devChannel}`"
|
||||
:params="{
|
||||
'streamPath': `${item.devId}/${item.devChannel}`
|
||||
}"
|
||||
:serviceHttps="item.https"
|
||||
ref="webrtcVideo"
|
||||
/> -->
|
||||
<div v-if="item" style="width: 100%; height: 100%">
|
||||
<e-live-player
|
||||
:videoUrl="`${item.https == true ? 'https' : 'http'}://${
|
||||
item.siteM7sHost
|
||||
}:${item.siteM7sPort}/hdl/${item.devId}/${item.devChannel}.flv`"
|
||||
:videoItem="item"
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
v-else
|
||||
src="/images/video.png"
|
||||
style="
|
||||
width: 180px;
|
||||
height: 80px;
|
||||
opacity: 0.3;
|
||||
filter: alpha(opacity=30);
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getRecord, setRecordIdx } from "./screenRecord";
|
||||
import {
|
||||
handleSendDirect,
|
||||
handleStartInviteLive,
|
||||
getServiceUrl
|
||||
} from "@/utils/gbsLive";
|
||||
import EWebrtcVideo from "./EWebrtcVideo";
|
||||
import ELivePlayer from "./ELivePlayer";
|
||||
export default {
|
||||
name: "EWebrtcScreen",
|
||||
components: {
|
||||
EWebrtcVideo,
|
||||
ELivePlayer,
|
||||
},
|
||||
props: {
|
||||
showList: {
|
||||
type: Array,
|
||||
require: true,
|
||||
},
|
||||
scale: {
|
||||
type: Number,
|
||||
require: true,
|
||||
},
|
||||
split: {
|
||||
type: Number,
|
||||
require: true,
|
||||
},
|
||||
serviceUrl: {
|
||||
type: String,
|
||||
require: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
list: [],
|
||||
selectionRow: 0,
|
||||
videoItemStyle: {
|
||||
width: "calc((100% - 15px) / 2)",
|
||||
height: "",
|
||||
margin: "1px",
|
||||
},
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.handleTypeDom(Number(this.split));
|
||||
},
|
||||
watch: {
|
||||
split(val) {
|
||||
this.handleTypeDom(Number(val));
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
EventPaly(e) {
|
||||
console.log("play--Event", e);
|
||||
},
|
||||
setPlayingIdx(e) {
|
||||
this.list.forEach((v, idx) => {
|
||||
if ( v && (v['devChannel'] === e['devChannel'] && v["devId"] === e['devId'])) {
|
||||
this.selectionRow = idx;
|
||||
this.$forceUpdate();
|
||||
}
|
||||
});
|
||||
},
|
||||
sendCloud(e) {
|
||||
let videoObj = this.list[this.selectionRow];
|
||||
if (videoObj) {
|
||||
let serviceUrl = `${getServiceUrl(
|
||||
videoObj.https ? "https://" : "http://",
|
||||
videoObj.siteM7sHost,
|
||||
videoObj.siteM7sPort
|
||||
)}`;
|
||||
console.log('http-url:', serviceUrl)
|
||||
handleSendDirect(
|
||||
serviceUrl,
|
||||
videoObj.siteM7sVersion || 'v3',
|
||||
{
|
||||
id: videoObj.devId,
|
||||
channel: videoObj.devChannel,
|
||||
},
|
||||
e
|
||||
);
|
||||
}
|
||||
},
|
||||
// 关闭 当前播放窗口
|
||||
closeVideo(index) {
|
||||
this.$emit('handleTreeNodes', this.list[index]);
|
||||
this.list[index] = null;
|
||||
setRecordIdx(null, index);
|
||||
this.$forceUpdate();
|
||||
},
|
||||
compVideoWidth() {
|
||||
if (this.split === 1) {
|
||||
return "100%";
|
||||
} else if (this.split === 4) {
|
||||
return `calc((100% - ${1 * 4}px) / 2)`;
|
||||
} else if (this.split === 9) {
|
||||
return `calc((100% - ${1 * 6}px) / 3)`;
|
||||
} else if (this.split === 16) {
|
||||
return `calc((100% - ${1 * 8}px) / 4)`;
|
||||
}
|
||||
},
|
||||
// 宫格类型 渲染 dom
|
||||
handleTypeDom(type) {
|
||||
this.list = [];
|
||||
const record = getRecord();
|
||||
for (let i = 0; i < type; i++) {
|
||||
if (record && record[i]) {
|
||||
// 从数据列表中找出这条数据
|
||||
this.handleOpenInviteLive(record[i], i);
|
||||
} else {
|
||||
this.list.push(null);
|
||||
}
|
||||
// this.list.push(null)
|
||||
}
|
||||
},
|
||||
// 通知开启 直播推流
|
||||
handleOpenInviteLive(row, idx) {
|
||||
this.list[idx] = Object.assign(row, {
|
||||
bLoading: true,
|
||||
});
|
||||
handleStartInviteLive(
|
||||
{
|
||||
https: row.https,
|
||||
devId: row.devId,
|
||||
m7sHost: row.siteM7sHost,
|
||||
m7sPort: row.siteM7sPort,
|
||||
m7sVersion: row.siteM7sVersion,
|
||||
},
|
||||
{
|
||||
devChannel: row.devChannel,
|
||||
}
|
||||
);
|
||||
this.$forceUpdate();
|
||||
},
|
||||
setPassagewayByIdx(row, playUrl) {
|
||||
if (this.selectionRow >= 0) {
|
||||
this.list[this.selectionRow] = row;
|
||||
this.$forceUpdate();
|
||||
}
|
||||
},
|
||||
getSelectIdx() {
|
||||
return this.selectionRow;
|
||||
},
|
||||
getIsPlaying(e) {
|
||||
let list = this.list.filter((v) => v && (v["devChannel"] === e['devChannel'] && v["devId"] === e['devId']));
|
||||
return list && list.length > 0;
|
||||
},
|
||||
// 视频点击
|
||||
videoViewClick(item, index) {
|
||||
this.selectionRow = index;
|
||||
},
|
||||
batchDestroyed() {},
|
||||
changeLayout() {
|
||||
var num = Math.sqrt(this.split);
|
||||
this.videoItemStyle["width"] = `calc((100% - ${num * 2}px) / ${num})`;
|
||||
if (this.fullscreen) {
|
||||
this.videoItemStyle["height"] = `calc((100vh - 40px - ${
|
||||
num * 2
|
||||
}px) / ${num})`;
|
||||
} else {
|
||||
this.videoItemStyle["height"] = `calc((100vh - 151px - ${
|
||||
num * 2
|
||||
}px) / ${num})`;
|
||||
}
|
||||
this.$forceUpdate();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.e-webrtc-screen {
|
||||
width: calc(100% - 0px);
|
||||
height: 100%;
|
||||
border: 1px solid rgb(121, 120, 120);
|
||||
.video-list {
|
||||
height: auto;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
background-color: #1e1e1e;
|
||||
padding: 0px;
|
||||
height: 100%;
|
||||
// justify-content: space-between;
|
||||
justify-content: flex-start;
|
||||
.item-option {
|
||||
display: none;
|
||||
justify-content: flex-end;
|
||||
padding-right: 20px;
|
||||
background: -webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
left bottom,
|
||||
color-stop(0%, #080808),
|
||||
color-stop(20%, #080808c2),
|
||||
color-stop(100%, #66676700)
|
||||
);
|
||||
position: relative;
|
||||
top: 0;
|
||||
z-index: 2001;
|
||||
.el-button--text {
|
||||
color: #f0f0f1;
|
||||
}
|
||||
}
|
||||
.item-video-div {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: rgb(86, 86, 86);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.video-div-hover {
|
||||
margin-top: -34px;
|
||||
}
|
||||
}
|
||||
.checked-video {
|
||||
border-radius: 3px;
|
||||
border: 2px solid #078fef;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,163 @@
|
|||
<template>
|
||||
<section style="display: block; width: 100%; height: 100%; overflow: hidden">
|
||||
<video
|
||||
class="full-height full-width"
|
||||
controls
|
||||
preload="auto"
|
||||
autoplay="true"
|
||||
muted
|
||||
style="width: 100%; height: 100%; object-fit: fill"
|
||||
ref="video"
|
||||
@click="handleVideo"
|
||||
></video>
|
||||
<div class="refresh-button" v-show="showRefresh">
|
||||
<i class="el-icon-video-play" @click="handleRefresh"></i>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getToken } from "@/utils/auth";
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
pc: null,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
params: {
|
||||
type: Object,
|
||||
},
|
||||
videoUrl: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
serverType: {
|
||||
type: String,
|
||||
default: "SRS",
|
||||
},
|
||||
serviceHttps: {
|
||||
type: Boolean,
|
||||
},
|
||||
overtime: {
|
||||
type: Number,
|
||||
default: () => {
|
||||
return 5;
|
||||
},
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getStream();
|
||||
},
|
||||
watch: {
|
||||
videoUrl(val) {
|
||||
if (val) {
|
||||
this.getStream();
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
timedRefresh: null,
|
||||
showRefresh: false,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
handleVideo(event) {
|
||||
event.preventDefault()
|
||||
},
|
||||
// 定时 重置方法
|
||||
handleTimedRefresh() {
|
||||
var _this = this;
|
||||
this.showRefresh = false;
|
||||
this.timedRefresh = setInterval(function () {
|
||||
_this.showRefresh = true;
|
||||
}, this.overtime * 1000);
|
||||
},
|
||||
videoPause() {},
|
||||
handleRefresh() {
|
||||
if (this.timedRefresh) {
|
||||
clearInterval(this.timedRefresh)
|
||||
this.showRefresh = true;
|
||||
}
|
||||
this.getStream()
|
||||
},
|
||||
getStream() {
|
||||
if (this.videoUrl) {
|
||||
if (this.pc) {
|
||||
this.pc.destroy();
|
||||
}
|
||||
let option = {
|
||||
video: this.$refs.video,
|
||||
autoplay: true,
|
||||
params: this.params || null,
|
||||
type: "offer",
|
||||
onPlay: (obj) => {
|
||||
if (this.timedRefresh) {
|
||||
clearInterval(this.timedRefresh)
|
||||
this.showRefresh = false;
|
||||
}
|
||||
},
|
||||
};
|
||||
if (!this.serverType || this.serverType === "SRS") {
|
||||
option.clientip = getToken();
|
||||
}
|
||||
option.crossType = this.serviceHttps == true ? "https" : "http";
|
||||
this.handleTimedRefresh();
|
||||
console.log(this.videoUrl)
|
||||
this.pc = new JSWebrtc.Player(this.videoUrl, option);
|
||||
}
|
||||
},
|
||||
videoFullScreen() {
|
||||
var ele = this.$refs.video;
|
||||
if (ele.requestFullscreen) {
|
||||
ele.requestFullscreen();
|
||||
} else if (ele.mozRequestFullScreen) {
|
||||
ele.mozRequestFullScreen();
|
||||
} else if (ele.webkitRequestFullScreen) {
|
||||
ele.webkitRequestFullScreen();
|
||||
}
|
||||
},
|
||||
videoExitFullscreen() {
|
||||
var de = document;
|
||||
if (de.exitFullscreen) {
|
||||
de.exitFullscreen();
|
||||
} else if (de.mozCancelFullScreen) {
|
||||
de.mozCancelFullScreen();
|
||||
} else if (de.webkitCancelFullScreen) {
|
||||
de.webkitCancelFullScreen();
|
||||
}
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
if (this.pc) {
|
||||
this.pc.destroy();
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
.full-width {
|
||||
height: 100%;
|
||||
transform: matrix(1, 0, 0, 1, 0, 0);
|
||||
}
|
||||
.refresh-button {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
background: -webkit-gradient(
|
||||
linear,
|
||||
left top,
|
||||
left bottom,
|
||||
color-stop(0%, #080808),
|
||||
color-stop(20%, #080808c2),
|
||||
color-stop(100%, #0c0c0c73)
|
||||
);
|
||||
position: relative;
|
||||
top: -102%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 50px;
|
||||
color: #9b9b9bd1;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,122 @@
|
|||
import Cookies from 'js-cookie'
|
||||
|
||||
const gonggeKey = 'screen-record'
|
||||
const typeKey = 'screen-type'
|
||||
const isWebRTC = 'is-webRTC'
|
||||
|
||||
// 初始左侧列表数据 和 记录数据
|
||||
export function init(list = []) {
|
||||
// 二级 Tree 结构
|
||||
let cookiesList = JSON.parse( Cookies.get(gonggeKey) || '[]')
|
||||
let treeChildList = []
|
||||
var newResult = []
|
||||
if (list && cookiesList && cookiesList.length > 0) {
|
||||
list.forEach(v => {
|
||||
if (v.children && v.children.length > 0) {
|
||||
v.children.forEach(i => {
|
||||
treeChildList = treeChildList.concat(i.children || [])
|
||||
})
|
||||
}
|
||||
})
|
||||
cookiesList.forEach((cook,idx) => {
|
||||
if (cook) {
|
||||
for(let i in treeChildList) {
|
||||
if (treeChildList[i].devChannel === cook['devChannel'] && treeChildList[i].devId === cook['devId']) {
|
||||
newResult[idx] = cook
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newResult[idx] = null
|
||||
}
|
||||
})
|
||||
setRecord(newResult)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function getRecord(index) {
|
||||
let record = Cookies.get(gonggeKey)
|
||||
let list = record ? JSON.parse(record): []
|
||||
var newList = []
|
||||
if (!list || list.length < 16) {
|
||||
for (let i = 0; i < 16; i++) {
|
||||
newList.push(null)
|
||||
}
|
||||
setRecord(newList)
|
||||
return newList
|
||||
} else {
|
||||
if (index !== undefined && index !== null) {
|
||||
return list[index]
|
||||
} else {
|
||||
return list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getType() {
|
||||
const type = Cookies.get(typeKey)
|
||||
if (!type) {
|
||||
setType('4')
|
||||
return '4'
|
||||
} else {
|
||||
return type
|
||||
}
|
||||
}
|
||||
|
||||
export function setRecordIdx(record, idx) {
|
||||
if (idx !== undefined && idx !== null) {
|
||||
let list = JSON.parse(Cookies.get(gonggeKey) || '[]')
|
||||
if (record) {
|
||||
filterRecordVideo(list, record)
|
||||
list[idx] = {
|
||||
devChannel: record.devChannel || record.devChannel,
|
||||
devId: record.devId,
|
||||
https: record.https,
|
||||
siteM7sHost: record.siteM7sHost,
|
||||
siteM7sPort: record.siteM7sPort,
|
||||
siteM7sVersion: record.siteM7sVersion,
|
||||
// label: record.label
|
||||
}
|
||||
} else {
|
||||
list[idx] = record
|
||||
}
|
||||
setRecord(list)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断 记录列表中是否已有记录当前 播放设备
|
||||
function filterRecordVideo(list, record) {
|
||||
const newList = [...list]
|
||||
newList.forEach((v, idx) => {
|
||||
if (v) {
|
||||
if (v['devChannel'] === record.devChannel && v['devId'] === record.devId) {
|
||||
list[idx] = null
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function setRecord(list) {
|
||||
return Cookies.set(gonggeKey, JSON.stringify(list))
|
||||
}
|
||||
|
||||
export function setType(type) {
|
||||
return Cookies.set(typeKey, type)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置分屏模式 是否 webRTC
|
||||
* @param {*} value 设置的新值
|
||||
* @returns
|
||||
*/
|
||||
export function setScreenIsWebRTC(value) {
|
||||
return Cookies.set(isWebRTC, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取分屏模式 是否 webRTC
|
||||
* @returns
|
||||
*/
|
||||
export function getScreenIsWebRTC() {
|
||||
return Cookies.get(isWebRTC)
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
'use strict'
|
||||
const path = require('path')
|
||||
const defaultSettings = require('./src/settings.js')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, dir)
|
||||
|
@ -47,6 +48,13 @@ module.exports = {
|
|||
externals: {
|
||||
AMap: 'AMap'
|
||||
},
|
||||
plugins: [
|
||||
new CopyWebpackPlugin([
|
||||
{ from: 'node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml'},
|
||||
{ from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf'},
|
||||
{ from: 'node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js', to: 'cdn/js/liveplayer/'},
|
||||
]),
|
||||
],
|
||||
name: name,
|
||||
resolve: {
|
||||
alias: {
|
||||
|
|
Loading…
Reference in New Issue