瀏覽代碼

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

yangyuxuan 3 月之前
父節點
當前提交
f1d47334ef

+ 2 - 4
src/api/globalMap/KeyVehicles.ts

@@ -12,12 +12,10 @@ export const getVehicleList = (data) => {
 // 轨迹信息
 export const getVehicleTrajectory = (vehicle_no) => {
   return request({
-    url: '/api/gateway/v2/get_vehicle_trajectory',
+    url: '/api/gateway/v1/get_vehicle_trajectory',
     method: 'post',
     data: {
-      query: {
-        vehicle_no: vehicle_no
-      }
+      vehicle_no: vehicle_no
     }
   });
 };

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

@@ -87,3 +87,12 @@ export function getLxHyVideoTagInfo(params) {
     params: params
   });
 }
+
+// 全域地图-视频点位信息
+export function getVideoList(params) {
+  return request({
+    url: '/api/videoResource/videoinfo/get_video_list',
+    method: 'get',
+    params: params
+  });
+}

二進制
src/assets/images/arrow.png


+ 24 - 24
src/components/Map/index.vue

@@ -183,36 +183,33 @@ const handlePointDetails = (data) => {
       titleDom.className = 'title-box';
       titleDom.innerHTML = '<div class="gradient-text">' + title + '</div></div>';
       div.appendChild(titleDom);
-      if (data.dataType === 2) {
-        let btnBox = document.createElement('div');
-        let btn = document.createElement('div');
-        btnBox.className = 'flex';
-        btn.className = 'btn';
-        btn.innerHTML = '<div class="video-icon"></div><div>物资详情</div>';
-        btn.onclick = () => {
-          emits('handleShowWarehouse', data);
-        };
-        btnBox.appendChild(btn);
-        div.appendChild(btnBox);
-      } else if (data.dataType === 4) {
-        let btnBox = document.createElement('div');
-        let btn = document.createElement('div');
-        btnBox.className = 'flex';
-        btn.className = 'btn';
-        btn.innerHTML = '<div class="video-icon"></div><div>附近视频</div>';
-        btn.onclick = () => {
-          emits('handleShowVideo', data);
+      if ([2, 4, 41, 43].includes(data.dataType)) {
+        const objs = {
+          '2': {
+            title: '物资详情',
+            method: 'handleShowWarehouse'
+          },
+          '4': {
+            title: '附近视频',
+            method: 'handleShowVideo'
+          },
+          '41': {
+            title: '人员列表',
+            method: 'handleShowPeople'
+          },
+          '43': {
+            title: '历史轨迹',
+            method: 'handleShowTrack'
+          }
         };
-        btnBox.appendChild(btn);
-        div.appendChild(btnBox);
-      } else if (data.dataType === 41) {
+        const obj = objs[data.dataType];
         let btnBox = document.createElement('div');
         let btn = document.createElement('div');
         btnBox.className = 'flex';
         btn.className = 'btn';
-        btn.innerHTML = '<div class="video-icon"></div><div>人员列表</div>';
+        btn.innerHTML = '<div class="video-icon"></div>' + obj.title + '<div></div>';
         btn.onclick = () => {
-          emits('handleShowPeople', data);
+          emits(obj.method, data);
         };
         btnBox.appendChild(btn);
         div.appendChild(btnBox);
@@ -261,6 +258,9 @@ const handlePointDetails = (data) => {
   });
 };
 const filterTd = (obj, dataType) => {
+  if (!obj) {
+    return [];
+  }
   let data = [];
   let tempData = {};
   let i = 0;

+ 293 - 57
src/components/TimeAxis/index.vue

@@ -35,7 +35,7 @@
         <div class="prevIcon" @click="toPrevTime" />
         <div class="playIcon" @click="toPlayTime" />
         <div class="nextIcon" @click="toNextTime(true)" />
-        <div class="speed-btn" @click="changeSpeed">{{ timeAxisState.speed === 1 ? 'x1' : 'x2' }}</div>
+        <div class="speed-btn" @click="changeSpeed">{{ timeAxisState.speed === 2 ? 'x1' : 'x2' }}</div>
         <div class="rankIcon" />
       </div>
     </div>
@@ -45,6 +45,15 @@
 <script lang="ts" setup name="TimeAxis">
 import { parseTime } from '@/utils/ruoyi';
 import carImg from '@/assets/images/car.png';
+import VectorSource from 'ol/source/Vector';
+import Feature from 'ol/Feature';
+import Point from 'ol/geom/Point';
+import Icon from 'ol/style/Icon';
+import Style from 'ol/style/Style';
+import { LineString } from 'ol/geom';
+import VectorLayer from 'ol/layer/Vector';
+import { Stroke } from 'ol/style';
+import arrowImg from '@/assets/images/arrow.png';
 
 const props = defineProps({
   activeMap: String
@@ -56,6 +65,7 @@ const AMapType = ['vectorgraph', 'satellite'];
 let mapUtils, map, AMap;
 // 轨迹数据
 let moveMarker, movePassedPolyline, movePolyline;
+
 let isNewMarkerPause = false;
 let trackPathArr = [];
 const timelineItems = ref([]);
@@ -69,7 +79,7 @@ const timeAxisState = reactive({
   playing: false,
   show: false,
   showDialog: false,
-  speed: 1,
+  speed: 2,
   data: []
 });
 let originalData = [];
@@ -128,34 +138,230 @@ const initDataToPlay = (obj) => {
   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"  //线样式
-      });
+      AMap = mapUtils?.getAMap();
+      trackPlayback1();
+    } else {
+      trackPlayback2();
+    }
+  }
+};
+// 高德地图轨迹
+const trackPlayback1 = () => {
+  clearObj();
+  // 绘制轨迹
+  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();
+};
+
+let carLayer, carFeature, traceFeature, traceFeature2;
+let lastTime;
+let distance = 0;
+let animationFlag = false;
+let route,
+  lastRoute = [];
+let first = 0;
+
+const trackPlayback2 = () => {
+  if (!!carLayer) {
+    clearObj();
+  } else {
+    const source = new VectorSource();
+    carLayer = new VectorLayer({
+      source: source
+    });
+    map.addLayer(carLayer);
+  }
 
-      movePassedPolyline = new AMap.Polyline({
-        map: map,
-        strokeColor: '#AF5', //线颜色
-        strokeWeight: 6 //线宽
-      });
-      startPlay();
+  const angle = getAngle(trackPathArr[0], trackPathArr[1]);
+  lastTime = Date.now();
+  carFeature = new Feature({
+    geometry: new Point(trackPathArr[0]),
+    zIndex: 999
+  });
+  const icon = new Icon({
+    crossOrigin: 'anonymous',
+    src: carImg,
+    width: 13,
+    height: 26,
+    anchor: [0.5, 0.5],
+    rotation: angle
+  });
+  carFeature.setStyle(
+    new Style({
+      image: icon
+    })
+  );
+  route = new Feature({
+    geometry: new LineString(trackPathArr[0])
+  });
+  traceFeature = new Feature({
+    geometry: new LineString(trackPathArr),
+    zIndex: 8
+  });
+  traceFeature.setStyle(arrowStyleFunction);
+  traceFeature2 = new Feature({
+    geometry: new LineString(trackPathArr[0]),
+    zIndex: 9
+  });
+  lastRoute = [trackPathArr[0]];
+  traceFeature2.setStyle(
+    new Style({
+      stroke: new Stroke({
+        color: '#AF5',
+        width: 6
+      })
+    })
+  );
+  carLayer.getSource().addFeatures([carFeature, traceFeature, traceFeature2]);
+  carLayer.on('postrender', move);
+  timeAxisState.activeIndex = 0;
+  timeAxisState.playing = true;
+  // 触发地图渲染
+  const geo = carFeature.getGeometry().clone();
+  carFeature.setGeometry(geo);
+};
+const move = (e) => {
+  if (!timeAxisState.playing) return;
+  const time = e.frameState.time;
+  // 时间戳差(毫秒)
+  const elapsedTime = time - lastTime;
+  // 距离(其实是比例的概念)
+  distance = distance + ((timeAxisState.speed === 2 ? 1 : 2) * 200 * elapsedTime) / 1e6;
+  if (distance >= 1) {
+    if (timeAxisState.activeIndex < trackPathArr.length - 1) {
+      // 一段走完后
+      lastRoute.push(traceFeature2.getGeometry().getCoordinates());
+      console.log(lastRoute);
+      timeAxisState.activeIndex += 1;
+      distance = 0;
+    } else if (first === 0) {
+      // 所有走完后有时会0.9->1.2导致路没走完
+      first = 1;
+      distance = 1;
+    } else {
+      first = 0;
+      distance = 0;
+      animationFlag = false;
+      stopAnimation();
+      return;
     }
   }
+  const arr = trackPathArr.slice(timeAxisState.activeIndex, timeAxisState.activeIndex + 2);
+  route = new Feature({
+    geometry: new LineString(arr)
+  });
+  // 保存当前时间
+  lastTime = time;
+  // 上次坐标
+  const lastCoord = carFeature.getGeometry().getCoordinates();
+  // 获取新位置的坐标点
+  let curCoord = route.getGeometry().getCoordinateAt(distance);
+  if (isNaNCoord(curCoord)) {
+    curCoord = trackPathArr[0];
+  }
+  // 设置新坐标
+  carFeature.getGeometry().setCoordinates(curCoord);
+  // 获取当前轨迹坐标数组
+  const currentCoords = traceFeature2.getGeometry().getCoordinates();
+  currentCoords.push(curCoord);
+  traceFeature2.getGeometry().setCoordinates(currentCoords);
+  map.getView().setCenter(curCoord);
+  // 设置角度
+  carFeature.getStyle().getImage().setRotation(getAngle(lastCoord, curCoord));
+  // 调用地图渲染
+  map.render();
+};
+const isNaNCoord = (coord) => {
+  return JSON.stringify(coord) === '[null,null]'; // NaN 在 JSON.stringify 中会被转换为 null
+};
+const stopAnimation = () => {
+  if (carLayer) {
+    carLayer.un('postrender', move);
+  }
+};
+const getAngle = (point1, point2) => {
+  // 处理无效输入或非数组情况
+  if (!point1 || !point2 || !point1.length || !point2.length) {
+    return 0;
+  }
+
+  const dx = point2[0] - point1[0];
+  const dy = point2[1] - point1[1];
+
+  // 处理两点相同的情况
+  if (dx === 0 && dy === 0) {
+    return 0;
+  }
+
+  // 使用 Math.atan2 计算角度,并确保结果在 0 到 2π 之间
+  let angle = Math.atan2(dx, dy);
+  if (angle < 0) {
+    angle += 2 * Math.PI;
+  }
+
+  return angle;
+};
+// 箭头样式生成函数
+const arrowStyleFunction = (feature, resolution) => {
+  const geometry = feature.getGeometry();
+  const styles = [
+    // 基础线样式
+    new Style({
+      stroke: new Stroke({
+        color: '#2196F3',
+        width: 6
+      })
+    })
+  ];
+
+  // 计算箭头间隔(每50像素一个箭头)
+  const length = geometry.getLength();
+  const pixelInterval = 50;
+  const geoInterval = pixelInterval * resolution;
+  const arrowCount = Math.floor(length / geoInterval);
+
+  // 生成箭头样式
+  for (let i = 0; i <= arrowCount; i++) {
+    const ratio = i / arrowCount;
+    const coord = geometry.getCoordinateAt(ratio);
+
+    // 获取线段方向
+    const prevCoord = geometry.getCoordinateAt(Math.max(0, ratio - 0.001));
+    const dx = coord[0] - prevCoord[0];
+    const dy = coord[1] - prevCoord[1];
+    const rotation = Math.atan2(dy, dx);
+
+    // styles.push(
+    //   new Style({
+    //     geometry: new Point(coord),
+    //     image: new Icon({
+    //       src: arrowImg, // 替换为实际箭头图标路径
+    //       anchor: [0.75, 0.5], // 图标锚点
+    //       rotateWithView: true, // 随地图旋转
+    //       rotation: -rotation, // 方向校准
+    //       scale: 0.05
+    //     }),
+    //     zIndex: 10
+    //   })
+    // );
+  }
+  return styles;
 };
 // 创建新标点 moveTo调用第二次不生效,重新生成marker
 const createMarker = () => {
@@ -214,6 +420,13 @@ const playOrPauseTrack = () => {
       moveMarker.pauseMove();
     }
     isNewMarkerPause = false;
+  } else {
+    if (!!timeAxisState.playing) {
+      lastTime = Date.now();
+      // 触发地图渲染
+      const geo = carFeature.getGeometry().clone();
+      carFeature.setGeometry(geo);
+    }
   }
 };
 // 轨迹开始播放
