Selaa lähdekoodia

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

# Conflicts:
#	src/views/globalMap/index.vue
hmm 7 kuukautta sitten
vanhempi
commit
9c8e18814a

+ 13 - 0
src/api/globalMap/MobilePlatform.ts

@@ -7,3 +7,16 @@ export const getMobileWorkstationList = (data) => {
     data: data
   });
 };
+
+// 列表信息
+export const getMobileWorkstationTrajectory = (id) => {
+  return request({
+    url: '/api/gateway/v2/get_mobile_workstation_trajectory',
+    method: 'post',
+    data: {
+      query: {
+        id: id
+      }
+    }
+  });
+};

+ 3 - 2
src/api/globalMap/TowerStatus.ts

@@ -8,10 +8,11 @@ export const getTowerStatus = () => {
 };
 
 // 各区县告警类型分析
-export const getTowerWarn = () => {
+export const getTowerWarn = (data) => {
   return request({
     url: '/api/gateway/v2/get_tower_area_status_count',
-    method: 'get'
+    method: 'POST',
+    data: data // 将入参作为请求体传递
   });
 };
 

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
src/assets/json/mm.json


+ 4 - 2
src/components/Map/YztMap/index.vue

@@ -6,6 +6,7 @@
 
 <script setup lang="ts">
 import 'ol/ol.css';
+import mmJson from '@/assets/json/mm.json'
 import { olMap } from '@/utils/olMap/olMap';
 import { PointType } from '@/api/globalMap/type';
 
@@ -49,13 +50,13 @@ watch(
   () => props.activeMap,
   () => {
     if (!map) return;
-    const id = props.activeMap === 'satellite2' ? ['YZT1715739306532', 'YZT1695608158269'] : ['YZT1708679726700', 'YZT1695608158269'];
+    const id = props.activeMap === 'imageMap' ? ['YZT1640925052482', 'YZT1695608158269'] : ['YZT1708679726700', 'YZT1695608158269'];
     map.replaceLayers(id);
   }
 );
 
 const init = () => {
-  const id = props.activeMap === 'satellite2' ? ['YZT1715739306532', 'YZT1695608158269'] : ['YZT1708679726700', 'YZT1695608158269'];
+  const id = props.activeMap === 'imageMap' ? ['YZT1640925052482', 'YZT1695608158269'] : ['YZT1708679726700', 'YZT1695608158269'];
   map = new olMap({
     dom: mapRef.value,
     id: id,
@@ -84,6 +85,7 @@ const init = () => {
     onLoadCompleted: (yMap) => {
       yztMap = yMap;
       // initMouseTool(map);
+      map.createVecByJson(mmJson, '茂名市');
       handleResize();
     }
   });

+ 34 - 6
src/components/Map/index.vue

@@ -42,8 +42,10 @@ import {
   getBuildingProjectDetails,
   getChemicalWarehouseDetails,
   getMiningOperationsDetails,
-  getEmergencyTransportResourcesDetails, getEmergencyDisasterInfoOfficerDetails, getMidmapDzzhDetails
-} from "@/api/globalMap/spatialAnalysis";
+  getEmergencyTransportResourcesDetails,
+  getEmergencyDisasterInfoOfficerDetails,
+  getMidmapDzzhDetails
+} from '@/api/globalMap/spatialAnalysis';
 import { pointDetailTemplate } from '@/views/globalMap/data/mapData';
 import ElementResizeDetectorMaker from 'element-resize-detector';
 import useAppStore from '@/store/modules/app';
@@ -59,7 +61,15 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { point_type } = toRefs<any>(proxy?.useDict('point_type'));
 const appStore = useAppStore();
 
-const emits = defineEmits(['update:drawing', 'selectGraphics', 'unSelectGraphics', 'showTextEditBox', 'onDrawCompleted', 'handleShowVideo', 'handleShowWarehouse']);
+const emits = defineEmits([
+  'update:drawing',
+  'selectGraphics',
+  'unSelectGraphics',
+  'showTextEditBox',
+  'onDrawCompleted',
+  'handleShowVideo',
+  'handleShowWarehouse'
+]);
 const containerRef = ref();
 const width = ref('100%');
 const height = ref('100%');
@@ -79,7 +89,21 @@ let AMap, map, scale;
 // 鼠标绘制工具
 const drawTool = useDrawTool();
 // 初始化地图
-const { getAMap, getMap, switchMap, addMarker, addSearchMarker, clearMarker, getMarkers, getScale, showInfo, hideInfo, handleHover } = useAMap({
+const {
+  getAMap,
+  getMap,
+  switchMap,
+  addMarker,
+  addSearchMarker,
+  clearMarker,
+  getMarkers,
+  getScale,
+  showInfo,
+  hideInfo,
+  handleHover,
+  creatMask,
+  trackPlayback
+} = useAMap({
   key: '30d3d8448efd68cb0b284549fd41adcf', // 申请好的Web端开发者Key,首次调用 load 时必填
   version: '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
   pitch: mapState.isThreeDimensional ? 45 : 0,
@@ -100,6 +124,10 @@ const { getAMap, getMap, switchMap, addMarker, addSearchMarker, clearMarker, get
       map.removeLayer();
     }
     map.on('zoomchange', zoomChangeHandler);
+    // 添加遮罩
+    // , { strokeColor: '#ff0000',strokeWeight: 2, offset }
+    //   { strokeColor: '#2a8797', strokeOpacity: 0.6,strokeWeight: 6, fillOpacity: 0},
+    creatMask([{ strokeWeight: 2 }]);
     drawTool.initMouseTool({ container: 'aMap', map, AMap });
     handleResize();
   },
@@ -400,7 +428,7 @@ const setCenter = (item) => {
   map.setCenter([item.longitude, item.latitude]);
 };
 
-defineExpose({ addMarker, addSearchMarker, setCenter, getMarkers, clearMarker, getMap, drawTool, handleHover });
+defineExpose({ addMarker, addSearchMarker, setCenter, getMarkers, clearMarker, getMap, drawTool, handleHover, trackPlayback });
 const handleResize = () => {
   const containerWidth = containerRef.value.clientWidth * containerScale().scaleX;
   const containerHeight = containerRef.value.clientHeight * containerScale().scaleY;
@@ -421,7 +449,7 @@ watch(
   () => {
     nextTick(() => {
       handleResize();
-    })
+    });
   }
 );
 onMounted(() => {

+ 96 - 4
src/hooks/AMap/useAMap.ts

@@ -12,7 +12,9 @@ export function useAMap(options) {
     AMapLoader.load({
       key: options.key, // 申请好的Web端开发者Key,首次调用 load 时必填
       version: !!options.version ? options.version : '2.0', // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
-      plugins: options.plugins ? options.plugins : ['AMap.Scale', 'AMap.RangingTool', 'AMap.MouseTool', 'AMap.PolygonEditor', 'AMap.MarkerCluster']
+      plugins: options.plugins
+        ? options.plugins
+        : ['AMap.Scale', 'AMap.RangingTool', 'AMap.MouseTool', 'AMap.PolygonEditor', 'AMap.MarkerCluster', 'AMap.DistrictSearch', 'AMap.MoveAnimation']
     }).then((res) => {
       AMap = res;
       map = new AMap.Map('aMap', {
@@ -62,8 +64,10 @@ export function useAMap(options) {
   };
   // 添加搜索的标记的
   const addSearchMarker = (item) => {
-    map.setCenter([item.longitude, item.latitude]);
-    addMarker(item, true);
+    debugger
+    map.setZoom(18);
+    map.setCenter(item.lnglat);
+    addMarker([item], true);
   };
 
   const addMarker = (points, isSearchItem?: boolean) => {
@@ -220,6 +224,92 @@ export function useAMap(options) {
     }
   };
 
+  const creatMask = (options, name = '茂名市') => {
+    new AMap.DistrictSearch({
+      extensions: 'all',
+      subdistrict: 0
+    }).search(name, function (status, result) {
+      // 外多边形坐标数组和内多边形坐标数组
+      const outer = [
+        new AMap.LngLat(-360, 90, true),
+        new AMap.LngLat(-360, -90, true),
+        new AMap.LngLat(360, -90, true),
+        new AMap.LngLat(360, 90, true)
+      ];
+      options.forEach((option) => {
+        const holes = result.districtList[0].boundaries;
+        if (option.offset) {
+
+          holes.forEach((items) => {
+
+          })
+        }
+        let pathArray = [outer];
+        pathArray.push.apply(pathArray, holes);
+        const polygon = new AMap.Polygon({
+          pathL: pathArray,
+          strokeColor: option.strokeColor ? option.strokeColor : '#268ab9',
+          strokeOpacity: option.strokeOpacity ? option.strokeOpacity : 1,
+          strokeWeight: option.strokeWeight ? option.strokeWeight : 1,
+          fillColor: option.fillColor ? option.fillColor : '#10243b',
+          fillOpacity: option.fillOpacity ? option.fillOpacity : 0.65
+        });
+        polygon.setPath(pathArray);
+        map.add(polygon);
+      });
+    });
+  };
+
+  let moveMarker, movePolyline, movePassedPolyline, timerId;
+  const trackPlayback = (lineArr) => {
+    if (timerId) {
+      clearTimeout(timerId);
+    }
+    movePolyline?.remove();
+    movePassedPolyline?.remove();
+    moveMarker?.remove();
+    moveMarker = new AMap.Marker({
+      map: map,
+      position: [116.478935, 39.997761],
+      icon: 'https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png',
+      offset: new AMap.Pixel(-13, -26)
+    });
+    // 绘制轨迹
+    movePolyline = new AMap.Polyline({
+      map: map,
+      path: lineArr,
+      showDir: true,
+      strokeColor: '#28F', //线颜色
+      // strokeOpacity: 1,     //线透明度
+      strokeWeight: 6 //线宽
+      // strokeStyle: "solid"  //线样式
+    });
+
+    movePassedPolyline = new AMap.Polyline({
+      map: map,
+      strokeColor: '#AF5', //线颜色
+      strokeWeight: 6 //线宽
+    });
+
+    moveMarker.on('moving', function (e) {
+      movePassedPolyline.setPath(e.passedPath);
+      map.setCenter(e.target.getPosition(), true);
+    });
+
+    moveMarker.on('moveend', function (e) {
+      timerId = setTimeout(() => {
+        movePolyline.remove();
+        movePassedPolyline.remove();
+        moveMarker.remove();
+      }, 2000);
+    });
+    moveMarker.moveAlong(lineArr, {
+      // 每一段的时长
+      duration: 1000, //可根据实际采集时间间隔设置
+      // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
+      autoRotation: true
+    });
+  };
   onMounted(() => {
     initMap(options);
   });
@@ -234,6 +324,8 @@ export function useAMap(options) {
     getScale,
     showInfo,
     hideInfo,
-    handleHover
+    handleHover,
+    creatMask,
+    trackPlayback
   };
 }

+ 65 - 4
src/utils/olMap/olMap.ts

@@ -18,8 +18,13 @@ import { Fill, Stroke } from 'ol/style';
 import proj4 from 'proj4';
 import { register } from 'ol/proj/proj4';
 import { defaults } from 'ol/control';
+import Vector from 'ol/layer/Vector';
+import SourceVector from 'ol/source/Vector';
+import GeoJSON from 'ol/format/GeoJSON';
 import { fromLonLat } from 'ol/proj';
 import axios from 'axios';
+import { fromExtent } from 'ol/geom/Polygon';
+import { LinearRing } from 'ol/geom';
 // import olPlot from 'ol-plot';
 // import { activate } from '../ol-plot/ol-plot'
 
@@ -94,7 +99,7 @@ export class olMap {
       // 如果 options.id 不是数组,但确实是一个图层,则直接处理
       await this.formatXml(options.id);
     }
-    console.log('wan')
+    console.log('wan');
     // 创建Vector层并添加到地图上
     this.vectorLayer = new VectorLayer({
       source: new VectorSource({
@@ -156,7 +161,7 @@ export class olMap {
     layer.set('layerName', code);
 
     this.map.addLayer(layer);
-    console.log(code)
+    console.log(code);
   }
 
   // 初始化绘画工具
@@ -232,11 +237,10 @@ export class olMap {
     this.map.addLayer(this.vectorLayer);
     const point = JSON.parse(JSON.stringify(this.markers));
     this.markers = [];
-    this.addMarker(point)
+    this.addMarker(point);
   }
 
   addMarker(points) {
-
     points.forEach((point) => {
       // 创建标注点
       const feature = new Feature({
@@ -275,4 +279,61 @@ export class olMap {
     if (!this.vectorLayer) return;
     this.vectorLayer.getSource().clear();
   }
+
+  /**
+   *
+   * @param {Geojon} chaozhou 根据geojson对象创建Featrue对象
+   * @param {String} layerName 图层名称
+   * @returns VectorLayer
+   */
+  createVecByJson(json, layerName = '') {
+    const format = new GeoJSON();
+    const fs = format.readFeatures(json);
+    const converLayer = new VectorLayer({
+      source: new VectorSource(),
+      style: new Style({
+        fill: new Fill({
+          color: 'rgba(16, 36, 59, 0.65)'
+        }),
+        stroke: new Stroke({
+          color: 'rgba(38, 138, 185, 1)',
+          width: 2
+        })
+      }),
+      zIndex: 99
+    });
+    this.map.addLayer(converLayer);
+    const extent = [-180, -90, 180, 90];
+    const polygonRing = fromExtent(extent);
+    fs.forEach((x) => {
+      const ft = x.values_.geometry;
+      const coords = ft.getCoordinates();
+      coords.forEach((coord) => {
+        const linearRing = new LinearRing(coord[0]);
+        polygonRing.appendLinearRing(linearRing);
+      });
+    });
+    const convertFt = new Feature({
+      geometry: polygonRing
+    });
+    converLayer.getSource().addFeature(convertFt);
+  }
+
+  /**
+   * @description 创建矢量图层
+   * @param {String} layerName 图层名称
+   * @param {Number} zIndex 地图层级默认是0
+   * @returns
+   */
+  createVecLayer(layerName = '', zIndex = 0) {
+    const source = new SourceVector({
+      crossOrigin: 'anonymous'
+    });
+    const layer = new Vector({
+      source,
+      zIndex
+    });
+    layer.set('layerName', layerName);
+    return layer;
+  }
 }

+ 29 - 0
src/views/globalMap/LeftMenu.vue

@@ -146,9 +146,38 @@ const initData = () => {
   });
 };
 
+const setMenuChange = (item, flag) => {
+  for (let i = 0; i < menuData.value.length; i++) {
+    if (item.meta.title === menuData.value[i].meta.title) {
+      menuData.value[i].checked = flag;
+      break;
+    } else if (!!menuData.value[i].children) {
+      const res = setChild(menuData.value[i].children, item, flag);
+      if (!!res) {
+        break;
+      }
+    }
+  }
+};
+const setChild = (data, item, flag) => {
+  let res = false;
+  for (let i = 0; i < data.length; i++) {
+    if (item.meta.title === data[i].meta.title) {
+      data[i].checked = flag;
+      break;
+    } else if (!!data[i].children) {
+      res = setChild(data[i].children, item, flag);
+      if (!!res) {
+        break;
+      }
+    }
+  }
+  return res;
+};
 onMounted(() => {
   initData();
 });
+defineExpose({ setMenuChange });
 </script>
 
 <style lang="scss" scoped>

+ 192 - 286
src/views/globalMap/RightMenu/CommunicationSupport.vue

@@ -1,19 +1,20 @@
 <template>
-  <div class="communication-container">
-    <div class="tabs">
-      <div v-for="(item, index) in menu" :key="index" :class="activeIndex === index ? 'tab tab_active' : 'tab'">
-        {{ item.name }}
-      </div>
-    </div>
-    <!--视频会商-->
-    <div v-show="activeIndex === 0" class="content">
+  <Dialog custom-show type="lg" title="通讯保障" hide-footer @close="handleClose">
+    <div class="content">
       <div class="left-content">
+        <el-input v-model="queryParams.keyword" class="custom-input" placeholder="组织架构搜索">
+          <template #prefix>
+            <el-icon class="el-input__icon"><search /></el-icon>
+          </template>
+        </el-input>
+        <div class="tree-container">
+          <div class="tree-box">
+            <el-tree :data="treeData" accordion @node-click="handleNodeClick" />
+          </div>
+        </div>
+      </div>
+      <div class="middle-content">
         <div class="search-box">
-          <el-input v-model="queryParams.keyword" class="custom-input" placeholder="组织架构搜索" style="width: 487px">
-            <template #prefix>
-              <el-icon class="el-input__icon"><search /></el-icon>
-            </template>
-          </el-input>
           <el-select
             v-model="queryParams.value1"
             class="custom-select select-box"
@@ -29,31 +30,24 @@
             </template>
           </el-input>
         </div>
-        <div class="tree-container">
-          <div class="tree-box">
-            <div style="overflow-y: auto; height: 100%">
-              <el-tree :data="treeData" accordion @node-click="handleNodeClick" />
+        <div class="user-box">
+          <div class="user-table">
+            <div class="tr">
+              <div class="td2">
+                <div :class="getCheckedClass()" @click="handleChecked"></div>
+              </div>
+              <div class="td">姓名</div>
+              <div class="td3">职务</div>
             </div>
-          </div>
-          <div class="user-box">
-            <div class="user-table">
-              <div class="tr">
+            <div class="table-content">
+              <div v-for="(item, index) in userList" :key="index" class="tr2">
                 <div class="td2">
-                  <div :class="getCheckedClass()" @click="handleChecked"></div>
+                  <div :class="item.checked ? 'common-checked-active' : 'common-checked'" @click="handleChecked2(item)"></div>
                 </div>
-                <div class="td">姓名</div>
-                <div class="td3">职务</div>
-              </div>
-              <div class="table-content">
-                <div v-for="(item, index) in userList" :key="index" class="tr2">
-                  <div class="td2">
-                    <div :class="item.checked ? 'common-checked-active' : 'common-checked'" @click="handleChecked2(item)"></div>
-                  </div>
-                  <div class="td">{{ item.name }}</div>
-                  <div class="td3">
-                    {{ item.duty }}
-                    <div class="phone-icon"></div>
-                  </div>
+                <div class="td">{{ item.name }}</div>
+                <div class="td3">
+                  {{ item.duty }}
+                  <div class="phone-icon"></div>
                 </div>
               </div>
             </div>
@@ -82,27 +76,14 @@
           </div>
         </div>
       </div>
-      <div class="btn-box">
-        <div class="btn">
-          <div class="icon1"></div>
-          <div class="text">会议号入会</div>
-        </div>
-        <div class="btn">
-          <div class="icon2"></div>
-          <div class="text">电话呼叫</div>
-        </div>
-        <div class="btn">
-          <div class="icon3"></div>
-          <div class="text">发起会议</div>
-        </div>
-      </div>
     </div>
-  </div>
+  </Dialog>
 </template>
 
 <script lang="ts" setup>
 import { Search } from '@element-plus/icons-vue';
 
+const emits = defineEmits(['close']);
 let activeIndex = ref(0);
 const options = ref([{ name: '全部', value: '全部' }]);
 const queryParams = ref({
@@ -250,273 +231,198 @@ const deleteItem = (item) => {
     }
   }
 };
+
+// 弹窗关闭后
+const handleClose = () => {
+  emits('close');
+};
 </script>
 
 <style lang="scss" scoped>
-.communication-container {
-  width: 1963px;
-  height: 659px;
-  background: url('@/assets/images/emergencyCommandMap/communication/communicationBg.png') no-repeat;
-  position: relative;
-  padding-top: 100px;
-  padding-left: 60px;
-  animation-name: slideLeft;
-  animation-duration: 2s;
-  .tabs {
-    display: flex;
-    .tab {
-      font-size: 44px;
-      font-family: YouSheBiaoTiHei;
-      text-align: center;
-      color: #b6bbcc;
-      width: 317px;
-      height: 78px;
-      line-height: 85px;
-      background: url('@/assets/images/emergencyCommandMap/communication/tab.png') no-repeat;
-      cursor: pointer;
-      &:hover {
-        color: #ffffff;
-        background: url('@/assets/images/emergencyCommandMap/communication/tabActive.png') no-repeat;
-      }
-    }
-
-    .tab_active {
-      color: #ffffff;
-      background: url('@/assets/images/emergencyCommandMap/communication/tabActive.png') no-repeat;
-    }
+.content {
+  display: flex;
+  margin-top: 12px;
+  .left-content {
+    width: 910px;
+    padding-right: 30px;
+    border-right: 1px solid #2187ff;
   }
-  .content {
-    display: flex;
-    margin-top: 12px;
-    .left-content {
-      .search-box {
-        display: flex;
-        .custom-input {
-          width: 305px;
-        }
-        .select-box {
-          width: 176px !important;
-          height: 56px;
-          line-height: 56px;
-          margin: 0 10px;
-          color: #83a3be;
-          font-size: 32px;
-        }
-        .custom-select-popper {
-          .el-scrollbar {
-            .el-select-dropdown__item {
-              color: #b1cae0;
-              font-size: 32px;
-              height: 56px;
-              line-height: 56px;
-            }
-          }
-        }
-        .input {
-          background: transparent;
-          color: #83a3be;
-          font-size: 32px;
-          outline: none;
-          appearance: none;
-          height: 100%;
-          border: none;
-          &::placeholder {
-            color: #83a3be;
-          }
-        }
+  .middle-content {
+    width: 910px;
+    padding: 0 30px;
+    border-right: 1px solid #2187ff;
+    .search-box {
+      display: flex;
+      .select-box {
+        flex-shrink: 0;
+        width: 176px !important;
+        height: 56px;
+        line-height: 56px;
+        margin: 0 10px;
+        color: #83a3be;
+        font-size: 32px;
       }
     }
-    .tree-container {
-      margin-top: 15px;
-      display: flex;
-      .tree-box {
-        width: 488px;
-        height: 354px;
-        background: url('@/assets/images/emergencyCommandMap/communication/treeBg.png') no-repeat;
-        padding: 15px 8px;
-        overflow: hidden;
-        :deep(.el-tree) {
-          background-color: transparent;
-          color: #fbffff;
-          font-size: 38px;
-          .el-tree-node__content {
-            height: auto;
-            padding-top: 10px;
-            padding-bottom: 10px;
-            white-space: normal;
-            word-break: break-all;
-          }
-          .el-tree-node__expand-icon {
-            color: #297cfc;
-            font-size: 23px;
-          }
-          .el-tree-node:focus > .el-tree-node__content,
-          .el-tree-node__content:hover {
-            background-color: transparent !important;
-          }
+    .user-box {
+      margin-left: 10px;
+      width: 100%;
+      height: 100%;
+      .user-table {
+        padding: 15px 0;
+        display: flex;
+        flex-direction: column;
+        font-size: 38px;
+        color: #fbffff;
+        .tr {
+          background-color: #102e76;
         }
-      }
-      .user-box {
-        margin-left: 10px;
-        width: 488px;
-        height: 354px;
-        background: url('@/assets/images/emergencyCommandMap/communication/treeBg.png') no-repeat;
-        background-size: 100% 100%;
-        .user-table {
-          padding: 15px 8px;
+        .tr,
+        .tr2 {
           display: flex;
-          flex-direction: column;
-          font-size: 38px;
-          color: #fbffff;
-          .tr {
-            background-color: #102e76;
-          }
-          .tr,
-          .tr2 {
+          padding: 6px 0;
+          .td {
+            flex: 1;
             display: flex;
-            padding: 6px 0;
-            .td {
-              flex: 2;
-              display: flex;
-              align-items: center;
-            }
-            .td2 {
-              width: 65px;
-              display: flex;
-              align-items: center;
-              justify-content: center;
-            }
-            .td3 {
-              flex: 3;
-              display: flex;
-              align-items: center;
-              justify-content: center;
-            }
-          }
-          .table-content {
-            height: 275px;
-            overflow-y: auto;
+            align-items: center;
           }
-          .tr2 {
-            margin-top: 10px;
-            background-color: #122868;
+          .td2 {
+            width: 65px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
           }
-          .phone-icon {
-            width: 62px;
-            height: 63px;
-            background: url('@/assets/images/emergencyCommandMap/communication/phone.png');
-            cursor: pointer;
+          .td3 {
+            flex: 2;
+            display: flex;
+            align-items: center;
           }
         }
+        .table-content {
+          height: 858px;
+          overflow-y: auto;
+        }
+        .tr2 {
+          margin-top: 10px;
+          background-color: #122868;
+        }
+        .phone-icon {
+          width: 62px;
+          height: 63px;
+          background: url('@/assets/images/emergencyCommandMap/communication/phone.png');
+          cursor: pointer;
+        }
       }
     }
-    .select-box2 {
-      margin-left: 10px;
-      width: 579px;
-      height: 421px;
-      background: url('@/assets/images/emergencyCommandMap/communication/peopleBg.png') no-repeat;
-      background-size: 100% 100%;
-      .select-header {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        color: #fbffff;
+  }
+
+  .custom-select-popper {
+    .el-scrollbar {
+      .el-select-dropdown__item {
+        color: #b1cae0;
         font-size: 32px;
-        border-bottom: 1px solid #247dff;
-        padding: 20px;
-        .left-item {
-          display: flex;
-          align-items: center;
-          .text {
-            margin: 0 10px;
-            color: #00e8ff;
-            font-family: 'BEBAS-1';
-          }
+        height: 56px;
+        line-height: 56px;
+      }
+    }
+  }
+  .input {
+    background: transparent;
+    color: #83a3be;
+    font-size: 32px;
+    outline: none;
+    appearance: none;
+    height: 100%;
+    border: none;
+    &::placeholder {
+      color: #83a3be;
+    }
+  }
+  .tree-container {
+    margin-top: 15px;
+    display: flex;
+    .tree-box {
+      width: 100%;
+      height: 920px;
+      overflow-y: auto;
+      padding: 15px 8px;
+      :deep(.el-tree) {
+        height: 100%;
+        background-color: transparent;
+        color: #fbffff;
+        font-size: 38px;
+        .el-tree-node__content {
+          height: auto;
+          padding-top: 10px;
+          padding-bottom: 10px;
+          white-space: normal;
+          word-break: break-all;
         }
-        .clear-btn {
-          color: #00e8ff;
-          cursor: pointer;
+        .el-tree-node__expand-icon {
+          color: #297cfc;
+          font-size: 23px;
         }
-      }
-      .select-content {
-        height: 305px;
-        overflow-y: auto;
-        .box-item {
-          border-bottom: 1px solid #247dff;
-          padding: 20px;
-          position: relative;
-          .line {
-            color: #fff;
-            font-size: 38px;
-            display: flex;
-            .text1 {
-              margin-right: 35px;
-            }
-            .text2 {
-              color: #a7ccdf;
-            }
-          }
-          .close-btn {
-            position: absolute;
-            right: 10px;
-            top: 50px;
-            cursor: pointer;
-            width: 29px;
-            height: 29px;
-            background: url('@/assets/images/emergencyCommandMap/communication/close.png') no-repeat;
-          }
+        .el-tree-node:focus > .el-tree-node__content,
+        .el-tree-node__content:hover {
+          background-color: transparent !important;
         }
       }
     }
-    .btn-box {
-      flex: 1;
-      height: 421px;
+  }
+  .select-box2 {
+    margin-left: 30px;
+    width: 910px;
+    height: 100%;
+    .select-header {
       display: flex;
-      flex-direction: column;
-      justify-content: center;
+      justify-content: space-between;
       align-items: center;
-      .btn {
-        width: 361px;
-        height: 136px;
-        background: url('@/assets/images/emergencyCommandMap/communication/btn.png') no-repeat;
+      color: #fbffff;
+      font-size: 32px;
+      border-bottom: 1px solid #247dff;
+      padding: 20px;
+      .left-item {
         display: flex;
         align-items: center;
-        justify-content: center;
-        cursor: pointer;
-        .icon1,
-        .icon2,
-        .icon3 {
-          margin-right: 20px;
-          margin-top: 10px;
-        }
-        .icon1 {
-          width: 64px;
-          height: 67px;
-          background: url('@/assets/images/emergencyCommandMap/communication/icon1.png') no-repeat;
-        }
-        .icon2 {
-          width: 64px;
-          height: 65px;
-          background: url('@/assets/images/emergencyCommandMap/communication/icon2.png') no-repeat;
-        }
-        .icon3 {
-          width: 64px;
-          height: 63px;
-          background: url('@/assets/images/emergencyCommandMap/communication/icon3.png') no-repeat;
-        }
         .text {
+          margin: 0 10px;
+          color: #00e8ff;
+          font-family: 'BEBAS-1';
+        }
+      }
+      .clear-btn {
+        color: #00e8ff;
+        cursor: pointer;
+      }
+    }
+    .select-content {
+      height: 858px;
+      overflow-y: auto;
+      .box-item {
+        border-bottom: 1px solid #247dff;
+        padding: 20px;
+        position: relative;
+        .line {
           color: #fff;
           font-size: 38px;
+          display: flex;
+          .text1 {
+            margin-right: 35px;
+          }
+          .text2 {
+            color: #a7ccdf;
+          }
+        }
+        .close-btn {
+          position: absolute;
+          right: 10px;
+          top: 50px;
+          cursor: pointer;
+          width: 29px;
+          height: 29px;
+          background: url('@/assets/images/emergencyCommandMap/communication/close.png') no-repeat;
         }
       }
     }
   }
 }
-
-.title {
-  position: absolute;
-  top: 6px;
-  left: 141px;
-  font-size: 60px;
-}
 </style>

+ 30 - 4
src/views/globalMap/RightMenu/MobilePlatform.vue

@@ -25,9 +25,9 @@
           <div class="td">{{ item.work_unit }}</div>
           <div class="td">{{ item.position }}</div>
           <div class="td">
-            <el-button type="text" size="small" @click="handleConnect(index, item)">连线</el-button>
-            <el-button type="text" size="small" @click="handleCollaborate(index, item)">协同</el-button>
-            <el-button type="text" size="small" @click="handleTrack(item)">轨迹</el-button>
+            <div class="text" @click="handleConnect(index, item)">连线</div>
+            <div class="text" @click="handleCollaborate(index, item)">协同</div>
+            <div class="text"  @click="handleTrack(item)">轨迹</div>
           </div>
         </div>
       </div>
@@ -37,8 +37,10 @@
 
 <script setup lang="ts">
 import { Search } from '@element-plus/icons-vue';
-import { getMobileWorkstationList } from '@/api/globalMap/MobilePlatform';
+import { getMobileWorkstationList, getMobileWorkstationTrajectory } from '@/api/globalMap/MobilePlatform';
 import { onMounted, reactive } from 'vue';
+
+const trackPlayback = inject('trackPlayback');
 // 数据列表,直接定义为数组
 const dataList = reactive([]);
 //入参
@@ -67,6 +69,22 @@ const handleCancel = () => {
   queryParams.keywords = '';
   initData();
 };
+const handleConnect = () => {
+
+}
+const handleCollaborate = () => {
+
+}
+// 轨迹
+const handleTrack = (item) => {
+  getMobileWorkstationTrajectory(item.id).then((res) => {
+    const trajectory = [];
+    res.rows.forEach((item) => {
+      trajectory.push([item.longitude, item.latitude]);
+    });
+    trackPlayback(trajectory);
+  });
+};
 //调用函数
 onMounted(() => {
   initData();
@@ -176,4 +194,12 @@ onMounted(() => {
     background-image: linear-gradient(to bottom, #ffffff 50%, #ff2f3c 100%);
   }
 }
+.text {
+  font-size: 38px;
+  color: #247dff;
+  margin-right: 20px;
+  &:last-child {
+    margin-right: 0;
+  }
+}
 </style>

+ 29 - 28
src/views/globalMap/RightMenu/RainMonitor/RainChart.vue

@@ -10,7 +10,7 @@
         <div class="text2" style="margin-left: 10px">{{ parseTime(updateTime, '{h}:{i}') }}</div>
       </div>
     </div>
-    <Chart :option="chartOption" style="flex: 1" />
+    <Chart :option="chartOption" style="height: 1200px" />
   </Dialog>
 </template>
 
@@ -174,34 +174,35 @@ const handleClose = () => {
       text-overflow: ellipsis;
     }
   }
-  .time-box {
-    width: 482px;
-    min-width: 482px;
-    height: 83px;
-    background: url('@/assets/images/map/rightMenu/rainMonitor/dateBox.png') no-repeat;
+}
+.time-box {
+  width: 482px;
+  min-width: 482px;
+  height: 83px;
+  background: url('@/assets/images/map/rightMenu/rainMonitor/dateBox.png') no-repeat;
+  display: flex;
+  align-items: center;
+  margin: 20px 0;
+  .text1 {
+    font-size: 32px;
+    color: #fff;
     display: flex;
-    align-items: center;
-    .text1 {
-      font-size: 32px;
-      color: #fff;
-      display: flex;
-      line-height: 75px;
-      padding-left: 108px;
-    }
-    .text2 {
-      font-size: 32px;
-      font-family: BEBAS-1;
-      /* 设置字体透明 */
-      color: transparent;
-      /* 设置线性渐变,从红色渐变到蓝色 */
-      background-image: linear-gradient(to bottom, #ffffff 25%, #2b72d6 100%);
-      /* 使用 -webkit-background-clip 属性将背景剪裁至文本形状 */
-      -webkit-background-clip: text;
-      /* 非Webkit内核浏览器需要使用标准前缀 */
-      background-clip: text;
-      /* 把当前元素设置为行内块,以便能够应用背景 */
-      display: inline-block;
-    }
+    line-height: 75px;
+    padding-left: 108px;
+  }
+  .text2 {
+    font-size: 32px;
+    font-family: BEBAS-1;
+    /* 设置字体透明 */
+    color: transparent;
+    /* 设置线性渐变,从红色渐变到蓝色 */
+    background-image: linear-gradient(to bottom, #ffffff 25%, #2b72d6 100%);
+    /* 使用 -webkit-background-clip 属性将背景剪裁至文本形状 */
+    -webkit-background-clip: text;
+    /* 非Webkit内核浏览器需要使用标准前缀 */
+    background-clip: text;
+    /* 把当前元素设置为行内块,以便能够应用背景 */
+    display: inline-block;
   }
 }
 .title {

+ 27 - 18
src/views/globalMap/RightMenu/TowerStatus.vue

@@ -143,7 +143,7 @@
 </template>
 
 <script lang="ts" setup>
-import { ref, onMounted } from 'vue';
+import { ref, reactive, onMounted } from 'vue';
 import { option8 } from './echartOptions';
 import { getTowerStatus, getTowerWarn, getTowerAbnormal } from '@/api/globalMap/TowerStatus';
 
@@ -167,31 +167,40 @@ const fetchAbnormalRateData = async () => {
   });
 };
 // 各区县告警类型分析
-// true 降序
 const queryParams = reactive({
-  sortName: '',
-  sort: ''
+  order_by: 'ffjr',
+  sort: 'asc'
 });
 const rangeData = ref([]);
+
+// 获取告警类型分析数据的方法
 const townshipList = async () => {
-  getTowerWarn().then((res) => {
-    rangeData.value = res.rows;
-  });
-};
-const handleSort = (type: string) => {
-  if (type === queryParams.sortName) {
-    if (queryParams.sort === 'desc') {
-      queryParams.sort = 'asc';
-    } else if (queryParams.sort === 'asc') {
-      queryParams.sort = '';
+  const data = {
+    query: {
+      order_by: queryParams.order_by,
+      sort: queryParams.sort
+    }
+  };
+  try {
+    const response = await getTowerWarn(data);
+    if (response.code === 0 && response.rows) {
+      rangeData.value = response.rows;
     } else {
-      queryParams.sort = 'desc';
+      console.error('获取告警类型分析数据失败:', response.msg);
     }
+  } catch (error) {
+    console.error('请求告警类型分析数据失败:', error);
+  }
+};
+// 处理排序
+const handleSort = (type: string) => {
+  if (type === queryParams.order_by) {
+    queryParams.sort = queryParams.sort === 'asc' ? 'desc' : 'asc';
   } else {
-    queryParams.sortName = type;
-    queryParams.sort = 'desc';
+    queryParams.order_by = type;
+    queryParams.sort = 'asc'; // 默认设置为升序
   }
-  townshipList();
+  townshipList(); // 重新获取数据
 };
 // 影响分析
 const analyzeData = ref([

+ 8 - 4
src/views/globalMap/SwitchMapTool.vue

@@ -28,11 +28,11 @@ const props = withDefaults(defineProps<Props>(), {});
 
 const emits = defineEmits(['switchMap']);
 const mapData = ref([
-  { name: '逻辑地图', key: 'logical' },
-  { name: '矢量地图', key: 'vectorgraph' },
+  // { name: '逻辑地图', key: 'logical' },
   { name: '卫星地图', key: 'satellite' },
-  { name: '粤政图', key: 'satellite2' },
-  { name: '粤政图2', key: 'satellite3' }
+  { name: '矢量地图', key: 'vectorgraph' },
+  { name: '影像图', key: 'imageMap' }
+  // { name: '粤政图2', key: 'satellite3' }
 ]);
 let open = ref(false);
 const selectItem = (key) => {
@@ -128,6 +128,10 @@ const handleExpand = () => {
     background: url('@/assets/images/map/satellite.png') no-repeat;
     background-size: 100% 100%;
   }
+  .imageMap {
+    background: url('@/assets/images/map/satellite2.png') no-repeat;
+    background-size: 100% 100%;
+  }
   .satellite2 {
     background: url('@/assets/images/map/satellite2.png') no-repeat;
     background-size: 100% 100%;

+ 69 - 18
src/views/globalMap/index.vue

@@ -2,11 +2,28 @@
   <div id="globalMap">
     <div class="global-map">
       <MapLogical v-if="activeMap === 'logical'" :map-data="mapData" />
-      <!--      <YMap v-else-if="['satellite2', 'satellite3'].includes(activeMap)" :activeMap="activeMap" />-->
-      <YztMap v-else-if="['satellite2', 'satellite3'].includes(activeMap)" ref="map2Ref" :active-map="activeMap" :point-type="pointType" />
-      <Map v-else ref="mapRef" :active-map="activeMap" :point-type="pointType" @handle-show-video="handleShowVideo" @handleShowWarehouse="handleShowWarehouse" />
+      <!--      <YMap v-else-if="['imageMap', 'satellite2', 'satellite3'].includes(activeMap)" :activeMap="activeMap" />-->
+      <YztMap
+        v-else-if="['imageMap'].includes(activeMap)"
+        ref="map2Ref"
+        :active-map="activeMap"
+        :point-type="pointType"
+      />
+      <Map
+        v-else
+        ref="mapRef"
+        :active-map="activeMap"
+        :point-type="pointType"
+        @handle-show-video="handleShowVideo"
+        @handle-show-warehouse="handleShowWarehouse"
+      />
       <!--左侧菜单-->
-      <LeftMenu style="position: absolute; top: 20px; left: 20px" @click-menu="clickMenu" @select-search-marker="selectSearchMarker" />
+      <LeftMenu
+        ref="leftMenuRef"
+        style="position: absolute; top: 20px; left: 20px"
+        @click-menu="clickMenu"
+        @select-search-marker="selectSearchMarker"
+      />
       <!--右侧菜单-->
       <RightMenu ref="rightMenuRef" :point-type="pointType" />
       <!--更换地图类型-->
@@ -15,7 +32,8 @@
       <TimeAxis />
       <DrawTools v-if="showDrawTools" @handle-analysis-data="handleAnalysisData" />
       <NearbyVideos v-if="showNearbyVideos" v-model="showNearbyVideos" :location="location" />
-      <MaterialDetail v-if="showWarehouse" v-model="showWarehouse" :warehouseData="warehouseData" />
+      <MaterialDetail v-if="showWarehouse" v-model="showWarehouse" :warehouse-data="warehouseData" />
+      <CommunicationSupport v-if="communicationSupport.show" @close="handleHideCommunicationSupport" />
     </div>
   </div>
 </template>
@@ -34,13 +52,19 @@ import { getPointInfo } from '@/api/globalMap';
 import RightMenu from './RightMenu/index.vue';
 import { PointType } from '@/api/globalMap/type';
 import DrawTools from '@/views/globalMap/RightMenu/DrawTools.vue';
+import CommunicationSupport from '@/views/globalMap/RightMenu/CommunicationSupport.vue';
 
 const rightMenuRef = ref(null);
 const mapData = reactive(logicalData);
 let mapRef = ref(null);
 let map2Ref = ref(null);
-// logical vectorgraph satellite satellite2 satellite3
-let activeMap = ref('logical');
+let leftMenuRef = ref(null);
+//  vectorgraph satellite imageMap 废弃:logical satellite2 satellite3
+let activeMap = ref('satellite');
+const communicationSupport = reactive({
+  show: false,
+  data: {}
+})
 
 const switchMap = (key) => {
   activeMap.value = key;
@@ -48,7 +72,7 @@ const switchMap = (key) => {
 let pointType = ref<PointType[]>([]);
 let markerList = ref([]);
 const addMarkers = (item) => {
-  const dom = activeMap.value === 'satellite2' ? map2Ref.value : mapRef.value;
+  const dom = activeMap.value === 'imageMap' ? map2Ref.value : mapRef.value;
   if (dom) {
     if (!item.checked) {
       let index = pointType.value.findIndex((item2) => item.component === item2.component);
@@ -96,7 +120,7 @@ const addMarkers = (item) => {
 };
 // 跳转指定地点
 const toAddress = (item) => {
-  const dom = activeMap.value === 'satellite2' ? map2Ref.value : mapRef.value;
+  const dom = activeMap.value === 'imageMap' ? map2Ref.value : mapRef.value;
   dom.setCenter(item);
 };
 
@@ -119,11 +143,20 @@ const clickMenu = (item, dataList) => {
     if (item.checked || (!item.checked && index === 0)) {
       rightMenuRef.value.updateMenu(
         checked,
-        ['易涝隐患点', '无人机', '铁塔运行监测', '物资与装备', '通讯保障', '手机工作台', '卫星电话'].includes(item.name) ? item : { name: '图层分析', meta: { icon: 'icon1' } }
+        ['易涝隐患点', '无人机', '铁塔运行监测', '物资与装备', '通讯保障', '手机工作台'].includes(item.name)
+          ? item
+          : { name: '图层分析', meta: { icon: 'icon1' } }
       );
     }
+  } else if (item.path === '3') {
+    communicationSupport.show = !communicationSupport.show;
+    communicationSupport.data = item;
   }
 };
+const handleHideCommunicationSupport = () => {
+  communicationSupport.show = false;
+  leftMenuRef.value.setMenuChange(communicationSupport.data, false);
+};
 const findChecked = (dataList, name) => {
   let index = 0;
   dataList.forEach((item) => {
@@ -139,12 +172,21 @@ const findChecked = (dataList, name) => {
 };
 // 点击搜索结果,添加标注
 const selectSearchMarker = (item) => {
-  const dom = activeMap.value === 'satellite2' ? map2Ref.value : mapRef.value;
+  const dom = activeMap.value === 'imageMap' ? map2Ref.value : mapRef.value;
   let item2 = deepClone(item);
-  if (iconList[item.component]) {
-    item2.image = iconList[item.component].image;
-    item2.size = iconList[item.component].size;
+  // 获取图标
+  if (iconList[item2.dataType]) {
+    item2.icon = iconList[item2.dataType].image;
+    item2.image = iconList[item2.dataType].image;
+    item2.imageHover = iconList[item2.dataType].imageHover;
+    item2.size = iconList[item2.dataType].size;
+  } else {
+    item2.icon = iconList['common'].image;
+    item2.image = iconList['common'].image;
+    item2.imageHover = iconList['common'].imageHover;
+    item2.size = iconList['common'].size;
   }
+  item2.lnglat = [item2.longitude, item2.latitude];
   dom.addSearchMarker(item2);
 };
 const handleAnalysisData = (data) => {
@@ -152,7 +194,7 @@ const handleAnalysisData = (data) => {
 };
 // 获取地图元素操作
 const getMap = () => {
-  if (['satellite2', 'satellite3'].includes(activeMap.value)) {
+  if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
     return map2Ref.value.getMap();
   } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
     return mapRef.value.getMap();
@@ -160,7 +202,7 @@ const getMap = () => {
   return {};
 };
 const showDetail = (data, dataType) => {
-  if (['satellite2', 'satellite3'].includes(activeMap.value)) {
+  if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
     return map2Ref.value.handleHover(data, dataType);
   } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
     return mapRef.value.handleHover(data, dataType);
@@ -168,7 +210,7 @@ const showDetail = (data, dataType) => {
   return {};
 };
 const getDrawTool = () => {
-  if (['satellite2', 'satellite3'].includes(activeMap.value)) {
+  if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
     return map2Ref.value.drawTool;
   } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
     return mapRef.value.drawTool;
@@ -176,13 +218,21 @@ const getDrawTool = () => {
   return {};
 };
 const getMarkers = () => {
-  if (['satellite2', 'satellite3'].includes(activeMap.value)) {
+  if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
     return map2Ref.value.getMarkers();
   } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
     return mapRef.value.getMarkers();
   }
   return {};
 };
+const trackPlayback = (data) => {
+  if (['imageMap', 'satellite2', 'satellite3'].includes(activeMap.value)) {
+    return map2Ref.value.trackPlayback(data);
+  } else if (['vectorgraph', 'satellite'].includes(activeMap.value)) {
+    return mapRef.value.trackPlayback(data);
+  }
+  return {};
+};
 let showNearbyVideos = ref(false);
 let location = reactive([]);
 // 显示附近视频
@@ -203,6 +253,7 @@ const handleShowWarehouse = (data) => {
 // })
 
 provide('getMap', getMap);
+provide('trackPlayback', trackPlayback);
 provide('showDetail', showDetail);
 provide('getDrawTool', getDrawTool);
 provide('getMarkers', getMarkers);

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä