Hwf пре 2 месеци
родитељ
комит
3797b59dc9

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

@@ -429,3 +429,16 @@ export const getPointInfoTransportationVideo = (id: string) => {
     }
   });
 };
+
+// 交通局视频
+export const getVehicleInfo = (id: string) => {
+  return request({
+    url: '/api/gateway/v2/get_vehicle_info',
+    method: 'post',
+    data: {
+      query: {
+        vehicle_no: id
+      }
+    }
+  });
+};

BIN
src/assets/images/dotIcon/42_transportation_video.png


BIN
src/assets/images/dotIcon/42_transportation_video_hover.png


BIN
src/assets/images/dotIcon/43_vehicle.png


BIN
src/assets/images/dotIcon/43_vehicle_hover.png


+ 6 - 1
src/components/Dialog/index.vue

@@ -1,5 +1,10 @@
 <template>
-  <div v-if="modelValue || customShow" v-drag="{draggable: draggable, position: 'fixed', scaleX: containerScale().scaleX, scaleY: containerScale().scaleY}" class="common-dialog" :style="{ width: computedWidth, height: computedHeight, zIndex: zIndex }">
+  <div
+    v-if="modelValue || customShow"
+    v-drag="{ draggable: draggable, position: 'fixed', scaleX: containerScale().scaleX, scaleY: containerScale().scaleY }"
+    class="common-dialog"
+    :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 : '弹窗' }}

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

