DIAMOND
12 months ago
23 changed files with 648 additions and 2895 deletions
@ -0,0 +1,8 @@ |
|||||
|
// 随机数
|
||||
|
export function guid() { |
||||
|
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { |
||||
|
var r = (Math.random() * 16) | 0, |
||||
|
v = c == 'x' ? r : (r & 0x3) | 0x8; |
||||
|
return v.toString(16); |
||||
|
}); |
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
export default class HandleNodeType { |
||||
|
#sn; |
||||
|
#sensorCallback; |
||||
|
#modelCallback; |
||||
|
#markerPositionCallback; |
||||
|
#polylineCallBack; |
||||
|
#default; |
||||
|
|
||||
|
constructor(sn) { |
||||
|
this.#sn = sn; |
||||
|
} |
||||
|
|
||||
|
sensor(callback) { |
||||
|
this.#sensorCallback = callback; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
// 模型回调
|
||||
|
modelCallback(callback) { |
||||
|
this.#modelCallback = callback; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
// 微波雷达回调
|
||||
|
markerPosition(callback) { |
||||
|
this.#markerPositionCallback = callback; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
// 区域回调
|
||||
|
polylineCallBack(callback) { |
||||
|
this.#polylineCallBack = callback; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
default(callback) { |
||||
|
this.#default = callback; |
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
run() { |
||||
|
// 判断节点的类型
|
||||
|
if (!this.#sn.czmObject) { |
||||
|
return null; |
||||
|
} |
||||
|
// 模型类型
|
||||
|
let tempCondition = this.#sn.czmObject.xbsjType; |
||||
|
switch (tempCondition) { |
||||
|
case 'Model': |
||||
|
this.#modelCallback ? this.#modelCallback() : this.#default(); |
||||
|
break; |
||||
|
case 'Pin': |
||||
|
this.#markerPositionCallback ? this.#markerPositionCallback() : this.#default(); |
||||
|
break; |
||||
|
case 'Polyline': |
||||
|
this.#polylineCallBack ? this.#polylineCallBack() : this.#default(); |
||||
|
break; |
||||
|
default: |
||||
|
this.#default ? this.#default() : null; |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,437 @@ |
|||||
|
|
||||
|
import _ from 'lodash'; |
||||
|
import { useUserStore } from '/@/store/modules/user'; |
||||
|
import { defHttp } from '/@/utils/http/axios'; |
||||
|
import $mitt from '@/utils/earthMap/mitt'; |
||||
|
import { useMessage } from "/@/hooks/web/useMessage"; |
||||
|
import earthUtils from '@/utils/earthMap/earth'; |
||||
|
import alarmImg from '@/assets/earthMap/alarm.gif'; |
||||
|
const { createMessage } = useMessage(); |
||||
|
|
||||
|
let userStore = useUserStore(); |
||||
|
let websock: any = []; |
||||
|
function initWebSocket(configName) { |
||||
|
if ('WebSocket' in window) { |
||||
|
let url = ''; |
||||
|
switch (configName) { |
||||
|
case 'domianURL': //接收后台模型数据
|
||||
|
// WebSocket与普通的请求所用协议有所不同,ws等同于http,wss等同于https
|
||||
|
// const userStore = useUserStore()
|
||||
|
// const orgCode = userStore.userInfo?.orgCode;
|
||||
|
// let userId = store.getters.userInfo.id;
|
||||
|
let userId = userStore.userInfo?.id; |
||||
|
url = window._CONFIG[configName].replace('https://', 'wss://').replace('http://', 'ws://') + '/websocket/' + userId; |
||||
|
// url = 'ws://127.0.0.1:5004'
|
||||
|
websock[configName] = new WebSocket(url); |
||||
|
websock[configName].onopen = websocketonopen; |
||||
|
websock[configName].onerror = websocketonerror; |
||||
|
websock[configName].onmessage = websocketonmessage; |
||||
|
websock[configName].onclose = websocketclose; |
||||
|
break; |
||||
|
case 'clientURL': //调用客户端监控视频窗口
|
||||
|
url = window._CONFIG['clientURL']; |
||||
|
websock[configName] = new WebSocket(url); |
||||
|
websock[configName].onopen = websocketonopen; |
||||
|
websock[configName].onerror = websocketonerror; |
||||
|
websock[configName].onclose = websocketclose; |
||||
|
break; |
||||
|
default: |
||||
|
console.log('websocket初始化失败'); |
||||
|
} |
||||
|
// console.log('url', url)
|
||||
|
} else { |
||||
|
console.log('当前浏览器不支持websocket,请更换浏览器!'); |
||||
|
} |
||||
|
} |
||||
|
function websocketonopen(e) { |
||||
|
console.log('WebSocket连接成功'); |
||||
|
} |
||||
|
function websocketonerror(e) { |
||||
|
console.log('WebSocket连接发生错误'); |
||||
|
} |
||||
|
const loreadAlarmInfo = _.debounce( |
||||
|
(url, eventSerialNum) => { |
||||
|
defHttp |
||||
|
.get( |
||||
|
{ |
||||
|
url: url, |
||||
|
params: eventSerialNum, |
||||
|
}, |
||||
|
{ isTransformResponse: false } |
||||
|
) |
||||
|
// getAction(url, {eventSerialNum: eventSerialNum})
|
||||
|
.then((res) => { |
||||
|
if (!res.success) { |
||||
|
console.log('重新发送websocket报警数据失败!'); |
||||
|
} else { |
||||
|
console.log('重新发送websocket报警数据成功!'); |
||||
|
} |
||||
|
}); |
||||
|
}, |
||||
|
2000, |
||||
|
{ maxWait: 3000, trailing: true } |
||||
|
); |
||||
|
|
||||
|
//
|
||||
|
async function websocketonmessage(e) { |
||||
|
//接收后端数据
|
||||
|
var data = eval('(' + e.data + ')'); |
||||
|
const cesium = window.Cesium; |
||||
|
// Cesium Math
|
||||
|
const math = cesium.Math; |
||||
|
// earth
|
||||
|
const earth = window.$earth; |
||||
|
//处理订阅信息
|
||||
|
if (data.cmd == 'new_warn_info') { |
||||
|
//有新增的预警信息
|
||||
|
//1.调起客户端窗体
|
||||
|
// chrome.call("formactive");
|
||||
|
//2.若警示界面打开着,则刷新列表
|
||||
|
if ($('.infoList').css('visibility') == 'visible') { |
||||
|
$mitt.emit('getWarnData'); |
||||
|
} |
||||
|
//3.弹出监控窗口或围栏信息
|
||||
|
if (data.msgTxt != undefined && data.dealStatus == 1) { |
||||
|
$mitt.emit('listenerVideoNum', data.msgTxt); |
||||
|
//显示报警位置
|
||||
|
window.$earth.sceneTree.$refs[data.labelCode].czmObject.color = [1, 0.09803921568627451, 0, 1]; |
||||
|
} else if (data.msgTxt != undefined && data.dealStatus == 3) { |
||||
|
this.$notification.open({ |
||||
|
key: 'fenceInfo', |
||||
|
message: '围栏信息通知', |
||||
|
description: data.msgTxt + '!', |
||||
|
duration: 0, |
||||
|
}); |
||||
|
} else if (data.dealStatus == 2) { |
||||
|
//消除单个报警位置
|
||||
|
window.$earth.sceneTree.$refs[data.labelCode].czmObject.color = [0.08235294117647059, 1, 0, 1]; |
||||
|
} else if (data.dealStatus == 0) { |
||||
|
//消除所有报警位置
|
||||
|
window.$earth.sceneTree.$refs.sensor.children.forEach((data, index) => { |
||||
|
data.czmObject.color = [0.08235294117647059, 1, 0, 1]; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
//4.提示音
|
||||
|
if (data.dealStatus !== 2 && data.dealStatus !== 0) { |
||||
|
await this.$refs.audio.play(); |
||||
|
setTimeout(() => { |
||||
|
this.$refs.audio.pause(); //N秒后暂停播放
|
||||
|
}, data.alarmNum * 1000); |
||||
|
} |
||||
|
} else if (data.cmd == 'new_microwave_warn_info' || data.cmd == 'new_radar_warn_info' || data.cmd == 'new_video_warn_info') { |
||||
|
if (this.alarmInfoMap.has(data.serialNum)) { |
||||
|
return; |
||||
|
} |
||||
|
const evalString = ` |
||||
|
if(p._div){ |
||||
|
return |
||||
|
} |
||||
|
let left=p.winPos[0]; |
||||
|
let bottom=p.winPos[3]; |
||||
|
const div = document.createElement('div'); |
||||
|
div.style="position: absolute;left:"+left+"px;bottom:"+bottom+"px " |
||||
|
const img = document.createElement('img'); |
||||
|
img.src="${alarmImg}"; |
||||
|
img.style="width:60px;height:60px" |
||||
|
div.appendChild(img); |
||||
|
div.onclick=()=>{ |
||||
|
p.flyTo() |
||||
|
} |
||||
|
p._div = div; |
||||
|
const root=document.getElementById('earthContainer'); |
||||
|
root.appendChild(div); |
||||
|
XE.MVVM.watch(p.winPos,() => { |
||||
|
left=p.winPos[0]-30; |
||||
|
bottom=p.winPos[3]; |
||||
|
div.style="position: absolute;left:"+left+"px;bottom:"+bottom+"px " |
||||
|
}) |
||||
|
`;
|
||||
|
const pinConfig: any = { |
||||
|
name: 'Pin1', |
||||
|
xbsjType: 'Pin', |
||||
|
position: [math.toRadians(data.lon), math.toRadians(data.lat), 0], |
||||
|
evalString: evalString, |
||||
|
// imageUrl: alarmImg,
|
||||
|
isDivImage: true, |
||||
|
show: false, |
||||
|
far: 3000, |
||||
|
}; |
||||
|
// scanline
|
||||
|
const scanlineConfig: any = { |
||||
|
name: 'AlarmScanline', |
||||
|
xbsjType: 'Scanline', |
||||
|
position: [math.toRadians(data.lon), math.toRadians(data.lat), 0], |
||||
|
playing: true, |
||||
|
radius: 30, |
||||
|
timeDuration: 0.5, |
||||
|
color: [1, 0, 0, 1], |
||||
|
show: false, |
||||
|
}; |
||||
|
const pin = new window.XE.Obj.Pin(window.$earth); |
||||
|
const scanline = new window.XE.Obj.Scanline(window.$earth); |
||||
|
//1、获取到世界坐标
|
||||
|
let start = cesium.Cartesian3.fromDegrees(data.lon, data.lat, 0); |
||||
|
let height = await window.$earth.czm.viewer.scene.clampToHeightMostDetailed([start]).then(function (clampedCartesians) { |
||||
|
//2、获取到经纬高度
|
||||
|
let ellipsoid = window.$earth.czm.viewer.scene.globe.ellipsoid; |
||||
|
let cartographic = ellipsoid.cartesianToCartographic(clampedCartesians[0]); |
||||
|
return cartographic.height; |
||||
|
}); |
||||
|
if (height > 0) { |
||||
|
pinConfig.position[2] = height; |
||||
|
} else if (window.$earth.sceneTree.$refs.terrain.czmObject.show) { |
||||
|
height = await cesium.sampleTerrainMostDetailed(earth._viewer.terrainProvider, [start]).then((updatedPositions) => { |
||||
|
return updatedPositions[0].height ? updatedPositions[0].height : 0; |
||||
|
}); |
||||
|
pinConfig.position[2] = height; |
||||
|
} else { |
||||
|
pinConfig.position[2] = 0; |
||||
|
} |
||||
|
|
||||
|
// 保存报警类型到对象上
|
||||
|
let customProp: any = {}; |
||||
|
customProp.alarmType = data.cmd; |
||||
|
pinConfig.customProp = JSON.stringify(customProp); |
||||
|
scanlineConfig.customProp = JSON.stringify(customProp); |
||||
|
pin.xbsjFromJSON(pinConfig); |
||||
|
scanline.xbsjFromJSON(scanlineConfig); |
||||
|
// 判断现在相机的高度来显示报警相关模型
|
||||
|
if (this._earth.camera.position[2] < 100) { |
||||
|
// 隐藏 pin, 显示 scanline
|
||||
|
pin._div.hidden = true; |
||||
|
scanline.show = true; |
||||
|
} else { |
||||
|
// 隐藏 scanline, 显示 pin
|
||||
|
pin._div.hidden = false; |
||||
|
scanline.show = false; |
||||
|
} |
||||
|
scanline.flyTo(); |
||||
|
this.alarmInfoMap.set(data.serialNum, { pin: pin, scanline: scanline, timestamp: Date.now() }); |
||||
|
//报警弹窗
|
||||
|
this.videoWindowProps.title = `实时报警窗口(${data.cameraName})`; |
||||
|
this.videoWindowProps.videoUrl = data.cameraCode; //相机编码
|
||||
|
this.videoWindowProps.isAlarm = true; |
||||
|
this.videoWindowProps.visible = true; |
||||
|
this.videoWindowProps.playRecord = false; |
||||
|
|
||||
|
this.videoWindowProps.warnEvent.happenTime = data.happenTime; |
||||
|
this.videoWindowProps.warnEvent.happenLoc = `${Number(data.lon).toFixed(6)},${Number(data.lat).toFixed(6)}`; |
||||
|
this.videoWindowProps.warnEvent.warnNum = 1; |
||||
|
this.videoWindowProps.warnEvent.warnLevel = filterDictTextByCache('ms_warn_level', data.warnLevel); |
||||
|
this.videoWindowProps.warnEvent.warnType = filterDictTextByCache('ms_warn_type', data.warnType); |
||||
|
this.videoWindowProps.warnEvent.warnContent = data.warnContent; |
||||
|
|
||||
|
//若警示界面打开着,则刷新列表
|
||||
|
if ($('.infoList').css('visibility') == 'visible') { |
||||
|
$mitt.emit('getWarnData'); |
||||
|
} |
||||
|
|
||||
|
//提示音
|
||||
|
await this.$refs.audio.play(); |
||||
|
setTimeout(() => { |
||||
|
this.$refs.audio.pause(); //N秒后暂停播放
|
||||
|
}, 3 * 1000); |
||||
|
} else if (data.cmd == 'earthMap_model_realtime_info') { |
||||
|
console.log(data); |
||||
|
console.log(this.radarAlarmDataMap); |
||||
|
// 雷达轨迹报警数据
|
||||
|
const alarmContent = data.content; |
||||
|
|
||||
|
if (this.radarAlarmDataMap.has(data.eventSerialNum)) { |
||||
|
// 存在雷达报警数据
|
||||
|
let radarAlarmData = this.radarAlarmDataMap.get(data.eventSerialNum); |
||||
|
let targetMap = radarAlarmData.target; |
||||
|
if (targetMap.has(data.modelId)) { |
||||
|
// 存在目标数据
|
||||
|
let targetData = targetMap.get(data.modelId); |
||||
|
let pathModel = targetData.path; |
||||
|
let groundImageModel = targetData.groundImage; |
||||
|
//更新目标数据
|
||||
|
// 更新报警数据
|
||||
|
let positionRadian = earthUtils.degreeToRadianInLngLatHeight(alarmContent.lon, alarmContent.lat, 0); |
||||
|
// 更新路径
|
||||
|
pathModel.positions.push(positionRadian); |
||||
|
groundImageModel.position = positionRadian; |
||||
|
if (pathModel.positions.length > 1) { |
||||
|
pathModel.show = true; |
||||
|
groundImageModel.show = true; |
||||
|
} |
||||
|
} else { |
||||
|
// 不存在目标数据
|
||||
|
// 创建目标数据
|
||||
|
let positionRadian = earthUtils.degreeToRadianInLngLatHeight(alarmContent.lon, alarmContent.lat, 0); |
||||
|
// 路径
|
||||
|
let pathModel = new window.XE.Obj.Path(window.$earth); |
||||
|
let pathConfig = { |
||||
|
name: 'path', |
||||
|
xbsjType: 'Path', |
||||
|
positions: [positionRadian], |
||||
|
loop: false, |
||||
|
playing: true, |
||||
|
width: 2, |
||||
|
color: [1, 0, 0, 1], |
||||
|
show: false, |
||||
|
showDirection: false, |
||||
|
currentSpeed: 30, |
||||
|
alwaysAlongThePath: true, |
||||
|
material: { |
||||
|
type: 'Color', |
||||
|
color: [1, 0, 0, 1], |
||||
|
}, |
||||
|
}; |
||||
|
pathModel.xbsjFromJSON(pathConfig); |
||||
|
// 地面图片
|
||||
|
let groundImageModel = new window.XE.Obj.GroundImage(window.$earth); |
||||
|
let imageUrls: any = []; |
||||
|
if (data.mainTarget) { |
||||
|
imageUrls.push(window._CONFIG['staticDomainURL'] + '/keyi_point1.png'); |
||||
|
imageUrls.push(window._CONFIG['staticDomainURL'] + '/keyi_point2.png'); |
||||
|
} else { |
||||
|
imageUrls.push(window._CONFIG['staticDomainURL'] + '/keyi_point3.png'); |
||||
|
imageUrls.push(window._CONFIG['staticDomainURL'] + '/keyi_point4.png'); |
||||
|
} |
||||
|
let groundImageConfig = { |
||||
|
name: 'groundImage', |
||||
|
xbsjType: 'GroundImage', |
||||
|
position: positionRadian, |
||||
|
width: 3, |
||||
|
height: 3, |
||||
|
playing: true, |
||||
|
imageUrls: imageUrls, |
||||
|
show: false, |
||||
|
}; |
||||
|
groundImageModel.xbsjFromJSON(groundImageConfig); |
||||
|
// 保存目标数据
|
||||
|
let targetData = { |
||||
|
path: pathModel, |
||||
|
groundImage: groundImageModel, |
||||
|
}; |
||||
|
targetMap.set(data.modelId, targetData); |
||||
|
} |
||||
|
// 更新时间
|
||||
|
const updateTime = Date.now(); |
||||
|
radarAlarmData.timestamp = updateTime; |
||||
|
// 更新 pin 的时间
|
||||
|
let alarm = this.alarmInfoMap.get(data.eventSerialNum); |
||||
|
if (alarm) { |
||||
|
alarm.timestamp = updateTime; |
||||
|
} |
||||
|
} else { |
||||
|
// 不存在报警数据
|
||||
|
// 路径
|
||||
|
let pathModel = new window.XE.Obj.Path(window.$earth); |
||||
|
let pathConfig = { |
||||
|
name: 'path', |
||||
|
xbsjType: 'Path', |
||||
|
positions: [earthUtils.degreeToRadianInLngLatHeight(alarmContent.lon, alarmContent.lat, 0)], |
||||
|
loop: false, |
||||
|
playing: true, |
||||
|
width: 2, |
||||
|
color: [1, 0, 0, 1], |
||||
|
show: false, |
||||
|
showDirection: false, |
||||
|
currentSpeed: 30, |
||||
|
alwaysAlongThePath: true, |
||||
|
material: { |
||||
|
type: 'Color', |
||||
|
color: [1, 0, 0, 1], |
||||
|
}, |
||||
|
}; |
||||
|
// 地面图片
|
||||
|
let groundImage = new window.XE.Obj.GroundImage(window.$earth); |
||||
|
let imageUrls: any = []; |
||||
|
if (data.mainTarget) { |
||||
|
imageUrls.push(window._CONFIG['staticDomainURL'] + '/keyi_point1.png'); |
||||
|
imageUrls.push(window._CONFIG['staticDomainURL'] + '/keyi_point2.png'); |
||||
|
} else { |
||||
|
imageUrls.push(window._CONFIG['staticDomainURL'] + '/keyi_point3.png'); |
||||
|
imageUrls.push(window._CONFIG['staticDomainURL'] + '/keyi_point4.png'); |
||||
|
} |
||||
|
let groundImageConfig = { |
||||
|
name: 'groundImage', |
||||
|
xbsjType: 'GroundImage', |
||||
|
playing: true, |
||||
|
width: 3, |
||||
|
height: 3, |
||||
|
position: earthUtils.degreeToRadianInLngLatHeight(alarmContent.lon, alarmContent.lat, 0), |
||||
|
imageUrls: imageUrls, |
||||
|
show: false, |
||||
|
}; |
||||
|
// 创建路径
|
||||
|
groundImage.xbsjFromJSON(groundImageConfig); |
||||
|
// 创建地面图片
|
||||
|
pathModel.xbsjFromJSON(pathConfig); |
||||
|
|
||||
|
// 保存数据到map中
|
||||
|
let target = { |
||||
|
path: pathModel, |
||||
|
groundImage: groundImage, |
||||
|
mainTarget: alarmContent.mainTarget, |
||||
|
}; |
||||
|
let targetMap = new Map(); |
||||
|
targetMap.set(data.modelId, target); |
||||
|
this.radarAlarmDataMap.set(data.eventSerialNum, { |
||||
|
target: targetMap, |
||||
|
timestamp: Date.now(), |
||||
|
}); |
||||
|
|
||||
|
if (!this.alarmInfoMap.has(data.eventSerialNum)) { |
||||
|
// 不存在告警信息(小灯或扫描线)时发送
|
||||
|
// 事件编号到后台使其重新发送websocket报警数据
|
||||
|
await new Promise((r) => setTimeout(r, 500)); |
||||
|
if (!this.alarmInfoMap.has(data.eventSerialNum)) { |
||||
|
console.log('发送websocket报警数据'); |
||||
|
this.loreadAlarmInfo(this.url.sendRadarAlarmByWebSocket, data.eventSerialNum); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if (this.videoWindowProps.visible) { |
||||
|
this.videoWindowProps.warnEvent.warnNum = this.radarAlarmDataMap.get(data.eventSerialNum).target.size; |
||||
|
} |
||||
|
// console.debug('雷达轨迹报警数据', this.radarAlarmDataMap);
|
||||
|
} else if (data.cmd == '') { |
||||
|
earth.sceneTree.$refs[data.eventSerialNum].destroy(); |
||||
|
} else if (data.cmd == 'eventPublish') { |
||||
|
window.getEventData(); |
||||
|
} |
||||
|
} |
||||
|
function websocketclose(e) { |
||||
|
console.log('connection closed (' + e.code + ')'); |
||||
|
createMessage.warn('websocket连接已断开', 3); |
||||
|
} |
||||
|
function websocketdosend(configName) { |
||||
|
//发送数据
|
||||
|
this.spinning = !this.spinning; //加载状态
|
||||
|
console.log('this.websock[configName]', websock[configName]); |
||||
|
let message = { |
||||
|
topic: 'Show_Single_Video', |
||||
|
msg: '192.168.1.65', |
||||
|
}; |
||||
|
//readyState:0:正在连接中,1:已建立连接,2:连接正在关闭,3:连接已关闭或连接失败
|
||||
|
if (websock[configName].readyState == 1) { |
||||
|
websock[configName].send(JSON.stringify(message)); |
||||
|
that.spinning = !that.spinning; //加载状态
|
||||
|
console.log('已发送'); |
||||
|
} else { |
||||
|
//重新连接websocket
|
||||
|
initWebSocket('clientURL'); |
||||
|
setTimeout(function () { |
||||
|
if (websock[configName].readyState == 1) { |
||||
|
websock[configName].send(JSON.stringify(message)); |
||||
|
} |
||||
|
that.spinning = !that.spinning; //加载状态
|
||||
|
}, 3000); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export { |
||||
|
initWebSocket, |
||||
|
websocketonopen, |
||||
|
websocketonerror, |
||||
|
loreadAlarmInfo, |
||||
|
websocketclose, |
||||
|
websocketonmessage, |
||||
|
websocketdosend, |
||||
|
websock, |
||||
|
} |
File diff suppressed because it is too large
Loading…
Reference in new issue