@@ -229,19 +442,41 @@ const prevPauseTime = () => {
   // 更新索引
   timeAxisState.playing = false;
   timeAxisState.activeIndex -= 1;
-  moveMarker.stopMove();
-  createMarker();
-  movePassedPolyline.setPath(trackPathArr.slice(0, timeAxisState.activeIndex + 1));
-  isNewMarkerPause = true;
+  if (AMapType.includes(props.activeMap)) {
+    moveMarker.stopMove();
+    createMarker();
+    movePassedPolyline.setPath(trackPathArr.slice(0, timeAxisState.activeIndex + 1));
+    isNewMarkerPause = true;
+  } else {
+    // 设置新坐标
+    const curCoord = trackPathArr[timeAxisState.activeIndex];
+    carFeature.getGeometry().setCoordinates(curCoord);
+    // 获取当前轨迹坐标数组
+    const currentCoords = lastRoute[timeAxisState.activeIndex];
+    lastRoute = lastRoute.slice(0, timeAxisState.activeIndex + 1);
+    traceFeature2.getGeometry().setCoordinates(currentCoords);
+    map.getView().setCenter(curCoord);
+  }
 };
 const nextPauseTime = () => {
   if (timeAxisState.activeIndex <= 0) return;
   // 更新索引
   timeAxisState.playing = false;
   timeAxisState.activeIndex += 1;
-  createMarker();
-  movePassedPolyline.setPath(trackPathArr.slice(0, timeAxisState.activeIndex + 1));
-  isNewMarkerPause = true;
+  if (AMapType.includes(props.activeMap)) {
+    createMarker();
+    movePassedPolyline.setPath(trackPathArr.slice(0, timeAxisState.activeIndex + 1));
+    isNewMarkerPause = true;
+  } else {
+    // 设置新坐标
+    const curCoord = trackPathArr[timeAxisState.activeIndex];
+    carFeature.getGeometry().setCoordinates(curCoord);
+    // 获取当前轨迹坐标数组
+    const currentCoords = lastRoute[lastRoute.length - 1].concat([curCoord]);
+    lastRoute.push(currentCoords);
+    traceFeature2.getGeometry().setCoordinates(currentCoords);
+    map.getView().setCenter(curCoord);
+  }
 };
 // 轨迹播放下一个节点
 const playNextNode = () => {
@@ -257,28 +492,6 @@ const playNextNode = () => {
     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;
-};
 // 滚动到可见到当前点位置
 watch(
   () => timeAxisState.activeIndex,
@@ -287,7 +500,6 @@ watch(
       const itemRef = timelineItems.value[index];
       if (itemRef) {
         const itemEl = itemRef.$el;
-        console.log(itemEl);
         itemEl.scrollIntoView({
           behavior: 'smooth'
         });
@@ -295,11 +507,35 @@ watch(
     });
   }
 );
-
+// 清除元素
+const clearObj = () => {
+  if (AMapType.includes(props.activeMap)) {
+    if (moveMarker) {
+      // 不停止remove还是有
+      moveMarker.stopMove();
+      moveMarker.remove();
+    }
+    movePolyline?.remove();
+    movePassedPolyline?.remove();
+  } else {
+    if (!!carFeature) {
+      carLayer.getSource().removeFeature(carFeature);
+    }
+    if (!!traceFeature) {
+      carLayer.getSource().removeFeature(traceFeature);
+    }
+    if (!!traceFeature2) {
+      carLayer.getSource().removeFeature(traceFeature2);
+    }
+  }
+};
 onMounted(() => {
   getInitTime();
 });
 
+onUnmounted(() => {
+  clearObj();
+});
 defineExpose({ initDataToPlay });
 </script>
 

+ 1 - 1
src/directive/common/drag.ts

@@ -8,7 +8,7 @@ export default {
       return;
     }
     let scaleMethod = scale;
-    if (dragHandle) {
+    if (!scaleMethod) {
       scaleMethod = () => {
         return { scaleX: 1, scaleY: 1 };
       };

+ 20 - 0
src/store/modules/map.ts

@@ -0,0 +1,20 @@
+export const useMapStore = defineStore('map', () => {
+  const map = ref(null);
+  const mapUtils = ref();
+
+  const trackState = reactive({
+    show: false,
+    data: []
+  });
+  // 轨迹
+  const setTrackState = (data: any) => {
+    trackState.data = data;
+    trackState.show = true;
+  };
+  return {
+    trackState,
+    setTrackState
+  };
+});
+
+export default useMapStore;

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

@@ -44,6 +44,8 @@ declare module 'vue' {
     ElRow: typeof import('element-plus/es')['ElRow']
     ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
     ElSelect: typeof import('element-plus/es')['ElSelect']
+    ElSkeleton: typeof import('element-plus/es')['ElSkeleton']
+    ElSkeletonItem: typeof import('element-plus/es')['ElSkeletonItem']
     ElSlider: typeof import('element-plus/es')['ElSlider']
     ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
     ElSwitch: typeof import('element-plus/es')['ElSwitch']
@@ -99,6 +101,7 @@ declare module 'vue' {
     VideoContainer2: typeof import('./../components/HKVideo/video-container2.vue')['default']
     VideoTagEdit: typeof import('./../components/VideoTagEdit/index.vue')['default']
     YMap: typeof import('./../components/Map/YMap.vue')['default']
+    YMapold: typeof import('./../components/Map/YMapold.vue')['default']
     YztMap: typeof import('./../components/Map/YztMap/index.vue')['default']
   }
   export interface ComponentCustomProperties {

+ 24 - 69
src/views/emergencyCommandMap/LeftSection/Communication.vue

@@ -97,27 +97,13 @@
         </div>
       </div>
     </div>
-    
-    <Drone v-show="activeIndex === 1"></Drone>
-    
-    <IndividualEquipment v-show="activeIndex === 2"></IndividualEquipment>
 
-    <Dialog v-if="showOpenMeeting" custom-show type="xs" height="660px" title="发起会议" @confirm="handleStartMeeting" @close="closeOpenDialog">
-      <el-form ref="form2Ref" :model="openMeetingForm" :rules="rules2">
-        
-        <el-form-item label="账号" label-width="200px" prop="username">
-          <el-input v-model="openMeetingForm.username" class="custom-input2" clearable placeholder="请输入设备账号" />
-        </el-form-item>
+    <Drone v-show="activeIndex === 1"></Drone>
 
-        <el-form-item label="密码" label-width="200px" prop="userpass">
-          <el-input v-model="openMeetingForm.userpass" type="password" class="custom-input2" clearable placeholder="请输入设备密码" />
-        </el-form-item>
-      </el-form>
-    </Dialog>
+    <IndividualEquipment v-show="activeIndex === 2"></IndividualEquipment>
 
     <Dialog v-if="showJoinMeeting" custom-show type="xs" height="760px" title="加入会议" @confirm="handleJoinMeeting" @close="closeDialog">
       <el-form ref="formRef" :model="meetingForm" :rules="rules">
-        
         <el-form-item label="会议号" label-width="200px" prop="roomcode">
           <el-input v-model="meetingForm.roomcode" class="custom-input2" clearable placeholder="请输入会议号" />
         </el-form-item>
@@ -132,9 +118,17 @@
       </el-form>
     </Dialog>
 
-    <Dialog v-if="showOpenMeeting" custom-show type="xs" height="660px" title="电话呼叫" @confirm="handleStartCall" @close="closeOpenDialog">
+    <Dialog
+      v-if="showOpenMeeting"
+      custom-show
+      type="xs"
+      height="660px"
+      :title="type === '0' ? '发起会议' : '电话呼叫'"
+      @confirm="handleStartCall"
+      @close="closeOpenDialog"
+    >
       <el-form ref="form2Ref" :model="openMeetingForm" :rules="rules2">
-        
+
         <el-form-item label="账号" label-width="200px" prop="username">
           <el-input v-model="openMeetingForm.username" class="custom-input2" clearable placeholder="请输入设备账号" />
         </el-form-item>
@@ -144,7 +138,6 @@
         </el-form-item>
       </el-form>
     </Dialog>
-
   </div>
 </template>
 
@@ -269,9 +262,11 @@ const rules = reactive({
   username: [{ required: true, message: '会议账号不能为空', trigger: 'blur' }],
   userpass: [{ required: true, message: '会议密码不能为空', trigger: 'blur' }]
 });
-
+// 0 会议 1 电话
+let type = ref('0');
 // 点击会议号入会
 const showJoinMeetingDialog = () => {
+  type.value = '0';
   showJoinMeeting.value = true;
 };
 const closeDialog = () => {
@@ -290,6 +285,7 @@ const rules2 = reactive({
   userpass: [{ required: true, message: '会议密码不能为空', trigger: 'blur' }]
 });
 const handleOpenMeeting = () => {
+  type.value = '1';
   showOpenMeeting.value = true;
 };
 const closeOpenDialog = () => {
@@ -320,8 +316,8 @@ const handleJoinMeeting = () => {
         a.click();
 
         // 保存账号和密码
-        localStorage.setItem('meeting_username', meetingForm.username)
-        localStorage.setItem('meeting_userpass', meetingForm.userpass)
+        localStorage.setItem('meeting_username', meetingForm.username);
+        localStorage.setItem('meeting_userpass', meetingForm.userpass);
       });
       closeDialog();
     }
@@ -335,7 +331,7 @@ const handleStartCall = () => {
       let dev_list = [];
       userList.value.forEach((item) => {
         if (item.checked && item.mobile != '') {
-          dev_list.push({ id: item.mobile, avtype: 'a' }); // a 音频 v 视频 默认 av
+          dev_list.push({ id: item.mobile, avtype: type.value === '0' ? 'av' : 'a' }); // a 音频 v 视频 默认 av
         }
       });
       if (dev_list.length == 0) {
@@ -362,58 +358,17 @@ const handleStartCall = () => {
         a.click();
 
         // 保存账号和密码
-        localStorage.setItem('meeting_username', openMeetingForm.username)
-        localStorage.setItem('meeting_userpass', openMeetingForm.userpass)
+        localStorage.setItem('meeting_username', openMeetingForm.username);
+        localStorage.setItem('meeting_userpass', openMeetingForm.userpass);
       });
       closeOpenDialog();
     }
-  })
+  });
 };
 
