视频轮询功能
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
# 生产环境
|
# 生产环境
|
||||||
NODE_ENV = 'production'
|
NODE_ENV = 'production'
|
||||||
# 渔船点位
|
# 渔船点位
|
||||||
VITE_WS_BASE_URL ='ws://100.95.225.221:6810/api/gisWs'
|
VITE_WS_BASE_URL ='ws://198.16.74.211:6060/video-service/SowWs/123'
|
||||||
|
|
||||||
VITE_APP_BASE_URL = 'http://198.16.74.211:7284/api'
|
VITE_APP_BASE_URL = 'http://198.16.74.211:7284/api'
|
||||||
# 智能体访问地址
|
# 智能体访问地址
|
||||||
|
|||||||
Binary file not shown.
@@ -72,4 +72,20 @@ export const findEnvPage = (data) => {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
// 视频监控详情信息
|
||||||
|
export const getVideoInfo = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/fishingPort/dsVideo/getVideoInfo',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 巡检报告导出
|
||||||
|
export const cctvExport = (data) => {
|
||||||
|
return request({
|
||||||
|
url: '/pollExport/cctvExport',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
}
|
}
|
||||||
@@ -24,6 +24,7 @@ const props = defineProps({
|
|||||||
let player = null
|
let player = null
|
||||||
let flag = 0
|
let flag = 0
|
||||||
let retryCount = 0
|
let retryCount = 0
|
||||||
|
let timeoutId = null
|
||||||
const MAX_RETRIES = 30
|
const MAX_RETRIES = 30
|
||||||
const initPlayer = () => {
|
const initPlayer = () => {
|
||||||
if (flvjs.isSupported()) {
|
if (flvjs.isSupported()) {
|
||||||
@@ -45,34 +46,28 @@ const initPlayer = () => {
|
|||||||
url: url
|
url: url
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// // 启用IO隐藏缓冲区
|
// 启用IO隐藏缓冲区
|
||||||
// // 如果需要实时(最小延迟)来进行实时流播放,则设置为false
|
// 如果需要实时(最小延迟)来进行实时流播放,则设置为false
|
||||||
// // 但是如果网络抖动,则可能会停顿
|
// 但是如果网络抖动,则可能会停顿
|
||||||
// enableStashBuffer: false,
|
enableStashBuffer: false,
|
||||||
// // 之时IO暂存缓冲区的初始大小,默认值为384kb,指出合适的尺寸可以改善视频负载/搜索时间
|
// 之时IO暂存缓冲区的初始大小,默认值为384kb,指出合适的尺寸可以改善视频负载/搜索时间
|
||||||
// stashInitialSize: 128
|
stashInitialSize: 128
|
||||||
|
|
||||||
// 启用缓冲区优化
|
|
||||||
enableStashBuffer: true, // 改为true启用缓冲
|
|
||||||
stashInitialSize: 1024 * 1024, // 设置初始缓冲大小
|
|
||||||
maxBufferLength: 30 // 最大缓冲时长(秒)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
player.attachMediaElement(videoElement)
|
player.attachMediaElement(videoElement)
|
||||||
player.load()
|
player.load()
|
||||||
player.play()
|
player.play()
|
||||||
console.log('player play')
|
|
||||||
flag += 1
|
flag += 1
|
||||||
|
|
||||||
player.on('error', () => {
|
player.on('error', () => {
|
||||||
console.log('errorrrrrrrrrrrrrrrrrrrrrrrr')
|
|
||||||
clear()
|
clear()
|
||||||
// 重试次数增加,延长时间指数增长,不超过10s
|
// 重试次数增加,延长时间指数增长,不超过10s
|
||||||
const retryDelay = Math.min(10000, 1000 * Math.pow(2, retryCount))
|
const retryDelay = Math.min(10000, 1000 * Math.pow(2, retryCount))
|
||||||
retryCount++
|
retryCount++
|
||||||
|
|
||||||
setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
|
timeoutId = null
|
||||||
console.log(retryCount, retryDelay, '重连次数......')
|
console.log(retryCount, retryDelay, '重连次数......')
|
||||||
if (retryCount <= MAX_RETRIES) {
|
if (retryCount <= MAX_RETRIES) {
|
||||||
initPlayer() // 重新初始化播放器
|
initPlayer() // 重新初始化播放器
|
||||||
@@ -90,6 +85,10 @@ const initPlayer = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const clear = () => {
|
const clear = () => {
|
||||||
|
if (timeoutId) {
|
||||||
|
clearTimeout(timeoutId)
|
||||||
|
timeoutId = null
|
||||||
|
}
|
||||||
if (player) {
|
if (player) {
|
||||||
player.pause()
|
player.pause()
|
||||||
player.destroy()
|
player.destroy()
|
||||||
|
|||||||
@@ -13,18 +13,16 @@
|
|||||||
<TrawlerInfoWindowComponent/>
|
<TrawlerInfoWindowComponent/>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onMounted, onUnmounted, watch } from 'vue'
|
import { computed, nextTick, onMounted, onUnmounted, watch } from 'vue'
|
||||||
import * as maptalks from 'maptalks'
|
import * as maptalks from 'maptalks'
|
||||||
import GlobalMap from './js/GlobalMap'
|
import GlobalMap from './js/GlobalMap'
|
||||||
import useMapStore from '@/store/modules/map'
|
import useMapStore from '@/store/modules/map'
|
||||||
import { getAssetsFile } from '@/utils/common'
|
|
||||||
import * as BoatUtil from './lbtbox/boatTerminal'
|
import * as BoatUtil from './lbtbox/boatTerminal'
|
||||||
import * as $configs from './map-config.js'
|
import * as $configs from './map-config.js'
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
import { monitors, uavs, stations, environmentals, fences, detailFences } from './js/mock.js'
|
import { monitors, uavs, stations, environmentals, fences, detailFences } from './js/mock.js'
|
||||||
import InfoWindowComponent from '@/components/Map/window/index.vue'
|
import InfoWindowComponent from '@/components/Map/window/index.vue'
|
||||||
import TrawlerInfoWindowComponent from '@/components/Map/window/trawler.vue'
|
import TrawlerInfoWindowComponent from '@/components/Map/window/trawler.vue'
|
||||||
import { dsVideoList, findUavPage, findEnvPage } from '@/api/device.js'
|
import { dsVideoList, findUavPage, getVideoInfo } from '@/api/device.js'
|
||||||
|
|
||||||
const mapStore = useMapStore()
|
const mapStore = useMapStore()
|
||||||
const UAV = computed(() => mapStore.legend.UAV)
|
const UAV = computed(() => mapStore.legend.UAV)
|
||||||
@@ -34,6 +32,7 @@ const ais_station = computed(() => mapStore.legend.ais_station)
|
|||||||
const environmental = computed(() => mapStore.legend.environmental)
|
const environmental = computed(() => mapStore.legend.environmental)
|
||||||
const fence = computed(() => mapStore.legend.fence)
|
const fence = computed(() => mapStore.legend.fence)
|
||||||
const sector = computed(() => mapStore.sector)
|
const sector = computed(() => mapStore.sector)
|
||||||
|
const locateData = computed(() => mapStore.locate.data)
|
||||||
let globalMap = null
|
let globalMap = null
|
||||||
let vector = {}
|
let vector = {}
|
||||||
const geography = {
|
const geography = {
|
||||||
@@ -118,7 +117,9 @@ const addMonitorToMap = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
marker.addTo(vector.monitor)
|
marker.addTo(vector.monitor)
|
||||||
drawSector('_monitor', [ item.longitude, item.latitude ], 5 * 1000, item.id, 30)
|
const visionDistance = item.visionDistance * 1000 || 5 * 1000
|
||||||
|
const pvalue = item.ptzcfg?.pValue || 0
|
||||||
|
drawSector('_monitor', [ item.longitude, item.latitude ], visionDistance, item.id, (90 - pvalue) % 360)
|
||||||
marker.on('click', (evt) => {
|
marker.on('click', (evt) => {
|
||||||
// 先隐藏所有扇形
|
// 先隐藏所有扇形
|
||||||
changeSectorsInLayer('sectors_monitor', false)
|
changeSectorsInLayer('sectors_monitor', false)
|
||||||
@@ -130,24 +131,63 @@ const addMonitorToMap = () => {
|
|||||||
|
|
||||||
// 显示当前点击项的所有相关扇形(圆、椭圆、线)
|
// 显示当前点击项的所有相关扇形(圆、椭圆、线)
|
||||||
const baseId = `sector__monitor${item.id}`
|
const baseId = `sector__monitor${item.id}`
|
||||||
const circleGeometry = vector.sectors_monitor.getGeometryById(baseId + '_circle')
|
vector.sectors_monitor.getGeometryById(baseId + '_circle')?.show()
|
||||||
const ellipseGeometry = vector.sectors_monitor.getGeometryById(baseId + '_ellipse')
|
vector.sectors_monitor.getGeometryById(baseId + '_ellipse')?.show()
|
||||||
const lineGeometry = vector.sectors_monitor.getGeometryById(baseId + '_line')
|
vector.sectors_monitor.getGeometryById(baseId + '_line')?.show()
|
||||||
|
|
||||||
if (circleGeometry) {
|
|
||||||
circleGeometry.show()
|
|
||||||
}
|
|
||||||
if (ellipseGeometry) {
|
|
||||||
ellipseGeometry.show()
|
|
||||||
}
|
|
||||||
if (lineGeometry) {
|
|
||||||
lineGeometry.show()
|
|
||||||
}
|
|
||||||
mapStore.updateWindowInfo({ visible: true, type: '_monitor', data: { ...item } })
|
mapStore.updateWindowInfo({ visible: true, type: '_monitor', data: { ...item } })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
vector.monitor.show()
|
vector.monitor.show()
|
||||||
|
}
|
||||||
|
// 要素/视频定位
|
||||||
|
const locateMoitor = (data) => {
|
||||||
|
const name = 'locate-monitor'
|
||||||
|
let layer = vector[name]
|
||||||
|
if (!layer) {
|
||||||
|
initLayerToMap('locate-monitor')
|
||||||
|
layer = vector['locate-monitor']
|
||||||
|
} else {
|
||||||
|
layer.clear()
|
||||||
|
}
|
||||||
|
const monitors = vector.monitor
|
||||||
|
const marker = monitors.getGeometryById(data.id)
|
||||||
|
if (marker) {
|
||||||
|
const coordinates = marker.getCoordinates()
|
||||||
|
geography.monitor.forEach((item) => {
|
||||||
|
if (item.id === data.id) {
|
||||||
|
// globalMap.map.animateTo(
|
||||||
|
// {
|
||||||
|
// center: [ coordinates.x, coordinates.y ]
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// duration: 1000 * 0.5,
|
||||||
|
// easing: 'out'
|
||||||
|
// }
|
||||||
|
// )
|
||||||
|
// 先隐藏所有扇形
|
||||||
|
changeSectorsInLayer('sectors_monitor', false)
|
||||||
|
getVideoInfo({ id: item.id }).then(res => {
|
||||||
|
const visionDistance = item.visionDistance * 1000 || 5 * 1000 // 视角距离
|
||||||
|
const pvalue = res.data.ptzcfg.pValue || 0 // 旋转角度
|
||||||
|
drawSector('_monitor', [ item.longitude, item.latitude ], visionDistance, item.id, (90 - pvalue) % 360)
|
||||||
|
|
||||||
|
// 确保扇形图层是可见的
|
||||||
|
if (!vector.sectors_monitor.isVisible()) {
|
||||||
|
vector.sectors_monitor.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 显示当前点击项的所有相关扇形(圆、椭圆、线)
|
||||||
|
const baseId = `sector__monitor${item.id}`
|
||||||
|
vector.sectors_monitor.getGeometryById(baseId + '_circle')?.show()
|
||||||
|
vector.sectors_monitor.getGeometryById(baseId + '_ellipse')?.show()
|
||||||
|
vector.sectors_monitor.getGeometryById(baseId + '_line')?.show()
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 叠加无人机数据
|
* 叠加无人机数据
|
||||||
@@ -189,7 +229,7 @@ const addUAVToMap = () => {
|
|||||||
if (circleGeometry) {
|
if (circleGeometry) {
|
||||||
circleGeometry.show()
|
circleGeometry.show()
|
||||||
}
|
}
|
||||||
if(item.sourceType) {
|
if(item.sourceType === '1' || item.sourceType === '2') {
|
||||||
mapStore.updateWindowInfo({ visible: true, type: '_UAV', data: { ...item } })
|
mapStore.updateWindowInfo({ visible: true, type: '_UAV', data: { ...item } })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -212,18 +252,29 @@ const changeSectorsInLayer = (layerName, show) => {
|
|||||||
}
|
}
|
||||||
// 需要监控的起始角度和结束角度,修改视野范围可以传递经纬度坐标
|
// 需要监控的起始角度和结束角度,修改视野范围可以传递经纬度坐标
|
||||||
const drawSector = (type, center, radius, id, angle) => {
|
const drawSector = (type, center, radius, id, angle) => {
|
||||||
|
const sectorLayerName = 'sectors' + type
|
||||||
|
|
||||||
|
// 检查是否存在扇形图层,不存在则初始化
|
||||||
|
if (!vector[sectorLayerName]) {
|
||||||
|
initLayerToMap(sectorLayerName.replace('sectors', 'sectors_')) // 例如 sectors_monitor -> sectors_monitor
|
||||||
|
}
|
||||||
|
|
||||||
const sectorId = `sector_${type}${id}`
|
const sectorId = `sector_${type}${id}`
|
||||||
|
|
||||||
// 如果已存在同ID的扇形,则先移除
|
// 如果已存在同ID的扇形,则先移除
|
||||||
const existingSector = vector['sectors' + type].getGeometryById(sectorId)
|
const existingCircle = vector[sectorLayerName].getGeometryById(sectorId + '_circle')
|
||||||
if (existingSector) {
|
const existingEllipse = vector[sectorLayerName].getGeometryById(sectorId + '_ellipse')
|
||||||
vector['sectors' + type].removeGeometry(existingSector)
|
const existingLine = vector[sectorLayerName].getGeometryById(sectorId + '_line')
|
||||||
}
|
|
||||||
|
|
||||||
// 如果已有该监控点的扇形图层,则先移除
|
if (existingCircle) {
|
||||||
if (globalMap.map.getLayer(sectorId)) {
|
vector[sectorLayerName].removeGeometry(existingCircle)
|
||||||
globalMap.map.getLayer(sectorId).remove()
|
}
|
||||||
|
if (existingEllipse) {
|
||||||
|
vector[sectorLayerName].removeGeometry(existingEllipse)
|
||||||
|
}
|
||||||
|
if (existingLine) {
|
||||||
|
vector[sectorLayerName].removeGeometry(existingLine)
|
||||||
}
|
}
|
||||||
|
|
||||||
let circle = new maptalks.Circle(center, radius, {
|
let circle = new maptalks.Circle(center, radius, {
|
||||||
id: sectorId + '_circle',
|
id: sectorId + '_circle',
|
||||||
symbol: {
|
symbol: {
|
||||||
@@ -234,15 +285,15 @@ const drawSector = (type, center, radius, id, angle) => {
|
|||||||
polygonOpacity: 0.16
|
polygonOpacity: 0.16
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if(angle) {
|
if(typeof angle === 'number' && !isNaN(angle)) {
|
||||||
let ellipse = new maptalks.Sector(center, radius - 1 * 1000, angle - 30, angle + 30, {
|
let ellipse = new maptalks.Sector(center, radius, angle - 10, angle + 10, {
|
||||||
id: sectorId + '_ellipse',
|
id: sectorId + '_ellipse',
|
||||||
symbol: {
|
symbol: {
|
||||||
lineColor: '#FF8D1C',
|
lineColor: '#FF8D1C',
|
||||||
polygonFill: '#ff8d1c29'
|
polygonFill: '#ff8d1c29'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let line = new maptalks.Sector(center, radius + 1 * 1000, angle, angle, {
|
let line = new maptalks.Sector(center, radius, angle, angle, {
|
||||||
id: sectorId + '_line',
|
id: sectorId + '_line',
|
||||||
symbol: {
|
symbol: {
|
||||||
lineColor: '#FF8D1C',
|
lineColor: '#FF8D1C',
|
||||||
@@ -256,7 +307,6 @@ const drawSector = (type, center, radius, id, angle) => {
|
|||||||
}
|
}
|
||||||
// 添加到可视域图层
|
// 添加到可视域图层
|
||||||
changeSectorsInLayer('sectors' + type, false)
|
changeSectorsInLayer('sectors' + type, false)
|
||||||
// vector['sectors' + type].hide()
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 叠加ais基站数据
|
* 叠加ais基站数据
|
||||||
@@ -280,8 +330,6 @@ const addAisStationToMap = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
marker.addTo(vector.ais_station)
|
marker.addTo(vector.ais_station)
|
||||||
marker.on('click', (evt) => {
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
vector.ais_station.show()
|
vector.ais_station.show()
|
||||||
@@ -308,8 +356,6 @@ const addEnvironmentalToMap = () => {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
marker.addTo(vector.environmental)
|
marker.addTo(vector.environmental)
|
||||||
marker.on('click', (evt) => {
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
vector.environmental.show()
|
vector.environmental.show()
|
||||||
@@ -329,10 +375,7 @@ const initUAV = () => {
|
|||||||
|
|
||||||
}
|
}
|
||||||
const initMonitor = () => {
|
const initMonitor = () => {
|
||||||
const params = {
|
const params = {}
|
||||||
pageNo: 1,
|
|
||||||
pageSize: 9999
|
|
||||||
}
|
|
||||||
dsVideoList(params).then(res => {
|
dsVideoList(params).then(res => {
|
||||||
geography.monitor = res.data
|
geography.monitor = res.data
|
||||||
addMonitorToMap()
|
addMonitorToMap()
|
||||||
@@ -354,7 +397,7 @@ const initFence = () => {
|
|||||||
addFenceToMap('detailFence')
|
addFenceToMap('detailFence')
|
||||||
}
|
}
|
||||||
const toModel = () => {
|
const toModel = () => {
|
||||||
mapStore.updateLargeModel(true)
|
mapStore.updateDialog({ visible: true, type: 'largeModel' })
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
initMap()
|
initMap()
|
||||||
@@ -374,6 +417,7 @@ watch(() => UAV.value, () => {
|
|||||||
initUAV()
|
initUAV()
|
||||||
}else{
|
}else{
|
||||||
vector.UAV?.hide()
|
vector.UAV?.hide()
|
||||||
|
changeSectorsInLayer('sectors_UAV', false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
watch(() => monitor.value, () => {
|
watch(() => monitor.value, () => {
|
||||||
@@ -381,6 +425,7 @@ watch(() => monitor.value, () => {
|
|||||||
initMonitor()
|
initMonitor()
|
||||||
}else{
|
}else{
|
||||||
vector.monitor?.hide()
|
vector.monitor?.hide()
|
||||||
|
changeSectorsInLayer('sectors_monitor', false)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
watch(() => ais_station.value, () => {
|
watch(() => ais_station.value, () => {
|
||||||
@@ -427,6 +472,12 @@ watch(() => sector.value.UAV, (newVal) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
// 定位数据变化
|
||||||
|
watch(() => locateData.value.videoCode, (newVal) => {
|
||||||
|
nextTick(() => {
|
||||||
|
locateMoitor(locateData.value)
|
||||||
|
})
|
||||||
|
})
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
globalMap.destroy()
|
globalMap.destroy()
|
||||||
globalMap = null
|
globalMap = null
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div :class="['screen-legend-left',isFold? 'fold':'']">
|
<div :class="['screen-legend-left',isFold? 'fold':'',retract?'retract':'']">
|
||||||
<div class="header" @click="toggleExpand">
|
<div class="header" @click="toggleExpand">
|
||||||
<span>图例 </span>
|
<span>图例 </span>
|
||||||
<img src="@/assets/images/map/legend/icon-suffix.png" alt="">
|
<img src="@/assets/images/map/legend/icon-suffix.png" alt="">
|
||||||
@@ -24,6 +24,12 @@
|
|||||||
|
|
||||||
const mapStore = useMapStore()
|
const mapStore = useMapStore()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
retract: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
})
|
||||||
const isFold = ref(true)
|
const isFold = ref(true)
|
||||||
|
|
||||||
const list = ref([
|
const list = ref([
|
||||||
@@ -152,6 +158,9 @@
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.retract{
|
||||||
|
left: 40px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.screen-legend-left::before {
|
.screen-legend-left::before {
|
||||||
content: '';
|
content: '';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<DialogComponent @mousedown="drag" @resize="handleResize" :style="{ resize: 'both', overflow: 'auto' }" v-if="visible && option[type]" :title="option[type].title" :width="type==='_UAV' ? 1800:395" :draggable="true" :modal="false" @close="close">
|
<DialogComponent @mousedown="drag" @resize="handleResize" :style="{ resize: 'both', overflow: 'auto' }" v-if="visible && option[type]" :title="title" :width="type==='_UAV' ? 1800:395" :draggable="true" :modal="false" @close="close">
|
||||||
<component :is="option[type].component" ref="component"/>
|
<component :is="option[type].component" ref="component"/>
|
||||||
</DialogComponent>
|
</DialogComponent>
|
||||||
</template>
|
</template>
|
||||||
@@ -33,6 +33,12 @@ const option = computed(() => ({
|
|||||||
component: MeteorologyComponent
|
component: MeteorologyComponent
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
const title = computed(() => {
|
||||||
|
if(type.value === '_UAV') {
|
||||||
|
return data.value.videoName + '--' + option.value[type.value].title
|
||||||
|
}
|
||||||
|
return option.value[type.value].title
|
||||||
|
})
|
||||||
const component = ref(null)
|
const component = ref(null)
|
||||||
const close = () => {
|
const close = () => {
|
||||||
mapStore.updateWindowInfo(false)
|
mapStore.updateWindowInfo(false)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, nextTick, onMounted, ref } from 'vue'
|
import { computed, nextTick, ref, watch } from 'vue'
|
||||||
import useMapStore from '@/store/modules/map'
|
import useMapStore from '@/store/modules/map'
|
||||||
import HikPlayerComponent from '@/components/Player/HikPlayer.vue'
|
import HikPlayerComponent from '@/components/Player/HikPlayer.vue'
|
||||||
|
|
||||||
@@ -16,11 +16,12 @@ const visible = ref(false)
|
|||||||
const data = computed(() => mapStore.windowInfo.data)
|
const data = computed(() => mapStore.windowInfo.data)
|
||||||
const HikCCTV = ref(null)
|
const HikCCTV = ref(null)
|
||||||
|
|
||||||
onMounted(() => {
|
watch(() => data.value.videoCode, () => {
|
||||||
|
visible.value = false
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
})
|
})
|
||||||
})
|
}, { immediate: true })
|
||||||
defineExpose({
|
defineExpose({
|
||||||
HikCCTV
|
HikCCTV
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ import { ElMessage } from 'element-plus'
|
|||||||
|
|
||||||
const mapStore = useMapStore()
|
const mapStore = useMapStore()
|
||||||
const data = computed(() => mapStore.windowInfo.data)
|
const data = computed(() => mapStore.windowInfo.data)
|
||||||
const url = computed(() => `http://198.16.74.210:3456/embed?projectId=4bd996b8-5201-4e5d-82b1-6879be360c20&authInfoId=eyJhbGciOiJIUzUxMiIsImNyaXQiOlsidHlwIiwiYWxnIiwia2lkIl0sImtpZCI6IjU3YmQyNmEwLTYyMDktNGE5My1hNjg4LWY4NzUyYmU1ZDE5MSIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50IjoiIiwiZXhwIjoyMDc1OTQ3NzIyLCJuYmYiOjE3NjA0MTQ5MjIsIm9yZ2FuaXphdGlvbl91dWlkIjoiOWRmMjlmYTgtNGI5OS00MThlLWJhMmQtMGY5ZWY5ZWVlMzkyIiwicHJvamVjdF91dWlkIjoiIiwic3ViIjoiZmgyIiwidXNlcl9pZCI6IjE3NjA0MTQxMDkzNTcwMDI0MjkifQ.DC_aS37W2fkqOjCtfvysDfhTn-4XVn3_IrXBnPD9rICGyrIBKBG3oPldeW_pqele5H_gCn1EgM0KXcbDgvq-dw&
|
const url = 'http://198.16.74.210:3456/embed?projectId=2&authInfoId=3&deviceSn=7601839813836800&deviceType=drone&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE3NjcxNzA1NTIsImlhdCI6MTc2NjU2NTc1Mn0._YhukLexaErvTc3QDIAV5MuOa6cqglYUfsixNCit3us'
|
||||||
deviceSn=${data.value.droneSn}&deviceType=drone&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE3NjcxNzA1NTIsImlhdCI6MTc2NjU2NTc1Mn0._YhukLexaErvTc3QDIAV5MuOa6cqglYUfsixNCit3us`)
|
// const url = computed(() => `http://198.16.74.210:3456/embed?projectId=4bd996b8-5201-4e5d-82b1-6879be360c20&authInfoId=eyJhbGciOiJIUzUxMiIsImNyaXQiOlsidHlwIiwiYWxnIiwia2lkIl0sImtpZCI6IjU3YmQyNmEwLTYyMDktNGE5My1hNjg4LWY4NzUyYmU1ZDE5MSIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50IjoiIiwiZXhwIjoyMDc1OTQ3NzIyLCJuYmYiOjE3NjA0MTQ5MjIsIm9yZ2FuaXphdGlvbl91dWlkIjoiOWRmMjlmYTgtNGI5OS00MThlLWJhMmQtMGY5ZWY5ZWVlMzkyIiwicHJvamVjdF91dWlkIjoiIiwic3ViIjoiZmgyIiwidXNlcl9pZCI6IjE3NjA0MTQxMDkzNTcwMDI0MjkifQ.DC_aS37W2fkqOjCtfvysDfhTn-4XVn3_IrXBnPD9rICGyrIBKBG3oPldeW_pqele5H_gCn1EgM0KXcbDgvq-dw&
|
||||||
|
// deviceSn=${data.value.droneSn}&deviceType=drone&token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE3NjcxNzA1NTIsImlhdCI6MTc2NjU2NTc1Mn0._YhukLexaErvTc3QDIAV5MuOa6cqglYUfsixNCit3us`)
|
||||||
// 算法开启关闭状态
|
// 算法开启关闭状态
|
||||||
const algorithmStatus = ref(false)
|
const algorithmStatus = ref(false)
|
||||||
const algorithms = [
|
const algorithms = [
|
||||||
|
|||||||
@@ -21,19 +21,22 @@ const useMapStore = defineStore(
|
|||||||
'UAV': false, // 无人机可视域开关
|
'UAV': false, // 无人机可视域开关
|
||||||
'monitor': false // 监控可视域开关
|
'monitor': false // 监控可视域开关
|
||||||
},
|
},
|
||||||
largeModel: false, // 智能体
|
|
||||||
hik: { // 海康插件设备层级
|
hik: { // 海康插件设备层级
|
||||||
level: 1,
|
level: 1,
|
||||||
data: {}
|
data: {}
|
||||||
},
|
},
|
||||||
dialog: {
|
dialog: {
|
||||||
visible: false,
|
visible: false,
|
||||||
type: '', // 弹窗类型 alarm/CCTV/UAV
|
type: '', // 弹窗类型 alarm/CCTV/UAV/largeModel
|
||||||
data: {}
|
data: {}
|
||||||
},
|
},
|
||||||
// 无人机信息
|
// 无人机信息
|
||||||
uavs: {
|
uavs: {
|
||||||
data: {}
|
data: {}
|
||||||
|
},
|
||||||
|
// cctv轮询定位
|
||||||
|
locate: {
|
||||||
|
data: {}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
@@ -49,9 +52,6 @@ const useMapStore = defineStore(
|
|||||||
updateSector(type, checked) {
|
updateSector(type, checked) {
|
||||||
this.sector[type] = checked
|
this.sector[type] = checked
|
||||||
},
|
},
|
||||||
updateLargeModel(option) {
|
|
||||||
this.largeModel = option
|
|
||||||
},
|
|
||||||
updateHik(option) {
|
updateHik(option) {
|
||||||
const { level = 1, data = {} } = option
|
const { level = 1, data = {} } = option
|
||||||
this.hik.level = level
|
this.hik.level = level
|
||||||
@@ -65,6 +65,9 @@ const useMapStore = defineStore(
|
|||||||
},
|
},
|
||||||
updateUavData(option) {
|
updateUavData(option) {
|
||||||
this.uavs.data = option
|
this.uavs.data = option
|
||||||
|
},
|
||||||
|
updateLocate(option) {
|
||||||
|
this.locate.data = option
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<ListCom/>
|
<ListCom @toggle-fold="toggle"/>
|
||||||
<DeviceCom/>
|
<DeviceCom/>
|
||||||
<MonitorCom/>
|
<MonitorCom/>
|
||||||
<LegendCom/>
|
<LegendCom :retract="retract"/>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -10,7 +10,12 @@ import ListCom from './list.vue'
|
|||||||
import DeviceCom from './device.vue'
|
import DeviceCom from './device.vue'
|
||||||
import MonitorCom from './monitor.vue'
|
import MonitorCom from './monitor.vue'
|
||||||
import LegendCom from '@/components/Map/legend.vue'
|
import LegendCom from '@/components/Map/legend.vue'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
|
const retract = ref(null)
|
||||||
|
const toggle = (value) => {
|
||||||
|
retract.value = value
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.screen-legend-left{
|
.screen-legend-left{
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import { reactive, ref } from 'vue'
|
|||||||
import useMapStore from '@/store/modules/map'
|
import useMapStore from '@/store/modules/map'
|
||||||
import { videoIdentificationPage } from '@/api/identification.js'
|
import { videoIdentificationPage } from '@/api/identification.js'
|
||||||
|
|
||||||
|
const emit = defineEmits([ 'toggle-fold' ])
|
||||||
const mapStore = useMapStore()
|
const mapStore = useMapStore()
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{
|
{
|
||||||
@@ -109,6 +110,7 @@ const initData = () => {
|
|||||||
}
|
}
|
||||||
const toggleFold = () => {
|
const toggleFold = () => {
|
||||||
isFold.value = !isFold.value
|
isFold.value = !isFold.value
|
||||||
|
emit('toggle-fold', isFold.value)
|
||||||
}
|
}
|
||||||
const toggle = (index) => {
|
const toggle = (index) => {
|
||||||
current.value = index
|
current.value = index
|
||||||
|
|||||||
@@ -7,42 +7,114 @@
|
|||||||
@click="handle(index)">{{item}}</div>
|
@click="handle(index)">{{item}}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="resize" :style="{ resize: 'both', overflow: 'auto' }"></div>
|
<div class="resize" :style="{ resize: 'both', overflow: 'auto' }"></div>
|
||||||
<!-- <div class="flv-container"><FlvPlayerComponent :url="uavDialog.url"/></div> -->
|
<div class="flv-container"><FlvPlayerComponent v-if="videoUrl" :url="videoUrl"/></div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { computed, nextTick, onMounted, onUnmounted, ref } from 'vue'
|
||||||
import { dragEvent, resizeEvent } from '@/utils/common'
|
import { dragEvent, resizeEvent } from '@/utils/common'
|
||||||
import FlvPlayerComponent from '@/components/FlvPlayer/index.vue'
|
import FlvPlayerComponent from '@/components/FlvPlayer/index.vue'
|
||||||
import { getAssetsFile } from '@/utils/common'
|
import { dsVideoList, cctvExport } from '@/api/device.js'
|
||||||
|
import useMapStore from '@/store/modules/map'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
|
||||||
|
const mapStore = useMapStore()
|
||||||
|
const videoData = computed(() => mapStore.locate.data)
|
||||||
const tabs = [
|
const tabs = [
|
||||||
'重新轮询', '巡检报告'
|
'锁定轮询', '重新轮询', '巡检报告'
|
||||||
]
|
]
|
||||||
const active = ref(0)
|
const active = ref(null)
|
||||||
|
|
||||||
|
const data = ref([])
|
||||||
|
const lock = ref(false)
|
||||||
|
let timer = null
|
||||||
|
let monitorIndex = 0
|
||||||
|
const videoUrl = ref('')
|
||||||
|
const arr = [ 'https://sl-shandong-stud-166141.chinatowercom.cn:10263/live/37021200001327000138_1_0_be18783a8d444023becb4e96c1c37ffc.flv',
|
||||||
|
'https://sl-shandong-stud-166141.chinatowercom.cn:10343/live/37021100001327000007_0_0_9626ad56bd3340cc9554c30454a66f2d.flv',
|
||||||
|
'https://sl-shandong-stud-022093.chinatowercom.cn:10073/live/37100200001327000003_0_0_e83bd475262b448b9d06c2d8085a7a9c.flv',
|
||||||
|
'http://198.16.74.214:80/Channels0001/Channels0001.live.flv?originTypeStr=pull&audioCodec=G711A&videoCodec=H264' ]
|
||||||
|
|
||||||
const handle = (index) => {
|
const handle = (index) => {
|
||||||
active.value = index
|
active.value = index
|
||||||
|
if(index === 0) {
|
||||||
|
lock.value = true
|
||||||
|
ElMessage.success('锁定成功')
|
||||||
|
}else if(index === 1) {
|
||||||
|
lock.value = false
|
||||||
|
ElMessage.success('成功轮询')
|
||||||
|
}else if(index === 2) { // 巡检报告下载
|
||||||
|
console.log(videoData.value, 'value')
|
||||||
|
// window.open(item.url, '_blank')
|
||||||
|
cctvExport({}).then(res => {
|
||||||
|
console.log(res, 'resssss')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const clearTimer = () => {
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(timer)
|
||||||
|
timer = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const initIndex = () => {
|
||||||
|
monitorIndex = 0
|
||||||
|
}
|
||||||
|
const init = () => {
|
||||||
|
const params = {}
|
||||||
|
videoUrl.value = ''
|
||||||
|
dsVideoList(params).then(res => {
|
||||||
|
data.value = res.data.filter(i => i.videoUrl).sort((a, b) => a.playIndex - b.playIndex)
|
||||||
|
videoUrl.value = data.value[monitorIndex].videoUrl
|
||||||
|
mapStore.updateLocate(data.value[monitorIndex])
|
||||||
|
clearTimer()
|
||||||
|
handlePolling(true) // 开始轮询
|
||||||
|
timer = setInterval(() => {
|
||||||
|
if(lock.value) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
videoUrl.value = ''
|
||||||
|
nextTick(() => {
|
||||||
|
if(monitorIndex >= data.value.length - 1) {
|
||||||
|
handlePolling(false) // 轮询结束
|
||||||
|
monitorIndex = 0
|
||||||
|
handlePolling(true) // 开始轮询
|
||||||
|
}else{
|
||||||
|
monitorIndex++
|
||||||
|
}
|
||||||
|
videoUrl.value = data.value[monitorIndex].videoUrl
|
||||||
|
})
|
||||||
|
mapStore.updateLocate(data.value[monitorIndex])
|
||||||
|
}, 60 * 1000 * 0.5)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const handlePolling = (flag) => {
|
||||||
|
console.log(flag + '---轮询')
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 拖拽事件
|
* 拖拽事件
|
||||||
* @param e
|
* @param e
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const drag = (e) => {
|
const drag = (e) => {
|
||||||
if(e.target.className === 'resize') {
|
if(e.target.className === 'resize') {
|
||||||
resizeEvent(e, 'resize', (i) => {
|
resizeEvent(e, 'resize', (i) => {
|
||||||
document.querySelector('.monitor-container').style.height = i.height + 'px'
|
document.querySelector('.monitor-container').style.height = i.height + 'px'
|
||||||
document.querySelector('.monitor-container').style.width = i.width + 'px'
|
document.querySelector('.monitor-container').style.width = i.width + 'px'
|
||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
dragEvent(e, 'monitor-container', () => {
|
dragEvent(e, 'monitor-container', () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
const resize = (e) => {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
// // 查询当前轮询到第几个
|
||||||
|
// initIndex()
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearTimer()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
||||||
@@ -82,7 +154,8 @@ const resize = (e) => {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 36px;
|
line-height: 36px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
&.active{
|
cursor: pointer;
|
||||||
|
&:active{
|
||||||
background: linear-gradient( 180deg, #2EA4F0 0%, rgba(46,164,240,0.35) 100%);
|
background: linear-gradient( 180deg, #2EA4F0 0%, rgba(46,164,240,0.35) 100%);
|
||||||
box-shadow: inset 0px 2px 4px 0px rgba(83,203,255,0.4);
|
box-shadow: inset 0px 2px 4px 0px rgba(83,203,255,0.4);
|
||||||
// border-radius: 2px 2px 0px 0px;
|
// border-radius: 2px 2px 0px 0px;
|
||||||
@@ -94,6 +167,7 @@ const resize = (e) => {
|
|||||||
}
|
}
|
||||||
.flv-container{
|
.flv-container{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: calc(100% - 50px);
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
.resize{
|
.resize{
|
||||||
@@ -101,7 +175,7 @@ const resize = (e) => {
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
width: 524px;
|
width: 524px;
|
||||||
height: 386px;
|
height: 386px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<router-view></router-view>
|
<router-view></router-view>
|
||||||
</div>
|
</div>
|
||||||
<Alarm/>
|
<Alarm/>
|
||||||
<LargeModelCom v-if="largeModel"/>
|
<LargeModelCom v-if="visible && type === 'largeModel'"/>
|
||||||
<IdentificationCom v-if="visible && type === 'alarm'"/>
|
<IdentificationCom v-if="visible && type === 'alarm'"/>
|
||||||
<WallCom v-if="visible && (type==='CCTV'|| type==='UAV')"/>
|
<WallCom v-if="visible && (type==='CCTV'|| type==='UAV')"/>
|
||||||
</div>
|
</div>
|
||||||
@@ -22,9 +22,6 @@ import useMapStore from '@/store/modules/map'
|
|||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
|
|
||||||
const mapStore = useMapStore()
|
const mapStore = useMapStore()
|
||||||
const largeModel = computed(() => {
|
|
||||||
return mapStore.largeModel
|
|
||||||
})
|
|
||||||
const visible = computed(() => mapStore.dialog.visible)
|
const visible = computed(() => mapStore.dialog.visible)
|
||||||
const type = computed(() => mapStore.dialog.type)
|
const type = computed(() => mapStore.dialog.type)
|
||||||
window.name = 'business_window'
|
window.name = 'business_window'
|
||||||
|
|||||||
@@ -11,13 +11,13 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="border">
|
|
||||||
|
</div>
|
||||||
|
<div :class="['border',show ? 'history-collapse' : 'history-expand']">
|
||||||
<img
|
<img
|
||||||
:class="[show ? 'history-collapse' : 'history-expand']"
|
|
||||||
src="@/assets/images/largeModel/icon-collapse.png" alt=""
|
src="@/assets/images/largeModel/icon-collapse.png" alt=""
|
||||||
@click="show = !show">
|
@click="show = !show">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -174,24 +174,17 @@ defineExpose({
|
|||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.border{
|
.history-collapse{
|
||||||
width: 20px;
|
display: none;
|
||||||
.history-collapse{
|
|
||||||
position: absolute;
|
|
||||||
right: 160px;
|
|
||||||
bottom: 40px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.3s ease-in-out;
|
||||||
transform: translateX(0);
|
transform: rotateY(180deg);
|
||||||
}
|
}
|
||||||
.history-expand{
|
.history-expand{
|
||||||
position: absolute;
|
width: 20px;
|
||||||
right: 10px;
|
|
||||||
bottom: 20px;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
transition: all 0.3s ease-in-out;
|
transition: all 0.3s ease-in-out;
|
||||||
transform: translateX(0);
|
transform: rotateY(180deg);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
@@ -105,7 +105,7 @@ const initList = () => {
|
|||||||
History.value.initList()
|
History.value.initList()
|
||||||
}
|
}
|
||||||
const close = () => {
|
const close = () => {
|
||||||
mapStore.updateLargeModel(false)
|
mapStore.updateDialog({ visible: false, type: 'largeModel' })
|
||||||
}
|
}
|
||||||
const openVideo = (data) => {
|
const openVideo = (data) => {
|
||||||
visible.value = data.visible
|
visible.value = data.visible
|
||||||
|
|||||||
Reference in New Issue
Block a user