From da1328913c8bfbb5bbab83c834556a09cad07d9f Mon Sep 17 00:00:00 2001
From: tuqin <tuqin@tuqin.cn>
Date: 星期四, 05 十一月 2026 16:34:06 +0800
Subject: [PATCH] fix(hrm): 考勤规则打开定位后点确认报 Cannot read properties of null (reading Map)

---
 src/components/map/src/utils.ts                               |   57 +++++++++++++++++++---------
 src/views/hrm/attendance/rule/modules/location-map-picker.vue |   40 +++++++++++++++++++-
 2 files changed, 76 insertions(+), 21 deletions(-)

diff --git a/src/components/map/src/utils.ts b/src/components/map/src/utils.ts
index c5ff378..fb0bcbc 100644
--- a/src/components/map/src/utils.ts
+++ b/src/components/map/src/utils.ts
@@ -1,6 +1,17 @@
-/* eslint-disable @typescript-eslint/no-dynamic-delete */
 /**
  * 鐧惧害鍦板浘 SDK 鍔犺浇宸ュ叿
+ *
+ * 閲嶈锛氳繖閲屽繀椤荤洿杩� getscript锛屼笉鑳界敤 api?... 鍦板潃銆�
+ * api?v=1.0&type=webgl&ak=xxx 杩斿洖鐨勬槸涓�娈�
+ *   document.write('<script src="https://api.map.baidu.com/getscript?..."></script>')
+ * 鑰岄�氳繃 document.body.append(script) 鍔ㄦ�佹彃鍏ョ殑鑴氭湰閲岋紝document.write 浼氳娴忚鍣ㄦ嫤鎴�
+ * 锛圕hrome 鐩存帴鎻愮ず "A parser-blocking, cross site script ... invoked via document.write was NOT executed"锛夛紝
+ * 瀵艰嚧鐪熸鐨� SDK 浠庢湭鍔犺浇銆亀indow.BMapGL 涓�鐩存槸 undefined/null銆�
+ * 浣� api 閲岀殑 callback 浠嶄細琚皟鐢紝璋冪敤鏂硅浠ヤ负鍔犺浇鎴愬姛锛屾帴鐫�鎵ц new BMapGL.Map()
+ * 灏辨姏鍑恒�孋annot read properties of null (reading 'Map')銆嶃��
+ *
+ * getscript 杩斿洖鐨勬槸 875KB 鐨勭湡瀹� SDK锛堝凡瀹炴祴 HTTP 200 涓斿惈 BMapGL 瀹氫箟锛夛紝
+ * 鐩存帴鐢� script.src 鍔犺浇鍗冲彲锛岃剼鏈墽琛屽畬 window.BMapGL 灏卞凡灏辩华銆�
  */
 
 // 鎵╁睍 Window 鎺ュ彛浠ュ寘鍚櫨搴﹀湴鍥� GL API
@@ -9,9 +20,6 @@
     BMapGL: any;
   }
 }
-
-// 鍏ㄥ眬鍥炶皟鍚嶇О
-const CALLBACK_NAME = '__BAIDU_MAP_LOAD_CALLBACK__';
 
 // SDK 鍔犺浇鐘舵��
 let loadPromise: null | Promise<void> = null;
@@ -32,30 +40,41 @@
     return loadPromise;
   }
 
