1
shuishen
2023-03-07 7d5ea484115e9afc35a38a3b5e7534ed3a5d1054
1
2 files modified
1 files added
1253 ■■■■ changed files
src/components/map/index.vue 14 ●●●●● patch | view | raw | blame | history
src/views/activity/components/videoControlBox.vue 626 ●●●●● patch | view | raw | blame | history
src/views/activity/index.vue 613 ●●●●● patch | view | raw | blame | history
src/components/map/index.vue
@@ -2,7 +2,7 @@
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2022-08-18 17:00:30
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2023-03-06 16:06:57
 * @LastEditTime: 2023-03-07 10:47:48
 * @FilePath: \srs-police-affairs\src\components\map\index.vue
 * @Description: 公用地图组件
 * 
@@ -528,10 +528,11 @@
         * @return {*}
         */
        highOrLightChange (type) {
            this.removeMxTileset('sdTilesetLayer', this.housingIndent)
            label.forEach(item => {
                this.removeMxTileset(`sdTilesetLayer${item}`, this.housingIndent)
            })
            // this.addMxTileset('sdTilesetLayer', `${tile3DUrl}/sf3d/361102/model/wanda/tileset.json`, this.housingIndent)
            if (this.tilesetLayerType == type) {
                this.tilesetLayerType = ''
@@ -541,10 +542,10 @@
                type == 'light' ?
                    label.forEach(item => {
                        this.addMxTileset('sdTilesetLayer', `${tile3DUrl}/sf3d/361102/model/all/${item}/tileset.json`, this.housingIndent)
                        this.addMxTileset(`sdTilesetLayer${item}`, `${tile3DUrl}/sf3d/361102/model/all/${item}/tileset.json`, this.housingIndent)
                    }) :
                    label.forEach(item => {
                        this.addMxTileset('sdTilesetLayer', `${tile3DUrl}/sf3d/361102/model/all1/${item}/tileset.json`, this.housingIndent)
                        this.addMxTileset(`sdTilesetLayer${item}`, `${tile3DUrl}/sf3d/361102/model/all1/${item}/tileset.json`, this.housingIndent)
                    })
            }
@@ -939,10 +940,11 @@
            tilesetObject[titlesetName].setHeight(-72)
            tilesetObject[titlesetName].on(global.DC.MouseEventType.CLICK, incident)
            tilesetLayer.addOverlay(tilesetObject[titlesetName])
            // global.viewer.flyTo(tilesetObject[titlesetName])
            tilesetObject[titlesetName].on(global.DC.MouseEventType.CLICK, incident)
        },
        /**
src/views/activity/components/videoControlBox.vue
New file
@@ -0,0 +1,626 @@
<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 = undefined
let track = undefined
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 {
    props: ['linePosition'],
    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 () {
            const that = this
            const line = this.$turf.lineString(this.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(this.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}`] = '警车周边暂无设备……'
                        }
                    }
                })
            })
            track.setModel('/model/qiche.gltf', {
                scale: 0.8
            })
            tc.addTrack(track)
            this.$parent.lineEditVisible = false
        },
        // 遍历监控图标
        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'
        })
        if (tc) {
            tc.remove()
        }
    },
}
</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>
src/views/activity/index.vue
@@ -2,7 +2,7 @@
 * @Author: shuishen 1109946754@qq.com
 * @Date: 2022-08-18 16:18:17
 * @LastEditors: shuishen 1109946754@qq.com
 * @LastEditTime: 2023-03-06 17:39:12
 * @LastEditTime: 2023-03-07 10:35:40
 * @FilePath: \srs-police-affairs\src\views\activity\index.vue
 * @Description: 安保活
 *
@@ -83,6 +83,8 @@
        <map-search-box></map-search-box>
        <video-control-box ref="VIDEOCONTROLBOX" :linePosition="linePosition"></video-control-box>
        <div class="plan-control" v-show="dialogVisible && (isHavePolice || isHaveArrow || isHaveLine)">
            <div class="row-box" v-show="isHavePolice">
                <div class="category">警力资源:</div>
@@ -99,6 +101,7 @@
                        inactive-color="#ccc"></el-switch>
                </div>
            </div>
            <div class="row-box" v-show="isHaveLine">
                <div class="category">巡逻路线:</div>
                <div class="category-value">
@@ -107,122 +110,6 @@
                </div>
            </div>
        </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>
            <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>
        <el-dialog :title="policeChooseCarTitle" :modal="false" :visible.sync="policeChooseCarVisible"
            :before-close="policeChooseCarBeforeClose" :close-on-click-modal="true" class="choose-policeCar-box">
@@ -287,7 +174,7 @@
                </div>
            </div>
            <div class="edit-line-btn-box">
                <el-button @click="watchVideo" v-show="isLineEdit">查看视频</el-button>
                <el-button @click="lookStartVideo" v-show="isLineEdit">查看视频</el-button>
                <el-button @click="editLineInfo" v-show="isLineEdit">编辑</el-button>
                <el-button @click="saveLineInfo" v-show="isLineEdit">保存</el-button>
                <el-button @click="deleteLine" v-show="isLineEdit">删除</el-button>
@@ -356,12 +243,12 @@
<script>
import { getSecurityList, getPoliceList, getCarList, addCarAndRange, addActivityPolice, getSecurityPoliceList, getSecurityCarList, updateActivityPolice, getServiceDictionary, getActivityType, addSecurityPlot, getSecurityPlotList, deleteActivityCar, deleteActivityPolice, deleteSecurityPlot, getSearchInfo, getPolicemanTree } from '@/api/activity/index.js'
import { getRegionList, getDevices } from '@/api/video/index.js'
import { getEquipmentAll } from '@/api/home/index.js'
import flvjs from 'flv.js'
import activityDetail from './components/activityDetail.vue'
import drawBtnBox from './components/drawBtnBox.vue'
import mapSearchBox from './components/mapSearchBox.vue'
import videoControlBox from './components/videoControlBox.vue'
let polylineAreaLayer = null
let arrowsListLayer = null
@@ -369,8 +256,6 @@
let pointCircleCarLayer = null
let lineLayer = undefined
let tc = undefined
let track = undefined
let loading = null
export default {
@@ -526,44 +411,9 @@
            isHaveLine: false,
            //当前登录用户的数据
            userInfo: {},
            monitorOption: [],
            monitor: {
                type1: '',
                type2: '',
                type3: '',
                type4: '',
            },
            isShowSelect: {
                video1: true,
                video2: true,
                video3: true,
                video4: true,
            },
            flvListPlayer: {
                flvPlayer1: null,
                flvPlayer2: null,
                flvPlayer3: null,
                flvPlayer4: null,
            },
            isHaveMonitor: {
                video1: false,
                video2: false,
                video3: false,
                video4: false,
            },
            playVideoHolders: {
                text1: '',
                text2: '',
                text3: '',
                text4: '',
            },
            valChoosed: '',
            argsChoosed: '',
            isShowActivityClearBtn: false,
            videoShow: false,
            lineEditVisible: false,
            lineEditTitle: '修改巡逻路线',
            polygonAddTitle: '新增标绘',
@@ -615,12 +465,7 @@
                'hsla(209, 100%, 56%)',
                '#c7158577'
            ],
            isShowVideoLoading: {
                video1: false,
                video2: false,
                video3: false,
                video4: false,
            },
            polygonAreaType: 1,
            polygonAreaOption: [{
                value: 1,
@@ -634,7 +479,7 @@
        }
    },
    components: { activityDetail, drawBtnBox, mapSearchBox },
    components: { activityDetail, drawBtnBox, mapSearchBox, videoControlBox },
    created () {
        let userInfo = sessionStorage.getItem("userInfo")
@@ -687,17 +532,6 @@
                global.viewer.addLayer(polylineAreaLayer)
            }
            tc = new global.DC.TrackController(global.viewer)
            // 轨迹
            // let positions = "116.023042, 28.684732; 116.023402, 28.679067; 116.023475, 28.678843; 116.023697, 28.678647; 116.024121, 28.678391; 116.026906, 28.678461; 116.027065, 28.676867; 116.033252, 28.676165"
            // tc = new global.DC.TrackController(global.viewer)
            // track = new global.DC.Track(positions, 15)
            // track.setModel('/model/qiche.gltf', {
            //     scale: 0.5
            // })
            // tc.addTrack(track)
        })
    },
@@ -705,6 +539,10 @@
    },
    methods: {
        lookStartVideo () {
            this.$refs.VIDEOCONTROLBOX.watchVideo()
        },
        loading () {
            loading = this.$loading({
                lock: true,
@@ -942,7 +780,6 @@
                        coords.forEach(item => {
                            positionStr += item[0] + ',' + item[1] + ';'
                        })
                        // this.getRegionList(positionStr)
                        let lineObj = new global.DC.Polyline(positionNewArr)
                        lineLayer.addOverlay(lineObj)
                        lineObj.setStyle({
@@ -1257,7 +1094,7 @@
                type: 'VectorLayer'
            })
            this.$EventBus.$emit('mapRemoveLayer', {
            this.$EventBus.$emit('mapClearLayer', {
                layerName: 'monitoringLayers',
                type: 'VectorLayer'
            })
@@ -1363,35 +1200,10 @@
            }
        },
        /**
         * @description: 轨迹开始
         * @return {*}
         */
        play () {
            // polylineAreaLayer.show = true
            tc.play()
            this.view('1', -20, 400)
        },
        // 暂停播放轨迹
        pause () {
            tc.pause()
        },
        // 恢复播放轨迹
        restore () {
            tc.restore()
        },
        // 轨迹视角切换
        view (mode, pitch, range) {
            tc.viewTrack(track, {
                mode: mode,
                pitch: pitch,
                range: range
            })
        },
        // 大小重置
        boxResize (val) {
@@ -1541,13 +1353,16 @@
        // 巡逻路线面点击事件
        lineOverlayTypeClick (e) {
            this.videoShow = false
            this.$refs.VIDEOCONTROLBOX.closeVideo()
            this.lineWidth = e.overlay.attrParams.width != -1 ? e.overlay.attrParams.width : 100
            this.chooseColor = e.overlay.attrParams.color != '' ? e.overlay.attrParams.color : '#1CA085'
            this.policeIconId = e.overlay.attrParams.id
            this.linePosition = e.overlay.attrParams.linePositionStr
            this.lineObjdata = e.overlay.attrParams.lineObj
            this.polygonPosition = e.overlay.attrParams.polygonPositionStr
            if (this.userInfo.dept_id == '1123598813738675201' || this.userInfo.dept_id == this.activityDeptId) {
                this.lineEditTitle = '修改巡逻路线'
                this.isLineEdit = true
@@ -1555,10 +1370,6 @@
            } else {
                this.lineEditVisible = false
            }
            this.$EventBus.$emit('mapRemoveLayer', {
                layerName: 'monitoringLayers',
                type: 'VectorLayer'
            })
        },
        // 保存活动标绘箭头
@@ -1775,225 +1586,10 @@
            this.searchClick()
        },
        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}`] = '设备离线中…'
            }
        },
        /**
         * @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}`] = '设备离线中……'
                        }
                    }
                })
            })
        },
        // 关闭视频展示
        closeVideo () {
            this.videoShow = false
            this.$EventBus.$emit('mapRemoveLayer', {
                layerName: 'monitoringLayers',
                type: 'VectorLayer'
            })
            if (tc) {
                tc.clear()
            }
        },
        playVideoList (flvItemPlayer, flvUrl, videoEleName, index) {
            console.log('flvUrl', flvUrl)
            if (this.flvListPlayer[flvItemPlayer] != null) {
                this.flvListPlayer[flvItemPlayer].pause()
                this.flvListPlayer[flvItemPlayer].unload()
                this.flvListPlayer[flvItemPlayer].detachMediaElement()
                this.flvListPlayer[flvItemPlayer].destroy()
                this.flvListPlayer[flvItemPlayer] = null
            }
            if (flvjs.isSupported() && flvUrl != 'nodata') {
                this.isShowVideoLoading[`video${index}`] = false
                let videoElement = document.getElementById(videoEleName)
                this.flvListPlayer[flvItemPlayer] = flvjs.createPlayer({
                    type: 'flv',
                    isLive: true,
                    hasAudio: false,
                    url: flvUrl
                })
                this.flvListPlayer[flvItemPlayer].attachMediaElement(videoElement)
                this.flvListPlayer[flvItemPlayer].load()
                this.flvListPlayer[flvItemPlayer].play()
            }
        },
        /**
         * @description: 轨迹点击弹窗中,查看视频
         * @return {*}
         */
        watchVideo () {
            const line = this.$turf.lineString(this.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(this.polygonPosition)
            this.videoShow = true
            if (tc) {
                tc.clear()
            }
            /**
             * @description:
             * @param {*} position 当前行驶位置信息
             * @param {*} isLast 是否为最后一个点位
             * @return {*}
             */
            track = new global.DC.Track(newPostion, time, (position, isLast) => {
                console.log(position, 65555)
                const carPosition = [position.lat, position.lng]
                let distanceArr = []
                this.monitorOption.forEach((item, index) => {
                    const itemPosition = [item.item.latitude, item.item.longitude]
                    var from = this.$turf.point(itemPosition)
                    var to = this.$turf.point(carPosition)
                    var distance = this.$turf.distance(from, to) * 1000
                    if (distance > this.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) {
                        console.log(item, 123)
                        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}`] = '警车周边暂无设备……'
                        }
                    }
                })
            })
            track.setModel('/model/qiche.gltf', {
                scale: 0.8
            })
            tc.addTrack(track)
            this.lineEditVisible = false
        },
        // 保存巡逻路线信息
        saveLineInfo () {
@@ -2007,22 +1603,7 @@
            this.cancelSaveLine()
        },
        // 遍历监控图标
        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',
                    },
                })
            })
        },
        // 修改巡逻路线位置信息
        editLineInfo () {
@@ -2263,11 +1844,6 @@
        })
        this.$EventBus.$emit('mapRemoveLayer', {
            layerName: 'monitoringLayers',
            type: 'VectorLayer'
        })
        this.$EventBus.$emit('mapRemoveLayer', {
            layerName: 'activeHeatLayer',
            type: 'HeatLayer'
        })
@@ -2309,9 +1885,7 @@
        }
        this.$refs.DRAWBTNBOX.removeDraw()
        this.$refs.DRAWBTNBOX.removeDrawArrow()
        if (tc) {
            tc.remove()
        }
        if (polylineAreaLayer) {
            polylineAreaLayer.remove()
        }
@@ -2562,156 +2136,11 @@
        }
    }
    .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%;
        }
    }
    .item-new-width {
        width: 25vw;
    }
    .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>