feat(AdPage): 添加网络错误弹窗及降级图片处理逻辑
当广告图片加载失败时显示网络错误弹窗,并提供操作指引 初始化时使用默认图片作为降级方案,优化错误处理流程
Showing
2 changed files
with
186 additions
and
17 deletions
| ... | @@ -43,6 +43,106 @@ | ... | @@ -43,6 +43,106 @@ |
| 43 | } | 43 | } |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | +/* 网络错误弹窗样式 */ | ||
| 47 | +.network-error-popup { | ||
| 48 | + position: fixed; | ||
| 49 | + top: 0; | ||
| 50 | + left: 0; | ||
| 51 | + width: 100vw; | ||
| 52 | + height: 100vh; | ||
| 53 | + z-index: 1000; | ||
| 54 | + display: flex; | ||
| 55 | + align-items: center; | ||
| 56 | + justify-content: center; | ||
| 57 | + | ||
| 58 | + .popup-overlay { | ||
| 59 | + position: absolute; | ||
| 60 | + top: 0; | ||
| 61 | + left: 0; | ||
| 62 | + width: 100%; | ||
| 63 | + height: 100%; | ||
| 64 | + background: rgba(0, 0, 0, 0.5); | ||
| 65 | + backdrop-filter: blur(4rpx); | ||
| 66 | + -webkit-backdrop-filter: blur(4rpx); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + .popup-content { | ||
| 70 | + position: relative; | ||
| 71 | + width: 600rpx; | ||
| 72 | + background: white; | ||
| 73 | + border-radius: 24rpx; | ||
| 74 | + padding: 60rpx 40rpx 40rpx; | ||
| 75 | + text-align: center; | ||
| 76 | + box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.15); | ||
| 77 | + | ||
| 78 | + .popup-icon { | ||
| 79 | + font-size: 80rpx; | ||
| 80 | + margin-bottom: 20rpx; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + .popup-title { | ||
| 84 | + font-size: 36rpx; | ||
| 85 | + font-weight: 600; | ||
| 86 | + color: #333; | ||
| 87 | + margin-bottom: 20rpx; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + .popup-message { | ||
| 91 | + font-size: 28rpx; | ||
| 92 | + color: #666; | ||
| 93 | + line-height: 1.5; | ||
| 94 | + margin-bottom: 30rpx; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + .popup-steps { | ||
| 98 | + text-align: left; | ||
| 99 | + margin-bottom: 40rpx; | ||
| 100 | + | ||
| 101 | + .step-item { | ||
| 102 | + font-size: 26rpx; | ||
| 103 | + color: #888; | ||
| 104 | + line-height: 1.6; | ||
| 105 | + margin-bottom: 10rpx; | ||
| 106 | + padding-left: 20rpx; | ||
| 107 | + } | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + .popup-buttons { | ||
| 111 | + display: flex; | ||
| 112 | + gap: 20rpx; | ||
| 113 | + | ||
| 114 | + .popup-button { | ||
| 115 | + flex: 1; | ||
| 116 | + height: 80rpx; | ||
| 117 | + line-height: 80rpx; | ||
| 118 | + text-align: center; | ||
| 119 | + border-radius: 12rpx; | ||
| 120 | + font-size: 28rpx; | ||
| 121 | + font-weight: 500; | ||
| 122 | + transition: all 0.3s ease; | ||
| 123 | + | ||
| 124 | + &.cancel { | ||
| 125 | + background: #f5f5f5; | ||
| 126 | + color: #666; | ||
| 127 | + | ||
| 128 | + &:active { | ||
| 129 | + background: #e8e8e8; | ||
| 130 | + } | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + &.confirm { | ||
| 134 | + background: #ff6b35; | ||
| 135 | + color: white; | ||
| 136 | + | ||
| 137 | + &:active { | ||
| 138 | + background: #e55a2b; | ||
| 139 | + } | ||
| 140 | + } | ||
| 141 | + } | ||
| 142 | + } | ||
| 143 | + } | ||
| 144 | +} | ||
| 145 | + | ||
| 46 | .loading-container { | 146 | .loading-container { |
| 47 | position: absolute; | 147 | position: absolute; |
| 48 | top: 0; | 148 | top: 0; | ... | ... |
| 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-28 14:03:53 | 4 | + * @LastEditTime: 2025-09-28 14:08:23 |
| 5 | * @FilePath: /lls_program/src/pages/AdPage/index.vue | 5 | * @FilePath: /lls_program/src/pages/AdPage/index.vue |
| 6 | * @Description: 广告页面 | 6 | * @Description: 广告页面 |
| 7 | --> | 7 | --> |
| ... | @@ -36,7 +36,7 @@ | ... | @@ -36,7 +36,7 @@ |
| 36 | <!-- 背景图片 --> | 36 | <!-- 背景图片 --> |
| 37 | <image | 37 | <image |
| 38 | v-show="!imageLoading && !imageLoadError" | 38 | v-show="!imageLoading && !imageLoadError" |
| 39 | - :src="adImageUrl || defaultAdImage" | 39 | + :src="adImageUrl" |
| 40 | class="ad-background" | 40 | class="ad-background" |
| 41 | mode="scaleToFill" | 41 | mode="scaleToFill" |
| 42 | @tap="handleImageClick" | 42 | @tap="handleImageClick" |
| ... | @@ -64,6 +64,30 @@ | ... | @@ -64,6 +64,30 @@ |
| 64 | <view v-if="loading" class="loading-container"> | 64 | <view v-if="loading" class="loading-container"> |
| 65 | <view class="loading-text">加载中...</view> | 65 | <view class="loading-text">加载中...</view> |
| 66 | </view> | 66 | </view> |
| 67 | + | ||
| 68 | + <!-- 网络错误提示弹窗 --> | ||
| 69 | + <view v-if="showNetworkErrorPopup" class="network-error-popup"> | ||
| 70 | + <view class="popup-overlay" @tap="closeNetworkErrorPopup"></view> | ||
| 71 | + <view class="popup-content"> | ||
| 72 | + <view class="popup-icon">⚠️</view> | ||
| 73 | + <view class="popup-title">网络不稳定</view> | ||
| 74 | + <view class="popup-message"> | ||
| 75 | + 当前网络连接不稳定,建议您: | ||
| 76 | + </view> | ||
| 77 | + <view class="popup-steps"> | ||
| 78 | + <view class="step-item">1. 检查网络连接</view> | ||
| 79 | + <view class="step-item">2. 删除小程序后重新进入</view> | ||
| 80 | + </view> | ||
| 81 | + <view class="popup-buttons"> | ||
| 82 | + <view class="popup-button cancel" @tap="closeNetworkErrorPopup"> | ||
| 83 | + 我知道了 | ||
| 84 | + </view> | ||
| 85 | + <view class="popup-button confirm" @tap="deleteAndReenter"> | ||
| 86 | + 删除重进 | ||
| 87 | + </view> | ||
| 88 | + </view> | ||
| 89 | + </view> | ||
| 90 | + </view> | ||
| 67 | </view> | 91 | </view> |
| 68 | </template> | 92 | </template> |
| 69 | 93 | ||
| ... | @@ -79,7 +103,7 @@ import "./index.less"; | ... | @@ -79,7 +103,7 @@ import "./index.less"; |
| 79 | const defaultAdImage = 'https://cdn.ipadbiz.cn/space_34093/%E5%BC%95%E5%AF%BC%E9%A1%B51_Fu2ZY_Tm6TL1OzbyrqQkeVRAdVfU.jpg?imageMogr2/strip/quality/60'; | 103 | const defaultAdImage = 'https://cdn.ipadbiz.cn/space_34093/%E5%BC%95%E5%AF%BC%E9%A1%B51_Fu2ZY_Tm6TL1OzbyrqQkeVRAdVfU.jpg?imageMogr2/strip/quality/60'; |
| 80 | 104 | ||
| 81 | // 定义响应式数据 | 105 | // 定义响应式数据 |
| 82 | -const adImageUrl = ref(''); | 106 | +const adImageUrl = ref(defaultAdImage); // 初始化为默认图片 |
| 83 | const loading = ref(true); | 107 | const loading = ref(true); |
| 84 | const hasFamily = ref(false); | 108 | const hasFamily = ref(false); |
| 85 | const imageLoading = ref(true); // 图片加载状态 | 109 | const imageLoading = ref(true); // 图片加载状态 |
| ... | @@ -89,6 +113,8 @@ const retryCount = ref(0); // 重试次数 | ... | @@ -89,6 +113,8 @@ const retryCount = ref(0); // 重试次数 |
| 89 | const maxRetries = ref(3); // 最大重试次数 | 113 | const maxRetries = ref(3); // 最大重试次数 |
| 90 | const isTimeout = ref(false); // 是否超时 | 114 | const isTimeout = ref(false); // 是否超时 |
| 91 | const showManualRefresh = ref(false); // 是否显示手动刷新按钮 | 115 | const showManualRefresh = ref(false); // 是否显示手动刷新按钮 |
| 116 | +const showNetworkErrorPopup = ref(false); // 是否显示网络错误弹窗 | ||
| 117 | +const useFallbackImage = ref(false); // 是否使用降级图片 | ||
| 92 | 118 | ||
| 93 | /** | 119 | /** |
| 94 | * 获取广告配置 | 120 | * 获取广告配置 |
| ... | @@ -96,12 +122,42 @@ const showManualRefresh = ref(false); // 是否显示手动刷新按钮 | ... | @@ -96,12 +122,42 @@ const showManualRefresh = ref(false); // 是否显示手动刷新按钮 |
| 96 | const fetchAdConfig = async () => { | 122 | const fetchAdConfig = async () => { |
| 97 | try { | 123 | try { |
| 98 | const { code, data } = await getBootPageAPI(); | 124 | const { code, data } = await getBootPageAPI(); |
| 99 | - if (code && data) { | 125 | + if (code && data && data.adImageUrl) { |
| 100 | adImageUrl.value = data.adImageUrl; | 126 | adImageUrl.value = data.adImageUrl; |
| 127 | + useFallbackImage.value = false; | ||
| 128 | + return true; | ||
| 129 | + } else { | ||
| 130 | + throw new Error('广告配置数据无效'); | ||
| 101 | } | 131 | } |
| 102 | } catch (error) { | 132 | } catch (error) { |
| 103 | console.error('获取广告配置失败:', error); | 133 | console.error('获取广告配置失败:', error); |
| 134 | + // 使用降级图片 | ||
| 135 | + adImageUrl.value = defaultAdImage; | ||
| 136 | + useFallbackImage.value = true; | ||
| 137 | + throw error; | ||
| 138 | + } | ||
| 139 | +}; | ||
| 140 | + | ||
| 141 | +/** | ||
| 142 | + * 关闭网络错误弹窗 | ||
| 143 | + */ | ||
| 144 | +const closeNetworkErrorPopup = () => { | ||
| 145 | + showNetworkErrorPopup.value = false; | ||
| 146 | +}; | ||
| 147 | + | ||
| 148 | +/** | ||
| 149 | + * 删除小程序并重新进入的提示 | ||
| 150 | + */ | ||
| 151 | +const deleteAndReenter = () => { | ||
| 152 | + Taro.showModal({ | ||
| 153 | + title: '操作提示', | ||
| 154 | + content: '请按以下步骤操作:\n1. 点击右上角"..."菜单\n2. 选择"删除"小程序\n3. 重新搜索进入小程序', | ||
| 155 | + showCancel: false, | ||
| 156 | + confirmText: '我知道了', | ||
| 157 | + success: () => { | ||
| 158 | + closeNetworkErrorPopup(); | ||
| 104 | } | 159 | } |
| 160 | + }); | ||
| 105 | }; | 161 | }; |
| 106 | 162 | ||
| 107 | /** | 163 | /** |
| ... | @@ -238,12 +294,20 @@ const handleLoadingTimeout = () => { | ... | @@ -238,12 +294,20 @@ const handleLoadingTimeout = () => { |
| 238 | retryLoadImage(); | 294 | retryLoadImage(); |
| 239 | }, 1000); | 295 | }, 1000); |
| 240 | } else { | 296 | } else { |
| 241 | - // 超过最大重试次数,显示手动刷新选项 | 297 | + // 超过最大重试次数 |
| 242 | imageLoading.value = false; | 298 | imageLoading.value = false; |
| 243 | loading.value = false; | 299 | loading.value = false; |
| 300 | + | ||
| 301 | + // 如果使用的是降级图片,显示网络错误弹窗 | ||
| 302 | + if (useFallbackImage.value) { | ||
| 303 | + showNetworkErrorPopup.value = true; | ||
| 304 | + console.log('使用降级图片,显示网络错误提示'); | ||
| 305 | + } else { | ||
| 306 | + // 否则显示手动刷新选项 | ||
| 244 | showManualRefresh.value = true; | 307 | showManualRefresh.value = true; |
| 245 | console.error('图片加载失败,已达到最大重试次数'); | 308 | console.error('图片加载失败,已达到最大重试次数'); |
| 246 | } | 309 | } |
| 310 | + } | ||
| 247 | }; | 311 | }; |
| 248 | 312 | ||
| 249 | /** | 313 | /** |
| ... | @@ -276,43 +340,48 @@ const initializePage = async () => { | ... | @@ -276,43 +340,48 @@ const initializePage = async () => { |
| 276 | await fetchAdConfig(); | 340 | await fetchAdConfig(); |
| 277 | adConfigSuccess = true; | 341 | adConfigSuccess = true; |
| 278 | } catch (adError) { | 342 | } catch (adError) { |
| 279 | - console.error('获取广告配置失败,但继续执行后续逻辑:', adError); | 343 | + console.error('获取广告配置失败,使用降级图片:', adError); |
| 344 | + adConfigSuccess = false; // 使用降级图片也算是一种"成功" | ||
| 280 | } | 345 | } |
| 281 | 346 | ||
| 282 | // 无论广告配置是否成功,都要检查家庭状态 | 347 | // 无论广告配置是否成功,都要检查家庭状态 |
| 283 | try { | 348 | try { |
| 284 | await checkUserFamily(); | 349 | await checkUserFamily(); |
| 285 | 350 | ||
| 286 | - // 如果家庭状态检查成功,但广告配置失败了,再次尝试获取广告配置 | 351 | + // 如果广告配置失败了(使用降级图片),再次尝试获取广告配置 |
| 287 | if (!adConfigSuccess) { | 352 | if (!adConfigSuccess) { |
| 288 | try { | 353 | try { |
| 289 | await fetchAdConfig(); | 354 | await fetchAdConfig(); |
| 290 | adConfigSuccess = true; | 355 | adConfigSuccess = true; |
| 291 | console.log('重试获取广告配置成功'); | 356 | console.log('重试获取广告配置成功'); |
| 292 | } catch (retryError) { | 357 | } catch (retryError) { |
| 293 | - console.error('重试获取广告配置仍然失败:', retryError); | 358 | + console.error('重试获取广告配置仍然失败,继续使用降级图片:', retryError); |
| 294 | } | 359 | } |
| 295 | } | 360 | } |
| 296 | 361 | ||
| 297 | - // 如果广告配置成功,清除超时定时器并设置成功状态 | 362 | + // 清除超时定时器并设置成功状态 |
| 298 | - if (adConfigSuccess) { | ||
| 299 | clearLoadingTimeout(); | 363 | clearLoadingTimeout(); |
| 300 | imageLoading.value = false; | 364 | imageLoading.value = false; |
| 301 | imageLoadError.value = false; | 365 | imageLoadError.value = false; |
| 302 | - } else { | 366 | + |
| 303 | - // 广告配置失败,触发重试逻辑 | 367 | + // 如果最终还是使用降级图片,显示网络错误提示 |
| 304 | - imageLoadError.value = true; | 368 | + if (useFallbackImage.value) { |
| 305 | - handleLoadingTimeout(); | 369 | + setTimeout(() => { |
| 370 | + showNetworkErrorPopup.value = true; | ||
| 371 | + }, 1000); // 延迟1秒显示,让用户先看到页面 | ||
| 306 | } | 372 | } |
| 307 | 373 | ||
| 308 | } catch (familyError) { | 374 | } catch (familyError) { |
| 309 | console.error('检查家庭状态失败:', familyError); | 375 | console.error('检查家庭状态失败:', familyError); |
| 310 | // 家庭状态检查失败,但仍然尝试显示广告 | 376 | // 家庭状态检查失败,但仍然尝试显示广告 |
| 311 | - if (adConfigSuccess) { | ||
| 312 | clearLoadingTimeout(); | 377 | clearLoadingTimeout(); |
| 313 | imageLoading.value = false; | 378 | imageLoading.value = false; |
| 314 | - } else { | 379 | + |
| 315 | - handleLoadingTimeout(); | 380 | + // 如果使用降级图片,显示网络错误提示 |
| 381 | + if (useFallbackImage.value) { | ||
| 382 | + setTimeout(() => { | ||
| 383 | + showNetworkErrorPopup.value = true; | ||
| 384 | + }, 1000); | ||
| 316 | } | 385 | } |
| 317 | } | 386 | } |
| 318 | } catch (error) { | 387 | } catch (error) { | ... | ... |
-
Please register or login to post a comment