@@ -284,8 +284,9 @@ const filterTd = (obj, dataType) => {
   let data = [];
   let tempData = {};
   let i = 0;
-  for (let key in obj) {
-    let keyLabel = pointDetailTemplate[dataType][key];
+  const pointDetailTemplateObj = pointDetailTemplate[dataType];
+  Object.keys(pointDetailTemplateObj).forEach((key) => {
+    let keyLabel = pointDetailTemplateObj[key];
     if (!!keyLabel) {
       if (i === 2) {
         i = 0;
@@ -312,7 +313,7 @@ const filterTd = (obj, dataType) => {
         }
       }
     }
-  }
+  });
   if (!!tempData && JSON.stringify(tempData) !== '{}') {
     data.push(tempData);
   }

+ 5 - 3
src/components/Map/data.ts

@@ -27,7 +27,7 @@ import {
   getWaterList,
   getVideoDrowning,
   getVideoForestFire,
-  getVideoDisasterPrevention, getVideoTraffic, getVideoTraffic2, getPointInfoTransportationVideo
+  getVideoDisasterPrevention, getVideoTraffic, getVideoTraffic2, getPointInfoTransportationVideo, getVehicleInfo
 } from '@/api/globalMap/spatialAnalysis';
 import { getRescueTeamsInfo } from '@/api/globalMap/rescueTeam';
 
@@ -67,7 +67,8 @@ export const methodList = {
   '34': getVideoDisasterPrevention,
   '35': getVideoTraffic,
   '41': getRescueTeamsInfo,
-  '42': getPointInfoTransportationVideo
+  '42': getPointInfoTransportationVideo,
+  '43': getVehicleInfo
 };
 export const titleList = {
   '1': '专家信息',
@@ -106,5 +107,6 @@ export const titleList = {
   '34': '防灾救援',
   '35': '交通视频',
   '41': '救援队伍',
-  '42': '交通局视频'
+  '42': '交通局视频',
+  '43': '重点车辆'
 };

+ 4 - 3
src/components/Map/index.vue

@@ -264,8 +264,9 @@ const filterTd = (obj, dataType) => {
   let data = [];
   let tempData = {};
   let i = 0;
-  for (let key in obj) {
-    let keyLabel = pointDetailTemplate[dataType][key];
+  const pointDetailTemplateObj = pointDetailTemplate[dataType];
+  Object.keys(pointDetailTemplateObj).forEach((key) => {
+    let keyLabel = pointDetailTemplateObj[key];
     if (!!keyLabel) {
       if (i === 2) {
         i = 0;
@@ -292,7 +293,7 @@ const filterTd = (obj, dataType) => {
         }
       }
     }
-  }
+  });
   if (!!tempData && JSON.stringify(tempData) !== '{}') {
     data.push(tempData);
   }

+ 192 - 93
src/components/TimeAxis/index.vue

@@ -40,29 +40,28 @@
         </div>
       </div>
     </div>
-    <Dialog v-model="timeAxisState.showDialog" title="气象图" hide-footer @close="dialogClose">
-      <img v-show="timeAxisState.activeIndex > -1" :src="timeAxisState.data[timeAxisState.activeIndex]?.img" style="width: 100%" />
-    </Dialog>
   </div>
 </template>
 
 <script lang="ts" setup name="TimeAxis">
 import { parseTime } from '@/utils/ruoyi';
-import Dialog from '@/components/Dialog/index.vue';
-import img1 from './tempImg/img1.jfif';
-import img2 from './tempImg/img2.jfif';
-import img3 from './tempImg/img3.jfif';
-import img4 from './tempImg/img4.jfif';
-import img5 from './tempImg/img5.jfif';
-import img6 from './tempImg/img6.jfif';
-import img7 from './tempImg/img7.jfif';
-import img8 from './tempImg/img8.jfif';
-import img9 from './tempImg/img9.jfif';
-import img10 from './tempImg/img10.jfif';
+import carImg from '@/assets/images/car.png';
 
+const props = defineProps({
+  activeMap: String
+});
 const containerScale = inject('containerScale');
+const getMapUtils = inject('getMapUtils');
+
+const AMapType = ['vectorgraph', 'satellite'];
+let mapUtils, map, AMap;
+// 轨迹数据
+let moveMarker, movePassedPolyline, movePolyline;
+let isNewMarkerPause = false;
+let trackPathArr = [];
 const timeAxisState = reactive({
   expand: false,
+  type: '',
   format: 'YYYY-MM-DD HH:mm',
   startTime: '',
   endTime: '',
@@ -71,51 +70,9 @@ const timeAxisState = reactive({
   show: false,
   showDialog: false,
   speed: 1,
-  data: [
-    {
-      time: '00:15',
-      img: img1
-    },
-    {
-      time: '01:15',
-      img: img2
-    },
-    {
-      time: '01:45',
-      img: img3
-    },
-    {
-      time: '02:15',
-      img: img4
-    },
-    {
-      time: '03:15',
-      img: img5
-    },
-    {
-      time: '04:15',
-      img: img6
-    },
-    {
-      time: '05:15',
-      img: img7
-    },
-    {
-      time: '06:15',
-      img: img8
-    },
-    {
-      time: '07:15',
-      img: img9
-    },
-    {
-      time: '07:45',
-      img: img10
-    }
-  ]
+  data: []
 });
-let timer;
-
+let originalData = [];
 // 展开收起
 const changeExpand = () => {
   timeAxisState.expand = !timeAxisState.expand;
@@ -133,46 +90,23 @@ const getInitTime = () => {
 
 // 返回上一个时间点
 const toPrevTime = () => {
-  timeAxisState.showDialog = true;
-  timeAxisState.playing = false;
-  if (timeAxisState.activeIndex === 0) {
-    timeAxisState.playing = false;
-  } else {
-    timeAxisState.activeIndex -= 1;
+  if (timeAxisState.type === 'track') {
+    prevPauseTime();
   }
 };
 
 // 播放
 const toPlayTime = () => {
-  timeAxisState.playing = true;
-  if (timeAxisState.activeIndex === timeAxisState.data.length - 1) {
-    timeAxisState.activeIndex = -1;
-  }
-  loopPlay();
-};
-
-// 循环播放
-const loopPlay = () => {
-  if (timeAxisState.playing === false) return;
-  toNextTime();
-  //  && timeAxisState.activeIndex < timeAxisState.data.length - 1
-  if (timeAxisState.playing) {
-    setTimeout(loopPlay, 1000 / timeAxisState.speed);
+  timeAxisState.playing = !timeAxisState.playing;
+  if (timeAxisState.type === 'track') {
+    playOrPauseTrack();
   }
 };
 
 // 前往下一个时间点
 const toNextTime = (flag?: boolean) => {
-  timeAxisState.showDialog = true;
-  if (flag) {
-    timeAxisState.playing = false;
-  } else if (!timeAxisState.playing) {
-    return;
-  }
-  if (timeAxisState.activeIndex === timeAxisState.data?.length - 1) {
-    timeAxisState.playing = false;
-  } else {
-    timeAxisState.activeIndex += 1;
+  if (timeAxisState.type === 'track') {
+    nextPauseTime();
   }
 };
 
@@ -184,11 +118,6 @@ const changeSpeed = () => {
 // 拖拽移动位置
 const dragMove = () => {};
 
-// 弹窗关闭后
-const dialogClose = () => {
-  timeAxisState.playing = false;
-};
-
 // 拖拽的参数
 const dragState = reactive({
   bottom: 180,
@@ -241,9 +170,179 @@ const stopDrag2 = () => {
   document.removeEventListener('mouseup', stopDrag2);
 };
 
+// 外部数据传入,开始播放
+const initDataToPlay = (obj) => {
+  timeAxisState.type = obj.type;
+  originalData = obj.data;
+  timeAxisState.data = obj.data;
+  trackPathArr = [];
+  timeAxisState.data.forEach((item) => {
+    trackPathArr.push(item.lnglat);
+  });
+  // 路线轨迹
+  if (timeAxisState.type === 'track') {
+    mapUtils = getMapUtils();
+    map = mapUtils?.getMap();
+    AMap = mapUtils?.getAMap();
+    if (AMapType.includes(props.activeMap)) {
+      if (moveMarker) {
+        // 不停止remove还是有
+        moveMarker.stopMove();
+        moveMarker.remove();
+      }
+      movePolyline?.remove();
+      movePassedPolyline?.remove();
+      // 绘制轨迹
+      movePolyline = new AMap.Polyline({
+        map: map,
+        path: trackPathArr,
+        showDir: true,
+        strokeColor: '#28F', //线颜色
+        // strokeOpacity: 1,     //线透明度
+        strokeWeight: 6 //线宽
+        // strokeStyle: "solid"  //线样式
+      });
+
+      movePassedPolyline = new AMap.Polyline({
+        map: map,
+        strokeColor: '#AF5', //线颜色
+        strokeWeight: 6 //线宽
+      });
+      startPlay();
+    }
+  }
+};
+// 创建新标点 moveTo调用第二次不生效,重新生成marker
+const createMarker = () => {
+  if (moveMarker) {
+    // 不停止remove还是有
+    moveMarker.stopMove();
+    moveMarker.remove();
+  }
+
+  const icon = new AMap.Icon({
+    size: new AMap.Size(13, 26),
+    image: carImg
+  });
+  moveMarker = new AMap.Marker({
+    map: map,
+    position: trackPathArr[timeAxisState.activeIndex],
+    icon: icon,
+    anchor: 'center'
+  });
+  moveMarker.on('moving', (e) => {
+    // 更新已通过路径
+    const position = e.target.getPosition();
+    const position2 = trackPathArr.slice(0, timeAxisState.activeIndex);
+    position2.push(position);
+    movePassedPolyline.setPath(position2);
+    map.setCenter(position, true);
+  });
+  // 监听移动结束事件,继续播放
+  moveMarker.on('moveend', () => {
+    if (timeAxisState.playing) {
+      createMarker();
+      playNextNode();
+    }
+  });
+};
+
+// 轨迹 开始/暂停
+const playOrPauseTrack = () => {
+  if (AMapType.includes(props.activeMap)) {
+    if (timeAxisState.playing) {
+      if (timeAxisState.activeIndex >= timeAxisState.data.length - 1) {
+        // 重新播放
+        timeAxisState.activeIndex = 0;
+        timeAxisState.playing = true;
+        createMarker();
+        movePassedPolyline.setPath([]);
+        nextTick(() => {
+          playNextNode();
+        });
+      } else if (isNewMarkerPause) {
+        playNextNode();
+      } else {
+        moveMarker.resumeMove();
+      }
+    } else {
+      moveMarker.pauseMove();
+    }
+    isNewMarkerPause = false;
+  }
+};
+// 轨迹开始播放
+const startPlay = () => {
+  timeAxisState.activeIndex = 0;
+  createMarker();
+  timeAxisState.playing = true;
+  playNextNode();
+};
+// 轨迹 上一步
+const prevPauseTime = () => {
+  if (timeAxisState.activeIndex <= 0) return;
+  // 更新索引
+  timeAxisState.playing = false;
+  timeAxisState.activeIndex -= 1;
+  moveMarker.stopMove();
+  createMarker();
+  movePassedPolyline.setPath(trackPathArr.slice(0, timeAxisState.activeIndex + 1));
+  isNewMarkerPause = true;
+};
+const nextPauseTime = () => {
+  if (timeAxisState.activeIndex <= 0) return;
+  // 更新索引
+  timeAxisState.playing = false;
+  timeAxisState.activeIndex += 1;
+  createMarker();
+  movePassedPolyline.setPath(trackPathArr.slice(0, timeAxisState.activeIndex + 1));
+  isNewMarkerPause = true;
+};
+// 轨迹播放下一个节点
+const playNextNode = () => {
+  if (timeAxisState.activeIndex >= timeAxisState.data.length - 1) {
+    timeAxisState.playing = false;
+    return;
+  }
+  // 更新索引
+  timeAxisState.activeIndex += 1;
+
+  // 移动到目标节点
+  moveMarker.moveTo(trackPathArr[timeAxisState.activeIndex], {
+    duration: timeAxisState.speed === 1 ? 2000 : 1000
+  });
+};
+//传入两个经纬度点得到车辆角度 设置车辆Marker角度
+const getAngle = (startPoint, endPoint) => {
+  if (!(startPoint && endPoint)) {
+    return 0;
+  }
+
+  let dRotateAngle = Math.atan2(
+    Math.abs(startPoint.lng - endPoint.lng),
+    Math.abs(startPoint.lat - endPoint.lat)
+  );
+  if (endPoint.lng >= startPoint.lng) {
+    if (endPoint.lat >= startPoint.lat) {
+    } else {
+      dRotateAngle = Math.PI - dRotateAngle;
+    }
+  } else {
+    if (endPoint.lat >= startPoint.lat) {
+      dRotateAngle = 2 * Math.PI - dRotateAngle;
+    } else {
+      dRotateAngle = Math.PI + dRotateAngle;
+    }
+  }
+  dRotateAngle = (dRotateAngle * 180) / Math.PI;
+  return dRotateAngle;
+};
+
 onMounted(() => {
   getInitTime();
 });
+
+defineExpose({ initDataToPlay });
 </script>
 
 <style lang="scss" scoped>

+ 2 - 3
src/directive/common/drag.ts

@@ -1,6 +1,6 @@
 export default {
   mounted(el, binding) {
-    const { draggable, position = 'absolute', scaleX = 1, scaleY = 1 } = binding.value;
+    const { draggable, position = 'absolute', scaleX = 1, scaleY = 1, dom } = binding.value;
     if (!draggable) {
       // 如果拖拽功能被禁用,则不执行任何拖拽相关的逻辑
       return;
@@ -8,8 +8,7 @@ export default {
 
     el.style.position = position;
     el.style.cursor = 'move';
-
-    const dragDom = el;
+    const dragDom = !!dom ? dom : el;
 
     let disX = 0; // 鼠标按下时,鼠标与拖拽元素的左边距
     let disY = 0; // 鼠标按下时,鼠标与拖拽元素的上边距

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

@@ -398,14 +398,13 @@ export function useAMap(options) {
     }
   };
   let moveMarker, movePolyline, movePassedPolyline, timerId;
-  const trackPlayback = (lineArr) => {
+  const trackPlayback = (lineArr, speed = 1000) => {
     if (timerId) {
       clearTimeout(timerId);
     }
     movePolyline?.remove();
     movePassedPolyline?.remove();
     moveMarker?.remove();
-    let index = 0;
     const icon = new AMap.Icon({
       size: new AMap.Size(13, 26),
       image: carImg
@@ -450,11 +449,11 @@ export function useAMap(options) {
     // });
     moveMarker.moveAlong(lineArr, {
       // 每一段的时长
-      duration: 1000, //可根据实际采集时间间隔设置
+      duration: speed, //可根据实际采集时间间隔设置
       // JSAPI2.0 是否延道路自动设置角度在 moveAlong 里设置
       autoRotation: true
     });
-    return [movePolyline, movePassedPolyline, moveMarker];
+    return { movePolyline, movePassedPolyline, moveMarker };
   };
 
   const drawData = (data) => {

+ 171 - 97
src/utils/olMap/olMap.ts

@@ -30,7 +30,7 @@ import { getPointsCenter, mergeGeoJsonPolygons } from '@/utils/gisUtils';
 import { Cluster } from 'ol/source';
 import CircleStyle from 'ol/style/Circle';
 import Overlay from 'ol/Overlay';
-import { Draw, Select } from 'ol/interaction';
+import { DoubleClickZoom, DragPan, Draw, Select } from 'ol/interaction';
 import { click } from 'ol/events/condition';
 import Circle from 'ol/geom/Circle';
 import { deepClone, getRgba, hexToRgba, initDrag, rgbToRgba } from '@/utils';
@@ -93,6 +93,7 @@ export class olMap {
   private traceFeature;
   // 自定义绘制结束调用方法
   private drawEndMethod;
+  private selectedFeature;
 
   constructor(options) {
     this.options = options;
@@ -136,6 +137,7 @@ export class olMap {
     // 创建选择交互
     this.select = new Select({
       condition: click,
+      style: null,
       filter: (feature, layer) => {
         // 只有vectorLayer图层可选择
         return layer === this.vectorLayer;
@@ -150,20 +152,16 @@ export class olMap {
         const originalFeature = features[0];
         const size = features.length;
         if (size === 1) {
-          // 设置新的样式(更换图标)
-          selectedFeatures.setStyle(
-            new Style({
-              image: new Icon({
-                anchor: [0.5, 0.5],
-                scale: 0.146,
-                anchorXUnits: 'fraction',
-                anchorYUnits: 'pixels',
-                src: originalFeature.get('imageHover')
-              })
-            })
-          );
-          const extData = originalFeature.get('extData');
-          options.onMarkerClick(extData);
+          if (this.selectedFeature !== originalFeature) {
+            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);
+            options.onMarkerClick(extData);
+          }
         } else {
           // 聚合要素
           this.select.getFeatures().clear();
@@ -311,7 +309,6 @@ export class olMap {
     // 继续编辑编辑
     this.drawGraphics(this.drawOptions.graphicsType);
   }
-
   // 绘制图形
   drawGraphics(newOptions: MouseTool) {
     const typeList = {
@@ -321,9 +318,9 @@ export class olMap {
       measureArea: 'Polygon',
       straightLine: 'LineString',
       marker: 'Point',
-      text: 'Point'
+      text: 'Point',
+      anyLine: 'AnyLine'
     };
-    debugger
     const data = getRgba(newOptions.color);
     let geometryFunction = null;
     if (newOptions.graphicsType === 'rectangle') {
@@ -359,52 +356,56 @@ export class olMap {
           this.drawOptions.size = newOptions.size;
         }
         this.closeDraw();
-        // 创建绘制交互
-        let style = new Style({
-          stroke: new Stroke({
-            color: rgbToRgba(this.drawOptions.strokeColor, this.drawOptions.strokeOpacity),
-            width: this.drawOptions.strokeWeight
-          }),
-          fill: new Fill({
-            color: rgbToRgba(this.drawOptions.fillColor, this.drawOptions.fillOpacity)
-          })
-        });
-        this.drawTool = new Draw({
-          source: this.drawVector.getSource(),
-          type: typeList[newOptions.graphicsType],
-          geometryFunction: geometryFunction,
-          style: style
-        });
-        // 添加绘制交互到地图
-        this.map.addInteraction(this.drawTool);
-        // 监听绘制结束事件
-        this.drawTool.on('drawend', (event) => {
-          const feature = event.feature;
-          // 获取几何对象
-          if (newOptions.graphicsType !== 'marker') {
-            if (newOptions.graphicsType === 'measureArea') {
-              const geometry = feature.getGeometry();
-              const coordinates = geometry.getCoordinates();
-              const pathArr = coordinates[0];
-              const area = turf.area(turf.polygon([pathArr]));
-              style = new Style({
-                stroke: style.getStroke(),
-                fill: style.getFill(),
-                text: new Text({
-                  text: '区域面积' + area.toFixed(2) + '平方米',
-                  font: '14px Calibri,sans-serif',
-                  fill: new Fill({ color: '#000' }),
-                  stroke: new Stroke({
-                    color: '#fff',
-                    width: 3
-                  }),
-                  overflow: true
-                })
-              });
+        if (newOptions.graphicsType === 'anyLine') {
+          this.drawAnyLine();
+        } else {
+          // 创建绘制交互
+          let style = new Style({
+            stroke: new Stroke({
+              color: rgbToRgba(this.drawOptions.strokeColor, this.drawOptions.strokeOpacity),
+              width: this.drawOptions.strokeWeight
+            }),
+            fill: new Fill({
+              color: rgbToRgba(this.drawOptions.fillColor, this.drawOptions.fillOpacity)
+            })
+          });
+          this.drawTool = new Draw({
+            source: this.drawVector.getSource(),
+            type: typeList[newOptions.graphicsType],
+            geometryFunction: geometryFunction,
+            style: style
+          });
+          // 添加绘制交互到地图
+          this.map.addInteraction(this.drawTool);
+          // 监听绘制结束事件
+          this.drawTool.on('drawend', (event) => {
+            const feature = event.feature;
+            // 获取几何对象
+            if (newOptions.graphicsType !== 'marker') {
+              if (newOptions.graphicsType === 'measureArea') {
+                const geometry = feature.getGeometry();
+                const coordinates = geometry.getCoordinates();
+                const pathArr = coordinates[0];
+                const area = turf.area(turf.polygon([pathArr]));
+                style = new Style({
+                  stroke: style.getStroke(),
+                  fill: style.getFill(),
+                  text: new Text({
+                    text: '区域面积' + area.toFixed(2) + '平方米',
+                    font: '14px Calibri,sans-serif',
+                    fill: new Fill({ color: '#000' }),
+                    stroke: new Stroke({
+                      color: '#fff',
+                      width: 3
+                    }),
+                    overflow: true
+                  })
+                });
+              }
+              feature.setStyle(style);
             }
-            feature.setStyle(style);
-          }
-        });
+          });
+        }
       }
     }
     return this.drawOptions;
@@ -484,6 +485,74 @@ export class olMap {
     data.id = id;
     return { text, data };
   }
+  drawAnyLine() {
+    document.addEventListener('touchend', this.handleTouchEnd);
+    this.map.on('pointerdown', this.handleTouchStart);
+    this.map.on('pointermove', this.handleTouchMove.bind(null, this.options));
+    document.addEventListener('mouseup', this.handleTouchEnd.bind(null, this.options));
+  }
+  handleTouchStart(e) {
+    this.drawing = true;
+    const interactions = this.map.getInteractions();
+    interactions.forEach((interaction) => {
+      if (interaction instanceof DragPan || interaction instanceof DoubleClickZoom) {
+        interaction.setActive(false); // 修改为需要的值,true或false
+      }
+    });
+
+    this.path = [e.lnglat];
+    // if (this.anyLine) {
+    //   map.remove(anyLine);
+    // }
+  }
+  handleTouchMove(options, e) {
+    if (!this.drawing) return;
+    this.path.push(e.lnglat);
+    // if (anyLine) {
+    //   map.remove(anyLine);
+    // }
+    this.anyLine = new Feature({
+      geometry: new LineString(this.path) // path为坐标数组,如[[x1,y1], [x2,y2]]
+    });
+    const lineStyle = new Style({
+      stroke: new Stroke({
+        color: hexToRgba(options.strokeColor, options.strokeOpacity), // 合并颜色与透明度
+        width: options.strokeWeight,
+        lineJoin: 'round' // 线段连接处圆角
+      })
+    });
+    this.anyLine.setStyle(lineStyle);
+    //   new AMap.Polyline({
+    //   path: path,
+    //   strokeColor: options.strokeColor,
+    //   strokeOpacity: options.strokeOpacity,
+    //   strokeWeight: options.strokeWeight,
+    //   strokeStyle: options.strokeStyle,
+    //   lineJoin: 'round'
+    // });
+    this.drawVector.getSource().addFeature(this.anyLine);
+  }
+  handleTouchEnd(options) {
+    // drawing = false;
+    // map.setStatus({
+    //   showIndoorMap: true,
+    //   dragEnable: true,
+    //   keyboardEnable: true,
+    //   doubleClickZoom: true,
+    //   zoomEnable: true,
+    //   rotateEnable: true
+    // });
+    // map.off('touchstart', handleTouchStart);
+    // map.on('touchmove', handleTouchMove.bind(null, options));
+    // document.addEventListener('touchend', handleTouchEnd.bind(null, options));
+    // map.off('mousedown', handleTouchStart);
+    // map.off('mousemove', handleTouchMove);
+    // document.removeEventListener('mouseup', handleTouchEnd);
+    // if (!!drawEndMethod) {
+    //   drawEndMethod(options, anyLine);
+    // }
+    // anyLine = null;
+  }
   // 关闭绘制
   closeDraw() {
     if (!this.drawTool) return;
@@ -551,21 +620,46 @@ export class olMap {
         })
       ];
     }
-
-    return new Style({
+    const pointSize = originalFeature.get('size');
+    const originalWidth = originalFeature.get('originalWidth');
+    const originalHeight = originalFeature.get('originalHeight');
+    const icon = originalFeature.get('icon');
+    const name = originalFeature.get('name');
+    const showName = originalFeature.get('showName');
+    const scale = !!pointSize[0] ? pointSize[0] / originalWidth : 1;
+    const style = new Style({
       geometry: originalFeature.getGeometry(),
       image: new Icon({
+        src: icon,
+        scale: scale,
         anchor: [0.5, 0.5],
-        scale: 0.146,
         anchorXUnits: 'fraction',
-        anchorYUnits: 'pixels',
-        src: originalFeature.get('icon')
+        anchorYUnits: 'fraction'
       })
     });
+    if (!!showName) {
+      style.setText(
+        new Text({
+          text: name,
+          font: '12px sans-serif',
+          fill: new Fill({
+            color: '#000'
+          }),
+          stroke: new Stroke({
+            color: '#fff',
+            width: 3
+          }),
+          offsetY: (originalHeight / 2) * scale + 4
+        })
+      );
+    }
+    return style;
   }
   addMarker(points) {
     this.clearMarker();
-    const features = [];
+    const vectorSource = new VectorSource({
+      features: []
+    });
     points.forEach((point) => {
       // 创建标注点
       const feature = new Feature({
@@ -573,47 +667,27 @@ export class olMap {
         geometry: new Point([Number(point.longitude), Number(point.latitude)]),
         name: point.name,
         icon: point.icon,
+        image: point.icon,
         imageHover: point.imageHover,
         size: point.size,
+        showName: point.showName,
         pointer: true,
         extData: point
       });
       // 设置自定义属性
-      feature.set('pointer', true);
       const img = new Image();
       img.onload = () => {
         // 图片加载完成后,可以访问其 width 和 height 属性
         const width = img.width;
-        const height = img.height;
-        const style = new Style({
-          image: new Icon({
-            anchor: [0.5, 0.5],
-            anchorXUnits: 'fraction',
-            anchorYUnits: 'pixels',
-            src: point.icon,
-            size: [width, height],
-            scale: !!point.size[0] ? point.size[0] / width : 1
-          }),
-          text: new Text({
-            text: point.name,
-            fill: new Fill({
-              color: '#000'
-            }),
-            stroke: new Stroke({
-              color: '#fff',
-              width: 3
-            })
-          })
-        });
-        features.setStyle(style);
+        const height = img.width;
+        feature.set('originalWidth', width);
+        feature.set('originalHeight', height);
+        feature.set('img', img);
+        vectorSource.addFeature(feature);
       };
       img.src = point.icon; // 设置图片的 URL,触发加载
-      features.push(feature);
       this.markers.push(point);
     });
-    const vectorSource = new VectorSource({
-      features: features
-    });
     const clusterSource = new Cluster({
       distance: 30,
       source: vectorSource
@@ -1004,7 +1078,7 @@ export class olMap {
     this.traceFeature = new Feature({
       geometry: new LineString(lineArr)
     });
-    let route = new LineString(lineArr);
+    const route = new LineString(lineArr);
     this.carLayer = new VectorLayer({
       source: source,
       style: new Style({

+ 10 - 5
src/views/globalMap/RightMenu/KeyVehicles.vue

@@ -40,12 +40,14 @@
 import { Search } from '@element-plus/icons-vue';
 import { getVehicleList, getVehicleTrajectory } from '@/api/globalMap/KeyVehicles';
 import { onMounted, reactive, inject } from 'vue';
+import { parseTime } from '@/utils/ruoyi';
 const AMapType = ['vectorgraph', 'satellite'];
-const trackPlayback = inject('trackPlayback');
+const initDataToPlay = inject('initDataToPlay');
 
 const props = defineProps({
   activeMap: String
 });
+
 // 数据列表,直接定义为数组
 const dataList = reactive([]);
 //入参
@@ -90,14 +92,17 @@ const handleCollaborate = () => {};
 //   showDetail(item, 30);
 // };
 // 轨迹
-let obj = []
+
 const handleTrack = (item) => {
   getVehicleTrajectory(item.vehicle_no).then((res) => {
     const trajectory = [];
     res.rows.forEach((item) => {
-      trajectory.push([item.lng, item.lat]);
+      trajectory.push({
+        time: !!item.gpsDate ? parseTime(item.gpsDate, '{h}:{i}') : '',
+        lnglat: [item.lng, item.lat]
+      });
     });
-    obj = trackPlayback(trajectory);
+    initDataToPlay({ type: 'track', data: trajectory });
     // handleShowDialog(trajectory);
   });
 };
@@ -114,7 +119,7 @@ onUnmounted(() => {
     const source = obj[0].getSource();
     if (source) {
       source.clear();
-    };
+    }
   }
 });
 </script>

+ 5 - 2
src/views/globalMap/RightMenu/OnlinePlotting/index.vue

@@ -377,7 +377,8 @@ const clickTab3 = (item, index) => {
     const drawTool = getDrawTool();
     if (mouseToolState.value.graphicsType === 'anyLine') {
       drawTool.setDrawEndMethod(handleEndDraw);
-    } else if (mouseToolState.value.graphicsType !== 'text') {
+    }
+    if (mouseToolState.value.graphicsType !== 'text') {
       const newOptions = drawTool.drawGraphics(mouseToolState.value);
       // 绘制完成事件
       initDrawMethod(newOptions);
@@ -610,7 +611,9 @@ const initDrawMethod = (options) => {
       // 发送
       sendWebSocket(data);
     };
-    mouseTool.on('drawend', onDraw);
+    if (!!mouseTool) {
+      mouseTool.on('drawend', onDraw);
+    }
   }
 };
 const handleEndDraw = (options, obj) => {

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

@@ -4316,9 +4316,14 @@ export const iconList = {
     size: [55, 60]
   },
   '42': {
-    image: getImageUrl('31_lakes_video.png'),
-    imageHover: getImageUrl('31_lakes_video_hover.png'),
+    image: getImageUrl('42_transportation_video.png'),
+    imageHover: getImageUrl('42_transportation_video_hover.png'),
     size: [40, 40]
+  },
+  '43': {
+    image: getImageUrl('43_vehicle.png'),
+    imageHover: getImageUrl('43_vehicle_hover.png'),
+    size: [40, 44]
   }
 };
 
@@ -4980,5 +4985,13 @@ export const pointDetailTemplate = {
     status: '状态',
     longitude: '经度',
     latitude: '纬度'
+  },
+  '43': {
+    vehicle_no: '车牌号',
+    vehicle_type: '车辆类型',
+    vehicle_color: '车牌类型',
+    vin: '车架号',
+    chelodmass: '核定吨位',
+    bnscope: '经营范围'
   }
 };

+ 59 - 27
src/views/globalMap/index.vue

@@ -34,7 +34,7 @@
       <!--更换地图类型-->
       <SwitchMapTool :active-map="activeMap" class="tool-box" @switch-map="switchMap" />
       <!--时间轴-->
-      <TimeAxis />
+      <TimeAxis ref="timeAxisRef" :activeMap="activeMap" />
       <DrawTools v-if="showDrawTools" :active-map="activeMap" @handle-analysis-data="handleAnalysisData" />
       <NearbyVideos v-if="showNearbyVideos" v-model="showNearbyVideos" :location="location" />
       <GridPointRainfall v-if="showRainfall" v-model="showRainfall" :location="location" />
@@ -71,6 +71,7 @@ let map;
 let mapRef = ref(null);
 let map2Ref = ref(null);
 let leftMenuRef = ref(null);
+let timeAxisRef = ref(null);
 let showMask = ref(true);
 //  vectorgraph satellite imageMap imageMap3 logical satellite2 satellite3
 let activeMap = ref('satellite');
@@ -89,6 +90,7 @@ const switchMap = (key) => {
 };
 let pointType = ref<PointType[]>([]);
 let markerList = ref([]);
+let addMarkersTimer;
 const addMarkers = (item) => {
   const dom = ['satellite2', 'satellite3', 'imageMap', 'imageMap2'].includes(activeMap.value) ? map2Ref.value : mapRef.value;
   if (dom) {
@@ -106,34 +108,55 @@ const addMarkers = (item) => {
       item.checked2 = true;
       pointType.value.push(item);
     }
-    let path = [];
+    const path = [];
     pointType.value.forEach((item) => {
       path.push(item.component);
     });
-    getPointInfo(path.toString()).then((res) => {
-      const data = res.data && res.data.list ? res.data?.list : [];
-      markerList.value = data;
-      data.forEach((item2) => {
-        // 获取图标
-        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;
-        }
-        if (item2.materia_name) {
-          item2.name = item2.materia_name;
-        }
-        item2.parentId = item.component;
-        item2.lnglat = [item2.longitude, item2.latitude];
-      });
-      dom.addMarker(data);
+    if (!path.includes('43') && addMarkersTimer) {
+      clearInterval(addMarkersTimer);
+      addMarkersTimer = null;
+    }
+    addMarkersMethod();
+  }
+};
+const addMarkersMethod = () => {
+  const dom = ['satellite2', 'satellite3', 'imageMap', 'imageMap2'].includes(activeMap.value) ? map2Ref.value : mapRef.value;
+  const path = [];
+  pointType.value.forEach((item) => {
+    path.push(item.component);
+  });
+  getPointInfo(path.toString()).then((res) => {
+    const data = res.data && res.data.list ? res.data?.list : [];
+    markerList.value = data;
+    data.forEach((item2) => {
+      // 获取图标
+      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;
+      }
+      if (item2.materia_name) {
+        item2.name = item2.materia_name;
+      }
+      if (item2.dataType === 43) {
+        item2.showName = true;
+      }
+      item2.lnglat = [item2.longitude, item2.latitude];
     });
+    dom?.addMarker(data);
+  });
+  if (addMarkersTimer) {
+    clearInterval(addMarkersTimer);
+    addMarkersTimer = null;
+  }
+  if (path.includes('43')) {
+    addMarkersTimer = setInterval(addMarkersMethod, 10 * 1000);
   }
 };
 // 跳转指定地点
@@ -157,7 +180,6 @@ const clickMenu = (item, dataList) => {
     let checked = item.checked ? '1' : '2';
     // 打点信息
     addMarkers(item);
-
     if (
       [
         '易涝隐患点',
@@ -171,7 +193,8 @@ const clickMenu = (item, dataList) => {
         '森林防火',
         '防灾救援',
         '救援队伍',
-        '交通局视频'
+        '交通局视频',
+        '重点车辆'
       ].includes(item.name)
     ) {
       rightMenuRef.value.updateMenu(checked, item);
@@ -364,6 +387,14 @@ const handleShowPeople = (data) => {
   teamId.value = data.id;
   showPeople.value = true;
 };
+
+// 传递数据给时间轴
+const initDataToPlay = (data) => {
+  if (!!tempMenu.value) {
+    timeAxisRef.value.initDataToPlay(data);
+  }
+};
+
 // onMounted(() => {
 //   mapRef.value.addEventListener('resize', handleResize);
 // })
@@ -384,6 +415,7 @@ provide('showDetail', showDetail);
 provide('getDrawTool', getDrawTool);
 provide('getMarkers', getMarkers);
 provide('getPlaceSearch', getPlaceSearch);
+provide('initDataToPlay', initDataToPlay);
 </script>
 
 <style lang="scss" scoped>