98 lines
3.2 KiB
TypeScript
98 lines
3.2 KiB
TypeScript
import type { WechatGpsLocation } from '@dukang/shared-types';
|
||
import { getRuntimePlatform, isWechatBrowser } from './env';
|
||
import { ensureJssdkReady } from './jssdk';
|
||
import type { WeixinSdkConfig } from './types';
|
||
|
||
export type WechatLocationOutcome = {
|
||
sdk: 'jssdk' | 'geolocation';
|
||
location: WechatGpsLocation | null;
|
||
errMsg?: string;
|
||
};
|
||
|
||
/** 获取 GPS 定位(微信 JSSDK / 小程序优先,否则 H5 Geolocation) */
|
||
export async function getWechatLocation(config?: WeixinSdkConfig): Promise<WechatGpsLocation | null> {
|
||
const outcome = await getWechatLocationDetailed(config);
|
||
return outcome.location;
|
||
}
|
||
|
||
export async function getWechatLocationDetailed(
|
||
config?: WeixinSdkConfig,
|
||
): Promise<WechatLocationOutcome> {
|
||
const platform = getRuntimePlatform();
|
||
|
||
if (platform === 'mini' && window.wx?.getLocation) {
|
||
return new Promise((resolve) => {
|
||
window.wx!.getLocation!({
|
||
type: 'gcj02',
|
||
success: (res) => resolve({ sdk: 'jssdk', location: res }),
|
||
fail: (res) => resolve({ sdk: 'jssdk', location: null, errMsg: res.errMsg }),
|
||
});
|
||
});
|
||
}
|
||
|
||
if (platform === 'wechat-h5' && config) {
|
||
try {
|
||
await ensureJssdkReady({
|
||
apiBase: config.apiBase ?? '/api/v1',
|
||
clientApp: config.clientApp,
|
||
getAccessToken: config.getAccessToken,
|
||
});
|
||
if (window.wx?.getLocation) {
|
||
const jsApiOk = await new Promise<boolean>((resolve) => {
|
||
window.wx!.checkJsApi?.({
|
||
jsApiList: ['getLocation'],
|
||
success: (res) => resolve(!!res.checkResult?.getLocation),
|
||
fail: () => resolve(false),
|
||
});
|
||
});
|
||
if (!jsApiOk) {
|
||
return { sdk: 'jssdk', location: null, errMsg: 'getLocation 未授权或不可用' };
|
||
}
|
||
return new Promise((resolve) => {
|
||
window.wx!.getLocation!({
|
||
type: 'gcj02',
|
||
success: (res) => resolve({ sdk: 'jssdk', location: res }),
|
||
fail: (res) => resolve({ sdk: 'jssdk', location: null, errMsg: res.errMsg }),
|
||
});
|
||
});
|
||
}
|
||
return { sdk: 'jssdk', location: null, errMsg: '微信 JSSDK getLocation 不可用' };
|
||
} catch (err) {
|
||
const errMsg = err instanceof Error ? err.message : String(err);
|
||
return { sdk: 'jssdk', location: null, errMsg };
|
||
}
|
||
}
|
||
|
||
if (typeof navigator === 'undefined' || !navigator.geolocation) {
|
||
return { sdk: 'geolocation', location: null, errMsg: '浏览器不支持定位' };
|
||
}
|
||
return new Promise((resolve) => {
|
||
navigator.geolocation.getCurrentPosition(
|
||
(pos) =>
|
||
resolve({
|
||
sdk: 'geolocation',
|
||
location: {
|
||
latitude: pos.coords.latitude,
|
||
longitude: pos.coords.longitude,
|
||
accuracy: pos.coords.accuracy,
|
||
},
|
||
}),
|
||
(err) =>
|
||
resolve({
|
||
sdk: 'geolocation',
|
||
location: null,
|
||
errMsg: err.message || '定位失败',
|
||
}),
|
||
{ enableHighAccuracy: false, timeout: 8000, maximumAge: 60_000 },
|
||
);
|
||
});
|
||
}
|
||
|
||
export function canUseWechatLocation(): boolean {
|
||
return getRuntimePlatform() !== 'browser' || typeof navigator?.geolocation !== 'undefined';
|
||
}
|
||
|
||
export function isWechatEnv(): boolean {
|
||
return isWechatBrowser() || getRuntimePlatform() === 'mini';
|
||
}
|