Files
chazhi/src/hooks/useLocation.ts
2026-01-07 17:34:41 +08:00

340 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { getLocationToCity } from '@/api/tea-room'
const LOCATION_EXPIRE_MS = 30 * 24 * 60 * 60 * 1000 // 定位缓存30天
const LOCATION_DENY_INTERVAL = 60 * 60 * 1000 // 未授权定位弹窗间隔1小时
export const LOCATION_EXPIRE_KEY = 'location_expire_time' // 定位缓存KEY
export const LOCATION_DENY_TIME_KEY = 'location_deny_time' // 未授权定位重新授权时间KEY
export const LOCATION_CITY_KEY = 'city' // 城市缓存KEY
export const LOCATION_LAT_KEY = 'latitude' // 城市缓存KEY
export const LOCATION_LNG_KEY = 'longitude' // 城市缓存KEY
export const LOCATION_CURRENT = 'current_city' // 城市缓存KEY
export const LOCATION_DEFAULT_CITY = '上海市' // 默认城市
export const LOCATION_DEFAULT_LNG = 121.473629 // 上海经度
export const LOCATION_DEFAULT_LAT = 31.230393 // 上海纬度
// 检查过期时间
export function handleCheckLocationCacheHooks() {
const expire = uni.getStorageSync(LOCATION_EXPIRE_KEY)
if (expire && Date.now() > expire) {
uni.removeStorageSync(LOCATION_LAT_KEY)
uni.removeStorageSync(LOCATION_LNG_KEY)
uni.removeStorageSync(LOCATION_EXPIRE_KEY)
return false
}
return true
}
// 设置经纬度缓存
export function handleSetLocationCacheHooks(lat: number, lng: number) {
uni.setStorageSync(LOCATION_LAT_KEY, lat)
uni.setStorageSync(LOCATION_LNG_KEY, lng)
// uni.setStorageSync(LOCATION_EXPIRE_KEY, Date.now() + LOCATION_EXPIRE_MS)
}
// TODO VERSION2: 在获取经纬度之前还有弹出是否搜索附近茶室?-初始化经纬度
// export async function handleEnsureLocationAuthHooks() {
// const SEARCH_CONFIRM_KEY = 'search_nearby_confirmed'
// const confirmed = uni.getStorageSync(SEARCH_CONFIRM_KEY)
// // 1. 检查缓存和是否已确认搜索附近茶室
// if (confirmed && handleCheckLocationCacheHooks()) {
// const lat = uni.getStorageSync(LOCATION_LAT_KEY)
// const lng = uni.getStorageSync(LOCATION_LNG_KEY)
// if (lat && lng) return { lat, lng }
// }
// // 2. 判断是否已弹过确认弹窗(授权后不再弹)
// return new Promise<{ lat: number, lng: number }>((resolve) => {
// if (confirmed) {
// // 已确认过,直接走授权
// uni.authorize({
// scope: 'scope.userLocation',
// success() {
// uni.getLocation({
// type: 'gcj02',
// success(res) {
// handleSetLocationCacheHooks(res.latitude, res.longitude)
// resolve({ lat: res.latitude, lng: res.longitude })
// },
// fail() {
// handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
// resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
// }
// })
// },
// fail() {
// // 用户拒绝授权
// if (shouldShowAuthModal()) {
// uni.setStorageSync(LOCATION_DENY_TIME_KEY, Date.now())
// uni.removeStorageSync(SEARCH_CONFIRM_KEY) // 授权失败,下次启动继续弹窗
// uni.showModal({
// title: '提示',
// content: '需要获取您的地理位置,请授权定位服务',
// showCancel: false,
// success: () => {
// uni.openSetting({})
// }
// })
// }
// handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
// resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
// }
// })
// } else {
// // 未确认,弹窗
// uni.showModal({
// title: '提示',
// content: '是否搜索附近茶室?',
// showCancel: true,
// confirmText: '是',
// cancelText: '否',
// success: (modalRes) => {
// console.log("🚀 ~ handleEnsureLocationAuthHooks ~ modalRes:", modalRes)
// if (modalRes.confirm) {
// // 用户点击“是”,标记已确认,下次不再弹窗
// uni.setStorageSync(SEARCH_CONFIRM_KEY, true)
// uni.authorize({
// scope: 'scope.userLocation',
// success() {
// uni.getLocation({
// type: 'gcj02',
// success(res) {
// handleSetLocationCacheHooks(res.latitude, res.longitude)
// console.log("🚀 ~ handleEnsureLocationAuthHooks ~ LOCATION_DEFAULT_LAT:", LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
// resolve({ lat: res.latitude, lng: res.longitude })
// },
// fail() {
// handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
// resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
// }
// })
// },
// fail() {
// // 用户拒绝授权
// if (shouldShowAuthModal()) {
// uni.setStorageSync(LOCATION_DENY_TIME_KEY, Date.now())
// uni.removeStorageSync(SEARCH_CONFIRM_KEY) // 授权失败,下次启动继续弹窗
// uni.showModal({
// title: '提示',
// content: '需要获取您的地理位置,请授权定位服务',
// showCancel: false,
// success: () => {
// uni.openSetting({})
// }
// })
// }
// handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
// console.log("🚀 ~ handleEnsureLocationAuthHooks ~ LOCATION_DEFAULT_LAT:", LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
// resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
// }
// })
// }
// if (modalRes.cancel) {
// // 用户点击“否”,直接返回默认上海
// handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
// console.log("🚀 ~ handleEnsureLocationAuthHooks ~ LOCATION_DEFAULT_LAT:", LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
// resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
// }
// }
// })
// }
// })
// }
// VERSION1: 初始化经纬度
export async function handleEnsureLocationAuthHooks() {
// 1. 检查缓存-先把缓存去掉
// if (handleCheckLocationCacheHooks()) {
// const lat = uni.getStorageSync(LOCATION_LAT_KEY)
// const lng = uni.getStorageSync(LOCATION_LNG_KEY)
// if (lat && lng) return { lat, lng }
// }
// 2. 获取定位
return new Promise<{ lat: number, lng: number, }>((resolve) => {
uni.authorize({
scope: 'scope.userLocation',
success() {
uni.getLocation({
type: 'gcj02',
success(res) {
handleSetLocationCacheHooks(res.latitude, res.longitude)
resolve({ lat: res.latitude, lng: res.longitude})
},
fail() {
// 定位失败,返回默认上海
handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG})
}
})
},
fail() {
// 用户拒绝授权
if (shouldShowAuthModal()) {
uni.setStorageSync(LOCATION_DENY_TIME_KEY, Date.now())
uni.showModal({
title: '提示',
content: '需要获取您的地理位置,请授权定位服务',
showCancel: false,
success: () => {
// 可引导用户去设置页面
uni.openSetting({})
}
})
}
// 返回默认上海
handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
}
})
})
}
/**
* 检查并弹窗授权地理位置(每小时弹一次,授权后自动获取定位)
* 返回 Promise<boolean>true 表示已授权false 表示未授权
*/
export function checkLocationAuthWithModal(): Promise<{ lat: number, lng: number } | false> {
return new Promise((resolve) => {
uni.getSetting({
success(settingRes) {
const hasAuth = settingRes.authSetting && settingRes.authSetting['scope.userLocation']
if (hasAuth) {
// 已授权,自动获取并返回经纬度
uni.getLocation({
type: 'gcj02',
success(res) {
handleSetLocationCacheHooks(res.latitude, res.longitude)
resolve({ lat: res.latitude, lng: res.longitude })
},
fail() {
resolve(false)
}
})
} else {
// 未授权,判断是否需要弹窗
const lastDeny = uni.getStorageSync(LOCATION_DENY_TIME_KEY)
if (!lastDeny || (Date.now() - lastDeny > LOCATION_DENY_INTERVAL)) {
uni.setStorageSync(LOCATION_DENY_TIME_KEY, Date.now())
uni.showModal({
title: '提示',
content: '需要获取您的地理位置,请授权定位服务',
showCancel: false,
success: () => {
uni.openSetting({
success(openRes) {
const nowAuth = openRes.authSetting && openRes.authSetting['scope.userLocation']
if (nowAuth) {
// 用户授权后,自动获取并返回经纬度
uni.getLocation({
type: 'gcj02',
success(res) {
handleSetLocationCacheHooks(res.latitude, res.longitude)
resolve({ lat: res.latitude, lng: res.longitude })
},
fail() {
resolve(false)
}
})
} else {
resolve(false)
}
}
})
}
})
} else {
resolve(false)
}
}
},
fail() {
resolve(false)
}
})
})
}
/**
* 设置城市
*/
export function setLocationCity(city: string) {
uni.setStorageSync(LOCATION_CITY_KEY, city)
}
/**
* 经纬度转换为城市
* @returns
*/
export async function handleGetLocationCity(lat: number, lng: number) {
try {
console.log("🚀 ~ handleGetLocationCity ~ res:", lat, lng)
const res = await getLocationToCity({ latitude: lat, longitude: lng })
if (res.message == "Success") {
const params = {
latitude: res.result.location.lat,
longitude: res.result.location.lng,
city: res.result.ad_info.city
}
// 通过腾讯地图返回的经纬度重新设置缓存
handleSetLocationCacheHooks(res.result.location.lat, res.result.location.lng)
setLocationCity(params.city)
uni.setStorageSync(LOCATION_CURRENT, params)
// uni.$emit('locationUpdate', params) // 通知页面
return params
} else {
setLocationCity(LOCATION_DEFAULT_CITY)
}
} catch (error) {
setLocationCity(LOCATION_DEFAULT_CITY)
}
}
// 检查是否需要弹授权框
function shouldShowAuthModal() {
const lastDeny = uni.getStorageSync(LOCATION_DENY_TIME_KEY)
return !lastDeny || (Date.now() - lastDeny > LOCATION_DENY_INTERVAL)
}
// 强制获取定位(不走缓存,每次都重新定位)
export function handleForceGetLocation(): Promise<{ lat: number, lng: number }> {
return new Promise((resolve) => {
uni.authorize({
scope: 'scope.userLocation',
success() {
uni.getLocation({
type: 'gcj02',
success(res) {
console.log("🚀 ~ 开始请求定位授权handleForceGetLocation ~ res:", res)
handleSetLocationCacheHooks(res.latitude, res.longitude)
resolve({ lat: res.latitude, lng: res.longitude })
},
fail() {
handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
}
})
},
fail() {
handleSetLocationCacheHooks(LOCATION_DEFAULT_LAT, LOCATION_DEFAULT_LNG)
resolve({ lat: LOCATION_DEFAULT_LAT, lng: LOCATION_DEFAULT_LNG })
}
})
})
}