Browse Source

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

yangyuxuan 1 month ago
parent
commit
b529f95779

+ 9 - 0
src/api/globalMap/index.ts

@@ -53,6 +53,15 @@ export const getEmergencyExpertNum = (params) => {
   });
 };
 
+// 全域地图-点位信息-详情列表(带视频点位)
+export const getPointInfoList2 = (data) => {
+  return request({
+    url: '/api/spatial_analysis/point/get_details',
+    method: 'post',
+    data: data
+  });
+};
+
 export const getSpatialAnalysis = (params) => {
   return request({
     url: '/api/spatial_analysis/get_info',

+ 34 - 0
src/api/videoMonitor/index.ts

@@ -9,6 +9,14 @@ export function getEmergencyVideoCata(data) {
   });
 }
 
+// 获取视频监控列表 新
+export function getVideoListNew(params) {
+  return request({
+    url: '/api/videoResource/videoinfo/get_video_list_new',
+    method: 'get',
+    params: params
+  });
+}
 // 获取视频地址
 export function getVideoUrlById(id: string) {
   return request({
@@ -107,3 +115,29 @@ export function getLocationVideos(params: LocationVideosParams) {
     params: params
   });
 }
+// 新 地图打点
+export function getPointInfo2(data: PointParams) {
+  return request({
+    url: '/api/spatial_analysis/point/get_info',
+    method: 'post',
+    data: data
+  });
+}
+
+// 地图菜单
+export function getTagList(params) {
+  return request({
+    url: '/api/videoResource/tag/notNull/list',
+    method: 'get',
+    params: params
+  });
+}
+
+// 视频标签打点
+export function setVideoTag(data: PointParams) {
+  return request({
+    url: '/api/videoResource/tag/labeling_video_tag',
+    method: 'post',
+    data: data
+  });
+}

+ 41 - 27
src/components/Dialog/index.vue

@@ -7,12 +7,14 @@
     :style="{ width: computedWidth, height: computedHeight, zIndex: zIndex }"
   >
     <div :class="type === 'xs' || headerType === 'header2' ? 'dialog-header2' : 'dialog-header'">
-      <div v-if="!hideTitle" class="dialog-title" :title="title ? title : '弹窗'">
-        {{ title ? title : '弹窗' }}
-      </div>
-      <div v-if="!!getTagId" class="tags">
-        <div v-for="(item, index) in tags" :key="index" class="tag">{{ item.dict_label }}</div>
-        <i :class="tags && tags.length > 0 ? 'collectFill' : 'collect'" @click="handleShowAddTag" />
+      <div class="header-left">
+        <div v-if="!hideTitle" class="dialog-title" :title="title ? title : '弹窗'">
+          {{ title ? title : '弹窗' }}
+        </div>
+        <div v-if="!!getTagId" class="tags">
+          <div v-for="(item, index) in tags" :key="index" class="tag">{{ item.dict_label }}</div>
+          <i :class="tags && tags.length > 0 ? 'collectFill' : 'collect'" @click="handleShowAddTag" />
+        </div>
       </div>
       <i class="decoration" />
       <i class="dialog-close" @click="closeDialog" />
@@ -32,7 +34,7 @@
     <i class="triangle3" />
     <i class="triangle4" />
   </div>
-  <VideoTagEdit v-if="showAddTag" v-model="showAddTag" :tags="tags" :id="getTagId" @updateVideoTag="getData(true)" />
+  <VideoTagEdit v-if="showAddTag" v-model="showAddTag" :tags="tags" :id="getTagId" @updateVideoTag="getData2" />
 </template>
 
 <script lang="ts" setup name="Dialog">
@@ -145,6 +147,10 @@ const getData = (needUpdate?: boolean) => {
     }
   });
 };
