import { defineComponent, reactive, PropType, onMounted, watchEffect, watch, computed, } from 'vue'; import { useRoute, useRouter } from 'vue-router'; import isString from 'lodash/isString'; import useMarkerStore, { MarkerType } from '@/store/useMarkerStore'; import MapView from '../MapView'; import { useDaHuaStore } from '@/store'; /** @ts-ignore */ import icon_map_yjcl from '@/assets/icons/home/yjcl.svg'; /** @ts-ignore */ import icon_map_yjsj from '@/assets/icons/home/yjsj.svg'; /** @ts-ignore */ import icon_map_yjdw from '@/assets/icons/home/yjdw.svg'; /** @ts-ignore */ import icon_map_yjdw_w from '@/assets/icons/home/icon_map_yjdw_w.svg'; /** @ts-ignore */ import icon_map_yjck from '@/assets/icons/home/yjck.svg'; /** @ts-ignore */ import icon_map_yjck_w from '@/assets/icons/home/icon_map_yjck_w.svg'; /** @ts-ignore */ import icon_map_spjk from '@/assets/icons/home/spjk.svg'; /** @ts-ignore */ import icon_map_dcz from '@/assets/icons/home/icon_map_dcz.svg'; /** @ts-ignore */ import icon_map_dpf from '@/assets/icons/home/dpf.svg'; /** @ts-ignore */ import icon_map_dbsb from '@/assets/icons/home/dbsb.svg'; import './index.scss'; import { GET_INCIDENT_DIALOG_HTML, GET_TEAM_DIALOG_HTML, GET_VEHICLES_DIALOG_HTML, GET_VIDEO_DIALOG_HTML, GET_WAREHOUSE_DIALOG_HTML, GET_SINGLE_DEVICE_DIALOG_HTML, renderElement, } from './dialog'; import { IncidentItemDetail } from '@/api/incident'; import { useIncidentStore } from '@/store'; import Popup from '../Popup'; import { ElMessage } from 'element-plus'; import { isEmpty } from 'lodash'; import clsx from 'clsx'; import { SingleDeviceItem } from '@/api/resource'; const MARKER_MAP_TYPES = [ // '待派发事件', // '待处置事件', '路况信息', '视频监控', '应急车辆', '应急队伍', '应急仓库', '应急事件', '单兵', ] as const; export type MarkerMapType = typeof MARKER_MAP_TYPES[number]; interface State { map: any; types: MarkerMapType[]; trafficLayerIds: any[]; timer?: NodeJS.Timer | null; trafficStatus: boolean; markers: MarkerType[]; positions: string[]; hasTypes: string[]; // theSocket: null; } interface ActionType { type: MarkerMapType; hasActioned: boolean; action: Function; remove: Function; } // locationType + resourceType const RESOURCE_ICON_MAP = { '11': icon_map_yjck_w, // 水上 仓库 '21': icon_map_yjck, // 陆上 仓库 '12': icon_map_yjdw_w, // 水上 队伍 '22': icon_map_yjdw, // 陆上 队伍 '13': icon_map_yjcl, // 水上 车辆 '23': icon_map_yjcl, // 陆上 车辆 }; const getResourceIcon = (locationType: string, resourceType: string) => { // @ts-ignore return RESOURCE_ICON_MAP[locationType + resourceType] || ''; }; // 路况信息刷新间隔 const REFRESH_TRAFFIC_TIME = 60000; // let theSocket = null; // let vPlayArea =null; const getIncidentImage = (status: MarkerType['status']) => status?.toString() === '1' ? icon_map_yjsj : status?.toString() === '2' ? icon_map_dpf : status?.toString() === '3' ? icon_map_dcz : icon_map_yjsj; export default defineComponent({ name: 'MarkerMap', props: { adrsMapTypes: { type: Array as PropType, default: MARKER_MAP_TYPES, }, marker: Object as PropType, readonly: Boolean, }, setup(props, ctx) { const state = reactive({ map: null, types: [], trafficLayerIds: [], timer: undefined, trafficStatus: false, markers: [], positions: [], hasTypes: [], // theSocket:null }); const store = useMarkerStore(); const incidentStore = useIncidentStore(); const daHuaStore = useDaHuaStore(); const router = useRouter(); const route = useRoute(); // const theSocket = null; const adrsMapTypes = computed(() => props.adrsMapTypes.map((i) => ({ name: i, disabled: route.query.id && i === '应急事件', })), ); const actionTypes = computed(() => [ { type: '路况信息', hasActioned: state.trafficStatus, action: toggleControlTraffic, remove: toggleControlTraffic, }, { type: '应急事件', hasActioned: state.hasTypes.includes('应急事件'), action: () => handleAddMarkers('应急事件', store.incident, icon_map_dpf), remove: () => handleRemoveMarkers('应急事件', store.incident), }, { type: '视频监控', hasActioned: state.hasTypes.includes('视频监控'), action: () => // console.log(store.videoSurveillance); handleAddMarkers('视频监控', store.videoSurveillance, icon_map_spjk), remove: () => handleRemoveMarkers('视频监控', store.videoSurveillance), }, { type: '应急车辆', hasActioned: state.hasTypes.includes('应急车辆'), action: () => handleAddMarkers('应急车辆', store.emergencyVehicles, icon_map_yjcl), remove: () => handleRemoveMarkers('应急车辆', store.emergencyVehicles), }, { type: '应急队伍', hasActioned: state.hasTypes.includes('应急队伍'), action: () => handleAddMarkers('应急队伍', store.emergencyTeam, icon_map_yjdw), remove: () => handleRemoveMarkers('应急队伍', store.emergencyTeam), }, { type: '应急仓库', hasActioned: state.hasTypes.includes('应急仓库'), action: () => handleAddMarkers('应急仓库', store.emergencyWarehouse, icon_map_yjck), remove: () => handleRemoveMarkers('应急仓库', store.emergencyWarehouse), }, { type: '单兵', hasActioned: state.hasTypes.includes('单兵'), action: () => handleAddMarkers('单兵', store.singleDevice, icon_map_dbsb), remove: () => handleRemoveMarkers('单兵', store.singleDevice), }, ]); const getMarkerPopupHTML = (type: MarkerMapType, marker: MarkerType) => { switch (type) { case '应急事件': // case '待派发事件': // case '预警事件': default: return GET_INCIDENT_DIALOG_HTML(marker, async () => { marker.id && (await incidentStore.getIncidentItem(marker.id)); await router.push(`/incidentDetail?id=${marker?.id}`); handleSetDetailMarker(marker); store.currentIncident = marker; }); case '单兵': { var callback = () => { console.log(marker['deviceCode']); console.log(marker['userId']); // daHuaStore.DAHUAUserObj(marker["userId"]).then(deviceUser=>{ // console.log(deviceUser); // let memberObj = { // userName:deviceUser.userName, // userId:deviceUser.userCode, // region:deviceUser.paasId, // type:'single', // // speak:'true', // number:deviceUser.userPhone, // deviceId:marker["deviceCode"], // channelId:marker["channelId"], // } // let meetObj = JSON.parse(localStorage.getItem('meeting')); // let memberList = []; // memberList.push(meetObj.member==null||meetObj.member==undefined?"":meetObj.member[0]); // memberList.push(memberObj); // meetObj.member = memberList // console.log(meetObj); // daHuaStore.DAHUAMeetingMember(meetObj).then(data=>{ // // console.log(11111111) // daHuaStore.DAHUAMeetingUser(meetObj.meetId); // daHuaStore.DAHUAUserInfo().then(u => { // console.log(u,'+++++++'); // initSocket(u.userCode,memberObj); // }) // }) // console.log(memberObj); // meetObj.mebmber.push(memberObj); const DAHUA = document.getElementById('DAHUA') as HTMLIFrameElement; DAHUA?.contentWindow?.postMessage( { key: 'danbing', value: marker['userId'], deviceId: marker['deviceCode'], channelId: marker['channelId'], }, '*', ); daHuaStore.dahuaUserVisible = true; // console.log(daHuaStore.deviceUser); }; return GET_SINGLE_DEVICE_DIALOG_HTML( marker as SingleDeviceItem, callback, ); } case '应急仓库': return GET_WAREHOUSE_DIALOG_HTML(marker); case '应急车辆': return GET_VEHICLES_DIALOG_HTML(marker); case '应急队伍': return GET_TEAM_DIALOG_HTML(marker); case '视频监控': return GET_VIDEO_DIALOG_HTML(marker, () => { if(marker['status'] == 1){ const DAHUA = document.getElementById('DAHUA') as HTMLIFrameElement; DAHUA?.contentWindow?.postMessage( { key: 'video', value: marker['userId'], deviceId: marker['deviceCode'], channelId: marker['channelId'], }, '*', ); daHuaStore.dahuaUserVisible = true; }else{ ElMessage.warning('设备离线,请联系大华相关人员'); } }); } }; const videoplay = (item: { type: string; userId: any; channelId: any }) => { console.log('播放视频'); console.log(item); if (!window.theSocket.websocket) { ElMessage.warning('请先打开视频插件'); return; } if (item.type == 'client') { window.slectOptionmini(item.userId).then((arr: any) => { if (arr) { window.vPlayArea.openAppVideo(arr); } }); } else if (item.type == 'single') { //播放单兵视频 pullFlow(item.channelId); } else if (item.type == 'vehicle') { //播放车载视频 pullFlow(item.channelId); } else if (item.type == 'uav_dev') { //播放无人机视频 pullFlow(item.channelId); } }; const pullFlow = (channelId: any) => { channelId && window.vPlayArea && window.vPlayArea.realTimeVideo([{ channelId }]); }; const initSocket = ( userCode: string, memberObj: { userName?: any; userId: any; region?: any; type: string; number?: any; deviceId?: any; channelId: any; }, ) => { const self = this; console.log(userCode); localStorage.setItem('userId', userCode); //初始websocket实例,保存在window中方便调用。一个浏览器tab页面只能初始化一次。所有的控件窗口,通过该websocket实例去生成不同的窗口实例,不同的控件窗口通过自己的窗口实例去调用初始化、关闭、隐藏等 window.theSocket = new window.InitWebSocketClass( userCode, localStorage.getItem('DAHUA_token'), { //客户端登陆成功通知; loginSuccess: (v: any) => { console.log(2222222222222222); console.log('loginSuccess-->', v); initWnd(); }, //客户端窗口被拉起通知 onCreateVideoSuccess: (v: any) => { console.log('客户端onCreateVideoSuccess-----', v); }, //重点:统一分发客户端ws消息;vue 可以统一用$bus分发.第三方消息分发自定 onSocketBackInfos: (data: { method: string; params: { result: number; handleName: string }; }) => { //视频窗口创建成功通知 if ( data && data.method === 'createVideoDialogReuslt' && data.params.result === 0 ) { if (data.params.handleName === '#vPlayArea') { //客户端窗口创建好后,界面显示窗口; window.vPlayArea.resize(); ElMessage.warning('视频窗口创建成功!'); videoplay(memberObj); } } }, }, ); // console.log(theSocket); //socket实例初始化websocket回调方法; window.theSocket .initWebSocket() .then((v: any) => { if (v) { ElMessage.warning('视频插件登陆完成!'); } }) .catch(() => { ElMessage.warning('若要观看实时视频,请先安装视频插件'); }); }; const initWnd = () => { console.log(1111); //左边窗口类型参数 分割 2行2列 const typeObj = { rows: 2, cols: 2, wndSpaceing: 10, embedVideoMode: true, playerCtrlBarEnable: false, displayMode: 0, playMode: 0, playParams: {}, }; //左边窗口实例 window.vPlayArea = new window.VideoPlay( '#vPlayArea', window.theSocket.websocket, //一个浏览器tab页面公用一个 window.theSocket.socketCode, //一个浏览器tab页面公用一个 typeObj, ); //左边窗口初始化 window.vPlayArea.init(); }; const updateTrafficSource = () => { if (state.map.getSource('Traffic')) { state.map.removeSource('Traffic'); } state.map.addSource('Traffic', { type: 'vector', traffic: true, tiles: [ 'mineserver://data/dynamic-traffic/ertic?servicetype=0&z={z}&x={x}&y={y}', ], }); }; const updateTrafficLayerVisibility = (v: 'none' | 'visible') => { state.trafficLayerIds.forEach(function (id) { if (state.map?.getLayer(id)) { state.map?.setLayoutProperty(id, 'visibility', v); } }); }; const toggleControlTraffic = () => { if (state.trafficStatus) { state.trafficStatus = false; if (state.timer) { clearInterval(state.timer); state.timer = null; } updateTrafficLayerVisibility('none'); } else { state.trafficStatus = true; if (state.timer) { clearInterval(state.timer); state.timer = null; } updateTrafficSource(); state.timer = setInterval(function () { updateTrafficSource(); }, REFRESH_TRAFFIC_TIME); updateTrafficLayerVisibility('visible'); } }; const handleAddMarkers = ( type: MarkerMapType, markers: State['markers'], image: any, ) => { console.log(state.markers); state.markers.push( ...markers.map((i) => { const nextImage = type === '应急事件' ? getIncidentImage(i?.status) : i.locationType && i.resourceType ? getResourceIcon( i.locationType.toString(), i.resourceType.toString(), ) : image; const popup = new window.minemap.Popup({ anchor: 'left', closeOnClick: true, closeButton: false, offset: [10, 25], maxWidth: 'max-content', // autoPan: true, }).setDOMContent(getMarkerPopupHTML(type, i)); return { locations: i.locations, popup, marker: i.locations && new window.minemap.Marker(renderElement(nextImage), { offset: [-25, -25], }) .setLngLat({ lng: i.locations?.split(',')[0], lat: i.locations?.split(',')[1], }) .setPopup(popup) .addTo(state.map), }; }), ); state.positions.push(...markers.map((i) => i.locations).filter(isString)); handleFitBounds(); }; const handleFitBounds = () => { if (state.positions.length === 0) { return; } const locations = state.positions.map((i) => i.split(',').map(Number)); const leftTop = locations.reduce((carry, next) => { if (carry.length === 0) return next; return [Math.min(carry[0], next[0]), Math.max(carry[1], next[1])]; }, []); const rightBottom = locations.reduce((carry, next) => { if (carry.length === 0) return next; return [Math.max(carry[0], next[0]), Math.min(carry[1], next[1])]; }, []); const leftTopBounds: number[][] = new window.minemap.LngLat(...leftTop) .toBounds(5000) .toArray(); const rightBottomBounds: number[][] = new window.minemap.LngLat( ...rightBottom, ) .toBounds(5000) .toArray(); state.map.fitBounds([ rightBottomBounds.reduce((carry, next) => { if (carry.length === 0) return next; return [Math.max(carry[0], next[0]), Math.min(carry[1], next[1])]; }, []), leftTopBounds.reduce((carry, next) => { if (carry.length === 0) return next; return [Math.min(carry[0], next[0]), Math.max(carry[1], next[1])]; }, []), ]); }; const handleRemoveMarkers = ( type: MarkerMapType, markers: State['markers'], ) => { state.hasTypes = state.hasTypes.filter((t) => t !== type); const locations = markers.map((i) => i.locations); state.markers.forEach((m) => { if (locations.includes(m.locations)) { m.marker?.remove(); m.popup?.remove(); m.popup = null; m.marker = null; } }); state.markers = state.markers.filter( (m) => !locations.includes(m.locations), ); state.positions = state.positions.filter((p) => !locations.includes(p)); handleFitBounds(); }; const handleRemoveAllMarkers = () => { state.markers.forEach((m) => { m.marker?.remove(); m.popup?.remove(); }); state.markers = []; state.positions = []; }; const handleSetDetailMarker = (marker: MarkerType) => { handleRemoveAllMarkers(); const locations = marker.locations?.split(',').map(Number); if (!locations) { ElMessage.error({ message: '该点位无地址经纬度' }); return; } // 获取事件周围的 5km 内的 监控点 const bounds: number[][] = new window.minemap.LngLat(...locations) .toBounds(10000) .toArray(); const videos = store.videoSurveillance.reduce((carry, next) => { const [lng, lat] = next.locations?.split(',') ?? []; // bounds [right-bottom[lng, lat],left-top[lng, lat], ] if ( Number(lng) > bounds[0][0] && Number(lng) < bounds[1][0] && Number(lat) > bounds[0][1] && Number(lat) < bounds[1][1] ) { carry.push(next); } return carry; }, [] as MarkerType[]); // 开启路况信息 if (!state.types.includes('路况信息')) { state.types.push('路况信息'); state.hasTypes.push('路况信息'); toggleControlTraffic(); } handleAddMarkers('应急事件', [marker], icon_map_dpf); handleAddMarkers('视频监控', videos, icon_map_spjk); // state.markers[0].marker.togglePopup(); }; onMounted(async () => { window.minemap.util.getJSON( 'http://61.147.254.211:21009/service/solu/style/id/12878', function (error, data) { data.layers.forEach(function (layer: any) { //判断是否道路线图层 if ( layer.type == 'line' && layer.source == 'Traffic' && layer['source-layer'] == 'Trafficrtic' ) { state.trafficLayerIds.push(layer.id); } }); }, ); try { const html = document.createElement("div"); actionTypes.value.forEach(atypes => { if (atypes?.action == null) return; const name = atypes.type; const c = (atypes?.action?.toString().split("handleAddMarkers")); if (c.length <= 1) return; const args1 = c[1].replaceAll("(","").replaceAll(")",""); // debugger const args = args1.split(","); if (eval(args[2]) == undefined) return; const div = document.createElement("div"); div.className = "tipitem" const imagee = renderElement((eval(args[2]))); div.append(imagee); const c1 = document.createElement("span"); c1.innerHTML = (name); div.append(c1); html.append(div); }); state.map["tipcontentRef"].append(html); } catch (ee) { } state.map.on('load', function () { updateTrafficSource(); //如果底图没有配置路况图层,需要自己手动增加 state.map.addLayer({ id: 'trafficlines', type: 'line', source: 'Traffic', 'source-layer': 'Trafficrtic', layout: { 'line-join': 'round', 'line-cap': 'round', }, paint: { 'line-color': { property: 'status', stops: [ [0, '#999999'], [1, '#66cc00'], [2, '#ff9900'], [3, '#cc0000'], [4, '#9d0404'], ], }, 'line-width': { stops: [ [5, 1], [18, 3], ], base: 1.2, }, }, }); state.trafficLayerIds.push('trafficlines'); state.trafficStatus = false; updateTrafficLayerVisibility('none'); store.getAllResources(); store.getAllsingleDevice(); store.getAllvideoDevice(); store.getHDIncidentList(); }); if (!route.query.id) return; // 如果存在id await incidentStore.getIncidentItem(route.query.id as string); // @ts-ignore handleSetDetailMarker(incidentStore.incidentDetail.baseInfo ?? {}); // const vPlayAreaEl = document.getElementById('vPlayArea'); // vPlayAreaEl && // (vPlayAreaEl.style.height = window.innerHeight - 20 + 'px'); // window.theSocket && window.theSocket.resize(); }); watch( () => store?.currentIncident, (next) => { if (!isEmpty(next)) { handleSetDetailMarker({ ...next, }); } else { handleRemoveAllMarkers(); if (state.types.includes('应急事件')) { state.types.forEach((next) => { actionTypes.value.forEach((item) => { if (next === item.type) { state.hasTypes.push(item.type); item.action(); } }); }); } else { state.map?.flyTo({ center: [118.29564, 33.97441], zoom: 14, bearing: 10, pitch: 30, duration: 2000, }); } } }, ); watch( () => state.types, (next) => { actionTypes.value.forEach((item) => { if (next.includes(item.type) && !item.hasActioned) { state.hasTypes.push(item.type); item.action(); } if (!next.includes(item.type) && item.hasActioned) { item.remove(); } }); }, ); return () => (
{/*
*/} {/*
*/} {/*
*/}
{adrsMapTypes.value && adrsMapTypes.value?.map((t) => ( <> {!t.disabled && ( )} ))}
); }, });