src/views/hrm/attendance/rule/modules/location-map-picker.vue
@@ -51,6 +51,17 @@
let marker: AnyMap;
let rangeCircle: AnyMap;
let geocoder: AnyMap;
/**
 * 组件是否已卸载。
 *
 * 百度地图 SDK 是异步加载的(loadBaiduMapSdk 内部创建 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;