+const getData2 = () => {
+  getData(true);
+  showAddTag.value = false;
+};
 onMounted(() => {
   if (props.customShow) {
     zIndex.value = appStore.getZIndex();
@@ -176,6 +182,7 @@ onMounted(() => {
     position: relative;
     min-height: 50px;
     line-height: 28px;
+    padding-bottom: 15px;
     .dialog-title {
       width: 500px;
       color: transparent;
@@ -241,6 +248,29 @@ onMounted(() => {
     .dialog-title {
       width: auto;
     }
+    .header-left {
+      position: relative;
+      &::before {
+        content: '';
+        position: absolute;
+        bottom: 6px;
+        left: 0;
+        width: 47px;
+        height: 20px;
+        background: url('@/assets/images/line.png') no-repeat;
+        background-size: 100% 100%;
+      }
+      &::after {
+        content: '';
+        position: absolute;
+        bottom: 15px;
+        left: 52px;
+        width: calc(100% - 47px);
+        height: 2px;
+        background-image: linear-gradient(to right, rgba(10, 154, 196, 1) 0%, rgba(10, 154, 196, 0) 100%);
+        background-size: 100% 100%;
+      }
+    }
     .tags {
       display: flex;
       align-items: center;
@@ -273,26 +303,6 @@ onMounted(() => {
         margin-left: 6px;
       }
     }
-    &::before {
-      content: '';
-      position: absolute;
-      bottom: 6px;
-      left: 0;
-      width: 47px;
-      height: 20px;
-      background: url('@/assets/images/line.png') no-repeat;
-      background-size: 100% 100%;
-    }
-    &::after {
-      content: '';
-      position: absolute;
-      bottom: 15px;
-      left: 52px;
-      width: calc(100% - 47px);
-      height: 2px;
-      background-image: linear-gradient(to right, rgba(10, 154, 196, 1) 0%, rgba(10, 154, 196, 0) 100%);
-      background-size: 100% 100%;
-    }
   }
   .el-form-item__label {
     font-size: 38px;
@@ -351,4 +361,8 @@ onMounted(() => {
 .common-btn-danger {
   margin-left: 20px;
 }
+.header-left {
+  display: flex;
+  flex-wrap: wrap;
+}
 </style>

+ 5 - 11
src/components/HKVideo/index2.vue

@@ -22,7 +22,7 @@
       <div class="video-header">
         <div class="label" :title="dot_data.name">{{ dot_data.name }}</div>
         <div class="video-header-right">
-          <i v-if="hiddenCollect" :class="tags && tags.length > 0 ? 'collectFill' : 'collect'" @click.stop="handleCollect" />
+          <i v-if="hiddenCollect" :class="dot_data.isTag ? 'collectFill' : 'collect'" @click.stop="handleCollect" />
           <img class="video-enlarge" src="@/assets/images/video/enlarge.png" alt="" @click.stop="handleFullScreen" />
         </div>
       </div>
@@ -40,9 +40,7 @@
       <div class="video-footer">
         <div class="label">{{ props.isIndex ? '首页' : '' }}</div>
         <div class="tags">
-          <div v-for="(item, index) in tags" :key="item.dict_value" class="tag">
-            {{ item.dict_label }}<template v-if="index < tags.length - 1">、</template>
-          </div>
+          {{ dot_data.tagLabels }}
         </div>
       </div>
     </div>
@@ -72,11 +70,13 @@ interface Tag {
 interface DotData {
   id: string;
   video_code: string;
-  tags?: Tag[];
+  tag?: Tag[];
   name?: string;
   status?: string;
   poster?: string;
   collect?: boolean;
+  isTag?: boolean;
+  tagLabels?: string;
 }
 interface Props {
   dot_data: DotData;
@@ -111,9 +111,6 @@ watch(
     posterVisible.value = true;
     errBKVisible.value = false;
     isPlaying.value = false;
-    if (props.dot_data.tags) {
-      tags.value = props.dot_data.tags;
-    }
     nextTick(() => {
       if (props.autoplay) {
         play_now(true);
@@ -147,9 +144,6 @@ let showFullScreenDialog = ref(false);
 const handleFullScreen = () => {
   showFullScreenDialog.value = true;
 };
-const changeTagsData = () => {
-  emits('change');
-};
 // 开始播放
 const play_now = async (check?: boolean) => {
   if (!props.dot_data || (props.dot_data && !props.dot_data.video_code)) {

+ 14 - 13
src/components/Map/YztMap/index.vue

@@ -17,10 +17,10 @@
 import 'ol/ol.css';
 import mmJson from '@/assets/json/mm2.json';
 import { olMap } from '@/utils/olMap/olMap';
-import { getPointInfoList } from '@/api/globalMap';
+import { getPointInfoList2 } from '@/api/globalMap';
 import { getDictLabel } from '@/utils/dict';
 import { methodList, titleList } from '../data';
-import { pointDetailTemplate } from '@/views/globalMap/data/mapData';
+import { iconList, pointDetailTemplate } from '@/views/globalMap/data/mapData';
 import useAppStore from '@/store/modules/app';
 import useMapStore from '@/store/modules/map';
 
@@ -118,16 +118,14 @@ const init = () => {
     onMarkerClick: (data) => {
       // 多点位
       if (data.type === '1') {
-        let path = [];
-        mapStore.pointType.forEach((item) => {
-          path.push(item.component);
-        });
-        getPointInfoList({
-          option: path.toString(),
+        getPointInfoList2({
+          option: mapStore.pointParams.option,
+          dict_value: mapStore.pointParams.dict_value.toString(),
+          zoom_level: mapStore.mapState.zoom,
           longitude: data.longitude.toString(),
           latitude: data.latitude.toString()
         }).then((res) => {
-          const data2 = res.data.list;
+          const data2 = res.data;
           let content = document.createElement('div');
           // content.style.cssText = 'transform: scale(' + containerScale().scaleX + ');';
           content.className = 'point-info';
@@ -144,8 +142,10 @@ const init = () => {
           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;
+            item.image = data.image;
+            item.imageHover = data.imageHover;
+            item.size = data.size;
+            item.scale = data.scale;
             const div = document.createElement('div');
             div.className = 'point-item point-item-hover';
             div.innerHTML =
@@ -161,7 +161,7 @@ const init = () => {
           closeBtn.className = 'close';
           closeBtn.onclick = () => mapUtils.hideInfo(true);
           content.appendChild(closeBtn);
-          mapUtils.showInfo(content, [data.longitude, data.latitude], true);
+          mapUtils.showInfo(content, [data.longitude, data.latitude], -data.scale * data.size[1], true);
         });
       } else {
         handlePointDetails(data);
@@ -255,7 +255,7 @@ const handlePointDetails = (data) => {
       closeBtn.className = 'close';
       closeBtn.onclick = () => mapUtils.hideInfo(true);
       div.appendChild(closeBtn);
-      mapUtils.showInfo(div, [data.longitude, data.latitude], true);
+      mapUtils.showInfo(div, [data.longitude, data.latitude], -data.scale * data.size[1], true);
     }
   });
 };
@@ -308,6 +308,7 @@ const clearMarker = () => {
   mapUtils.clearMarker();
 };
 const handleResize = () => {
+  if (!containerRef.value) return;
   const containerWidth = containerRef.value.clientWidth * containerScale().scaleX;
   const containerHeight = containerRef.value.clientHeight * containerScale().scaleY;
   width.value = containerWidth + 'px';

+ 14 - 28
src/components/Map/index.vue

@@ -7,9 +7,8 @@
 <script setup lang="ts" name="Map">
 import { useAMap } from '@/hooks/AMap/useAMap';
 import { useDrawTool } from '@/hooks/AMap/useDrawTool';
-import { getPointInfoList } from '@/api/globalMap';
+import { getPointInfoList2 } from '@/api/globalMap';
 import { getDictLabel } from '@/utils/dict';
-import { PointType } from '@/api/globalMap/type';
 import { methodList, titleList } from './data';
 import { pointDetailTemplate } from '@/views/globalMap/data/mapData';
 import useAppStore from '@/store/modules/app';
@@ -77,16 +76,14 @@ const mapUtils = useAMap({
   onMarkerClick: (data) => {
     // 多点位
     if (data.type === '1') {
-      let path = [];
-      mapStore.pointType.forEach((item) => {
-        path.push(item.component);
-      });
-      getPointInfoList({
-        option: path.toString(),
+      getPointInfoList2({
+        option: mapStore.pointParams.option,
+        dict_value: mapStore.pointParams.dict_value.toString(),
+        zoom_level: mapStore.mapState.zoom,
         longitude: data.longitude.toString(),
         latitude: data.latitude.toString()
       }).then((res) => {
-        const data2 = res.data.list;
+        const data2 = res.data;
         let content = document.createElement('div');
         // content.style.cssText = 'transform: scale(' + containerScale().scaleX + ');';
         content.className = 'point-info';
@@ -103,8 +100,9 @@ const mapUtils = useAMap({
         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;
+          item.image = data.image;
+          item.imageHover = data.imageHover;
+          item.size = data.size;
           const div = document.createElement('div');
           div.className = 'point-item point-item-hover';
           div.innerHTML =
@@ -120,27 +118,16 @@ const mapUtils = useAMap({
         closeBtn.className = 'close';
         closeBtn.onclick = hideInfo;
         content.appendChild(closeBtn);
-        showInfo(content, [data.longitude, data.latitude], true);
+        showInfo(content, [data.longitude, data.latitude], -data.size[1], true);
       });
     } else {
       handlePointDetails(data);
     }
   }
 });
-const {
-  getMap,
-  getAMap,
-  switchMap,
-  addMarker,
-  addSearchMarker,
-  clearMarker,
-  showInfo,
-  hideInfo,
-  handleHover,
-  creatMask2,
-  removeMask2,
-  trackPlayback
-} = { ...mapUtils };
+const { getMap, getAMap, switchMap, addSearchMarker, clearMarker, showInfo, hideInfo, handleHover, creatMask2, removeMask2, trackPlayback } = {
+  ...mapUtils
+};
 const handlePointDetails = (data) => {
   let method = methodList[data.dataType];
   let title = !!titleList[data.dataType] ? titleList[data.dataType] : '信息';
@@ -227,7 +214,7 @@ const handlePointDetails = (data) => {
       closeBtn.className = 'close';
       closeBtn.onclick = hideInfo;
       div.appendChild(closeBtn);
-      showInfo(div, [data.longitude, data.latitude], true);
+      showInfo(div, [data.longitude, data.latitude], -data.size[1], true);
     }
   });
 };
@@ -345,7 +332,6 @@ onUnmounted(() => {
 });
 
 defineExpose({
-  addMarker,
   addSearchMarker,
   setCenter,
   clearMarker,

+ 5 - 5
src/components/VideoTagEdit/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <Dialog v-model="show" title="视频标签" height="auto" draggable @close="handleClose" @confirm="handleAdd">
+  <Dialog v-model="show" title="视频标签" custom-show height="auto" draggable @close="handleClose" @confirm="handleAdd">
     <div class="title-box">
       <div class="title">当前标签</div>
     </div>
@@ -19,8 +19,8 @@
 </template>
 
 <script lang="ts" setup name="VideoTagEdit">
-import { addVideoTag } from '@/api/videoMonitor';
 import { getDicts } from '@/api/system/dict/data';
+import { setVideoTag } from '@/api/videoMonitor';
 
 interface Tag {
   dict_label: string;
@@ -34,6 +34,7 @@ interface Props {
 
 const props = defineProps<Props>();
 const emits = defineEmits(['update:modelValue', 'updateVideoTag']);
+const proxy = getCurrentInstance()?.proxy;
 let videoType = ref([]);
 const show = computed({
   get() {
@@ -68,10 +69,9 @@ const handleAdd = () => {
   selectTags.value.forEach((item) => {
     tagsId.push(item.value);
   });
-  addVideoTag({ video_code: props.id, dict_value: tagsId, dict_type: 'video_type' }).then(() => {
-    showSuccessMsg('新增成功');
+  setVideoTag({ video_code: props.id, dict_value_list: tagsId }).then(() => {
+    proxy.$modal.msgSuccess('新增成功');
     emits('updateVideoTag');
-    handleClose();
   });
 };
 

+ 77 - 34
src/hooks/AMap/useAMap.ts

@@ -3,7 +3,7 @@ import { nanoid } from 'nanoid';
 import { deepClone, initDrag } from '@/utils';
 import { mergeGeoJsonPolygons, wgs_gcj_encrypts } from '@/utils/gisUtils';
 import carImg from '@/assets/images/car.png';
-import { getImageUrl } from '@/views/globalMap/data/mapData';
+import { getImageUrl, iconList } from '@/views/globalMap/data/mapData';
 
 export function useAMap(options) {
   let AMap, map, scale, cluster;
@@ -230,42 +230,68 @@ export function useAMap(options) {
   };
   // 添加多个点2 后台做点聚合
   const addMarker2 = (obj) => {
-    if (plotLayers['points2']) {
-      plotLayers['points2'] = new AMap.TileLayer({
+    // 新增图层
+    if (!plotLayers['points2']) {
+      plotLayers['points2'] = new AMap.OverlayGroup({
         zIndex: 10, // 设置图层层级
         visible: true
       });
       map.add(plotLayers['points2']);
+    } else {
+      plotLayers['points2'].clearOverlays();
+      addPoints = [];
     }
     Object.keys(obj).forEach((key: string) => {
-      if (obj[key].videos && obj[key].videos.length > 1) {
+      const data = obj[key];
+      if (data.type === '3') {
         // 聚合点
+        const div = document.createElement('div');
+        div.style.backgroundColor = 'rgba(78,179,211,.5)';
+        const size = Math.round(25 + Math.pow(1 / 5, 1 / 5) * 20);
+        div.style.width = div.style.height = size + 'px';
+        div.style.border = 'solid 1px rgba(78,179,211,1)';
+        div.style.borderRadius = size / 2 + 'px';
+        div.innerHTML = data.count;
+        div.style.lineHeight = size + 'px';
+        div.style.color = '#ffffff';
+        div.style.fontSize = '12px';
+        div.style.textAlign = 'center';
+        const marker = new AMap.Marker({
+          position: [data.longitude, data.latitude],
+          content: div,
+          anchor: 'center',
+          offset: new AMap.Pixel(0, 0),
+          map: map
+        });
+        marker.setContent(div);
+        marker.on('click', (e) => {
+          const bounds = e.target.getBounds();
+          map.setZoomAndCenter(map.getZoom() + 1, bounds.getCenter());
+        });
+        plotLayers['points2'].addOverlay(marker);
+        addPoints.push(data);
       } else {
         // 单个点
-        const data = obj[key].videos[0];
-        data.image = getImageUrl('31_lakes_video.png');
-        data.imageHover = getImageUrl('31_lakes_video_hover.png');
-        data.icon = data.image;
-        data.size = [40, 40];
-        data.id = data.cameraIndexCode;
-        const content =
-          '<div style="display: flex;flex-direction: column;align-items: center;justify-content: center">' +
-          '<div style="background: url(' +
-          data.icon +
-          ') no-repeat; width: ' +
-          data.size[0] +
-          'px;height: ' +
-          data.size[1] +
-          'px;cursor: pointer; background-size: cover"></div>' +
-          // '<div style="font-size: 36px;white-space: nowrap">'+ context.data[0].name +'</div>' +
-          '</div>';
+        const iconConfig = iconList[data.dataType] || iconList.common;
+        data.image = iconConfig.image;
+        data.imageHover = iconConfig.imageHover;
+        data.size = iconConfig.size;
+        if (data.materia_name) {
+          data.name = data.materia_name;
+        }
+        if (data.dataType === 43) {
+          data.showName = true;
+        }
+        if (!data.id) {
+          data.id = nanoid(8);
+        }
+        data.lnglat = [data.longitude, data.latitude];
         const marker = new AMap.Marker({
           position: [data.longitude, data.latitude],
-          content: content,
+          content: getContent(data.image, data.size),
           anchor: 'bottom-center',
           offset: new AMap.Pixel(0, 0),
-          map: map,
-          layer: plotLayers['points2']
+          map: map
         });
         marker.setExtData(data);
         marker.on('click', function (e) {
@@ -273,15 +299,13 @@ export function useAMap(options) {
           let index = 0;
           let index2 = 0;
           for (let i = 0; i < addPoints.length; i++) {
-            if (addPoints[i].id === extData.id && addPoints[i].imageHover) {
-              addPoints[i].icon = addPoints[i].imageHover;
-              marker.setContent(content);
+            if (addPoints[i].id === extData.id) {
+              marker.setContent(getContent(data.imageHover, data.size));
               index++;
             } else if (!!clickMarker) {
               const extData2 = clickMarker.getExtData();
               if (addPoints[i].id === extData2.id) {
-                addPoints[i].icon = addPoints[i].image;
-                clickMarker.setContent(content);
+                clickMarker.setContent(getContent(extData2.image, extData2.size));
                 index2++;
               }
             }
@@ -289,14 +313,28 @@ export function useAMap(options) {
               break;
             }
           }
-          // addMarker(addPoints);
           clickMarker = e.target;
           options.onMarkerClick(extData);
         });
+        plotLayers['points2'].addOverlay(marker);
         addPoints.push(data);
       }
     });
   };
+  const getContent = (icon: string, size: number[]) => {
+    const content =
+      '<div style="display: flex;flex-direction: column;align-items: center;justify-content: center">' +
+      '<div style="background: url(' +
+      icon +
+      ') no-repeat; width: ' +
+      size[0] +
+      'px;height: ' +
+      size[1] +
+      'px;cursor: pointer; background-size: cover"></div>' +
+      // '<div style="font-size: 36px;white-space: nowrap">'+ context.data[0].name +'</div>' +
+      '</div>';
+    return content;
+  };
   // 清除所有标加
   const clearMarker = (id) => {
     if (!cluster || !markers[id]) return;
@@ -304,7 +342,10 @@ export function useAMap(options) {
     markers[id] = [];
   };
   const clearMarker2 = (id) => {
-
+    if (!!plotLayers['points2']) {
+      plotLayers['points2'].clearOverlays();
+      addPoints = [];
+    }
   };
 
   const handleHover = (extData, dataType) => {
@@ -337,14 +378,14 @@ export function useAMap(options) {
 
   // 显示信息框
   let infoWindow;
-  const showInfo = (content, position, isCustom) => {
+  const showInfo = (content, position, offsetY, isCustom) => {
     hideInfo();
     // 实例化InfoWindow
     infoWindow = new AMap.InfoWindow({
       // 完全自定义
       isCustom: isCustom,
       autoMove: false,
-      offset: new AMap.Pixel(0, -20) // 信息窗体的偏移量
+      offset: new AMap.Pixel(0, offsetY ? offsetY : 0) // 信息窗体的偏移量
       // 可以根据需要设置其他InfoWindow的属性
     });
     const lnglat = new AMap.LngLat(position[0], position[1]);
@@ -366,8 +407,9 @@ export function useAMap(options) {
         for (let i = 0; i < addPoints.length; i++) {
           if (addPoints[i].id === extData.id) {
             addPoints[i].icon = addPoints[i].image;
+            clickMarker.setContent(getContent(addPoints[i].icon, addPoints[i].size));
             clickMarker = null;
-            addMarker(addPoints);
+            // addMarker(addPoints);
             break;
           }
         }
@@ -746,6 +788,7 @@ export function useAMap(options) {
     addMarker2,
     addSearchMarker,
     clearMarker,
+    clearMarker2,
     getScale,
     showInfo,
     hideInfo,

+ 66 - 27
src/store/modules/map.ts

@@ -22,7 +22,7 @@ export const useMapStore = defineStore('map', () => {
   // 地图加载是否完成
   const mapLoaded = ref(false);
   // 当前地图类型
-  const activeMap = ref<string>('satellite');
+  const activeMap = ref<string>('');
   // 是否显示边界遮罩
   const showMask = ref<boolean>(true);
   // 高德地图类型
@@ -41,11 +41,10 @@ export const useMapStore = defineStore('map', () => {
   // 是否在选点
   const isMapSelect = ref(false);
   // 视频打点参数
-  const videoPointParams = ref({
-    // 触发请求
-    flag: false,
+  const pointParams = ref({
     // 选择条件
-    dict_value: ''
+    dict_value: [],
+    option: ''
   });
   // 设置地图加载完成状态
   const setMapLoaded = (loaded: boolean) => {
@@ -72,27 +71,48 @@ export const useMapStore = defineStore('map', () => {
   const setIsMapSelect = (flag: boolean) => {
     isMapSelect.value = flag;
   };
-  // 跳转界面时 初始化所有数据
-  const initData = () => {
-    activeMap.value = 'satellite';
-    showMask.value = true;
-    trackState.show = false;
-    trackState.data = [];
-    isMapSelect.value = false;
-    videoPointParams.value = {
-      flag: false,
-      dict_value: ''
-    };
-    menuState.value = {
-      showMenu: false,
-      activeIndex: 0,
-      menuData: []
-    };
-    initMenuData();
+  // 更多视频界面、设置视频打点标识
+  const setPointParams = (dictValue: string) => {
+    if (dictValue !== '573204ca-e814-11ef-a825-fa163e4bf12e' && !pointParams.value.dict_value.includes(dictValue)) {
+      // 还没选中,则进入选中
+      const data = menuData.value;
+      let shouldBreak = false;
+      for (let i = 0; i < data.length; i++) {
+        if (data[i].children && data[i].children.length > 0) {
+          const data2 = data[i].children;
+          for (let k = 0; k < data2.length; k++) {
+            if (data2[k].name === '图像资源') {
+              if (data2[k].children && data2[k].children.length > 0) {
+                const data3 = data2[k].children;
+                for (let z = 0; z < data3.length; z++) {
+                  // if (dictValue === data3[z].name) {
+                  if (dictValue === '7' && data3[z].name === '台风视频') {
+                    data3[z].checked = true;
+                    shouldBreak = true;
+                    pointParams.value.dict_value.push(dictValue);
+                    break;
+                  }
+                }
+                if (shouldBreak) {
+                  break;
+                }
+              }
+            }
+          }
+          if (shouldBreak) {
+            break;
+          }
+        }
+      }
+    }
   };
-  // 设置视频打点标识
-  const setVideoPointParams = (data: any) => {
-    videoPointParams.value = data;
+  // 打点option变化
+  const setPointOption = () => {
+    const path = [];
+    pointType.value.forEach((item) => {
+      path.push(item.component);
+    });
+    pointParams.value.option = path.toString();
   };
   // 初始化左侧菜单数据
   const initMenuData = () => {
@@ -135,6 +155,24 @@ export const useMapStore = defineStore('map', () => {
       menuData: []
     };
   };
+  // 跳转界面时 初始化所有数据
+  const initData = () => {
+    activeMap.value = 'satellite';
+    showMask.value = true;
+    trackState.show = false;
+    trackState.data = [];
+    isMapSelect.value = false;
+    pointParams.value = {
+      dict_value: [],
+      option: ''
+    };
+    menuState.value = {
+      showMenu: false,
+      activeIndex: 0,
+      menuData: []
+    };
+    initMenuData();
+  };
   return {
     mapState,
     menuData,
@@ -148,7 +186,7 @@ export const useMapStore = defineStore('map', () => {
     pointType,
     trackState,
     isMapSelect,
-    videoPointParams,
+    pointParams,
     setMapLoaded,
     setZoom,
     setActiveMap,
@@ -156,7 +194,8 @@ export const useMapStore = defineStore('map', () => {
     setTrackState,
     setIsMapSelect,
     initData,
-    setVideoPointParams,
+    setPointParams,
+    setPointOption,
     handleCancelAllChecked
   };
 });

+ 9 - 3
src/types/components.d.ts

@@ -24,15 +24,20 @@ declare module 'vue' {
     DistributionMap: typeof import('./../components/Map/YztMap/DistributionMap.vue')['default']
     DrawMap: typeof import('./../components/Map/YztMap/DrawMap.vue')['default']
     Editor: typeof import('./../components/Editor/index.vue')['default']
+    ElAnchor: typeof import('element-plus/es')['ElAnchor']
+    ElAnchorLink: typeof import('element-plus/es')['ElAnchorLink']
     ElAutocomplete: typeof import('element-plus/es')['ElAutocomplete']
     ElBadge: typeof import('element-plus/es')['ElBadge']
     ElButton: typeof import('element-plus/es')['ElButton']
     ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
+    ElCheckboxButton: typeof import('element-plus/es')['ElCheckboxButton']
     ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
     ElCol: typeof import('element-plus/es')['ElCol']
     ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
     ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider']
     ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
+    ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
+    ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
     ElDialog: typeof import('element-plus/es')['ElDialog']
     ElDivider: typeof import('element-plus/es')['ElDivider']
     ElDrawer: typeof import('element-plus/es')['ElDrawer']
@@ -45,7 +50,6 @@ declare module 'vue' {
     ElIcon: typeof import('element-plus/es')['ElIcon']
     ElImage: typeof import('element-plus/es')['ElImage']
     ElInput: typeof import('element-plus/es')['ElInput']
-    ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
     ElMenu: typeof import('element-plus/es')['ElMenu']
     ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
     ElOption: typeof import('element-plus/es')['ElOption']
@@ -59,10 +63,14 @@ declare module 'vue' {
     ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
     ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem']
     ElSlider: typeof import('element-plus/es')['ElSlider']
+    ElStep: typeof import('element-plus/es')['ElStep']
+    ElSteps: typeof import('element-plus/es')['ElSteps']
     ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
     ElSwitch: typeof import('element-plus/es')['ElSwitch']
     ElTable: typeof import('element-plus/es')['ElTable']
     ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
+    ElTabPane: typeof import('element-plus/es')['ElTabPane']
+    ElTabs: typeof import('element-plus/es')['ElTabs']
     ElTag: typeof import('element-plus/es')['ElTag']
     ElText: typeof import('element-plus/es')['ElText']
     ElTimeline: typeof import('element-plus/es')['ElTimeline']
@@ -83,8 +91,6 @@ declare module 'vue' {
     HikvisionPlayer: typeof import('./../components/HKVideo/hikvision-player.vue')['default']
     HKVideo: typeof import('./../components/HKVideo/index.vue')['default']
     IconSelect: typeof import('./../components/IconSelect/index.vue')['default']
-    IEpCaretBottom: typeof import('~icons/ep/caret-bottom')['default']
-    IEpCaretTop: typeof import('~icons/ep/caret-top')['default']
     IFrame: typeof import('./../components/iFrame/index.vue')['default']
     ImagePreview: typeof import('./../components/ImagePreview/index.vue')['default']
     ImageUpload: typeof import('./../components/ImageUpload/index.vue')['default']

+ 7 - 5
src/types/video.d.ts

@@ -1,7 +1,9 @@
-interface LocationVideosParams {
+interface PointParams {
   zoom_level: number;
-  longitude_max: string;
-  longitude_min: string;
-  latitude_max: string;
-  latitude_min: string;
+  longitude_max: string | number;
+  longitude_min: string | number;
+  latitude_max: string | number;
+  latitude_min: string | number;
+  option?: string;
+  dict_value?: string;
 }

+ 114 - 27
src/utils/olMap/olMap.ts

@@ -40,6 +40,7 @@ import * as turf from '@turf/turf';
 import { nanoid } from 'nanoid';
 import carImg from '@/assets/images/car.png';
 import { globalHeaders } from '@/utils/request';
+import { iconList } from '@/views/globalMap/data/mapData';
 
 const tk = 'a8df87f1695d224d2679aa805c1268d9';
 const commonUrl = import.meta.env.VITE_APP_BASE_API2 + 'api/oneShare/proxyHandler/gd/';
@@ -79,7 +80,6 @@ export class olMap {
     icon: '',
     iconName: ''
   };
-  private plot;
   private drawVector;
   private drawTool;
   private vectorLayer;
@@ -153,37 +153,35 @@ export class olMap {
     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) {
-          if (this.selectedFeature !== originalFeature) {
+      const feature = event.selected[0]; // 获取被选中的要素集合
+      const extData = feature.get('extData');
+      if (!!feature) {
+        if(['1', '2'].includes(extData.type)) {
+          // 多点位 单点
+          if (this.selectedFeature !== feature) {
             if (this.selectedFeature) {
               this.selectedFeature.set('icon', this.selectedFeature.get('image'));
             }
-            this.selectedFeature = originalFeature;
-            const icon = originalFeature.get('imageHover');
-            const extData = originalFeature.get('extData');
-            originalFeature.set('icon', icon);
+            this.selectedFeature = feature;
+            feature.setStyle(
+              new Style({
+                image: new Icon({
+                  src: extData.imageHover,
+                  scale: extData.scale,
+                  anchor: [0.5, 0.5],
+                  anchorXUnits: 'fraction',
+                  anchorYUnits: 'fraction'
+                })
+              })
+            );
             options.onMarkerClick(extData);
           }
-        } else {
+        } else if (extData.type === '3') {
           // 聚合要素
           this.select.getFeatures().clear();
           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);
+          this.map.getView().setCenter(feature.geometry.coordinates);
           event.selected = [];
         }
       }
@@ -204,7 +202,8 @@ export class olMap {
     this.vectorLayer = new VectorLayer({
       source: new VectorSource({
         features: []
-      })
+      }),
+      zIndex: options.zIndex ? options.zIndex : 100
     });
     this.map.addLayer(this.vectorLayer);
     if (typeof this.options.onLoadCompleted === 'function') {
@@ -701,19 +700,107 @@ export class olMap {
     this.vectorLayer.setStyle(this.clusterStyle);
     this.vectorLayer.setSource(clusterSource);
   }
+  addMarker2(obj) {
+    this.clearMarker2();
+    Object.keys(obj).forEach((key: string) => {
+      const data = obj[key];
+      if (data.type === '3') {
+        // 聚合点
+        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)'
+          })
+        });
+        const feature = new Feature({
+          // 必须是数字类型,字符串不识别
+          geometry: new Point([Number(data.longitude), Number(data.latitude)]),
+          name: data.name,
+          pointer: true,
+          extData: data
+        });
+
+        feature.setStyle(
+          new Style({
+            image: outerCircle,
+            text: new Text({
+              text: data.count.toString(),
+              font: '14px sans-serif',
+              fill: new Fill({
+                color: '#ffff'
+              })
+            })
+          })
+        );
+        this.vectorLayer.getSource().addFeature(feature);
+        this.markers.push(data);
+      } else {
+        // 单个点
+        const iconConfig = iconList[data.dataType] || iconList.common;
+        data.image = iconConfig.image;
+        data.imageHover = iconConfig.imageHover;
+        data.size = iconConfig.size;
+        if (data.materia_name) {
+          data.name = data.materia_name;
+        }
+        if (data.dataType === 43) {
+          data.showName = true;
+        }
+        if (!data.id) {
+          data.id = nanoid(8);
+        }
+        data.lnglat = [data.longitude, data.latitude];
+        const feature = new Feature({
+          // 必须是数字类型,字符串不识别
+          geometry: new Point([Number(data.longitude), Number(data.latitude)]),
+          name: data.name,
+          pointer: true,
+          extData: data
+        });
+        // 设置自定义属性
+        const img = new Image();
+        img.onload = () => {
+          // 图片加载完成后,可以访问其 width 和 height 属性
+          const scale = data.size[0] ? data.size[0] / img.width : 1;
+          data.scale = scale;
+          feature.set('extData', data);
+          feature.setStyle(
+            new Style({
+              image: new Icon({
+                src: data.image,
+                scale: scale,
+                anchor: [0.5, 0.5],
+                anchorXUnits: 'fraction',
+                anchorYUnits: 'fraction'
+              })
+            })
+          );
+          this.vectorLayer.getSource().addFeature(feature);
+        };
+        img.src = data.image; // 设置图片的 URL,触发加载
+        this.markers.push(data);
+      }
+    });
+  }
   // 清除所有标加
   clearMarker() {
     if (!this.vectorLayer) return;
     this.vectorLayer.getSource().clear();
   }
-
-  showInfo(content, position, isCustom) {
+  clearMarker2() {
+    if (!this.vectorLayer) return;
+    this.vectorLayer.getSource().clear();
+  }
+  showInfo(content, position, offsetY, isCustom) {
     this.hideInfo();
     if (!this.infoWindow) {
       this.infoWindow = new Overlay({
         element: content,
         positioning: 'bottom-center', // 你可以根据需要调整定位方式
-        offset: [0, -10] // 偏移量,用于调整覆盖层相对于要素的位置
+        offset: [0, offsetY ? offsetY : 0] // 偏移量,用于调整覆盖层相对于要素的位置
       });
     }
     this.infoWindow.setPosition(position);

+ 3 - 3
src/views/emergencyCommandMap/LeftSection/VideoMonitor.vue

@@ -12,7 +12,7 @@
 </template>
 
 <script lang="ts" setup name="VideoMonitor">
-import { getVideoListByUser } from '@/api/videoMonitor';
+import { getVideoListNew } from '@/api/videoMonitor';
 import VideoMonitorEdit from './VideoMonitorEdit.vue';
 import HKVideo from '@/components/HKVideo/index2.vue';
 
@@ -29,13 +29,13 @@ let lngLat = reactive({
 const initData = () => {
   lngLat.longitude = props.longitude ? props.longitude : 110.925176;
   lngLat.latitude = props.latitude ? props.latitude : 21.678993;
-  getVideoListByUser({
+  getVideoListNew({
     longitude: lngLat.longitude,
     latitude: lngLat.latitude,
     page: 1,
     pageSize: 4
   }).then((res) => {
-    listData.value = res.rows;
+    listData.value = res.data;
   });
 };
 const updateData = (data, index) => {

+ 38 - 117
src/views/emergencyCommandMap/LeftSection/VideoMonitorEdit.vue

@@ -3,41 +3,32 @@
     <div class="search-box">
       <div class="box-left">
         <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-position="left">
-          <el-form-item label="区划" prop="area" label-width="30px">
+          <el-form-item label="区划" prop="area_code" label-width="30px">
             <el-select
-              v-model="treeData.area"
+              v-model="queryParams.area_code"
               class="custom-select"
               popper-class="custom-select-popper"
               :teleported="false"
               style="width: 150px; margin-left: 10px"
-              @change="handleAreaChange"
             >
-              <el-option v-for="item in treeData.areaList" :key="item.id" :label="item.label" :value="item.id" />
-            </el-select>
-            <el-select
-              v-model="treeData.town"
-              class="custom-select"
-              popper-class="custom-select-popper"
-              :teleported="false"
-              style="width: 150px; margin-left: 10px"
-              @change="handleTownChange"
-            >
-              <el-option v-for="item in treeData.townList" :key="item.id" :label="item.label" :value="item.id" />
+              <el-option label="茂名市" value="" />
+              <el-option v-for="item in district_type2" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
+          </el-form-item>
+          <el-form-item label="视频来源" prop="video_from" label-width="70px">
             <el-select
-              v-model="treeData.village"
+              v-model="queryParams.video_from"
               class="custom-select"
               popper-class="custom-select-popper"
               :teleported="false"
               style="width: 150px; margin-left: 10px"
-              @change="handleVillageChange"
             >
-              <el-option v-for="item in treeData.villageList" :key="item.id" :label="item.label" :value="item.id" />
+<!--              <el-option v-for="item in district_type2" :key="item.value" :label="item.label" :value="item.value" />-->
             </el-select>
           </el-form-item>
-          <el-form-item label="实景视频" prop="dict_value" label-width="70px">
+          <el-form-item label="实景视频" prop="video_tag" label-width="70px">
             <el-select
-              v-model="queryParams.dict_value"
+              v-model="queryParams.video_tag"
               class="custom-select"
               popper-class="custom-select-popper"
               :teleported="false"
@@ -46,8 +37,8 @@
               <el-option v-for="item in video_type" :key="item.value" :label="item.label" :value="item.value" />
             </el-select>
           </el-form-item>
-          <el-form-item prop="name">
-            <el-input v-model="queryParams.name" class="custom-input2" placeholder="请输入摄像头名称" style="width: 313px" />
+          <el-form-item prop="video_name">
+            <el-input v-model="queryParams.video_name" class="custom-input2" placeholder="请输入摄像头名称" style="width: 313px" />
           </el-form-item>
           <el-form-item style="margin-right: 0">
             <div class="common-btn-primary" @click="handleQuery">搜索</div>
@@ -78,27 +69,27 @@
       <div v-for="(item, index) in dialogListData" :key="index" class="video-box" @click="selectItem(item)">
         <div style="width: 100%; height: 100%; display: flex; align-items: center; justify-content: center">
           <div v-if="editVideo">
-            <div v-if="getCheckStatus(item.video_code)" class="active-tag"></div>
-            <div :class="getCheckStatus(item.video_code) ? 'common-checked-active' : 'common-checked'"></div>
-            <div class="img"></div>
+            <div v-if="item.isUserVideos" class="active-tag" />
+            <div :class="item.isUserVideos ? 'common-checked-active' : 'common-checked'" />
+            <div class="img" />
             <div class="video-label">
               <span class="label">{{ item.name }}</span>
             </div>
           </div>
-          <HKVideo v-else :dot_data="item" autoplay :is-index="item.sort" />
+          <HKVideo v-else :dot_data="item" autoplay :is-index="item.isUserVideos" />
         </div>
       </div>
     </div>
     <div class="footer">
       <pagination
-        v-show="total > queryParams.size"
-        v-model:page="queryParams.current"
-        v-model:limit="queryParams.size"
+        v-show="total > queryParams.pageSize"
+        v-model:page="queryParams.page"
+        v-model:limit="queryParams.pageSize"
         :total="total"
         layout="total, prev, pager, next"
         @pagination="getList"
       />
-      <div v-if="total === 0" style="width: 100%; text-align: center; font-size: 38px; font-weight: bold">暂无数据</div>
+      <div v-if="total === 0" style="width: 100%; text-align: center; font-size: 16px; font-weight: bold">暂无数据</div>
     </div>
     <div id="container" style="display: none"></div>
   </Dialog>
@@ -106,12 +97,11 @@
 </template>
 
 <script lang="ts" setup>
-import { getEmergencyVideoCata, getUserVideoPoints, getVideoList, updateUserVideoPoints } from '@/api/videoMonitor';
+import { getUserVideoPoints, getVideoListNew, updateUserVideoPoints } from '@/api/videoMonitor';
 import { deepClone } from '@/utils';
 import useAppStore from '@/store/modules/app';
 import useMapStore from '@/store/modules/map';
 import HKVideo from '@/components/HKVideo/index2.vue';
-import { getRegionalTree } from '@/api/PreventionResponsible';
 
 interface LngLat {
   longitude: number;
@@ -131,24 +121,17 @@ const props = defineProps({
 const mapStore = useMapStore();
 const emits = defineEmits(['update:modelValue']);
 const proxy = getCurrentInstance()?.proxy;
-const { video_type } = toRefs<any>(proxy?.useDict('video_type'));
-
+const { district_type2, video_type } = toRefs<any>(proxy?.useDict('district_type2', 'video_type'));
 //查看更多数据
 const queryFormRef = ref();
-const treeData = reactive({
-  area: '',
-  town: '',
-  village: '',
-  areaList: [],
-  townList: [],
-  villageList: []
-});
+
 const queryParams = reactive({
-  current: 1,
-  size: 8,
-  dict_value: '',
-  name: '',
-  area: ''
+  area_code: '',
+  video_from: '',
+  video_tag: '573204ca-e814-11ef-a825-fa163e4bf12e',
+  video_name: '',
+  page: 1,
+  pageSize: 8
 });
 let total = ref(0);
 let editVideo = ref(false);
@@ -173,32 +156,18 @@ const getList = (flag?: boolean) => {
   let newParams = {
     latitude: props.lngLat.latitude,
     longitude: props.lngLat.longitude,
-    current: queryParams.current,
-    size: queryParams.size,
-    query: {
-      name: queryParams.name
-    }
+    ...queryParams
   };
-  if (!!queryParams.dict_value) {
-    newParams.query.dict_value = queryParams.dict_value;
-  }
-  getEmergencyVideoCata(newParams).then((res) => {
-    dialogListData.value = res.rows;
+  getVideoListNew(newParams).then((res) => {
+    dialogListData.value = res.data;
     total.value = res.total;
     getUserVideoPoints().then((res2) => {
-      filterData(res2.data.videoInfos);
       editData.value = deepClone(res2.data.videoInfos);
     });
   });
 };
 const getVideoInfoList = () => {
-  mapStore.setVideoPointParams({
-    flag: true,
-    dict_value: queryParams.dict_value
-  });
-  getVideoList(queryParams).then((res) => {
-    mapStore.setTrackState(res.data);
-  });
+  mapStore.setPointParams(queryParams.video_tag);
 };
 const selectItem = (item) => {
   if (editVideo.value) {
@@ -222,20 +191,15 @@ const reset = () => {
 
 /** 搜索按钮操作 */
 const handleQuery = () => {
-  queryParams.current = 1;
+  queryParams.page = 1;
   getList();
-  // getVideoInfoList();
+  getVideoInfoList();
 };
 
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
-  treeData.area = '';
-  treeData.townList = [];
-  treeData.town = '';
-  treeData.villageList = [];
-  treeData.village = '';
-  queryParams.current = 1;
+  queryParams.page = 1;
   handleQuery();
 };
 
@@ -243,16 +207,6 @@ const resetQuery = () => {
 const activeEdit = () => {
   editVideo.value = true;
 };
-const filterData = (data) => {
-  data.forEach((item) => {
-    for (let i = 0; i < dialogListData.value.length; i++) {
-      if (item.video_code_int === dialogListData.value[i].video_code) {
-        dialogListData.value[i].sort = true;
-        break;
-      }
-    }
-  });
-};
 // 关闭编辑
 const handleCancel = () => {
   editVideo.value = false;
@@ -268,43 +222,10 @@ const handleSave = () => {
     handleCancel();
   });
 };
-// 区变化
-const handleAreaChange = () => {
-  getAreaTreeList('townList', treeData.area);
-  treeData.town = '';
-  treeData.village = '';
-  queryParams.area = treeData.area;
-};
-// 镇变化
-const handleTownChange = () => {
-  getAreaTreeList('villageList', treeData.town);
-  treeData.village = '';
-  queryParams.area = treeData.town;
-};
-// 村变化
-const handleVillageChange = () => {
-  queryParams.area = treeData.village;
-};
-// 获取区划树
-const getAreaTreeList = (datasource, id) => {
-  getRegionalTree(id).then((res) => {
-    treeData[datasource] = res.data;
-  });
-};
-const getCheckStatus = (id) => {
-  let flag = false;
-  for (let i = 0; i < editData.value.length; i++) {
-    if (editData.value[i].video_code_int === id) {
-      flag = true;
-      break;
-    }
-  }
-  return flag;
-};
+
 onMounted(() => {
   getList();
-  getAreaTreeList('areaList', 2);
-  // getVideoInfoList();
+  getVideoInfoList();
 });
 </script>
 

+ 10 - 5
src/views/globalMap/data/mapData.ts

@@ -22,11 +22,6 @@ export const iconList = {
     imageHover: getImageUrl('4_easy_flood_point_hover.png'),
     size: [60, 60]
   },
-  'common': {
-    image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
-    imageHover: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
-    size: [19, 31]
-  },
   '5': {
     image: getImageUrl('5_school.png'),
     imageHover: getImageUrl('5_school_hover.png'),
@@ -221,6 +216,16 @@ export const iconList = {
     image: getImageUrl('45_elderly_care_institution.png'),
     imageHover: getImageUrl('45_elderly_care_institution_hover.png'),
     size: [40, 44]
+  },
+  'video': {
+    image: getImageUrl('31_lakes_video.png'),
+    imageHover: getImageUrl('31_lakes_video_hover.png'),
+    size: [40, 40]
+  },
+  'common': {
+    image: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
+    imageHover: 'https://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
+    size: [19, 31]
   }
 };
 

+ 86 - 56
src/views/globalMap/index.vue

@@ -10,7 +10,7 @@
         @handle-show-track="handleShowTrack"
       />
       <YztMap
-        v-else
+        v-else-if="!!mapStore.activeMap"
         ref="map2Ref"
         @handle-show-video="handleShowVideo"
         @handle-show-warehouse="handleShowWarehouse"
@@ -61,12 +61,12 @@ import CommunicationSupport from './RightMenu/CommunicationSupport.vue';
 import GridPointRainfall from './RightMenu/GridPointRainfall.vue';
 import EmergencyCrew from './RightMenu/EmergencyCrew.vue';
 import useMapStore from '@/store/modules/map';
-import { getPointInfo } from '@/api/globalMap';
 import { getVehicleTrajectory } from '@/api/globalMap/KeyVehicles';
 import { iconList } from './data/mapData';
-import { deepClone } from '@/utils';
+import { debounce, deepClone } from '@/utils';
 import { parseTime } from '@/utils/ruoyi';
-import { getLocationVideos } from '@/api/videoMonitor';
+import { getPointInfo2 } from '@/api/videoMonitor';
+import { toLonLat } from 'ol/proj';
 
 //dom元素
 const rightMenuRef = ref(null);
@@ -89,7 +89,6 @@ const communicationSupport = reactive({
   show: false,
   data: {}
 });
-let markerList = ref([]);
 let addMarkersTimer;
 // 添加打点
 const addMarkers = (item) => {
@@ -100,16 +99,12 @@ const addMarkers = (item) => {
       if (index > -1) {
         mapStore.pointType.splice(index, 1);
       }
-      if (mapStore.pointType && mapStore.pointType.length === 0) {
-        dom.clearMarker('point');
-        return;
-      }
     } else {
       // 右侧图层分析状态
       item.checked2 = true;
       mapStore.pointType.push(item);
     }
-    addMarkersMethod();
+    mapStore.setPointOption();
   }
 };
 const adjustPoint = (data) => {
@@ -137,25 +132,66 @@ const adjustPoint = (data) => {
   return data;
 };
 
-const addMarkersMethod = () => {
-  const dom = mapStore.isAMap ? mapRef.value : map2Ref.value;
-  const path = [];
-  mapStore.pointType.forEach((item) => {
-    path.push(item.component);
-  });
-  getPointInfo(path.toString()).then((res) => {
-    const data = res.data && res.data.list ? res.data?.list : [];
-    markerList.value = adjustPoint(data);
-    dom?.addMarker(data);
-  });
-  if (!path.includes('43') && addMarkersTimer) {
-    clearInterval(addMarkersTimer);
-    addMarkersTimer = null;
-  }
-  if (path.includes('43')) {
-    addMarkersTimer = setInterval(addMarkersMethod, 60 * 1000);
-  }
-};
+const addMarkersMethod = debounce(
+  function () {
+    if (!mapUtils || Object.keys(mapUtils).length === 0) return;
+    const queryParams: PointParams = {
+      zoom_level: mapStore.mapState.zoom,
+      latitude_min: '',
+      latitude_max: '',
+      longitude_min: '',
+      longitude_max: '',
+      // option: '22',
+      option: mapStore.pointParams.option,
+      // dict_value: 'slfh'
+      dict_value: mapStore.pointParams.dict_value.toString()
+    };
+    if (!queryParams.option && !queryParams.dict_value) {
+      return mapUtils.clearMarker2();
+    }
+    if (mapStore.isAMap) {
+      const AMap = mapUtils.getAMap();
+      const pixel = new AMap.Pixel(0, 0);
+      const size = mapRef.value.getMapDomSize();
+      const pixel2 = new AMap.Pixel(size[0], size[1]);
+      const lnglat = map.containerToLngLat(pixel);
+      const lnglat2 = map.containerToLngLat(pixel2);
+      queryParams.longitude_min = lnglat.lng;
+      queryParams.latitude_max = lnglat.lat;
+      queryParams.longitude_max = lnglat2.lng;
+      queryParams.latitude_min = lnglat2.lat;
+    } else {
+      // 获取地图容器尺寸
+      const size = map.getSize();
+      // 获取左上角和右下角像素坐标
+      const topLeftPixel = [0, 0];
+      const bottomRightPixel = [size[0], size[1]];
+      // 转换为地图投影坐标
+      const topLeftMap = map.getCoordinateFromPixel(topLeftPixel);
+      const bottomRightMap = map.getCoordinateFromPixel(bottomRightPixel);
+      // 转换为经纬度
+      const lnglat = toLonLat(topLeftMap, map.getView().getProjection());
+      const lnglat2 = toLonLat(bottomRightMap, map.getView().getProjection());
+      queryParams.longitude_min = lnglat[0];
+      queryParams.latitude_max = lnglat[1];
+      queryParams.longitude_max = lnglat2[0];
+      queryParams.latitude_min = lnglat2[1];
+    }
+    getPointInfo2(queryParams).then((res) => {
+      const data = res.data ? res.data : [];
+      mapUtils.addMarker2(data);
+    });
+    if (!mapStore.pointParams.option.includes('43') && addMarkersTimer) {
+      clearInterval(addMarkersTimer);
+      addMarkersTimer = null;
+    }
+    if (mapStore.pointParams.option.includes('43')) {
+      addMarkersTimer = setInterval(addMarkersMethod, 60 * 1000);
+    }
+  },
+  300,
+  false
+);
 // 跳转指定地点
 const toAddress = (item) => {
   const dom = mapStore.activeMap === 'imageMap' ? map2Ref.value : mapRef.value;
@@ -396,12 +432,19 @@ const initDataToPlay = (data) => {
   }
 };
 
+const mapMoveEnd = () => {
+  if (!mapStore.pointParams.dict_value && !mapStore.pointParams.option) return;
+  addMarkersMethod();
+};
 watch(
   () => mapStore.mapLoaded,
   (loaded) => {
     if (loaded) {
       map = getMap();
       mapUtils = getMapUtils();
+      if (!!map) {
+        map.on('moveend', mapMoveEnd);
+      }
     }
   },
   {
@@ -410,34 +453,19 @@ watch(
 );
 // 监听视频打点
 watch(
-  () => mapStore.videoPointParams,
+  () => mapStore.pointParams,
   () => {
-    if (!mapStore.videoPointParams.flag) return;
-    const queryParams = {
-      zoom_level: mapStore.mapState.zoom,
-      // zoom_level: 8,
-      latitude_min: '',
-      latitude_max: '',
-      longitude_min: '',
-      longitude_max: '',
-      dict_value: 'slfh'
-      // dict_value: mapStore.videoPointParams.dict_value
-    };
-    if (mapStore.isAMap) {
-      const AMap = mapUtils.getAMap();
-      const pixel = new AMap.Pixel(0, 0);
-      const size = mapRef.value.getMapDomSize();
-      const pixel2 = new AMap.Pixel(size[0], size[1]);
-      const lnglat = map.containerToLngLat(pixel);
-      const lnglat2 = map.containerToLngLat(pixel2);
-      queryParams.longitude_min = lnglat.lng;
-      queryParams.latitude_max = lnglat.lat;
-      queryParams.longitude_max = lnglat2.lng;
-      queryParams.latitude_min = lnglat2.lat;
-    }
-    getLocationVideos(queryParams).then((res) => {
-      mapUtils.addMarker2(res.data);
-    });
+    addMarkersMethod();
+  },
+  {
+    deep: true
+  }
+);
+// 监听层级变化
+watch(
+  () => mapStore.mapState.zoom,
+  () => {
+    mapMoveEnd();
   },
   {
     deep: true
@@ -450,8 +478,10 @@ onBeforeUnmount(() => {
   if (!!map) {
     if (mapStore.isAMap) {
       map.off('click', handleClickMap);
+      map.off('moveend', handleClickMap);
     } else {
       map.un('click', handleClickMap);
+      map.un('moveend', handleClickMap);
     }
     mapStore.setIsMapSelect(false);
   }

+ 18 - 6
src/views/routineCommandMap/PositionMap.vue

@@ -1,8 +1,6 @@
 <template>
   <div class="dialog">
-
-
-    <Dialog type="md" :title="!!id ? '修改灾害信息' : '请选择事发地点'" draggable height="780px" customShow @close="handleClose" @confirm="submit">
+    <Dialog type="md" :title="!!id ? '修改灾害信息' : '请选择事发地点'" draggable height="780px" custom-show @close="handleClose" @confirm="submit">
       <div class="custom-dialog">
         <el-form ref="queryFormRef" :model="form">
           <div class="form">
@@ -83,9 +81,16 @@
           </div>
         </el-form>
         <div ref="containerRef" class="map_box">
-          <div id="positionMap">
-            <div id="map" class="map" :style="{ width: width, height: height }"></div>
-          </div>
+          <div
+            id="map"
+            class="map"
+            :style="{
+              width: width,
+              height: height,
+              transform: 'scale(' + inverseScale.inverseScaleX + ', ' + inverseScale.inverseScaleY + ')',
+              transformOrigin: '0 0'
+            }"
+          />
         </div>
       </div>
     </Dialog>
@@ -118,6 +123,7 @@ const proxy = getCurrentInstance()?.proxy;
 const { mm_event_level } = toRefs(proxy?.useDict('mm_event_level'));
 const router = useRouter();
 const emits = defineEmits(['update:visible', 'confirm']);
+const containerScale = inject('containerScale');
 // 地图对象
 let map = null;
 let amap = {};
@@ -339,7 +345,13 @@ function handleClose() {
 }
 let queryFormRef = ref();
 let containerRef = ref();
+let inverseScale = ref({
+  inverseScaleX: 1,
+  inverseScaleY: 1
+});
 function handleResize() {
+  inverseScale.value.inverseScaleX = 1 / containerScale().scaleX;
+  inverseScale.value.inverseScaleY = 1 / containerScale().scaleY;
   const containerWidth = containerRef.value.clientWidth * (document.body.clientWidth / 1920);
   const containerHeight = containerRef.value.clientHeight * (document.body.clientHeight / 1080);
   width.value = containerWidth + 'px';