<template>
|
<div>
|
<div class="btn-box" v-show="videoShow">
|
<ul>
|
<li>
|
<button @click="play()">播放</button>
|
</li>
|
<li>
|
<button @click="pause()">暂停</button>
|
</li>
|
<li>
|
<button @click="restore()">恢复</button>
|
</li>
|
<li>
|
<button @click="view('1', -20, 100)">第一视角</button>
|
</li>
|
<li>
|
<button @click="view('2')">上帝视角</button>
|
</li>
|
<li>
|
<button @click="view('tracked')">跟随视角</button>
|
</li>
|
<li>
|
<button @click="view('free')">自由视角</button>
|
</li>
|
</ul>
|
</div>
|
|
<div class="item video1" v-show="videoShow">
|
<video-loading v-show="isShowVideoLoading.video1"></video-loading>
|
<div class="select" v-show="isShowSelect.video1">
|
<el-select size="small" v-model="monitor.type1" @change="((val) => { navClick(val, 1) })" placeholder="请选择"
|
ref="videoSelect1">
|
<el-option v-for="item in monitorOption" :key="item.value" :label="item.label" :value="item.value"
|
class="activity-video-option-css">
|
<div class="video-status" :style="{ background: (item.status == 0 ? '#adadad' : '#4ccc7d') }">
|
</div>
|
{{ item.label }}
|
</el-option>
|
</el-select>
|
</div>
|
<div class="video" v-show="isHaveMonitor.video1">
|
<video id="videoElement1" autoplay controls width="100%" height="100%" style="object-fit: fill"></video>
|
</div>
|
<div class="no-video" v-show="!isHaveMonitor.video1">
|
{{ playVideoHolders.text1 }}
|
</div>
|
</div>
|
|
<div class="item video2" v-show="videoShow">
|
<video-loading v-show="isShowVideoLoading.video2"></video-loading>
|
<div class="select" v-show="isShowSelect.video2">
|
<el-select size="small" v-model="monitor.type2" @change="((val) => { navClick(val, 2) })" placeholder="请选择"
|
ref="videoSelect2">
|
<el-option v-for="item in monitorOption" :key="item.value" :label="item.label" :value="item.value"
|
class="activity-video-option-css">
|
<div class="video-status" :style="{ background: (item.status == 0 ? '#adadad' : '#4ccc7d') }">
|
</div>
|
{{ item.label }}
|
</el-option>
|
</el-select>
|
</div>
|
<div class="video" v-show="isHaveMonitor.video2">
|
<video id="videoElement2" autoplay controls width="100%" height="100%" style="object-fit: fill"></video>
|
</div>
|
<div class="no-video" v-show="!isHaveMonitor.video2">
|
{{ playVideoHolders.text2 }}
|
</div>
|
</div>
|
|
<div class="item video3" v-show="videoShow">
|
<video-loading v-show="isShowVideoLoading.video3"></video-loading>
|
<div class="select" v-show="isShowSelect.video3">
|
<el-select size="small" v-model="monitor.type3" v-show="isShowSelect.video3"
|
@change="((val) => { navClick(val, 3) })" placeholder="请选择" ref="videoSelect3">
|
<el-option v-show="isShowSelect.video3" v-for="item in monitorOption" :key="item.value"
|
:label="item.label" :value="item.value" class="activity-video-option-css">
|
<div class="video-status" :style="{ background: (item.status == 0 ? '#adadad' : '#4ccc7d') }">
|
</div>
|
{{ item.label }}
|
</el-option>
|
</el-select>
|
</div>
|
<div class="video" v-show="isHaveMonitor.video3">
|
<video id="videoElement3" autoplay controls width="100%" height="100%" style="object-fit: fill"></video>
|
</div>
|
<div class="no-video" v-show="!isHaveMonitor.video3">
|
{{ playVideoHolders.text3 }}
|
</div>
|
</div>
|
|
<div class="item video4" v-show="videoShow">
|
<video-loading v-show="isShowVideoLoading.video4"></video-loading>
|
<div class="select" v-show="isShowSelect.video4">
|
<el-select size="small" v-model="monitor.type4" @change="((val) => { navClick(val, 4) })" placeholder="请选择"
|
ref="videoSelect4">
|
<el-option v-for="item in monitorOption" :key="item.value" :label="item.label" :value="item.value"
|
class="activity-video-option-css">
|
<div class="video-status" :style="{ background: (item.status == 0 ? '#adadad' : '#4ccc7d') }">
|
</div>
|
{{ item.label }}
|
</el-option>
|
</el-select>
|
</div>
|
<div class="video" v-show="isHaveMonitor.video4">
|
<video id="videoElement4" autoplay controls width="100%" height="100%" style="object-fit: fill"></video>
|
</div>
|
<div class="no-video" v-show="!isHaveMonitor.video4">
|
{{ playVideoHolders.text4 }}
|
</div>
|
</div>
|
|
<div class="deleteVideo" v-show="videoShow" @click="closeVideo">关闭</div>
|
</div>
|
</template>
|
|
<script>
|
let tc = null
|
let track = null
|
|
let flvListPlayer = {
|
flvPlayer1: null,
|
flvPlayer2: null,
|
flvPlayer3: null,
|
flvPlayer4: null,
|
}
|
|
import flvjs from 'flv.js'
|
|
import { getRegionList, getDevices } from '@/api/video/index.js'
|
|
export default {
|
data () {
|
return {
|
valChoosed: '',
|
argsChoosed: '',
|
|
monitorOption: [],
|
|
isHaveMonitor: {
|
video1: false,
|
video2: false,
|
video3: false,
|
video4: false,
|
},
|
|
monitor: {
|
type1: '',
|
type2: '',
|
type3: '',
|
type4: '',
|
},
|
|
isShowSelect: {
|
video1: true,
|
video2: true,
|
video3: true,
|
video4: true,
|
},
|
|
playVideoHolders: {
|
text1: '',
|
text2: '',
|
text3: '',
|
text4: '',
|
},
|
|
isShowVideoLoading: {
|
video1: false,
|
video2: false,
|
video3: false,
|
video4: false,
|
},
|
|
videoShow: false
|
}
|
},
|
|
mounted () {
|
this.$nextTick(() => {
|
tc = new global.DC.TrackController(global.viewer)
|
})
|
},
|
|
methods: {
|
/**
|
* @description: 轨迹点击弹窗中,查看视频
|
* @return {*}
|
*/
|
watchVideo (linePosition, polygonPosition) {
|
const that = this
|
|
const line = this.$turf.lineString(linePosition.split(';').filter(item => item != '').map(item => item.split(',').map(i => Number(i))))
|
// const lineLength = this.$turf.length(line) * 1000
|
const chunkLine = this.$turf.lineChunk(line, 0.1)
|
let arr = chunkLine.features.reduce((pre, cur) =>
|
pre.concat(cur.geometry.coordinates)
|
, []).map(item => item.join(','))
|
|
|
const time = arr.filter(item => arr.indexOf(item) == arr.lastIndexOf(item)).length * 16
|
const newPostion = arr.filter((item, index) => index == arr.lastIndexOf(item)).join(';')
|
|
this.getRegionList(polygonPosition)
|
this.videoShow = true
|
|
if (tc) {
|
tc.clear()
|
}
|
|
/**
|
* @description:
|
* @param {*} position 当前行驶位置信息
|
* @param {*} isLast 是否为最后一个点位
|
* @return {*}
|
*/
|
track = new global.DC.Track(newPostion, time, (position, isLast) => {
|
|
const carPosition = [position.lat, position.lng]
|
|
let distanceArr = []
|
|
that.monitorOption.forEach((item, index) => {
|
const itemPosition = [item.item.latitude, item.item.longitude]
|
|
var from = that.$turf.point(itemPosition)
|
var to = that.$turf.point(carPosition)
|
|
var distance = that.$turf.distance(from, to) * 1000
|
|
if (distance > that.lineWidth) {
|
distanceArr.push({
|
...item,
|
trackDistanceStatus: 0,
|
distance
|
})
|
} else {
|
|
distanceArr.push({
|
...item,
|
trackDistanceStatus: 1,
|
distance
|
})
|
}
|
|
})
|
|
distanceArr.sort((a, b) => a.distance < b.distance ? -1 : a.distance > b.distance ? 1 : 0)
|
|
distanceArr.forEach((item, index) => {
|
const ind = index + 1
|
|
if (index < 4) {
|
|
if (item.trackDistanceStatus == 1) {
|
this.monitor[`type${ind}`] = item.item.name
|
|
if (item.item.status == 1) {
|
this.isHaveMonitor[`video${ind}`] = true
|
|
getDevices(item.item.channelId).then(res => {
|
let flvAddress = ''
|
if ('data' in res.data) {
|
flvAddress = res.data.data.flv
|
} else {
|
flvAddress = 'nodata'
|
}
|
|
this.playVideoList(`flvPlayer${ind}`, `${flvAddress}`, `videoElement${ind}`, `${ind}`)
|
})
|
} else {
|
this.isHaveMonitor[`video${ind}`] = false
|
this.playVideoHolders[`text${ind}`] = '设备离线中……'
|
}
|
|
} else {
|
this.monitor[`type${ind}`] = ''
|
this.isHaveMonitor[`video${ind}`] = false
|
this.playVideoHolders[`text${ind}`] = '警车周边暂无设备……'
|
}
|
|
}
|
})
|
}, {
|
headingOffset: -90
|
})
|
|
track.setModel('/model/qiche.gltf', {
|
scale: 1.2
|
})
|
|
tc.addTrack(track)
|
},
|
|
// 遍历监控图标
|
initMonitoringIcon (monitoringList) {
|
monitoringList.forEach(item => {
|
this.$EventBus.$emit('layerPointAdd', {
|
layerName: 'monitoringLayers',
|
type: "billboard",
|
params: {
|
name: item.name,
|
lng: item.longitude,
|
lat: item.latitude,
|
alt: 1,
|
url: '/img/icon/video.png',
|
},
|
})
|
})
|
},
|
|
/**
|
* @description: 获取视频播放列表
|
* @param {*} positionNewStr
|
* @return {*}
|
*/
|
getRegionList (positionNewStr) {
|
getRegionList({ page: 1, count: 15, range: positionNewStr }).then(res => {
|
let monitorData = res.data.data.list
|
this.initMonitoringIcon(monitorData)
|
this.monitorOption = []
|
monitorData.forEach((item, index) => {
|
|
this.monitorOption.push({ value: `${index}`, label: `${item.name}`, status: `${item.status}`, item })
|
|
if (index < 4) {
|
const ind = index + 1
|
|
this.monitor[`type${ind}`] = item.name
|
|
if (item.status == 1) {
|
this.isHaveMonitor[`video${ind}`] = true
|
this.isShowVideoLoading[`video${ind}`] = true
|
|
getDevices(item.channelId).then(res => {
|
let flvAddress = ''
|
if ('data' in res.data) {
|
flvAddress = res.data.data.flv
|
} else {
|
flvAddress = 'nodata'
|
}
|
|
this.playVideoList(`flvPlayer${ind}`, `${flvAddress}`, `videoElement${ind}`)
|
})
|
} else {
|
this.isHaveMonitor[`video${ind}`] = false
|
this.playVideoHolders[`text${ind}`] = '设备离线中……'
|
}
|
|
}
|
|
})
|
})
|
},
|
|
/**
|
* @description: 轨迹开始
|
* @return {*}
|
*/
|
play () {
|
// polylineAreaLayer.show = true
|
tc.play()
|
this.view('1', -20, 400)
|
},
|
|
playVideoList (flvItemPlayer, flvUrl, videoEleName, index) {
|
if (flvListPlayer[flvItemPlayer] != null) {
|
flvListPlayer[flvItemPlayer].pause()
|
flvListPlayer[flvItemPlayer].unload()
|
flvListPlayer[flvItemPlayer].detachMediaElement()
|
flvListPlayer[flvItemPlayer].destroy()
|
flvListPlayer[flvItemPlayer] = null
|
}
|
|
if (flvjs.isSupported() && flvUrl != 'nodata') {
|
this.isShowVideoLoading[`video${index}`] = false
|
let videoElement = document.getElementById(videoEleName)
|
flvListPlayer[flvItemPlayer] = flvjs.createPlayer({
|
type: 'flv',
|
isLive: true,
|
hasAudio: false,
|
url: flvUrl
|
})
|
flvListPlayer[flvItemPlayer].attachMediaElement(videoElement)
|
flvListPlayer[flvItemPlayer].load()
|
flvListPlayer[flvItemPlayer].play()
|
}
|
},
|
|
// 暂停播放轨迹
|
pause () {
|
tc.pause()
|
},
|
|
// 恢复播放轨迹
|
restore () {
|
tc.restore()
|
},
|
|
// 轨迹视角切换
|
view (mode, pitch, range) {
|
tc.viewTrack(track, {
|
mode: mode,
|
pitch: pitch,
|
range: range
|
})
|
},
|
|
// 关闭视频展示
|
closeVideo () {
|
if (this.videoShow == false) return
|
this.videoShow = false
|
|
for (let i = 1; i < 5; i++) {
|
if (flvListPlayer[i] != null) {
|
flvListPlayer[i].pause()
|
flvListPlayer[i].unload()
|
flvListPlayer[i].detachMediaElement()
|
flvListPlayer[i].destroy()
|
flvListPlayer[i] = null
|
}
|
}
|
|
this.$EventBus.$emit('mapClearLayer', {
|
layerName: 'monitoringLayers',
|
type: 'VectorLayer'
|
})
|
|
if (tc) {
|
tc.clear()
|
}
|
},
|
|
navClick (val, args) {
|
if (this.valChoosed == val && this.argsChoosed == args) return
|
this.valChoosed = val
|
this.argsChoosed = args
|
|
this.monitor[`type${args}`] = this.monitorOption[val].item.name
|
|
if (this.monitorOption[val].item.status == 1) {
|
this.isHaveMonitor[`video${args}`] = true
|
this.isShowVideoLoading[`video${args}`] = true
|
|
getDevices(this.monitorOption[val].item.channelId).then(res => {
|
let flvAddress = ''
|
if ('data' in res.data) {
|
flvAddress = res.data.data.flv
|
} else {
|
flvAddress = 'nodata'
|
}
|
|
this.playVideoList(`flvPlayer${args}`, `${flvAddress}`, `videoElement${args}`, `${args}`)
|
})
|
|
} else {
|
this.isHaveMonitor[`video${args}`] = false
|
this.playVideoHolders[`text${args}`] = '设备离线中…'
|
}
|
},
|
},
|
|
destroyed () {
|
this.closeVideo()
|
|
this.$EventBus.$emit('mapRemoveLayer', {
|
layerName: 'monitoringLayers',
|
type: 'VectorLayer'
|
})
|
|
tc = null
|
},
|
}
|
</script>
|
|
<style lang="scss" scoped>
|
.btn-box {
|
position: fixed;
|
// bottom: calc(360 / 1080 * 100vh);
|
// position: absolute;
|
top: calc(680 / 1080 * 100vh);
|
// left: 50%;
|
left: calc(780 / 1920 * 100vw);
|
// transform: translate(-40%, 0);
|
z-index: 100;
|
min-height: 40px;
|
padding: 10px 10px 0 10px;
|
white-space: nowrap;
|
border-radius: 10px;
|
color: #fff;
|
user-select: none;
|
|
ul {
|
display: flex;
|
|
li {
|
button {
|
height: 30px;
|
margin: 0 5px;
|
background-color: $bg-color;
|
border: 1px solid #cecece;
|
border-radius: 4px;
|
color: #fff;
|
cursor: pointer;
|
outline: none;
|
}
|
}
|
}
|
}
|
|
.item {
|
background-color: $bg-color;
|
// position: absolute;
|
position: fixed;
|
z-index: 100;
|
width: calc((1920 - 400) / 4 / 1920 * 100vw);
|
height: calc((1080 - 60) / 3 / 1080 * 100vh);
|
top: calc(740 / 1080 * 100vh);
|
|
.select {
|
position: absolute;
|
top: 6%;
|
width: 100%;
|
z-index: 999;
|
}
|
|
.video {
|
height: 100%;
|
padding: 1%;
|
}
|
|
.no-video {
|
// color: #fff;
|
// font-size: 32px;
|
// letter-spacing: 4px;
|
// width: 98%;
|
// height: 98%;
|
// background-color: rgba(0, 0, 0, 0.7);
|
// margin: 1%;
|
// display: flex;
|
// align-items: center;
|
// justify-content: center;
|
position: absolute;
|
color: #eee;
|
letter-spacing: 2px;
|
font-size: 24px;
|
width: 100%;
|
text-align: center;
|
top: 40%;
|
}
|
}
|
|
.video1 {
|
left: calc(400 / 1920 * 100vw);
|
|
.video {
|
padding: 1% 0 1% 1%;
|
}
|
|
.no-video {
|
margin: 1% 0 1% 1%;
|
}
|
}
|
|
.video2 {
|
left: calc(780 / 1920 * 100vw);
|
|
.video {
|
padding: 1% 0 1% 1%;
|
}
|
|
.no-video {
|
margin: 1% 0 1% 1%;
|
}
|
}
|
|
.video3 {
|
left: calc(1160 / 1920 * 100vw);
|
|
.video {
|
padding: 1% 0 1% 1%;
|
}
|
|
.no-video {
|
margin: 1% 0 1% 1%;
|
}
|
}
|
|
.video4 {
|
left: calc(1540 / 1920 * 100vw);
|
}
|
|
.video1-new-left {
|
left: 0;
|
}
|
|
.video2-new-left {
|
left: 25vw;
|
}
|
|
.video3-new-left {
|
left: 50vw;
|
}
|
|
.video4-new-left {
|
left: 75vw;
|
}
|
|
.deleteVideo {
|
// position: absolute;
|
position: fixed;
|
width: 60px;
|
height: 26px;
|
line-height: 26px;
|
color: #fff;
|
background-color: $bg-color;
|
left: calc(1860 / 1920 * 100vw);
|
top: calc(710 / 1080 * 100vh);
|
cursor: pointer;
|
z-index: 100;
|
}
|
</style>
|