+  const accessKey = String(import.meta.env.VITE_BAIDU_MAP_KEY ?? '').trim();
+  if (!accessKey) {
+    return Promise.reject(new Error('鏈厤缃� VITE_BAIDU_MAP_KEY'));
+  }
+
   loadPromise = new Promise((resolve, reject) => {
     const timeoutId = setTimeout(() => {
       loadPromise = null;
-      reject(new Error('鐧惧害鍦板浘 SDK 鍔犺浇瓒呮椂'));
+      reject(new Error('鐧惧害鍦板浘 SDK 鍔犺浇瓒呮椂锛岃妫�鏌ョ綉缁�'));
     }, timeout);
 
-    // 鍏ㄥ眬鍥炶皟
-    (window as any)[CALLBACK_NAME] = () => {
-      clearTimeout(timeoutId);
-      delete (window as any)[CALLBACK_NAME];
-      resolve();
-    };
-
-    // 鍒涘缓 script 鏍囩
     const script = document.createElement('script');
-    script.src = `https://api.map.baidu.com/api?v=1.0&type=webgl&ak=${
-      import.meta.env.VITE_BAIDU_MAP_KEY
-    }&callback=${CALLBACK_NAME}`;
-    script.addEventListener('onerror', () => {
+    script.src = `https://api.map.baidu.com/getscript?type=webgl&v=1.0&ak=${accessKey}&services=&t=${Date.now()}`;
+    script.async = true;
+
+    script.addEventListener('load', () => {
+      clearTimeout(timeoutId);
+      if (!window.BMapGL) {
+        // ak 鏃犳晥 / 鍩熷悕鏈巿鏉� / 琚嫤鎴椂锛岃剼鏈兘鍔犺浇浣嗕笉浼氭寕杞� BMapGL
+        loadPromise = null;
+        reject(
+          new Error('鐧惧害鍦板浘鍔犺浇寮傚父锛氭湭鑾峰彇鍒板湴鍥惧璞★紝璇锋鏌� Key 鎴栧煙鍚嶆巿鏉�'),
+        );
+        return;
+      }
+      resolve();
+    });
+
+    // 娉ㄦ剰锛氫簨浠跺悕鏄� error锛屼笉鏄� onerror锛堝啓 onerror 姘歌繙涓嶄細瑙﹀彂锛�
+    script.addEventListener('error', () => {
       clearTimeout(timeoutId);
       loadPromise = null;
-      delete (window as any)[CALLBACK_NAME];
-      reject(new Error('鐧惧害鍦板浘 SDK 鍔犺浇澶辫触'));
+      reject(new Error('鐧惧害鍦板浘 SDK 鍔犺浇澶辫触锛岃妫�鏌ョ綉缁�'));
     });
+
     document.body.append(script);
   });
 
diff --git a/src/views/hrm/attendance/rule/modules/location-map-picker.vue b/src/views/hrm/attendance/rule/modules/location-map-picker.vue
index d793219..63014eb 100644
--- a/src/views/hrm/attendance/rule/modules/location-map-picker.vue
+++ b/src/views/hrm/attendance/rule/modules/location-map-picker.vue
@@ -51,6 +51,17 @@
 let marker: AnyMap;
 let rangeCircle: AnyMap;
 let geocoder: AnyMap;
+/**
+ * 缁勪欢鏄惁宸插嵏杞姐��
+ *
+ * 鐧惧害鍦板浘 SDK 鏄紓姝ュ姞杞界殑锛坙oadBaiduMapSdk 鍐呴儴鍒涘缓 script 鏍囩锛夈��
+ * 鐢ㄦ埛鎵撳紑瀹氫綅鍚庡鏋滃緢蹇偣銆岀‘璁ゃ�嶆垨銆屽彇娑堛�嶏紝寮圭獥鍏抽棴 鈫� 鏈粍浠跺嵏杞� 鈫� 鍦板浘瀹瑰櫒浠� DOM 绉婚櫎锛�
+ * 浣嗗姞杞芥祦绋嬩粛鍦� await 涓户缁紝绛� SDK 灏辩华鍚庝細鎵ц new BMapGL.Map(mapContainer.value)锛�
+ * 姝ゆ椂 mapContainer 宸叉槸 null锛岀櫨搴﹀湴鍥惧唴閮ㄤ細鎶�
+ * "Cannot read properties of null (reading 'Map')"銆�
+ * 鐢ㄨ繖涓爣蹇椾綅璁╁紓姝ユ祦绋嬪湪鍗歌浇鍚庣珛鍗抽��鍑恒��
+ */
+let disposed = false;
 
 const baiduMapKey = String(import.meta.env.VITE_BAIDU_MAP_KEY ?? '').trim();
 const hasMapConfig = computed(() => Boolean(baiduMapKey));
@@ -274,13 +285,31 @@
   loading.value = true;
   try {
     await loadBaiduMapSdk(15_000);
+    // 鍗歌浇鍚庣珛鍗抽��鍑猴細姝ゆ椂鍦板浘瀹瑰櫒宸蹭粠 DOM 绉婚櫎锛岀户缁垵濮嬪寲浼氭姏 null.Map
+    if (disposed || !mapContainer.value) {
+      return;
+    }
     await nextTick();
+    if (disposed || !mapContainer.value) {
+      return;
+    }
+    // SDK 鍥炶皟瑙﹀彂浣� BMapGL 鏈寕杞斤紙甯歌浜� ak 鏃犳晥 / 鍩熷悕鏈巿鏉� / 琚綉缁滄嫤鎴級
+    if (!window.BMapGL) {
+      message.error('鐧惧害鍦板浘鍔犺浇澶辫触锛岃妫�鏌ュ湴鍥� Key 閰嶇疆鎴栫綉缁�');
+      return;
+    }
     const hasCoordinates =
       Number.isFinite(props.longitude) && Number.isFinite(props.latitude);
     const center = hasCoordinates
       ? wgs84ToBd09(Number(props.longitude), Number(props.latitude))
       : DEFAULT_CENTER;
     map = new window.BMapGL.Map(mapContainer.value);
+    if (disposed) {
+      // 鍒濆鍖栬繃绋嬩腑琚嵏杞斤紝鐩存帴閿�姣侊紝閬垮厤娈嬬暀瀹炰緥
+      map?.destroy?.();
+      map = undefined;
+      return;
+    }
     map.centerAndZoom(
       new window.BMapGL.Point(center[0], center[1]),
       hasCoordinates ? 19 : 12,
@@ -333,8 +362,15 @@
 onMounted(initializeMap);
 
 onBeforeUnmount(() => {
-  map?.clearOverlays?.();
-  map?.destroy?.();
+  // 鍏堢疆鏍囧織浣嶏紝璁╄繕鍦� await 涓殑 initializeMap 绔嬪嵆閫�鍑�
+  disposed = true;
+  try {
+    map?.clearOverlays?.();
+    map?.destroy?.();
+  } catch (error) {
+    // 鍦板浘瀹炰緥鑻ュ浜庡崐鍒濆鍖栫姸鎬侊紝destroy 鍐呴儴鍙兘鎶ラ敊锛岃繖閲屽悶鎺夐伩鍏嶅奖鍝嶅脊绐楀叧闂�
+    console.warn('[LocationMapPicker] 閿�姣佸湴鍥惧疄渚嬪け璐�', error);
+  }
   map = undefined;
   marker = undefined;
   rangeCircle = undefined;

--
Gitblit v1.9.3