75 lines
2.3 KiB
TypeScript
75 lines
2.3 KiB
TypeScript
import type { CheckInLocationSnapshot } from '@/domain/check-in'
|
|||
|
|
|
||
|
|
interface CurrentLocationOptions {
|
||
|
|
highAccuracyExpireTime?: number
|
||
|
|
timeoutMs?: number
|
||
|
|
}
|
||
|
|
|
||
|
|
function locationOptionsSupported(): boolean {
|
||
|
|
try {
|
||
|
|
return typeof uni.canIUse !== 'function'
|
||
|
|
|| uni.canIUse('getLocation.object.isHighAccuracy')
|
||
|
|
}
|
||
|
|
catch {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function isLocationPermissionDenied(error: unknown): boolean {
|
||
|
|
if (!error || typeof error !== 'object')
|
||
|
|
return false
|
||
|
|
const message = String((error as { errMsg?: unknown }).errMsg ?? '')
|
||
|
|
return !/privacy/i.test(message)
|
||
|
|
&& /auth deny|auth denied|authorize:fail|permission/i.test(message)
|
||
|
|
}
|
||
|
|
|
||
|
|
export function getCurrentGcj02Location(options: CurrentLocationOptions = {}): Promise<CheckInLocationSnapshot> {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
const highAccuracyExpireTime = Math.max(3000, options.highAccuracyExpireTime ?? 8000)
|
||
|
|
const timeoutMs = Math.max(3000, options.timeoutMs ?? 15000)
|
||
|
|
let settled = false
|
||
|
|
let timeout: ReturnType<typeof setTimeout> | null = null
|
||
|
|
const finish = (callback: () => void) => {
|
||
|
|
if (settled)
|
||
|
|
return
|
||
|
|
settled = true
|
||
|
|
if (timeout)
|
||
|
|
clearTimeout(timeout)
|
||
|
|
callback()
|
||
|
|
}
|
||
|
|
timeout = setTimeout(() => {
|
||
|
|
finish(() => reject(new Error('定位超时,请到开阔处重试')))
|
||
|
|
}, timeoutMs)
|
||
|
|
const commonOptions = {
|
||
|
|
type: 'gcj02' as const,
|
||
|
|
success: (result: UniNamespace.GetLocationSuccess) => {
|
||
|
|
const longitude = Number(result.longitude)
|
||
|
|
const latitude = Number(result.latitude)
|
||
|
|
const accuracy = Number(result.accuracy ?? result.horizontalAccuracy)
|
||
|
|
if (!Number.isFinite(longitude) || !Number.isFinite(latitude)) {
|
||
|
|
finish(() => reject(new Error('定位结果无效,请稍后重试')))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
finish(() => resolve({
|
||
|
|
longitude,
|
||
|
|
latitude,
|
||
|
|
accuracy: Number.isFinite(accuracy) && accuracy >= 0 ? accuracy : null,
|
||
|
|
receivedAt: new Date().toISOString(),
|
||
|
|
coordinateSystem: 'GCJ02',
|
||
|
|
}))
|
||
|
|
},
|
||
|
|
fail: (error: unknown) => finish(() => reject(error)),
|
||
|
|
}
|
||
|
|
|
||
|
|
if (locationOptionsSupported()) {
|
||
|
|
uni.getLocation({
|
||
|
|
...commonOptions,
|
||
|
|
isHighAccuracy: true,
|
||
|
|
highAccuracyExpireTime,
|
||
|
|
})
|
||
|
|
return
|
||
|
|
}
|
||
|
|
uni.getLocation(commonOptions)
|
||
|
|
})
|
||
|
|
}
|