Files
TakeoutSaaS.TenantUI/apps/web-antd/src/views/store/delivery/composables/useTencentMapLoader.ts

130 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 文件职责:按需加载腾讯地图 JS SDK。
* 1. 使用全局 callback + 单例 Promise避免重复注入脚本。
* 2. 与 AdminUI 的加载策略保持一致,降低多实例冲突风险。
*/
declare global {
interface Window {
TMap?: any;
__tenantTencentMapInit?: () => void;
}
}
const SCRIPT_ID = 'tenant-tencent-map-gljs-sdk';
const CALLBACK_NAME = '__tenantTencentMapInit';
const SCRIPT_LOAD_TIMEOUT_MS = 12_000;
const TENCENT_MAP_LIBRARIES = 'visualization,geometry,vector,tools,service';
let mapSdkPromise: null | Promise<any> = null;
let scriptLoading = false;
const pendingResolvers: Array<(value: any) => void> = [];
const pendingRejectors: Array<(error: Error) => void> = [];
function getTencentMapKey() {
return (import.meta.env.VITE_TENCENT_MAP_KEY as string | undefined)?.trim();
}
function flushSuccess(tmap: any) {
const resolvers = pendingResolvers.splice(0);
pendingRejectors.splice(0);
resolvers.forEach((resolve) => resolve(tmap));
}
function flushError(error: Error) {
const rejectors = pendingRejectors.splice(0);
pendingResolvers.splice(0);
rejectors.forEach((reject) => reject(error));
}
function buildScriptUrl(mapKey: string) {
return `https://map.qq.com/api/gljs?v=1.exp&key=${encodeURIComponent(
mapKey,
)}&libraries=${TENCENT_MAP_LIBRARIES}&callback=${CALLBACK_NAME}`;
}
export async function loadTencentMapSdk() {
if (typeof window === 'undefined') {
throw new TypeError('当前环境不支持加载地图');
}
if (window.TMap) {
return window.TMap;
}
const mapKey = getTencentMapKey();
if (!mapKey) {
throw new Error('未配置腾讯地图 KeyVITE_TENCENT_MAP_KEY');
}
if (mapSdkPromise) {
return mapSdkPromise;
}
mapSdkPromise = new Promise<any>((resolve, reject) => {
pendingResolvers.push(resolve);
pendingRejectors.push(reject);
if (scriptLoading) {
return;
}
scriptLoading = true;
const completeWithError = (error: Error) => {
scriptLoading = false;
mapSdkPromise = null;
flushError(error);
};
const timeoutHandle = window.setTimeout(() => {
completeWithError(new Error('腾讯地图 SDK 加载超时'));
}, SCRIPT_LOAD_TIMEOUT_MS);
window[CALLBACK_NAME] = () => {
window.clearTimeout(timeoutHandle);
scriptLoading = false;
if (!window.TMap) {
completeWithError(new Error('腾讯地图 SDK 加载失败'));
return;
}
flushSuccess(window.TMap);
};
const existingScript = document.querySelector<HTMLScriptElement>(
`#${SCRIPT_ID}`,
);
if (existingScript) {
existingScript.addEventListener(
'error',
() => {
window.clearTimeout(timeoutHandle);
completeWithError(new Error('腾讯地图 SDK 加载失败'));
},
{ once: true },
);
return;
}
const script = document.createElement('script');
script.id = SCRIPT_ID;
script.type = 'text/javascript';
script.async = true;
script.defer = true;
script.src = buildScriptUrl(mapKey);
script.addEventListener(
'error',
() => {
window.clearTimeout(timeoutHandle);
completeWithError(new Error('腾讯地图 SDK 加载失败'));
},
{ once: true },
);
document.body.append(script);
});
return mapSdkPromise;
}