Pārlūkot izejas kodu

Merge remote-tracking branch 'origin/dev' into dev

yangyuxuan 4 mēneši atpakaļ
vecāks
revīzija
68a50f7213

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 331 - 331
package-lock.json


+ 1 - 1
package.json

@@ -21,7 +21,7 @@
     "@amap/amap-jsapi-loader": "^1.0.1",
     "@element-plus/icons-vue": "2.3.1",
     "@highlightjs/vue-plugin": "2.1.0",
-    "@turf/turf": "^7.1.0",
+    "@turf/turf": "^7.2.0",
     "@univerjs/core": "^0.4.1",
     "@univerjs/design": "^0.4.1",
     "@univerjs/docs": "^0.4.1",

+ 216 - 16
src/components/Map/YztMap/index.vue

@@ -1,27 +1,40 @@
 <template>
   <div ref="containerRef" class="map-container">
-    <div ref="mapRef" id="YztMap" class="map-container" :style="{ width: width, height: height }"></div>
+    <div
+      ref="mapRef"
+      id="YztMap"
+      class="map-container"
+      :style="{
+        width: width,
+        height: height
+      }"
+    ></div>
     <rightTool :mapState="mapState" type="YztMap" :showMask="showMask" @changeShowMask="changeShowMask" />
   </div>
 </template>
 
 <script setup lang="ts">
 import 'ol/ol.css';
-import ScaleLine from 'ol/control/ScaleLine';
+import rightTool from '../rightTool.vue';
 import mmJson from '@/assets/json/mm2.json';
 import { olMap } from '@/utils/olMap/olMap';
 import { PointType } from '@/api/globalMap/type';
-import QuickZoom from '@/components/Map/quickZoom.vue';
+import { ScaleLine } from 'ol/control';
+import { getPointInfoList } from '@/api/globalMap';
+import { getDictLabel } from '@/utils/dict';
+import { methodList, titleList } from '../data';
+import { pointDetailTemplate } from '@/views/globalMap/data/mapData';
 
 interface Props {
   activeMap: string;
-  // 获取需要查询点的类型
-  pointType?: PointType[];
+  pointType: PointType[];
   showMask: boolean;
 }
 const containerScale = inject('containerScale');
 const props = withDefaults(defineProps<Props>(), {});
-const emits = defineEmits(['update:drawing', 'update:showMask', 'selectGraphics']);
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const { point_type } = toRefs<any>(proxy?.useDict('point_type'));
+const emits = defineEmits(['update:drawing', 'update:showMask', 'selectGraphics', 'handleShowWarehouse', 'handleShowVideo', 'handleShowPeople']);
 
 const mapRef = ref(null);
 const mapState = reactive({
@@ -100,8 +113,8 @@ const init = () => {
       }
     },
     // 加载完成事件
-    onLoadCompleted: (yMap) => {
-      map = yMap;
+    onLoadCompleted: (YztMap) => {
+      map = YztMap;
       // initMouseTool(mapUtils);
       scale = new ScaleLine();
       map.addControl(scale);
@@ -112,13 +125,195 @@ const init = () => {
         mapUtils.createVecByJson2(mmJson, { strokeWeight: 2 });
       }
       handleResize();
+    },
+    onMarkerClick: (data) => {
+      // 多点位
+      if (data.type === '1') {
+        let path = [];
+        props.pointType.forEach((item) => {
+          path.push(item.component);
+        });
+        getPointInfoList({
+          option: path.toString(),
+          longitude: data.longitude.toString(),
+          latitude: data.latitude.toString()
+        }).then((res) => {
+          const data2 = res.data.list;
+          let content = document.createElement('div');
+          // content.style.cssText = 'transform: scale(' + containerScale().scaleX + ');';
+          content.className = 'point-info';
+          let content2 = '';
+          content2 += '<div class="title-box"><div class="gradient-text">多点位信息</div></div>';
+          content2 += '<div class="icon1"></div>';
+          content2 += '<div class="icon2"></div>';
+          content2 += '<div class="icon3"></div>';
+          content2 += '<div class="icon4"></div>';
+          content.innerHTML = content2;
+          let tableBox = document.createElement('div');
+          tableBox.className = 'table-box';
+          let table = document.createElement('div');
+          table.className = 'table';
+          table.innerHTML = '<div class="point-item"><div class="td3">主题</div><div class="td3">名称</div></div>';
+          data2.forEach((item) => {
+            item.longitude = data.longitude;
+            item.latitude = data.latitude;
+            const div = document.createElement('div');
+            div.className = 'point-item point-item-hover';
+            div.innerHTML =
+              '<div class="td4">' + getDictLabel(point_type.value, item.dataType.toString()) + '</div><div class="td4">' + item.name + '</div>';
+            div.addEventListener('click', () => {
+              handlePointDetails(item);
+            });
+            table.appendChild(div);
+          });
+          tableBox.appendChild(table);
+          content.appendChild(tableBox);
+          let closeBtn = document.createElement('div');
+          closeBtn.className = 'close';
+          closeBtn.onclick = () => mapUtils.hideInfo(true);
+          content.appendChild(closeBtn);
+          mapUtils.showInfo(content, [data.longitude, data.latitude], true);
+        });
+      } else {
+        handlePointDetails(data);
+      }
     }
   });
 };
