hookehuyr

fix(WeRunAuth): 修复授权状态初始显示问题并添加自动检查控制

refactor(ActivitiesCover): 优化定位授权流程和错误处理

- 将WeRunAuth组件初始状态设为null避免闪烁
- 添加auto-check prop控制自动授权检查
- 重构ActivitiesCover定位逻辑,仅在用户操作时请求授权
- 增加定位超时和失败的错误处理
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"
......