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 会被浏览器拦截
 * (Chrome 直接提示 "A parser-blocking, cross site script ... invoked via document.write was NOT executed"),
 * 导致真正的 SDK 从未加载、window.BMapGL 一直是 undefined/null。
 * 但 api 里的 callback 仍会被调用,调用方误以为加载成功,接着执行 new BMapGL.Map()
 * 就抛出「Cannot 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);
  });