+const handlePointDetails = (data) => {
+  let method = methodList[data.dataType];
+  let title = !!titleList[data.dataType] ? titleList[data.dataType] : '信息';
+  if (!method) return;
+  method(data.id).then((res) => {
+    if (!!pointDetailTemplate[data.dataType]) {
+      let div = document.createElement('div');
+      // div.style.cssText = 'transform: scale(' + containerScale().scaleX + ');';
+      div.className = 'point-info';
+      let titleDom = document.createElement('div');
+      titleDom.className = 'title-box';
+      titleDom.innerHTML = '<div class="gradient-text">' + title + '</div></div>';
+      div.appendChild(titleDom);
+      if (data.dataType === 2) {
+        let btnBox = document.createElement('div');
+        let btn = document.createElement('div');
+        btnBox.className = 'flex';
+        btn.className = 'btn';
+        btn.innerHTML = '<div class="video-icon"></div><div>物资详情</div>';
+        btn.onclick = () => {
+          emits('handleShowWarehouse', data);
+        };
+        btnBox.appendChild(btn);
+        div.appendChild(btnBox);
+      } else if (data.dataType === 4) {
+        let btnBox = document.createElement('div');
+        let btn = document.createElement('div');
+        btnBox.className = 'flex';
+        btn.className = 'btn';
+        btn.innerHTML = '<div class="video-icon"></div><div>附近视频</div>';
+        btn.onclick = () => {
+          emits('handleShowVideo', data);
+        };
+        btnBox.appendChild(btn);
+        div.appendChild(btnBox);
+      } else if (data.dataType === 41) {
+        let btnBox = document.createElement('div');
+        let btn = document.createElement('div');
+        btnBox.className = 'flex';
+        btn.className = 'btn';
+        btn.innerHTML = '<div class="video-icon"></div><div>人员列表</div>';
+        btn.onclick = () => {
+          emits('handleShowPeople', data);
+        };
+        btnBox.appendChild(btn);
+        div.appendChild(btnBox);
+      }
+      let icon1 = document.createElement('div');
+      icon1.className = 'icon1';
+      let icon2 = document.createElement('div');
+      icon2.className = 'icon2';
+      let icon3 = document.createElement('div');
+      icon3.className = 'icon3';
+      let icon4 = document.createElement('div');
+      icon4.className = 'icon4';
+      div.appendChild(icon1);
+      div.appendChild(icon2);
+      div.appendChild(icon3);
+      div.appendChild(icon4);
+      let table = document.createElement('div');
+      table.className = 'table-box';
+      let content = '';
+      content += '<div class="table">';
+      const newData = filterTd(res.rows[0], data.dataType);
+      newData.forEach((item) => {
+        if (item.type === 'shortText') {
+          content += '<div class="tr">';
+          item.data.forEach((item2) => {
+            content += '<div class="point-item">';
+            content += '<div class="td1">' + item2.label + '</div><div class="td2">' + item2.value + '</div>';
+            content += '</div>';
+          });
+          content += '</div>';
+        } else {
+          content += '<div class="point-item2">';
+          content += '<div class="td1">' + item.data[0].label + '</div><div class="td2">' + item.data[0].value + '</div>';
+          content += '</div>';
+        }
+      });
+      content += '</div>';
+      table.innerHTML = content;
+      div.appendChild(table);
+      let closeBtn = document.createElement('div');
+      closeBtn.className = 'close';
+      closeBtn.onclick = () => mapUtils.hideInfo(true);
+      div.appendChild(closeBtn);
+      mapUtils.showInfo(div, [data.longitude, data.latitude], true);
+    }
+  });
+};
+const filterTd = (obj, dataType) => {
+  let data = [];
+  let tempData = {};
+  let i = 0;
+  for (let key in obj) {
+    let keyLabel = pointDetailTemplate[dataType][key];
+    if (!!keyLabel) {
+      if (i === 2) {
+        i = 0;
+      }
+      const value = !!obj[key] ? obj[key] : '';
+      if (value && value.length > 8) {
+        if (i === 0) {
+          data.push({ type: 'longText', data: [{ label: keyLabel, value: value }] });
+          i = 0;
+        } else {
+          tempData = { type: 'longText', data: [{ label: keyLabel, value: value }] };
+        }
+      } else {
+        if (i === 0) {
+          data.push({ type: 'shortText', data: [{ label: keyLabel, value: value }] });
+        } else {
+          data[data.length - 1].data.push({ label: keyLabel, value: value });
+        }
+        i++;
+        if (!!tempData && JSON.stringify(tempData) !== '{}') {
+          data.push(tempData);
+          tempData = {};
+          i = 0;
+        }
+      }
+    }
+  }
+  if (!!tempData && JSON.stringify(tempData) !== '{}') {
+    data.push(tempData);
+  }
+  if (data[data.length - 1].data && data[data.length - 1].data.length === 1 && data[data.length - 1].type === 'shortText') {
+    data[data.length - 1].data[1] = { label: '', value: '' };
+  }
+  return data;
+};
 const addMarker = (points) => {
   mapUtils.addMarker(points);
 };
