export const WECHAT_OPEN_LOCATION_PAGE_PATH = '/pages/open-location/index' export interface WechatOpenLocationTarget { latitude: number longitude: number name: string address?: string } export interface WechatOpenLocationPageOptions { latitude?: unknown longitude?: unknown name?: unknown address?: unknown } export type WechatOpenLocationValidationResult = | { ok: true; value: WechatOpenLocationTarget } | { ok: false; message: string } const MAX_NAME_LENGTH = 100 const MAX_ADDRESS_LENGTH = 300 const firstValue = (value: unknown) => ( Array.isArray(value) ? value[0] : value ) const normalizeText = (value: unknown) => { const first = firstValue(value) return typeof first === 'string' ? first.trim() : '' } const normalizeCoordinate = (value: unknown) => { const first = firstValue(value) if (typeof first === 'string' && !first.trim()) return null if (typeof first !== 'string' && typeof first !== 'number') return null const coordinate = Number(first) return Number.isFinite(coordinate) ? coordinate : null } export const validateWechatOpenLocationTarget = ( target: WechatOpenLocationPageOptions ): WechatOpenLocationValidationResult => { const latitude = normalizeCoordinate(target.latitude) const longitude = normalizeCoordinate(target.longitude) const name = normalizeText(target.name) const address = normalizeText(target.address) if (latitude === null || longitude === null) { return { ok: false, message: '地图坐标缺失或格式错误' } } if (latitude < -90 || latitude > 90 || longitude < -180 || longitude > 180) { return { ok: false, message: '地图坐标超出有效范围' } } if (!name) { return { ok: false, message: '目的地名称不能为空' } } if (name.length > MAX_NAME_LENGTH || address.length > MAX_ADDRESS_LENGTH) { return { ok: false, message: '目的地名称或地址过长' } } return { ok: true, value: { latitude, longitude, name, address } } } export const buildWechatOpenLocationPageUrl = ( target: WechatOpenLocationPageOptions ) => { const result = validateWechatOpenLocationTarget(target) if (!result.ok) throw new TypeError(result.message) const params = new URLSearchParams() params.set('latitude', String(result.value.latitude)) params.set('longitude', String(result.value.longitude)) params.set('name', result.value.name) params.set('address', result.value.address || '') // 微信页面路由对加号的解码行为不统一,空格固定使用百分号编码。 const query = params.toString().replace(/\+/g, '%20') return `${WECHAT_OPEN_LOCATION_PAGE_PATH}?${query}` } export const parseWechatOpenLocationPageOptions = ( options: WechatOpenLocationPageOptions = {} ) => validateWechatOpenLocationTarget(options)