94 lines
2.8 KiB
TypeScript
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)
|