-
 const clearMarker = () => {
   mapUtils.clearMarker();
 };
@@ -132,6 +327,15 @@ const handleResize = () => {
   height.value = containerHeight + 'px';
   map.updateSize();
 };
+const getMap = () => {
+  return map;
+};
+const getScale = () => {
+  return scale;
+};
+const getMapUtils = () => {
+  return mapUtils;
+};
 // 加载事件
 onMounted(() => {
   init();
@@ -141,18 +345,14 @@ onMounted(() => {
 onUnmounted(() => {
   window.removeEventListener('resize', handleResize);
 });
-const getMap = () => {
-  return map;
-};
-const getScale = () => {
-  return scale;
-};
+provide('getMapUtils', getMapUtils);
 provide('getMap', getMap);
 provide('getScale', getScale);
-defineExpose({ addMarker, clearMarker });
+defineExpose({ getMapUtils, addMarker, clearMarker });
 </script>
 
 <style scoped>
+@import '../map.scss';
 .map-container {
   width: 100%;
   height: 100%;

+ 106 - 0
src/components/Map/data.ts

@@ -0,0 +1,106 @@
+import {
+  getEmergencyExpertDetails,
+  getEmergencyShelterTypeDetails,
+  getGasolinestationDetails,
+  getHospitalDetails,
+  getMiningcompanyDetails,
+  getWarehouseDetails,
+  getChemicalcompanyDetails,
+  getSchoolDetails,
+  getWaterloggedRoadsDetails,
+  getShipRealtilmePositionDetails,
+  getUAVDetails,
+  getRainbowDetails,
+  getTouristAttractionDetails,
+  getConstructionSitesDetails,
+  getYardSitesDetails,
+  getStationInfoDetails,
+  getMajorHazardSourceDetails,
+  getBuildingProjectDetails,
+  getChemicalWarehouseDetails,
+  getMiningOperationsDetails,
+  getEmergencyTransportResourcesDetails,
+  getEmergencyDisasterInfoOfficerDetails,
+  getMidmapDzzhDetails,
+  getVehicleDetails,
+  getMDPUnitDetails,
+  getWaterList,
+  getVideoDrowning,
+  getVideoForestFire,
+  getVideoDisasterPrevention
+} from '@/api/globalMap/spatialAnalysis';
+import { getRescueTeamsInfo } from '@/api/globalMap/rescueTeam';
+
+export const methodList = {
+  '1': getEmergencyExpertDetails,
+  '2': getWarehouseDetails,
+  '3': getEmergencyShelterTypeDetails,
+  '4': getWaterloggedRoadsDetails,
+  '5': getSchoolDetails,
+  '6': getHospitalDetails,
+  '7': getGasolinestationDetails,
+  '8': getMiningcompanyDetails,
+  // '9': getChemicalcompanyDetails,
+  '10': getShipRealtilmePositionDetails,
+  '11': getChemicalcompanyDetails,
+  '12': getChemicalcompanyDetails,
+  '13': getChemicalcompanyDetails,
+  '14': getChemicalcompanyDetails,
+  '15': getUAVDetails,
+  '16': getRainbowDetails,
+  '17': getMidmapDzzhDetails,
+  '18': getMiningOperationsDetails,
+  '20': getMDPUnitDetails,
+  '21': getBuildingProjectDetails,
+  '22': getChemicalWarehouseDetails,
+  '23': getMajorHazardSourceDetails,
+  '24': getStationInfoDetails,
+  '25': getYardSitesDetails,
+  '26': getTouristAttractionDetails,
+  '27': getConstructionSitesDetails,
+  '28': getEmergencyTransportResourcesDetails,
+  '29': getEmergencyDisasterInfoOfficerDetails,
+  '30': getVehicleDetails,
+  '31': getWaterList,
+  '32': getVideoDrowning,
+  '33': getVideoForestFire,
+  '34': getVideoDisasterPrevention,
+  '41': getRescueTeamsInfo
+};
+export const titleList = {
+  '1': '专家信息',
+  '2': '物资与装备仓库信息',
+  '3': '避难所信息',
+  '4': '易涝点信息',
+  '5': '学校信息',
+  '6': '医院信息',
+  '7': '加油站信息',
+  '8': '非煤矿山企业信息',
+  '9': '危化企业信息',
+  '10': '船舶动态信息',
+  '11': '危险化学品经营企业信息',
+  '12': '危险化学品生产企业信息',
+  '13': '危险化学品使用企业(使用许可)信息',
+  '14': '化工企业(不发使用许可)信息',
+  '15': '无人机信息',
+  '16': '雨窝点',
+  '17': '地质灾害隐患点',
+  '18': '矿山施工',
+  '19': '工矿商贸',
+  '20': '气象灾害防御重点单位',
+  '21': '建筑工程',
+  '22': '储罐信息',
+  '23': '重大危险源',
+  '24': '客运站',
+  '25': '堆场',
+  '26': '旅游场所',
+  '27': '在建工地',
+  '28': '运输资源',
+  '29': '灾害信息员',
+  '30': '重点车辆信息',
+  '31': '江湖河库',
+  '32': '防溺水',
+  '33': '森林防火',
+  '34': '防灾救援',
+  '41': '救援队伍'
+};

+ 1 - 103
src/components/Map/index.vue

@@ -13,39 +13,9 @@ import { useDrawTool } from '@/hooks/AMap/useDrawTool';
 import { getPointInfoList } from '@/api/globalMap';
 import { getDictLabel } from '@/utils/dict';
 import { PointType } from '@/api/globalMap/type';
-import {
-  getEmergencyExpertDetails,
-  getEmergencyShelterTypeDetails,
-  getGasolinestationDetails,
-  getHospitalDetails,
-  getMiningcompanyDetails,
-  getWarehouseDetails,
-  getChemicalcompanyDetails,
-  getSchoolDetails,
-  getWaterloggedRoadsDetails,
-  getShipRealtilmePositionDetails,
-  getUAVDetails,
-  getRainbowDetails,
-  getTouristAttractionDetails,
-  getConstructionSitesDetails,
-  getYardSitesDetails,
-  getStationInfoDetails,
-  getMajorHazardSourceDetails,
-  getBuildingProjectDetails,
-  getChemicalWarehouseDetails,
-  getMiningOperationsDetails,
-  getEmergencyTransportResourcesDetails,
-  getEmergencyDisasterInfoOfficerDetails,
-  getMidmapDzzhDetails,
-  getVehicleDetails,
-  getVideoDrowning,
-  getVideoForestFire,
-  getVideoDisasterPrevention
-} from '@/api/globalMap/spatialAnalysis';
+import { methodList, titleList } from './data';
 import { pointDetailTemplate } from '@/views/globalMap/data/mapData';
 import useAppStore from '@/store/modules/app';
-import { getWaterList } from '@/api/globalMap/reservoir';
-import { getRescueTeamsInfo } from '@/api/globalMap/rescueTeam';
 import mmJson from '@/assets/json/mm2.json';
 interface Props {
   activeMap: string;
@@ -194,78 +164,6 @@ const {
   trackPlayback
 } = { ...mapUtils };
 const handlePointDetails = (data) => {
-  let methodList = {
-    '1': getEmergencyExpertDetails,
-    '2': getWarehouseDetails,
-    '3': getEmergencyShelterTypeDetails,
-    '4': getWaterloggedRoadsDetails,
-    '5': getSchoolDetails,
-    '6': getHospitalDetails,
-    '7': getGasolinestationDetails,
-    '8': getMiningcompanyDetails,
-    // '9': getChemicalcompanyDetails,
-    '10': getShipRealtilmePositionDetails,
-    '11': getChemicalcompanyDetails,
-    '12': getChemicalcompanyDetails,
-    '13': getChemicalcompanyDetails,
-    '14': getChemicalcompanyDetails,
-    '15': getUAVDetails,
-    '16': getRainbowDetails,
-    '17': getMidmapDzzhDetails,
-    '18': getMiningOperationsDetails,
-    '21': getBuildingProjectDetails,
-    '22': getChemicalWarehouseDetails,
-    '23': getMajorHazardSourceDetails,
-    '24': getStationInfoDetails,
-    '25': getYardSitesDetails,
-    '26': getTouristAttractionDetails,
-    '27': getConstructionSitesDetails,
-    '28': getEmergencyTransportResourcesDetails,
-    '29': getEmergencyDisasterInfoOfficerDetails,
-    '30': getVehicleDetails,
-    '31': getWaterList,
-    '32': getVideoDrowning,
-    '33': getVideoForestFire,
-    '34': getVideoDisasterPrevention,
-    '41': getRescueTeamsInfo
-  };
-  let titleList = {
-    '1': '专家信息',
-    '2': '物资与装备仓库信息',
-    '3': '避难所信息',
-    '4': '易涝点信息',
-    '5': '学校信息',
-    '6': '医院信息',
-    '7': '加油站信息',
-    '8': '非煤矿山企业信息',
-    '9': '危化企业信息',
-    '10': '船舶动态信息',
-    '11': '危险化学品经营企业信息',
-    '12': '危险化学品生产企业信息',
-    '13': '危险化学品使用企业(使用许可)信息',
-    '14': '化工企业(不发使用许可)信息',
-    '15': '无人机信息',
-    '16': '雨窝点',
-    '17': '地质灾害隐患点',
-    '18': '矿山施工',
-    '19': '工矿商贸',
-    '20': '气象灾害防御重点单位',
-    '21': '建筑工程',
-    '22': '储罐信息',
-    '23': '重大危险源',
-    '24': '客运站',
-    '25': '堆场',
-    '26': '旅游场所',
-    '27': '在建工地',
-    '28': '运输资源',
-    '29': '灾害信息员',
-    '30': '重点车辆信息',
-    '31': '江湖河库',
-    '32': '防溺水',
-    '33': '森林防火',
-    '34': '防灾救援',
-    '41': '救援队伍'
-  };
   let method = methodList[data.dataType];
   let title = !!titleList[data.dataType] ? titleList[data.dataType] : '信息';
   if (!method) return;

+ 1 - 0
src/hooks/AMap/useAMap.ts

@@ -601,6 +601,7 @@ export function useAMap(options) {
     initMap(options);
   });
   return {
+    initMap,
     getAMap,
     getMap,
     switchMap,

+ 6 - 0
src/utils/gisUtils.ts

@@ -181,3 +181,9 @@ export const mergeGeoJsonPolygons = (geoJsonData) => {
   }
   return merged;
 };
+
+// 获取多个坐标点的中心
+export const getPointsCenter = (points) => {
+  const features = turf.points(points);
+  return turf.center(features);
+}

+ 196 - 69
src/utils/olMap/olMap.ts

@@ -24,12 +24,14 @@ import GeoJSON from 'ol/format/GeoJSON';
 import { fromLonLat } from 'ol/proj';
 import axios from 'axios';
 import { fromExtent } from 'ol/geom/Polygon';
-import { LinearRing, Polygon } from 'ol/geom';
-import { Tile } from 'ol';
+import { LinearRing, LineString, Polygon } from 'ol/geom';
 import {Graticule} from "ol/layer";
-import { mergeGeoJsonPolygons } from '@/utils/gisUtils';
-// import olPlot from 'ol-plot';
-// import { activate } from '../ol-plot/ol-plot'
+import { getPointsCenter, mergeGeoJsonPolygons } from '@/utils/gisUtils';
+import { Cluster } from 'ol/source';
+import CircleStyle from 'ol/style/Circle';
+import Overlay from 'ol/Overlay';
+import { Select } from 'ol/interaction';
+import { click } from 'ol/events/condition';
 
 const commonUrl = import.meta.env.VITE_APP_BASE_API2 + 'api/oneShare/proxyHandler/gd/';
 // proj4.defs('EPSG:4490', '+proj=longlat +ellps=GRS80 +no_defs +type=crs');
@@ -63,14 +65,14 @@ export class olMap {
     fillOpacity: 0,
     strokeStyle: 'solid'
   };
-  // private { currentState, commit, undo, history, future } = useHistory();
-  private overlays = [];
-  private overlaysData = [];
-  private graphicsType = '';
   private plot;
   private vectorLayer;
+  // 边界遮罩图层
   private maskLayer;
-  private maskLayer2 = [];
+  private maskLayer2;
+  // 显示信息框
+  private infoWindow;
+  private select;
 
   constructor(options) {
     this.options = options;
@@ -97,6 +99,71 @@ export class olMap {
       this.initMouseTool(options.drawTool);
     }
     this.initLayer(options);
+    // 给标注点添加手势
+    this.map.on('pointermove', (e) => {
+      this.map.getTargetElement().style.cursor = 'auto';
+      const features = this.map.getFeaturesAtPixel(e.pixel);
+      features.forEach((feature) => {
+        const originalFeature = feature.get('features') ? feature.get('features')[0] : '';
+        if (!!originalFeature && originalFeature.get('pointer')) {
+          this.map.getTargetElement().style.cursor = 'pointer'; //设置鼠标样式
+        } else {
+          this.map.getTargetElement().style.cursor = 'auto';
+        }
+      });
+    });
+
+    // 创建选择交互
+    this.select = new Select({
+      condition: click,
+      filter: (feature, layer) => {
+        // 只有vectorLayer图层可选择
+        return layer === this.vectorLayer;
+      }
+    });
+    this.map.addInteraction(this.select);
+    // 监听Select交互的select事件
+    this.select.on('select', (event) => {
+      const selectedFeatures = event.selected[0]; // 获取被选中的要素集合
+      const features = selectedFeatures.get('features');
+      if (selectedFeatures && !!features) {
+        const originalFeature = features[0];
+        const size = features.length;
+        if (size === 1) {
+          // 设置新的样式(更换图标)
+          selectedFeatures.setStyle(
+            new Style({
+              image: new Icon({
+                anchor: [0.5, 0.5],
+                scale: 0.146,
+                anchorXUnits: 'fraction',
+                anchorYUnits: 'pixels',
+                src: originalFeature.get('imageHover')
+              })
+            })
+          );
+          const extData = originalFeature.get('extData');
+          options.onMarkerClick(extData);
+        } else {
+          // 聚合要素
+          const currentZoom = this.map.getView().getZoom();
+          this.map.getView().setZoom(currentZoom + 1);
+          const points = [];
+          features.forEach((feature) => {
+            const geometry = feature.getGeometry(); // 获取要素的几何对象
+            const type = geometry.getType(); // 获取几何类型
+            if (type === 'Point') {
+              points.push(geometry.getCoordinates());
+            }
+          });
+          const newFeature = getPointsCenter(points);
+          this.map.getView().setCenter(newFeature.geometry.coordinates);
+          event.selected = [];
+        }
+      } else {
+
+      }
+    });
   }
   async initLayer(options) {
     // 添加新的图层
@@ -254,15 +321,62 @@ export class olMap {
       loadendFunc();
     }
   }
+  // 集群点样式
+  clusterStyle(feature) {
+    const originalFeature = feature.get('features')[0];
+    const size = feature.get('features').length;
+    if (size > 1) {
+      const outerCircle = new CircleStyle({
+        radius: 20,
+        fill: new Fill({
+          color: 'rgba(79, 176, 206, 0.5)'
+        }),
+        stroke: new Stroke({
+          color: 'rgba(79, 176, 206, 1)'
+        })
+      });
+      return [
+        new Style({
+          image: outerCircle,
+          text: new Text({
+            text: size.toString(),
+            font: '14px sans-serif',
+            fill: new Fill({
+              color: '#ffff'
+            })
+          })
+        })
+      ];
+    }
 
+    return new Style({
+      geometry: originalFeature.getGeometry(),
+      image: new Icon({
+        anchor: [0.5, 0.5],
+        scale: 0.146,
+        anchorXUnits: 'fraction',
+        anchorYUnits: 'pixels',
+        src: originalFeature.get('icon')
+      })
+    });
+  }
   addMarker(points) {
-    this.clearMarker('point');
+    this.clearMarker();
+    const features = [];
     points.forEach((point) => {
       // 创建标注点
       const feature = new Feature({
-        geometry: new Point(point.lnglat),
-        name: point.name
+        // 必须是数字类型,字符串不识别
+        geometry: new Point([Number(point.longitude), Number(point.latitude)]),
+        name: point.name,
+        icon: point.icon,
+        imageHover: point.imageHover,
+        size: point.size,
+        pointer: true,
+        extData: point
       });
+      // 设置自定义属性
+      feature.set('pointer', true);
       // 定义样式
       const style = new Style({
         image: new Icon({
@@ -283,19 +397,46 @@ export class olMap {
           })
         })
       });
-
       feature.setStyle(style);
+      features.push(feature);
       this.markers.push(point);
-      this.vectorLayer.getSource().addFeature(feature);
     });
+    const vectorSource = new VectorSource({
+      features: features
+    });
+    const clusterSource = new Cluster({
+      distance: 30,
+      source: vectorSource
+    });
+    this.vectorLayer.setStyle(this.clusterStyle);
+    this.vectorLayer.setSource(clusterSource);
   }
-
   // 清除所有标加
-  clearMarker(id) {
+  clearMarker() {
     if (!this.vectorLayer) return;
     this.vectorLayer.getSource().clear();
   }
 
+  showInfo(content, position, isCustom) {
+    this.hideInfo();
+    if (!this.infoWindow) {
+      this.infoWindow = new Overlay({
+        element: content,
+        positioning: 'bottom-center', // 你可以根据需要调整定位方式
+        offset: [0, -10] // 偏移量,用于调整覆盖层相对于要素的位置
+      });
+    }
+    this.infoWindow.setPosition(position);
+    this.map.addOverlay(this.infoWindow);
+  }
+
+  hideInfo(flag) {
+    this.map.removeOverlay(this.infoWindow);
+    this.infoWindow = null;
+    if (!!flag && this.select) {
+      this.select.clear();
+    }
+  }
   /**
    *
    * @param {Geojon} chaozhou 根据geojson对象创建Featrue对象
@@ -334,12 +475,24 @@ export class olMap {
     this.maskLayer.getSource().addFeature(convertFt);
   }
   createVecByJson2(json, options) {
-    if (this.maskLayer2 && this.maskLayer2.length > 0) {
-      this.maskLayer2.forEach((layer) => {
-        this.map.addLayer(layer);
-      });
+    if (!!this.maskLayer2) {
+      // this.map.addLayer(this.maskLayer);
+      this.map.addLayer(this.maskLayer2);
     } else {
-      // const layer = new VectorLayer({
+      this.maskLayer2 = new VectorLayer({
+        source: new VectorSource(),
+        style: new Style({
+          fill: new Fill({
+            color: 'rgba(0, 0, 0, 0)'
+          }),
+          stroke: new Stroke({
+            color: options.strokeColor ? options.strokeColor : '#268ab9',
+            width: options.strokeWeight ? options.strokeWeight : 1
+          })
+        })
+      });
+      this.map.addLayer(this.maskLayer2);
+      // this.maskLayer = new VectorLayer({
       //   source: new VectorSource(),
       //   style: new Style({
       //     fill: new Fill({
@@ -369,57 +522,21 @@ export class olMap {
       // const convertFt = new Feature({
       //   geometry: polygonRing
       // });
-      // layer.getSource().addFeature(convertFt);
-      // this.maskLayer2.push(layer);
-      // this.map.addLayer(layer);
+      // this.maskLayer.getSource().addFeature(convertFt);
+      // this.map.addLayer(this.maskLayer);
       // 边界部分
       json.features.forEach((feature) => {
         if (feature.geometry.type === 'Polygon') {
-          const polygonPath = feature.geometry.coordinates[0].map((coord) => {
-            return [coord[0], coord[1]];
-          });
           const feature2 = new Feature({
-            geometry: new Polygon([polygonPath])
+            geometry: new LineString(feature.geometry.coordinates[0])
           });
-          const vector = new VectorLayer({
-            source: new VectorSource(),
-            style: new Style({
-              fill: new Fill({
-                color: 'rgba(0, 0, 0, 0)'
-              }),
-              stroke: new Stroke({
-                color: options.strokeColor ? options.strokeColor : '#268ab9',
-                width: options.strokeWeight ? options.strokeWeight : 1
-              })
-            })
-          });
-          vector.getSource().addFeature(feature2);
-          this.maskLayer2.push(vector);
-          this.map.addLayer(vector);
+          this.maskLayer2.getSource().addFeature(feature2);
         } else if (feature.geometry.type === 'MultiPolygon') {
           feature.geometry.coordinates.forEach((polygonCoords) => {
-            const polygonPath = polygonCoords.map((ring) => {
-              return ring.map((coord) => {
-                return [coord[0], coord[1]];
-              });
+            const feature2 = new Feature({
+              geometry: new LineString(polygonCoords[0])
             });
-            const outerPath = polygonPath;
-            const feature2 = new Feature({ geometry: new Polygon(outerPath), });
-            const vector = new VectorLayer({
-              source: new VectorSource(),
-              style: new Style({
-                fill: new Fill({
-                  color: 'rgba(0, 0, 0, 0)'
-                }),
-                stroke: new Stroke({
-                  color: options.strokeColor ? options.strokeColor : '#268ab9',
-                  width: options.strokeWeight ? options.strokeWeight : 1
-                })
-              })
-            });
-            vector.getSource().addFeature(feature2);
-            this.maskLayer2.push(vector);
-            this.map.addLayer(vector);
+            this.maskLayer2.getSource().addFeature(feature2);
           });
         }
       });
@@ -493,10 +610,14 @@ export class olMap {
     }
   }
   removeMask3(isHide) {
-    if (this.maskLayer2 && this.maskLayer2.length > 0) {
-      this.maskLayer2.forEach((layer) => {
-        this.map.removeLayer(layer);
-      });
+    if (this.maskLayer) {
+      this.map.removeLayer(this.maskLayer);
+      if (!isHide) {
+        this.maskLayer = [];
+      }
+    }
+    if (this.maskLayer2) {
+      this.map.removeLayer(this.maskLayer2);
       if (!isHide) {
         this.maskLayer2 = [];
       }
@@ -554,4 +675,10 @@ export class olMap {
       }
     });
   }
+  getVectorLayer() {
+    return this.vectorLayer;
+  }
+  getMap() {
+    return this.map;
+  }
 }

+ 0 - 2
src/views/globalMap/data/mapData.ts

@@ -4969,5 +4969,3 @@ export const pointDetailTemplate = {
     latitude: '纬度'
   }
 };
-
-export const creatDetailTemplate = (data, type) => {};

+ 3 - 0
src/views/globalMap/index.vue

@@ -8,6 +8,9 @@
         :active-map="activeMap"
         :point-type="pointType"
         v-model:showMask="showMask"
+        @handle-show-video="handleShowVideo"
+        @handle-show-warehouse="handleShowWarehouse"
+        @handle-show-people="handleShowPeople"
       />
       <Map
         v-else

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels