Files
erqi-web/src/components/Map/lbtbox/boatTerminal.js
2025-12-25 18:33:15 +08:00

293 lines
8.6 KiB
JavaScript
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.

import * as maptalks from 'maptalks'
import { PointLayer } from '@maptalks/vt'
import GlobalMap from '../js/GlobalMap.js'
import { getAssetsFile } from '@/utils/common'
import WebSocketClient from '@/utils/WebSocketClient'
import { findByCurrent } from '@/api/map/index.js'
import dayjs from 'dayjs'
const danger = getAssetsFile('map/boat/danger.png')
const passenger = getAssetsFile('map/boat/passenger.png')
const trawler = getAssetsFile('map/boat/trawler.png')
const other = getAssetsFile('map/boat/other.png')
const radar = getAssetsFile('map/boat/radar.png')
const netsonde = getAssetsFile('map/boat/netsonde.png')
let storeInstance = null
let globalMap = null
let glgroup = null
let dynamicBoatInfoWebSocket = null // websock
let boatsMarkerlayer = null // 渔船图层
let cleanupTimer = null
const init = (store) => {
storeInstance = store
globalMap = GlobalMap.instance
glgroup = globalMap.glGroup
glgroup.setZIndex(8)
setStyleToBoatLayer('_trawler_dynamic_boat', 8)
}
// 设置渔船样式
const setStyleToBoatLayer = (key, zIndex) => {
const style = {
style: [
{
name: 'boatStyle',
filter: true,
renderPlugin: {
dataConfig: {
type: 'point',
only2D: true
},
sceneConfig: {
fading: true,
depthFunc: 'always'
},
type: 'icon'
},
symbol: [
{
markerType: 'triangle',
markerWidth: {
type: 'interval',
stops: [
[ 5, 5 ],
[ 10, 10 ]
// [ 11, 0 ]
]
},
markerHeight: {
type: 'interval',
stops: [
[ 5, 10 ],
[ 10, 20 ]
// [ 11, 0 ]
]
},
markerFill: {
type: 'categorical',
property: 'deviceType',
default: '#f4ea2a',
// stops: [
// [ 'AIS', { type: 'categorical', property: 'boatType', stops: [
// [ '危险品货物运输船', '#d81e06' ],
// [ '液货船', '#d81e06' ],
// [ '客船', '#73f34f' ],
// [ '公务船', '#73f34f' ],
// [ '拖轮', '#73f34f' ],
// [ '渔船', '#fff' ],
// [ '其他', '#f4ea2a' ],
// [ '网位移', '#e6e6e6' ],
// [ '无线索船', '#e6e6e6' ]
// ] } ],
// [ 'RADAR', radar ]
// ],
stops: [
[ 'AIS', '#f4ea2a' ]
]
},
markerLineColor: [ 0.2, 0.29, 0.39, 1 ],
markerLineWidth: 1,
markerRotation: {
property: 'cog',
type: 'identity'
}
},
{
markerWidth: {
type: 'interval',
stops: [
[ 10, 0 ],
[ 11, 25 ],
[ 14, 25 ]
]
},
markerHeight: {
type: 'interval',
stops: [
[ 10, 0 ],
[ 11, 30 ],
[ 14, 30 ]
]
},
markerRotation: {
property: 'cog',
type: 'identity'
},
markerFile: {
type: 'categorical',
property: 'deviceType',
default: other,
// stops: [
// [ 'AIS', { type: 'categorical', property: 'boatType', stops: [
// [ '危险品货物运输船', danger ],
// [ '液货船', danger ],
// [ '客船', passenger ],
// [ '公务船', passenger ],
// [ '拖轮', passenger ],
// [ '渔船', trawler ],
// [ '其他', other ],
// [ '网位移', netsonde ],
// [ '无线索船', netsonde ]
// ] } ],
// [ 'RADAR', radar ],
// ],
stops: [
[ 'AIS', other ]
]
},
textName: {
property: 'boatName',
type: 'identity'
},
textFill: '#fff',
textHaloFill: '#3300cc',
textHaloRadius: 2,
textHaloBlur: 20,
textDy: 10,
textSize: {
type: 'interval',
stops: [
[ 14, 0 ],
[ 15, 15 ]
]
}
}
]
}
]
}
const name = `vt_${key}`
if (boatsMarkerlayer) {
boatsMarkerlayer.remove()
}
// 初始化动态渔船图层
boatsMarkerlayer = new PointLayer(name, {
cursor: 'pointer'
})
boatsMarkerlayer.setStyle(style)
boatsMarkerlayer.addTo(glgroup)
glgroup.setZIndex(zIndex)
}
// 单独的清理函数
const cleanupExpiredBoats = () => {
boatsMarkerlayer.getGeometries().forEach(item => {
const properties = item.getProperties()
if (dayjs().diff(properties.gpsTime, 'hours') > 24) {
item.remove()
}
})
}
const getShip = () => {
findByCurrent().then(res => {
console.log('初始获取')
addBoats(res.result)
})
// ----------船只数据------------------
dynamicBoatInfoWebSocket = new WebSocketClient(`${import.meta.env.VITE_WS_BASE_URL}`)
dynamicBoatInfoWebSocket.onopen(event => {
})
dynamicBoatInfoWebSocket.onmessage(event => {
console.log('接收数据:', JSON.parse(event.data))
if(Array.isArray(JSON.parse(event.data))) {
addBoats(JSON.parse(event.data))
}
})
dynamicBoatInfoWebSocket.onclose(event => {
// 可以尝试重新连接
dynamicBoatInfoWebSocket.reconnect()
})
dynamicBoatInfoWebSocket.onerror(event => {
dynamicBoatInfoWebSocket.close()
dynamicBoatInfoWebSocket = null
})
// 启动定期清理任务每5分钟检查一次
if (cleanupTimer) {
clearInterval(cleanupTimer)
}
cleanupTimer = setInterval(() => {
cleanupExpiredBoats()
}, 5 * 60 * 1000) // 5分钟
// 初始化连接
dynamicBoatInfoWebSocket.connect()
}
const addBoats = (boatList) => {
boatList.forEach((boat) => {
// let types = [ '危险品货物运输船', '液货船', '客船', '公务船', '拖轮', '渔船', '其他', '网位移', '无线索船' ]
let { longitude, latitude, cog, boatName, sog, terminalCode, deviceType, gpsTime } = boat
let isContain = boatsMarkerlayer.getGeometryById(terminalCode)
if (isContain !== null) {
isContain.setCoordinates([ longitude, latitude ])
isContain.setProperties({
cog: 360 - Number(cog),
angle: Number(cog),
sog: Number(sog),
boatName,
latitude,
longitude,
deviceType,
gpsTime
// boatType: types[Math.floor(Math.random() * types.length)]
})
} else {
let mm = new maptalks.Marker([ longitude, latitude ], {
id: terminalCode,
properties: {
cog: 360 - Number(cog),
angle: Number(cog),
sog: Number(sog),
boatName,
latitude,
longitude,
deviceType,
gpsTime
// boatType: types[Math.floor(Math.random() * types.length)]
},
cursor: 'pointer'
})
mm.on('click', (e) => {
storeInstance.updateWindowInfo({
visible: true,
type: '_trawler_dynamic',
data: { ...boat,
...e.target.getProperties()
// boatType: types[Math.floor(Math.random() * types.length)]
}
})
globalMap.map.animateTo(
{
zoom: 20,
center: [ boat.longitude, boat.latitude ]
},
{
duration: 1000 * 0.5,
easing: 'out'
}
)
})
mm.addTo(boatsMarkerlayer)
}
})
}
const destroyWebsocket = () => {
dynamicBoatInfoWebSocket.close()
if (cleanupTimer) {
clearInterval(cleanupTimer)
cleanupTimer = null
}
}
export {
destroyWebsocket,
init,
getShip,
boatsMarkerlayer
}