浏览代码

feat: 首页故障报警模块点击查看按钮跳转到地图上对应的点位,以临时mock坐标为例子,等有真实接口数据后替换mock数据

sequoia tungfang 1 月之前
父节点
当前提交
93862777f7
共有 2 个文件被更改,包括 60 次插入97 次删除
  1. 48 92
      src/components/TongzhouTrafficMap.vue
  2. 12 5
      src/views/Home.vue

+ 48 - 92
src/components/TongzhouTrafficMap.vue

@@ -56,7 +56,7 @@ export default {
         { name: "特殊控制", start: [116.6820, 39.9215], end: [116.6825, 39.8815], color: "#A26218" }, // 临河里路
         { name: "离线", start: [116.6415, 39.9235], end: [116.6850, 39.9240], color: "#7A7A7A" }, // 北关大街-潞苑
         { name: "降级", start: [116.6365, 39.8850], end: [116.6800, 39.8860], color: "#D9C13B" }, // 万盛南街段
-        { name: "故障", start: [116.6950, 39.9150], end: [116.6955, 39.8850], color: "#FF3938" }  // 潞通大街
+        { name: "故障", start: [116.6950, 39.9150], end: [116.6955, 39.885], color: "#FF3938" }  // 潞通大街
       ]
     };
   },
@@ -123,21 +123,6 @@ export default {
               path = [config.start, config.end];
             }
 
-            // --- 【关键修改】:注释掉以下 Polyline 的定义 ---
-            /*
-            const polyline = new AMap.Polyline({
-              path: path,
-              strokeColor: config.color,
-              strokeWeight: 8,
-              strokeOpacity: 0.8,
-              showDir: false,
-              lineJoin: 'round',
-              zIndex: 15,
-              map: null
-            });
-            */
-
-            // 1. 只有“干线协调”和“勤务路线”才创建路线对象
             let polyline = null;
             const needRouteLine = ["干线协调", "勤务路线"].includes(config.name);
 
@@ -154,24 +139,29 @@ export default {
               });
             }
 
-
-            // 2. 在路径上分布点 (保持原样)
-            // 修改 points 的采样逻辑,例如每隔 10 个坐标点取一个点
             const points = [];
             const step = 10; // 步长越大,点越稀疏
             for (let i = 0; i < path.length; i += step) {
               points.push(path[i]);
             }
+
             // 确保终点也被加上
             if ((path.length - 1) % step !== 0) {
               points.push(path[path.length - 1]);
             }
 