-// 发起会议
-const handleStartMeeting = () => {
-  form2Ref.value?.validate((valid) => {
-    if (valid) {
-      let dev_list = [];
-      userList.value.forEach((item) => {
-        if (item.checked && item.mobile != '') {
-          dev_list.push({ id: item.mobile, avtype: 'av' }); // a 音频 v 视频 默认 av
-        }
-      });
-      if (dev_list.length == 0) {
-        proxy?.$modal.msgError('请勾选人员');
-        return false;
-      }
-      const screenWidth = window.screen.width * window.devicePixelRatio;
-      const screenHeight = window.screen.height * window.devicePixelRatio;
-      const data = {
-        'userid': openMeetingForm.username, // 空表示后台获取当前用户对应融合通信dev_id
-        'password': openMeetingForm.userpass,
-        windowpos: { 'x': 0, 'y': 0, 'width': screenWidth, 'height': screenHeight, 'top': true },
-        members: {
-          num: dev_list.length + 2, // 配置多少个座位,一般就是邀请人多少个就多少个
-          'dev-list': dev_list
-        }
-      };
-      getStartMiniParam(data).then((res) => {
-        // 创建一个a标签元素
-        const a = document.createElement('a');
-        // 设置a标签的href属性
-        a.href = res.data;
-        // 触发点击事件
-        a.click();
-        
-        // 保存账号和密码
-        localStorage.setItem('meeting_username', openMeetingForm.username)
-        localStorage.setItem('meeting_userpass', openMeetingForm.userpass)
-      });
-      closeOpenDialog();
-    }
-  })
-};
 onMounted(() => {
-  const meeting_username = localStorage.getItem('meeting_username') || "";
-  const meeting_userpass = localStorage.getItem('meeting_userpass') || "";
+  const meeting_username = localStorage.getItem('meeting_username') || '';
+  const meeting_userpass = localStorage.getItem('meeting_userpass') || '';
   meetingForm.username = meeting_username;
   meetingForm.userpass = meeting_userpass;
   openMeetingForm.username = meeting_username;

+ 33 - 21
src/views/emergencyCommandMap/LeftSection/VideoMonitorEdit.vue

@@ -1,5 +1,5 @@
 <template>
-  <Dialog customShow type="xl" title="视频监控" class="dialog" hide-footer @close="reset">
+  <Dialog custom-show type="xl" title="视频监控" class="dialog" hide-footer draggable @close="reset">
     <div class="search-box">
       <div class="box-left">
         <el-form ref="queryFormRef" :model="queryParams" :inline="true" label-width="180px" label-position="left">
@@ -13,7 +13,6 @@
               popper-class="custom-select-popper"
               :teleported="false"
               placeholder="全部"
-              @change="handleQuery"
               style="width: 450px"
             >
               <el-option label="全部" value="" />
@@ -75,9 +74,10 @@
 </template>
 
 <script lang="ts" setup>
-import { getEmergencyVideoCata, getUserVideoPoints, updateUserVideoPoints } from '@/api/videoMonitor';
+import { getEmergencyVideoCata, getUserVideoPoints, getVideoList, updateUserVideoPoints } from '@/api/videoMonitor';
 import { deepClone } from '@/utils';
 import useAppStore from '@/store/modules/app';
+import useMapStore from '@/store/modules/map';
 interface LngLat {
   longitude: number;
   latitude: number;
@@ -93,6 +93,7 @@ const props = defineProps({
     type: Object as () => LngLat
   }
 });
+const mapStore = useMapStore();
 const emits = defineEmits(['update:modelValue']);
 const proxy = getCurrentInstance()?.proxy;
 const { video_type } = toRefs<any>(proxy?.useDict('video_type'));
@@ -108,7 +109,6 @@ const queryParams = reactive({
 let total = ref(0);
 let editVideo = ref(false);
 // 选中的视频
-let selectData = ref([]);
 let editData = ref([]);
 let dialogListData = ref([]);
 let showTip = ref(false);
@@ -124,11 +124,7 @@ watch(
   },
   { immediate: true }
 );
-
-const getList = async () => {
-  await getUserVideoPoints().then((res) => {
-    selectData.value = res.data.videoInfos;
-  });
+const getList = () => {
   let newParams = {
     latitude: props.lngLat.latitude,
     longitude: props.lngLat.longitude,
@@ -142,16 +138,16 @@ const getList = async () => {
     newParams.query.dict_value = queryParams.dict_value;
   }
   getEmergencyVideoCata(newParams).then((res) => {
-    selectData.value.forEach((item) => {
-      for (let i = 0; i < res.rows.length; i++) {
-        if (item.video_code_int === res.rows[i].video_code) {
-          res.rows[i].sort = true;
-          break;
-        }
-      }
-    });
     dialogListData.value = res.rows;
     total.value = res.total;
+    if (editVideo.value && editData.value) {
+      filterData(editData.value);
+    }
+  });
+};
+const getVideoInfoList = () => {
+  getVideoList(queryParams).then((res) => {
+    mapStore.setTrackState(res.data);
   });
 };
 const selectItem = (item) => {
@@ -181,6 +177,7 @@ const reset = () => {
 const handleQuery = () => {
   queryParams.current = 1;
   getList();
+  // getVideoInfoList();
 };
 
 /** 重置按钮操作 */
@@ -188,11 +185,23 @@ const resetQuery = () => {
   queryFormRef.value?.resetFields();
   handleQuery();
 };
-
 // 开启编辑视频
 const activeEdit = () => {
-  editData.value = deepClone(selectData.value);
-  editVideo.value = true;
+  getUserVideoPoints().then((res) => {
+    filterData(res.data.videoInfos);
+    editData.value = deepClone(res.data.videoInfos);
+    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 = () => {
@@ -210,7 +219,10 @@ const handleSave = () => {
   });
 };
 
-getList();
+onMounted(() => {
+  getList();
+  // getVideoInfoList();
+});
 </script>
 
 <style lang="scss" scoped>

+ 1 - 2
src/views/globalMap/RightMenu/KeyVehicles.vue

@@ -101,14 +101,13 @@ const handleCollaborate = () => {};
 const handleTrack = (item) => {
   getVehicleTrajectory(item.vehicle_no).then((res) => {
     const trajectory = [];
-    res.rows.forEach((item) => {
+    res.data.list.forEach((item) => {
       trajectory.push({
         time: !!item.gpsDate ? parseTime(item.gpsDate, '{h}:{i}') : '',
         lnglat: [item.lng, item.lat]
       });
     });
     initDataToPlay({ type: 'track', data: trajectory });
-    // handleShowDialog(trajectory);
   });
 };
 //调用函数

+ 0 - 2
src/views/globalMap/RightMenu/TyphoonVideo.vue

@@ -125,7 +125,6 @@ const initDataByTyphoon = async () => {
   }
 };
 
-
 const fetchData = async (apiFunction, params) => {
   try {
     const response = await apiFunction(params);
@@ -168,7 +167,6 @@ const initData = async () => {
     console.error('Error initializing data:', error);
   }
 };
-
 </script>
 
 <style lang="scss" scoped>

+ 65 - 25
src/views/globalMap/index.vue

@@ -11,6 +11,7 @@
         @handle-show-video="handleShowVideo"
         @handle-show-warehouse="handleShowWarehouse"
         @handle-show-people="handleShowPeople"
+        @handle-show-track="handleShowTrack"
       />
       <Map
         v-else
@@ -21,6 +22,7 @@
         @handle-show-video="handleShowVideo"
         @handle-show-warehouse="handleShowWarehouse"
         @handle-show-people="handleShowPeople"
+        @handle-show-track="handleShowTrack"
       />
       <!--左侧菜单-->
       <LeftMenu
@@ -62,11 +64,15 @@ import DrawTools from '@/views/globalMap/RightMenu/DrawTools.vue';
 import CommunicationSupport from '@/views/globalMap/RightMenu/CommunicationSupport.vue';
 import GridPointRainfall from '@/views/globalMap/RightMenu/GridPointRainfall.vue';
 import EmergencyCrew from '@/views/globalMap/RightMenu/EmergencyCrew.vue';
+import { getVehicleTrajectory } from '@/api/globalMap/KeyVehicles';
+import { parseTime } from '@/utils/ruoyi';
+import useMapStore from '@/store/modules/map';
 
 const AMapType = ['vectorgraph', 'satellite'];
 const YMapType = ['satellite2', 'satellite3', 'imageMap', 'imageMap2'];
 const rightMenuRef = ref(null);
 const mapData = reactive(logicalData);
+const mapStore = useMapStore();
 let map;
 let mapRef = ref(null);
 let map2Ref = ref(null);
@@ -119,36 +125,40 @@ const addMarkers = (item) => {
     addMarkersMethod();
   }
 };
+const adjustPoint = (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];
+  });
+  return data;
+};
+
 const addMarkersMethod = () => {
-  const dom = ['satellite2', 'satellite3', 'imageMap', 'imageMap2'].includes(activeMap.value) ? map2Ref.value : mapRef.value;
+  const dom = YMapType.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];
-    });
+    markerList.value = adjustPoint(data);
     dom?.addMarker(data);
   });
   if (addMarkersTimer) {
@@ -156,7 +166,7 @@ const addMarkersMethod = () => {
     addMarkersTimer = null;
   }
   if (path.includes('43')) {
-    addMarkersTimer = setInterval(addMarkersMethod, 10 * 1000);
+    addMarkersTimer = setInterval(addMarkersMethod, 60 * 1000);
   }
 };
 // 跳转指定地点
@@ -388,9 +398,35 @@ const handleShowPeople = (data) => {
   showPeople.value = true;
 };
 
+watch(
+  () => mapStore.trackState.show,
+  (show) => {
+    if (!!show) {
+      const dom = YMapType.includes(activeMap.value) ? map2Ref.value : mapRef.value;
+      dom?.addMarker(adjustPoint(mapStore.trackState.data));
+      mapStore.trackState.data = [];
+      mapStore.trackState.show = false;
+    }
+  }
+);
+const handleShowTrack = (data) => {
+  getVehicleTrajectory(data.id).then((res) => {
+    const trajectory = [];
+    if (res.data && res.data.list) {
+      res.data.list.forEach((item) => {
+        trajectory.push({
+          time: !!item.gpsDate ? parseTime(item.gpsDate, '{h}:{i}') : '',
+          lnglat: [item.lng, item.lat]
+        });
+      });
+      // console.log(data, res.data.list);
+      initDataToPlay({ type: 'track', data: trajectory });
+    }
+  });
+};
 // 传递数据给时间轴
 const initDataToPlay = (data) => {
-  if (!!tempMenu.value) {
+  if (!!timeAxisRef.value) {
     timeAxisRef.value.initDataToPlay(data);
   }
 };
@@ -406,6 +442,10 @@ onBeforeUnmount(() => {
       map.un('click', handleClickMap);
     }
   }
+  if (!!addMarkersTimer) {
+    clearInterval(addMarkersTimer);
+    addMarkersTimer = null;
+  }
 });
 
 provide('getMapUtils', getMapUtils);