feat(project): align store delivery pages with live APIs and geocode status
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 文件职责:按需加载腾讯地图 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('未配置腾讯地图 Key(VITE_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;
|
||||
}
|
||||
Reference in New Issue
Block a user