Parcourir la source

fix: 优化TongzhouTrafficMap组件代码结构和性能

sequoia tungfang il y a 1 mois
Parent
commit
9f3d17414c
1 fichiers modifiés avec 139 ajouts et 114 suppressions
  1. 139 114
      src/components/TongzhouTrafficMap.vue

+ 139 - 114
src/components/TongzhouTrafficMap.vue

@@ -103,28 +103,44 @@ export default {
     // 1. 立即设置销毁状态
     this._isDestroyed = true;
 
-    // 2. 清理全局回调
-    window.closeMapInfoWindow = null;
-
-    // 3. 关闭弹窗
+    // 2. 关闭弹窗
     if (this.infoWindow) {
-      this.infoWindow.close();
+      try {
+        this.infoWindow.close();
+      } catch (e) {
+        console.warn('关闭信息窗口时出错:', e);
+      }
       this.infoWindow = null;
     }
 
-    // 4. 清理覆盖物引用
-    Object.values(this.routeGroups).forEach(overlays => {
-      if (Array.isArray(overlays)) {
-        overlays.forEach(o => o.setMap && o.setMap(null));
-      }
-    });
-    this.routeGroups = {};
+    // 3. 清理覆盖物引用
+    if (this.routeGroups) {
+      Object.values(this.routeGroups).forEach(overlays => {
+        if (Array.isArray(overlays)) {
+          overlays.forEach(o => {
+            try {
+              if (o.setMap) o.setMap(null);
+            } catch (e) {
+              console.warn('清理覆盖物时出错:', e);
+            }
+          });
+        }
+      });
+      this.routeGroups = {};
+    }
 
-    // 5. 销毁地图实例并清空引用
+    // 4. 销毁地图实例并清空引用
     if (this.map) {
-      this.map.destroy();
+      try {
+        this.map.destroy();
+      } catch (e) {
+        console.warn('销毁地图实例时出错:', e);
+      }
       this.map = null;
     }
+
+    // 5. 清理其他引用
+    this.AMap = null;
   },
   computed: {
     isAllSelected() {
@@ -170,6 +186,8 @@ export default {
     },
 
     async initAMap() {
+      if (this._isDestroyed) return;
+      
       window._AMapSecurityConfig = { securityJsCode: this.securityJsCode };
       try {
         const AMap = await AMapLoader.load({
@@ -196,13 +214,6 @@ export default {
       }
     },
 
-
-
-    // ... 其他代码保持不变
-    isMapReady() {
-      return !this._isDestroyed && this.map && typeof this.map.add === 'function';
-    },
-
     drawStaticRoutes() {
       if (!this.isMapReady()) return;
 
@@ -211,78 +222,92 @@ export default {
         setTimeout(() => {
           if (!this.isMapReady()) return;
 
-          const driving = new this.AMap.Driving({
-            map: null,
-            hideMarkers: true,
-            autoFitView: false
-          });
-
-          // 这里必须用箭头函数 (status, result) => { ... }
-          driving.search(config.start, config.end, (status, result) => {
-            // 这里的 this 才能访问到 isMapReady
-            if (!this.isMapReady()) return;
-
-            let path = [];
-            if (status === 'complete' && result.routes[0]) {
-              result.routes[0].steps.forEach(step => { path = path.concat(step.path); });
-            } else {
-              path = [config.start, config.end];
-            }
-
-            const markers = [];
-            let polyline = null;
-
-            // 路线逻辑
-            if (["干线协调", "勤务路线"].includes(config.name)) {
-              polyline = new this.AMap.Polyline({
-                path: path,
-                strokeColor: config.color,
-                strokeWeight: 6,
-                strokeOpacity: 0.6,
-                zIndex: 15
-              });
-            }
-
-            // --- 稀疏化逻辑 ---
-            const isAbnormalStatus = ["离线", "降级", "故障"].includes(config.name);
-            // 异常状态(离线等)每 40 个点取一个,普通状态每 15 个点取一个
-            const stepSize = isAbnormalStatus ? 40 : 15;
-
-            for (let i = 0; i < path.length; i += stepSize) {
-              markers.push(this.createTrafficLightMarker(path[i], config));
-            }
-
-            const overlays = [...markers, polyline].filter(Boolean);
-            this.routeGroups[config.name] = overlays;
-
-            if (this.isMapReady() && this.activeLegends.includes(config.name)) {
-              this.map.add(overlays);
-            }
-          });
+          try {
+            const driving = new this.AMap.Driving({
+              map: null,
+              hideMarkers: true,
+              autoFitView: false
+            });
+
+            // 这里必须用箭头函数 (status, result) => { ... }
+            driving.search(config.start, config.end, (status, result) => {
+              // 这里的 this 才能访问到 isMapReady
+              if (!this.isMapReady()) return;
+
+              try {
+                let path = [];
+                if (status === 'complete' && result && result.routes && result.routes[0]) {
+                  result.routes[0].steps.forEach(step => { path = path.concat(step.path); });
+                } else {
+                  path = [config.start, config.end];
+                }
+
+                const markers = [];
+                let polyline = null;
+
+                // 路线逻辑
+                if (["干线协调", "勤务路线"].includes(config.name)) {
+                  polyline = new this.AMap.Polyline({
+                    path: path,
+                    strokeColor: config.color,
+                    strokeWeight: 6,
+                    strokeOpacity: 0.6,
+                    zIndex: 15
+                  });
+                }
+
+                // --- 稀疏化逻辑 ---
+                const isAbnormalStatus = ["离线", "降级", "故障"].includes(config.name);
+                // 异常状态(离线等)每 40 个点取一个,普通状态每 15 个点取一个
+                const stepSize = isAbnormalStatus ? 40 : 15;
+
+                for (let i = 0; i < path.length; i += stepSize) {
+                  markers.push(this.createTrafficLightMarker(path[i], config));
+                }
+
+                const overlays = [...markers, polyline].filter(Boolean);
+                this.routeGroups[config.name] = overlays;
+
+                if (this.isMapReady() && this.activeLegends.includes(config.name)) {
+                  this.map.add(overlays);
+                }
+              } catch (e) {
+                console.warn('处理路线数据时出错:', e);
+              }
+            });
+          } catch (e) {
+            console.warn('创建驾车实例时出错:', e);
+          }
         }, index * 200);
       });
     },
 
     createTrafficLightMarker(position, config) {
-      const isAbnormal = ["离线", "降级", "故障"].includes(config.name);
-      const lng = Number(position[0] || position.lng);
-      const lat = Number(position[1] || position.lat);
-
-      // 3. 【视觉优化】调整 Marker 大小比例
-      // 异常状态图标略大(为了警示),普通点位略小且半透明
-      const size = isAbnormal ? '18px' : '14px';
-      const opacity = isAbnormal ? '1' : '0.85';
-      const shadow = isAbnormal ? `0 0 10px ${config.color}` : `0 0 5px ${config.color}`;
-
-      const marker = new this.AMap.Marker({
-        position: [lng, lat],
-        zIndex: isAbnormal ? 110 : 100, // 异常图标显示在更上层
-        content: `
+      if (!position || !config) return null;
+      
+      try {
+        const isAbnormal = ["离线", "降级", "故障"].includes(config.name);
+        const lng = Number(position[0] || position.lng);
+        const lat = Number(position[1] || position.lat);
+
+        // 验证坐标有效性
+        if (isNaN(lng) || isNaN(lat)) return null;
+
+        // 3. 【视觉优化】调整 Marker 大小比例
+        // 异常状态图标略大(为了警示),普通点位略小且半透明
+        const size = isAbnormal ? '18px' : '14px';
+        const opacity = isAbnormal ? '1' : '0.85';
+        const shadow = isAbnormal ? `0 0 10px ${config.color || '#999'}` : `0 0 5px ${config.color || '#999'}`;
+
+        const marker = new this.AMap.Marker({
+          position: [lng, lat],
+          zIndex: isAbnormal ? 110 : 100, // 异常图标显示在更上层
+          content: `
           <div class="pure-light-node ${isAbnormal ? 'breathe abnormal-node' : ''}" 
               style="
                 width: ${size}; 
                 height: ${size}; 
-                background: ${config.color}; 
+                background: ${config.color || '#999'}; 
                 box-shadow: ${shadow}; 
                 opacity: ${opacity};
                 border: 1.5px solid rgba(255,255,255,0.7);
@@ -300,7 +325,7 @@ export default {
         extData: {
           ...config,
           position: [lng, lat],
-          statusColor: config.color,
+          statusColor: config.color || '#999',
           statusLabel: isAbnormal ? config.name : "正常运行",
           road: '北京路与南京路',
           time: '2026.1.23.12:00'
@@ -308,19 +333,26 @@ export default {
       });
 
       marker.on('click', (e) => {
-        this.openLightInfo(e.target.getExtData(), e.lnglat);
-        this.$emit('map-crossing-click', e.target.getExtData(), e.lnglat);
+        if (!this._isDestroyed) {
+          this.openLightInfo(e.target.getExtData(), e.lnglat);
+          this.$emit('map-crossing-click', e.target.getExtData(), e.lnglat);
+        }
       });
 
       return marker;
+      } catch (e) {
+        console.warn('创建标记时出错:', e);
+        return null;
+      }
     },
 
     openLightInfo(data, position) {
       if (!this.isMapReady()) return;
 
+      const infoWindowId = `info-window-${Date.now()}`;
       const content = `
-        <div class="custom-info-card">
-          <div class="close-btn" onclick="window.closeMapInfoWindow()">✕</div>
+        <div class="custom-info-card" id="${infoWindowId}">
+          <div class="close-btn" data-id="${infoWindowId}">✕</div>
           <div class="card-header">
             <div class="status-dot" style="background: ${data.statusColor}">
               <span>${data.name.charAt(0)}</span>
@@ -334,18 +366,25 @@ export default {
         </div>
       `;
 
-      window.closeMapInfoWindow = () => {
-        if (this.infoWindow) this.infoWindow.close();
-      };
-
       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);
+      
+      // 添加关闭按钮事件监听器
+      setTimeout(() => {
+        const closeBtn = document.querySelector(`#${infoWindowId} .close-btn`);
+        if (closeBtn) {
+          closeBtn.addEventListener('click', () => {
+            if (this.infoWindow) this.infoWindow.close();
+          });
+        }
+      }, 100);
     },
 
     toggleAll() {
@@ -423,14 +462,7 @@ export default {
   height: 100%;
 }
 
-::v-deep .pure-light-node {
-  width: 16px;
-  height: 16px;
-  border-radius: 50%;
-  border: 2px solid rgba(255, 255, 255, 0.8);
-  cursor: pointer;
-  transition: all 0.3s;
-}
+
 
 ::v-deep .pure-light-node.breathe {
   animation: light-breathe 2s infinite ease-in-out;
@@ -447,19 +479,7 @@ export default {
   filter: brightness(1.2);
 }
 
-@keyframes light-breathe {
 
-  0%,
-  100% {
-    opacity: 0.7;
-    transform: scale(1);
-  }
-
-  50% {
-    opacity: 1;
-    transform: scale(1.15);
-  }
-}
 
 ::v-deep .close-btn {
   position: absolute;
@@ -547,11 +567,13 @@ export default {
   z-index: 100;
   transition: all 0.3s ease-in-out;
   opacity: 1;
+  max-width: 200px;
+  overflow: hidden;
 }
 
 .map-legend.legend-hidden {
   opacity: 0;
-  transform: translateX(100%);
+  transform: translateX(calc(100% + 20px));
   pointer-events: none;
 }
 
@@ -733,7 +755,10 @@ export default {
 }
 
 ::v-deep .pure-light-node {
+  width: 16px;
+  height: 16px;
   border-radius: 50%;
+  border: 2px solid rgba(255, 255, 255, 0.8);
   cursor: pointer;
   transition: all 0.3s;
   display: flex;