Files
frontend-miniapp/src/utils/wechatOpenLocationProtocol.ts
lyf f9fefa11ef
Some checks failed
CI / verify (push) Has been cancelled
修复小程序内来馆地图导航
2026-07-11 17:24:45 +08:00

94 lines
2.8 KiB
TypeScript

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)