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 { const outcome = await getWechatLocationDetailed(config); return outcome.location; } export async function getWechatLocationDetailed( config?: WeixinSdkConfig, ): Promise { 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((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'; }