fix(WeRunAuth): 修复授权状态初始显示问题并添加自动检查控制
refactor(ActivitiesCover): 优化定位授权流程和错误处理 - 将WeRunAuth组件初始状态设为null避免闪烁 - 添加auto-check prop控制自动授权检查 - 重构ActivitiesCover定位逻辑,仅在用户操作时请求授权 - 增加定位超时和失败的错误处理
Showing
3 changed files
with
93 additions
and
21 deletions
| 1 | <template> | 1 | <template> |
| 2 | <view class="werun-auth-container"> | 2 | <view class="werun-auth-container"> |
| 3 | <!-- 未授权状态 --> | 3 | <!-- 未授权状态 --> |
| 4 | - <view v-if="!isAuthorized" class="auth-prompt"> | 4 | + <view v-if="isAuthorized === false" class="auth-prompt"> |
| 5 | <view class="px-5 py-6 bg-white rounded-xl shadow-md mx-4 mt-4"> | 5 | <view class="px-5 py-6 bg-white rounded-xl shadow-md mx-4 mt-4"> |
| 6 | <view class="flex flex-col items-center justify-center py-8"> | 6 | <view class="flex flex-col items-center justify-center py-8"> |
| 7 | <!-- <view class="mb-4"> | 7 | <!-- <view class="mb-4"> |
| ... | @@ -32,24 +32,38 @@ | ... | @@ -32,24 +32,38 @@ |
| 32 | </view> | 32 | </view> |
| 33 | 33 | ||
| 34 | <!-- 已授权状态 - 显示步数相关内容 --> | 34 | <!-- 已授权状态 - 显示步数相关内容 --> |
| 35 | - <view v-else> | 35 | + <view v-else-if="isAuthorized === true"> |
| 36 | <slot :isLoading="isLoading" /> | 36 | <slot :isLoading="isLoading" /> |
| 37 | </view> | 37 | </view> |
| 38 | + | ||
| 39 | + <!-- 初始状态或检查中 - 不显示任何内容,避免闪烁 --> | ||
| 40 | + <view v-else> | ||
| 41 | + <slot :isLoading="true" /> | ||
| 42 | + </view> | ||
| 38 | </view> | 43 | </view> |
| 39 | </template> | 44 | </template> |
| 40 | 45 | ||
| 41 | <script setup> | 46 | <script setup> |
| 42 | -import { ref, onMounted, defineEmits } from 'vue' | 47 | +import { ref, onMounted, defineEmits, defineProps } from 'vue' |
| 43 | import Taro from '@tarojs/taro' | 48 | import Taro from '@tarojs/taro' |
| 44 | 49 | ||
| 45 | // import { syncWxStepAPI } from '@/api/points' | 50 | // import { syncWxStepAPI } from '@/api/points' |
| 46 | import { fetch } from '@/api/fn' | 51 | import { fetch } from '@/api/fn' |
| 47 | 52 | ||
| 53 | +// 定义props | ||
| 54 | +const props = defineProps({ | ||
| 55 | + // 是否自动检查授权状态,默认为false,避免页面加载时立即显示授权提示 | ||
| 56 | + autoCheck: { | ||
| 57 | + type: Boolean, | ||
| 58 | + default: false | ||
| 59 | + } | ||
| 60 | +}) | ||
| 61 | + | ||
| 48 | // 定义事件 | 62 | // 定义事件 |
| 49 | const emit = defineEmits(['auth-change', 'steps-update', 'steps-synced', 'sync-failed']) | 63 | const emit = defineEmits(['auth-change', 'steps-update', 'steps-synced', 'sync-failed']) |
| 50 | 64 | ||
| 51 | // 响应式数据 | 65 | // 响应式数据 |
| 52 | -const isAuthorized = ref(false) | 66 | +const isAuthorized = ref(null) // 初始值为null,避免未检查前显示未授权状态 |
| 53 | const isLoading = ref(false) | 67 | const isLoading = ref(false) |
| 54 | const showManualUpdate = ref(false) | 68 | const showManualUpdate = ref(false) |
| 55 | 69 | ||
| ... | @@ -73,6 +87,7 @@ const checkAuthStatus = async (shouldGetData = false) => { | ... | @@ -73,6 +87,7 @@ const checkAuthStatus = async (shouldGetData = false) => { |
| 73 | } | 87 | } |
| 74 | } catch (error) { | 88 | } catch (error) { |
| 75 | console.error('检查授权状态失败:', error) | 89 | console.error('检查授权状态失败:', error) |
| 90 | + // 检查失败时设置为false,表示未授权 | ||
| 76 | isAuthorized.value = false | 91 | isAuthorized.value = false |
| 77 | emit('auth-change', false) | 92 | emit('auth-change', false) |
| 78 | } | 93 | } |
| ... | @@ -220,9 +235,11 @@ defineExpose({ | ... | @@ -220,9 +235,11 @@ defineExpose({ |
| 220 | showManualUpdate | 235 | showManualUpdate |
| 221 | }) | 236 | }) |
| 222 | 237 | ||
| 223 | -// 组件挂载时检查授权状态,但不获取步数数据 | 238 | +// 组件挂载时根据props决定是否检查授权状态 |
| 224 | onMounted(() => { | 239 | onMounted(() => { |
| 240 | + if (props.autoCheck) { | ||
| 225 | checkAuthStatus(false) | 241 | checkAuthStatus(false) |
| 242 | + } | ||
| 226 | }) | 243 | }) |
| 227 | </script> | 244 | </script> |
| 228 | 245 | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2022-09-19 14:11:06 | 2 | * @Date: 2022-09-19 14:11:06 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-09-06 00:22:56 | 4 | + * @LastEditTime: 2025-09-06 00:32:56 |
| 5 | * @FilePath: /lls_program/src/pages/ActivitiesCover/index.vue | 5 | * @FilePath: /lls_program/src/pages/ActivitiesCover/index.vue |
| 6 | * @Description: 活动海报页面 - 展示活动信息并处理定位授权 | 6 | * @Description: 活动海报页面 - 展示活动信息并处理定位授权 |
| 7 | --> | 7 | --> |
| ... | @@ -24,8 +24,8 @@ | ... | @@ -24,8 +24,8 @@ |
| 24 | 24 | ||
| 25 | <!-- 底部按钮区域 --> | 25 | <!-- 底部按钮区域 --> |
| 26 | <view class="bottom-section"> | 26 | <view class="bottom-section"> |
| 27 | - <!-- 未授权定位提示 --> | 27 | + <!-- 未授权定位提示 - 仅在用户点击参加活动且未授权时显示 --> |
| 28 | - <view v-if="!hasLocationAuth && !locationError" class="location-tip" @click="retryGetLocation"> | 28 | + <view v-if="showLocationPrompt && !hasLocationAuth && !locationError" class="location-tip" @click="retryGetLocation"> |
| 29 | <view class="tip-content"> | 29 | <view class="tip-content"> |
| 30 | <view class="tip-icon">📍</view> | 30 | <view class="tip-icon">📍</view> |
| 31 | <view class="tip-text">需要获取您的位置信息来参与活动</view> | 31 | <view class="tip-text">需要获取您的位置信息来参与活动</view> |
| ... | @@ -116,6 +116,7 @@ const locationError = ref(false) // 位置获取是否失败 | ... | @@ -116,6 +116,7 @@ const locationError = ref(false) // 位置获取是否失败 |
| 116 | const isJoining = ref(false) // 是否正在加入活动 | 116 | const isJoining = ref(false) // 是否正在加入活动 |
| 117 | const userLocation = ref({ lng: null, lat: null }) // 用户位置信息 | 117 | const userLocation = ref({ lng: null, lat: null }) // 用户位置信息 |
| 118 | const hasJoinedFamily = ref(false); | 118 | const hasJoinedFamily = ref(false); |
| 119 | +const showLocationPrompt = ref(false) // 是否显示定位权限提示 | ||
| 119 | 120 | ||
| 120 | // 海报生成相关状态 | 121 | // 海报生成相关状态 |
| 121 | const show_post = ref(false) // 显示海报预览 | 122 | const show_post = ref(false) // 显示海报预览 |
| ... | @@ -171,12 +172,14 @@ const checkLocationAuth = async () => { | ... | @@ -171,12 +172,14 @@ const checkLocationAuth = async () => { |
| 171 | 172 | ||
| 172 | /** | 173 | /** |
| 173 | * 获取用户位置信息 | 174 | * 获取用户位置信息 |
| 175 | + * @param {boolean} skipAuthCheck - 是否跳过授权检查(当调用方已经检查过授权状态时) | ||
| 174 | */ | 176 | */ |
| 175 | -const getUserLocation = async () => { | 177 | +const getUserLocation = async (skipAuthCheck = false) => { |
| 176 | try { | 178 | try { |
| 177 | locationError.value = false // 重置错误状态 | 179 | locationError.value = false // 重置错误状态 |
| 178 | 180 | ||
| 179 | - // 检查是否已有位置权限 | 181 | + // 如果没有跳过授权检查,则检查权限状态 |
| 182 | + if (!skipAuthCheck) { | ||
| 180 | const authSetting = await Taro.getSetting() | 183 | const authSetting = await Taro.getSetting() |
| 181 | const hasLocationAuth = authSetting.authSetting['scope.userLocation'] | 184 | const hasLocationAuth = authSetting.authSetting['scope.userLocation'] |
| 182 | 185 | ||
| ... | @@ -197,9 +200,13 @@ const getUserLocation = async () => { | ... | @@ -197,9 +200,13 @@ const getUserLocation = async () => { |
| 197 | return false | 200 | return false |
| 198 | } | 201 | } |
| 199 | } | 202 | } |
| 203 | + } | ||
| 200 | 204 | ||
| 201 | const location = await Taro.getLocation({ | 205 | const location = await Taro.getLocation({ |
| 202 | - type: 'gcj02' | 206 | + type: 'gcj02', |
| 207 | + altitude: false, // 不需要海拔信息,提高获取速度 | ||
| 208 | + isHighAccuracy: true, // 开启高精度定位 | ||
| 209 | + highAccuracyExpireTime: 4000 // 高精度定位超时时间 | ||
| 203 | }) | 210 | }) |
| 204 | 211 | ||
| 205 | userLocation.value = { | 212 | userLocation.value = { |
| ... | @@ -208,6 +215,9 @@ const getUserLocation = async () => { | ... | @@ -208,6 +215,9 @@ const getUserLocation = async () => { |
| 208 | } | 215 | } |
| 209 | 216 | ||
| 210 | console.log('获取到用户位置:', userLocation.value) | 217 | console.log('获取到用户位置:', userLocation.value) |
| 218 | + // 获取位置成功后隐藏提示 | ||
| 219 | + showLocationPrompt.value = false | ||
| 220 | + hasLocationAuth.value = true | ||
| 211 | return true | 221 | return true |
| 212 | } catch (error) { | 222 | } catch (error) { |
| 213 | console.error('获取位置失败:', error) | 223 | console.error('获取位置失败:', error) |
| ... | @@ -226,11 +236,28 @@ const getUserLocation = async () => { | ... | @@ -226,11 +236,28 @@ const getUserLocation = async () => { |
| 226 | } | 236 | } |
| 227 | } | 237 | } |
| 228 | }) | 238 | }) |
| 239 | + } else if (error.errMsg && error.errMsg.includes('timeout')) { | ||
| 240 | + // 定位超时 | ||
| 241 | + locationError.value = true | ||
| 242 | + Taro.showToast({ | ||
| 243 | + title: '定位超时,请检查网络或GPS', | ||
| 244 | + icon: 'none', | ||
| 245 | + duration: 3000 | ||
| 246 | + }) | ||
| 247 | + } else if (error.errMsg && error.errMsg.includes('fail')) { | ||
| 248 | + // 定位失败,可能是GPS关闭或网络问题 | ||
| 249 | + locationError.value = true | ||
| 250 | + await Taro.showModal({ | ||
| 251 | + title: '定位失败', | ||
| 252 | + content: '请确保已开启GPS定位服务,并检查网络连接是否正常', | ||
| 253 | + showCancel: false, | ||
| 254 | + confirmText: '我知道了' | ||
| 255 | + }) | ||
| 229 | } else { | 256 | } else { |
| 230 | - // 网络或其他问题导致的获取失败 | 257 | + // 其他未知错误 |
| 231 | locationError.value = true | 258 | locationError.value = true |
| 232 | Taro.showToast({ | 259 | Taro.showToast({ |
| 233 | - title: '获取位置失败', | 260 | + title: '获取位置失败,请重试', |
| 234 | icon: 'none' | 261 | icon: 'none' |
| 235 | }) | 262 | }) |
| 236 | } | 263 | } |
| ... | @@ -269,7 +296,7 @@ const checkFamilyStatusAndJoinActivity = async () => { | ... | @@ -269,7 +296,7 @@ const checkFamilyStatusAndJoinActivity = async () => { |
| 269 | */ | 296 | */ |
| 270 | const retryGetLocation = async () => { | 297 | const retryGetLocation = async () => { |
| 271 | try { | 298 | try { |
| 272 | - const success = await getUserLocation() | 299 | + const success = await getUserLocation(false) // 不跳过授权检查,重新处理授权逻辑 |
| 273 | if (success) { | 300 | if (success) { |
| 274 | hasLocationAuth.value = true | 301 | hasLocationAuth.value = true |
| 275 | locationError.value = false | 302 | locationError.value = false |
| ... | @@ -290,17 +317,45 @@ const handleJoinActivity = async () => { | ... | @@ -290,17 +317,45 @@ const handleJoinActivity = async () => { |
| 290 | isJoining.value = true | 317 | isJoining.value = true |
| 291 | 318 | ||
| 292 | try { | 319 | try { |
| 293 | - // 如果没有定位授权,先获取授权和位置信息 | 320 | + // 首先检查用户是否已加入家庭 |
| 294 | - if (!hasLocationAuth.value) { | 321 | + if (!hasJoinedFamily.value) { |
| 295 | - const success = await getUserLocation() | 322 | + Taro.showModal({ |
| 323 | + title: '提示', | ||
| 324 | + content: '没有加入家庭是无法参加活动的', | ||
| 325 | + cancelText: '关闭', | ||
| 326 | + confirmText: '前往加入', | ||
| 327 | + success: (res) => { | ||
| 328 | + if (res.confirm) { | ||
| 329 | + Taro.navigateTo({ | ||
| 330 | + url: '/pages/Welcome/index', | ||
| 331 | + }); | ||
| 332 | + } | ||
| 333 | + }, | ||
| 334 | + }); | ||
| 335 | + isJoining.value = false | ||
| 336 | + return | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + // 检查定位授权状态 | ||
| 340 | + const authSetting = await Taro.getSetting() | ||
| 341 | + const hasLocationPermission = authSetting.authSetting['scope.userLocation'] | ||
| 342 | + | ||
| 343 | + if (hasLocationPermission === false) { | ||
| 344 | + // 用户之前拒绝过授权,显示提示让用户手动开启 | ||
| 345 | + showLocationPrompt.value = true | ||
| 346 | + isJoining.value = false | ||
| 347 | + return | ||
| 348 | + } else if (hasLocationPermission === undefined) { | ||
| 349 | + // 未请求过授权,直接尝试获取位置(会触发授权弹窗) | ||
| 350 | + const success = await getUserLocation(false) // 不跳过授权检查,让getUserLocation处理授权逻辑 | ||
| 296 | if (!success) { | 351 | if (!success) { |
| 352 | + showLocationPrompt.value = true | ||
| 297 | isJoining.value = false | 353 | isJoining.value = false |
| 298 | return | 354 | return |
| 299 | } | 355 | } |
| 300 | - hasLocationAuth.value = true | ||
| 301 | } else { | 356 | } else { |
| 302 | // 已有授权,直接获取位置 | 357 | // 已有授权,直接获取位置 |
| 303 | - const success = await getUserLocation() | 358 | + const success = await getUserLocation(true) // 跳过授权检查,直接获取位置 |
| 304 | if (!success) { | 359 | if (!success) { |
| 305 | isJoining.value = false | 360 | isJoining.value = false |
| 306 | return | 361 | return |
| ... | @@ -678,8 +733,7 @@ const initPageData = async () => { | ... | @@ -678,8 +733,7 @@ const initPageData = async () => { |
| 678 | hasJoinedFamily.value = true | 733 | hasJoinedFamily.value = true |
| 679 | } | 734 | } |
| 680 | } | 735 | } |
| 681 | - // 检查定位授权弹窗 | 736 | + // 移除页面初始化时的定位权限检查,改为在用户点击参加活动时检查 |
| 682 | - checkLocationAuth() | ||
| 683 | } | 737 | } |
| 684 | 738 | ||
| 685 | // 处理页面加载时的授权检查 | 739 | // 处理页面加载时的授权检查 | ... | ... |
| ... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
| 16 | <!-- 微信步数授权组件 --> | 16 | <!-- 微信步数授权组件 --> |
| 17 | <WeRunAuth | 17 | <WeRunAuth |
| 18 | ref="weRunAuthRef" | 18 | ref="weRunAuthRef" |
| 19 | + :auto-check="false" | ||
| 19 | @auth-change="handleAuthChange" | 20 | @auth-change="handleAuthChange" |
| 20 | @steps-synced="handleStepsSynced" | 21 | @steps-synced="handleStepsSynced" |
| 21 | @sync-failed="handleSyncFailed" | 22 | @sync-failed="handleSyncFailed" | ... | ... |
-
Please register or login to post a comment