-            // const points = path.length > 2
-            //   ? [path[0], path[Math.floor(path.length / 2)], path[path.length - 1]]
-            //   : [path[0], path[1]];
+            // 临时逻辑,有真实接口后可以删除
+            points.forEach((pos, idx) => {
+              if (index === 8 && idx === 0) {
+                localStorage.setItem('pos1', pos);
+              }
+              if (index === 9 && idx === 0) {
+                localStorage.setItem('pos2', pos);
+              }
+              if (index === 10 && idx === 0) {
+                localStorage.setItem('pos3', pos);
+              }
 
-            points.forEach(pos => {
               markers.push(this.createTrafficLightMarker(pos, config));
             });
 
@@ -179,12 +169,6 @@ export default {
             const overlays = [...markers, polyline].filter(Boolean);
             this.routeGroups[config.name] = overlays;
 
-            // if (this.activeLegends.includes(config.name)) {
-            //   this.map.add(overlays);
-            //   // 这里的 setFitView 会根据点的位置自动聚焦
-            //   this.map.setFitView(overlays, false, [60, 60, 60, 60]);
-            // }
-
             if (this.activeLegends.includes(config.name)) {
               this.map.add(overlays);
             }
@@ -212,6 +196,7 @@ export default {
         offset: new this.AMap.Pixel(-10, -10),
         extData: {
           ...config,
+          position: [lng, lat],
           statusColor: config.color, // 统一弹窗小圆点颜色
           statusLabel: displayStatus, // 统一弹窗状态文字
           road: '北京路与南京路',
@@ -223,35 +208,7 @@ export default {
       return marker;
     },
 
-    // openLightInfo(data, position) {
-    //   const content = `
-    //     <div class="traffic-window">
-    //       <div class="window-header" style="background: ${data.lightDetail.color}">
-    //         <span class="title">路口信号机: ${data.name}</span>
-    //       </div>
-    //       <div class="window-body">
-    //         <div class="data-row"><span class="label">设备序列:</span><span>${data.lightDetail.sn}</span></div>
-    //         <div class="data-row">
-    //           <span class="label">当前相位:</span>
-    //           <span style="color: ${data.lightDetail.color}; font-weight:bold">${data.lightDetail.status}</span>
-    //         </div>
-    //         <div class="data-row"><span class="label">相位余时:</span><span class="highlight">${data.lightDetail.timeLeft}s</span></div>
-    //         <div class="data-row"><span class="label">运行模式:</span><span>智能感应</span></div>
-    //         <div class="progress-container">
-    //            <div class="progress-bar" style="width: ${(data.lightDetail.timeLeft / 60) * 100}%; background: ${data.lightDetail.color}"></div>
-    //         </div>
-    //       </div>
-    //     </div>
-    //   `;
-
-    //   if (!this.infoWindow) {
-    //     this.infoWindow = new this.AMap.InfoWindow({ isCustom: true, offset: new this.AMap.Pixel(0, -20) });
-    //   }
-    //   this.infoWindow.setContent(content);
-    //   this.infoWindow.open(this.map, position);
-    // },
     openLightInfo(data, position) {
-      // 在 openLightInfo 内部
       const content = `
         <div class="custom-info-card">
           <div class="close-btn" onclick="window.closeMapInfoWindow()">✕</div>
@@ -290,20 +247,6 @@ export default {
       this.infoWindow.open(this.map, position);
     },
 
-    // 全选/全不选逻辑
-    // toggleAll() {
-    //   if (this.isAllSelected) {
-    //     // 如果当前是全选,则清空激活列表,并隐藏地图上所有组
-    //     this.activeLegends = [];
-    //     Object.values(this.routeGroups).forEach(group => group && group.hide());
-    //     if (this.infoWindow) this.infoWindow.close();
-    //   } else {
-    //     // 如果当前不是全选,则填充所有图例名称,并显示地图上所有组
-    //     this.activeLegends = this.legendConfig.map(item => item.name);
-    //     Object.values(this.routeGroups).forEach(group => group && group.show());
-    //   }
-    // },
-
     // 全选/全不选逻辑修正版
     toggleAll() {
       const targetState = !this.isAllSelected; // 获取点击后的目标状态(true为全选,false为全不选)
@@ -338,20 +281,6 @@ export default {
       }
     },
 
-    // 保留你原有的单个切换方法,但确保逻辑一致
-    // toggleRouteVisible(name) {
-    //   const group = this.routeGroups[name];
-    //   const index = this.activeLegends.indexOf(name);
-    //   if (index > -1) {
-    //     this.activeLegends.splice(index, 1);
-    //     group && group.hide();
-    //     this.infoWindow && this.infoWindow.close();
-    //   } else {
-    //     this.activeLegends.push(name);
-    //     group && group.show();
-    //   }
-    // },
-
     toggleRouteVisible(name) {
       const overlays = this.routeGroups[name] || []; // 获取的是数组
       const index = this.activeLegends.indexOf(name);
@@ -363,6 +292,37 @@ export default {
         this.activeLegends.push(name);
         this.map.add(overlays); // 改用 add
       }
+    },
+
+    // 其他组件点击定位到地图指定的点
+    focusByLocation(targetPos) {
+      if (!targetPos || targetPos.length !== 2) return;
+
+      let foundMarker = null;
+
+      // 1. 遍历所有路线组
+      Object.values(this.routeGroups).forEach(group => {
+        // 2. 在组内寻找 Marker
+        const marker = group.find(item => {
+          if (!(item instanceof this.AMap.Marker)) return false;
+          const pos = item.getExtData().position;
+          // 3. 坐标比对(考虑到浮点数精度,建议使用 AMap 自带的几何工具或简单比对)
+          return pos[0] === targetPos[0] && pos[1] === targetPos[1];
+        });
+        if (marker) foundMarker = marker;
+      });
+
+      if (foundMarker) {
+        // 4. 定位并打开弹窗
+        const finalPos = foundMarker.getPosition();
+        this.map.setZoomAndCenter(17, finalPos, false, 500); // 17级视角,平滑移动
+
+        setTimeout(() => {
+          this.openLightInfo(foundMarker.getExtData(), finalPos);
+        }, 600);
+      } else {
+        console.warn("未在地图上找到该坐标对应的点位:", targetPos);
+      }
     }
   }
 };
@@ -396,9 +356,6 @@ export default {
 }
 
 ::v-deep .pure-light-node span {
-  display: inline-block;
-  width: 16px;
-  height: 16px;
   display: flex;
   transform: scale(0.75);
   align-items: center;
@@ -478,10 +435,9 @@ export default {
   justify-content: center;
   align-items: center;
   margin-right: 8px;
-  font-size: 11px;
-  color: #000;
-  /* 图标内文字为黑色 */
-  font-weight: bold;
+  font-size: 12px;
+  padding: 16px;
+  box-sizing: border-box;
 }
 
 ::v-deep .status-dot span {

+ 12 - 5
src/views/Home.vue

@@ -12,6 +12,7 @@
     <!-- 地图 -->
     <template #map>
         <TongzhouTrafficMap
+          ref="trafficMapRef"
           amapKey="db2da7e3e248c3b2077d53fc809be63f"
           securityJsCode="a7413c674852c5eaf01d90813c5b7ef6"
         />
@@ -152,21 +153,24 @@ export default {
           title: '通讯中断',
           type: 'error', // 渲染为红色
           time: '16:28:28',
-          description: '中关村大街-科学院南路口-设备离线'
+          description: '中关村大街-科学院南路口-设备离线',
+          position: [116.695702, 39.892886]
         },
         {
           id: '2',
           title: '2.降级黄闪',
           type: 'warning', // 渲染为黄色
           time: '16:28:28', // 
-          description: '中关村大街-科学院南路口-设备离线'
+          description: '中关村大街-科学院南路口-设备离线',
+          position: [116.6365, 39.8850]
         },
         {
           id: '3',
           title: '3.降级黄闪',
           type: 'warning',
           time: '16:28:28',
-          description: '中关村大街-科学院南路口-设备离线'
+          description: '中关村大街-科学院南路口-设备离线',
+          position: [116.6800, 39.8860]
         }
       ],
       // 1. 表头
@@ -225,8 +229,11 @@ export default {
     },
     // 处理查看逻辑
     onAlarmView({ item, index }) {
-      console.log('点击了查看:', item.title);
-      // 这里可以触发打开一个弹窗 (调用你之前的 SmartDialog 或者路由跳转)
+      console.log('点击了查看:', item);
+      // 临时逻辑,有真实接口后可以删除
+      const position = localStorage.getItem(`pos${index + 1}`).split(',');
+      
+      this.$refs.trafficMapRef.focusByLocation([Number(position[0]), Number(position[1])]);
     },
     onIntersectionRowClick({ row, index }) {
       console.log(`准备跳转查看关键路口详情,当前路口:`, row.id, row.intersection);