Files
erqi-web/src/components/Map/lbtbox/boatTerminal.js

293 lines
8.6 KiB
JavaScript
Raw Normal View History

2025-12-24 18:19:05 +08:00
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 ],
2025-12-25 18:33:15 +08:00
[ 10, 10 ]
// [ 11, 0 ]
2025-12-24 18:19:05 +08:00
]
},
markerHeight: {
type: 'interval',
stops: [
[ 5, 10 ],
2025-12-25 18:33:15 +08:00
[ 10, 20 ]
// [ 11, 0 ]
2025-12-24 18:19:05 +08:00
]
},
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
}