Files
erqi-web/src/components/Map/window/trawler.vue
2025-12-24 18:19:05 +08:00

322 lines
8.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>