93
src/utils/wechatOpenLocationProtocol.ts
Normal file
93
src/utils/wechatOpenLocationProtocol.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user