322 lines
8.0 KiB
Vue
322 lines
8.0 KiB
Vue
<template>
|
||
<!-- 渔船信息 弹窗 -->
|
||
<DialogComponent v-if="visible && info" :title="data.boatName" width="450" :draggable="true" :modal="false" :btn="true" @handle="handleTrack" @close="closeInfo">
|
||
<div class="content-wrapper">
|
||
|
||
<ul class="list-wrapper">
|
||
<li class="list-item" v-for="item in columns" :key="item.prop">
|
||
<span class="label">{{item.label}}:</span>
|
||
<span class="value">{{data[item.prop]}}{{ item.unit }}</span>
|
||
</li>
|
||
<div class="subtitle">监控列表:</div>
|
||
|
||
<div class="row" v-for="item in monitors" :key="item.videoName">
|
||
<div class="left">
|
||
<img src="@/assets/images/map/devices/icon-monitor.png" alt="">
|
||
<span class="name" :title="item.videoName">{{ item.videoName }}</span>
|
||
<span class="distance">({{item.distance}}km)</span>
|
||
</div>
|
||
<div class="button" @click="handleFollow(item)">
|
||
<img src="@/assets/images/map/devices/icon-view.png" alt="">
|
||
光电联动
|
||
</div>
|
||
</div>
|
||
</ul>
|
||
|
||
</div>
|
||
</DialogComponent>
|
||
<!-- 光电随动视频 -->
|
||
<DialogComponent class="monitor-follow-dialog" v-if="visible && monitor.visible" :title="monitor.data.videoName" width="450" :draggable="true" :modal="false" @close="closeMonitor" @mousedown="drag">
|
||
<div class="monitor-follow video-windowfollow">
|
||
<HikPlayerComponent ref="HikFollow" v-if="monitor.data&&monitor.data.url" :cameraIndexCode="monitor.data.url" id="follow"/>
|
||
</div>
|
||
</DialogComponent>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, nextTick, reactive, ref, watch } from 'vue'
|
||
import DialogComponent from '@/components/Dialog/screen.vue'
|
||
import HikPlayerComponent from '@/components/Player/HikPlayer.vue'
|
||
import { findAISPointPositionByMmsi, getDevicesForServo, getDevicesIsCover, sitMoveByGps, servoByRadar, exitServoByRadar } from '@/api/map'
|
||
import { dragEvent } from '@/utils/common'
|
||
import GlobalMap from '@/components/map/js/GlobalMap'
|
||
import ShipPathInMap from '@/components/map/js/ShipPathInMap'
|
||
import useMapStore from '@/store/modules/map'
|
||
|
||
const mapStore = useMapStore()
|
||
const visible = computed(() => mapStore.windowInfo.visible)
|
||
const type = computed(() => mapStore.windowInfo.type)
|
||
const data = computed(() => mapStore.windowInfo.data)
|
||
const info = ref(true)
|
||
const monitor = reactive({
|
||
visible: true,
|
||
data: {}
|
||
})
|
||
const columns = [
|
||
{
|
||
label: 'AIS编号',
|
||
prop: 'terminalCode'
|
||
},
|
||
{
|
||
label: '船牌号',
|
||
prop: 'boatName'
|
||
},
|
||
{
|
||
label: '航速',
|
||
prop: 'sog',
|
||
unit: '节'
|
||
},
|
||
{
|
||
label: '航向',
|
||
prop: 'angle',
|
||
unit: '度'
|
||
}
|
||
]
|
||
const monitors = ref([])
|
||
const HikFollow = ref(null)
|
||
// 光电随动控制标识
|
||
const currentServo = ref('')
|
||
let globalMap = null
|
||
|
||
/**
|
||
* 拖拽事件
|
||
* @param e
|
||
*
|
||
*/
|
||
const drag = (e) => {
|
||
dragEvent(e, 'el-dialog', () => {
|
||
HikFollow.value.initResize(false)
|
||
})
|
||
}
|
||
const getMonitorList = () => {
|
||
const params = {
|
||
gpsX: data.value.longitude,
|
||
gpsY: data.value.latitude
|
||
}
|
||
getDevicesForServo(params).then(res => {
|
||
monitors.value = res.data
|
||
if(res.data.length > 0) {
|
||
// 光电联动 默认预览第一个监控视频
|
||
handleFollow(res.data[0])
|
||
}
|
||
})
|
||
}
|
||
const closeInfo = () => {
|
||
info.value = false
|
||
if(!monitor.visible) {
|
||
close()
|
||
}
|
||
}
|
||
const closeMonitor = () => {
|
||
monitor.visible = false
|
||
monitor.data = {}
|
||
if(!info.value) {
|
||
close()
|
||
}
|
||
// 退出随动
|
||
if(currentServo.value) {
|
||
handleExitServo()
|
||
}
|
||
}
|
||
const close = () => {
|
||
mapStore.updateWindowInfo(false)
|
||
}
|
||
// 判断监控设备和将要联动的定位目标是否超出可视范围、是否处于视角遮挡区
|
||
const handleFollow = (item) => {
|
||
const params = {
|
||
deviceCode: item.videoCode,
|
||
gpsX: data.value.longitude,
|
||
gpsY: data.value.latitude
|
||
}
|
||
getDevicesIsCover(params).then(res => {
|
||
if (res.msg.includes('超出')) {
|
||
ElMessage.warning(res.msg)
|
||
}
|
||
handleSitMoveByGps(item)
|
||
})
|
||
}
|
||
// 联动控制
|
||
const handleSitMoveByGps = (item) => {
|
||
closeMonitor()
|
||
const params = {
|
||
deviceCode: item.videoCode,
|
||
terminalCode: data.value.terminalCode,
|
||
gpsX: data.value.longitude,
|
||
gpsY: data.value.latitude
|
||
}
|
||
sitMoveByGps(params).then(res => {
|
||
if (res.code === 200) {
|
||
monitor.visible = true
|
||
nextTick(() => {
|
||
monitor.data.videoName = item.videoName
|
||
monitor.data.url = item.videoCode
|
||
})
|
||
}
|
||
// 光电随动控制
|
||
handleServoByRadar(item)
|
||
})
|
||
}
|
||
// 光电随动
|
||
const handleServoByRadar = (item) => {
|
||
const params = {
|
||
deviceCode: item.videoCode,
|
||
terminalCode: data.value.terminalCode,
|
||
gpsX: data.value.longitude,
|
||
gpsY: data.value.latitude
|
||
}
|
||
|
||
servoByRadar(params).then(res => {
|
||
if (res.code === 200) {
|
||
currentServo.value = data.value.terminalCode
|
||
}
|
||
})
|
||
}
|
||
// 退出随动
|
||
const handleExitServo = () => {
|
||
const params = {
|
||
terminalCode: currentServo.value
|
||
}
|
||
|
||
exitServoByRadar(params).then(res => {
|
||
if (res.code === 200) {
|
||
currentServo.value = ''
|
||
}
|
||
})
|
||
}
|
||
/**
|
||
* 格式化轨迹数据
|
||
* @param data 原始数据
|
||
* @return {Array}
|
||
*/
|
||
const formatTrackData = (data) => {
|
||
const list = []
|
||
|
||
const trackObj = data.map((_item) => {
|
||
const info = { ..._item }
|
||
info.longitude = Number(_item.longitude.toFixed(6))
|
||
info.latitude = Number(_item.latitude.toFixed(6))
|
||
info.time = new Date(_item.gpsTime).getTime()
|
||
return info
|
||
}).filter((point) => Math.abs(point.latitude) < 90 && Math.abs(point.longitude) < 180)
|
||
list.push(trackObj)
|
||
return list
|
||
}
|
||
// 查询轨迹
|
||
const handleTrack = () => {
|
||
globalMap = GlobalMap.instance
|
||
findAISPointPositionByMmsi({ mmsi: data.value.terminalCode }).then(res => {
|
||
if (res.success) {
|
||
const arr = res.result[data.value.terminalCode]
|
||
new ShipPathInMap(globalMap.map, globalMap.map.getLayer('track'), formatTrackData(arr))
|
||
}
|
||
}).finally(() => {
|
||
mapStore.updateWindowInfo(false)
|
||
})
|
||
}
|
||
watch(() => data.value, () => {
|
||
if(type.value === '_trawler_dynamic') {
|
||
info.value = true
|
||
getMonitorList()
|
||
}else{
|
||
info.value = false
|
||
monitor.visible = false
|
||
}
|
||
})
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
.content-wrapper {
|
||
width: 100%;
|
||
overflow: auto;
|
||
|
||
.list-wrapper {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
|
||
.list-item {
|
||
width: 100%;
|
||
display: flex;
|
||
height: 18px;
|
||
align-items: center;
|
||
|
||
.label {
|
||
width: 100px;
|
||
font-size: 14px;
|
||
color: #00C0FFFF;
|
||
text-align: left;
|
||
}
|
||
|
||
.value {
|
||
color: #FFFFFFFF;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
.subtitle {
|
||
width: 100%;
|
||
height: 28px;
|
||
background-color: #00C0FF33;
|
||
color: #00C0FFFF;
|
||
font-size: 14px;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 0 4px;
|
||
box-sizing: border-box;
|
||
|
||
&::after {
|
||
content: '';
|
||
display: block;
|
||
width: 14px;
|
||
height: 14px;
|
||
background-image: url('@/assets/images/common/icon-triangle.png');
|
||
background-size: 100% 100%;
|
||
background-repeat: no-repeat;
|
||
}
|
||
}
|
||
.row{
|
||
display: flex;
|
||
justify-content: space-between;
|
||
.name{
|
||
color: rgba(0, 192, 255, 1);
|
||
margin: 0 5px;
|
||
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
overflow: hidden;
|
||
min-width: 0;
|
||
}
|
||
.distance{
|
||
color: rgba(255, 255, 255, 1);
|
||
}
|
||
.left{
|
||
display: flex;
|
||
flex: 1;
|
||
align-items: center;
|
||
min-width: 0;
|
||
}
|
||
.button{
|
||
color: rgba(0, 246, 255, 1);
|
||
display: flex;
|
||
align-items: center;
|
||
cursor: pointer;
|
||
img{
|
||
margin-right: 2px;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
.monitor-follow-dialog{
|
||
margin-left: calc(50% + 225px) !important;
|
||
.el-dialog__body{
|
||
padding: 0 !important;
|
||
}
|
||
.monitor-follow{
|
||
height: 289px;
|
||
width: 100%;
|
||
}
|
||
}
|
||
</style> |