hookehuyr

feat(AdPage): 添加手动刷新功能和加载超时处理

添加手动刷新UI组件和加载超时处理逻辑,当图片加载失败或超时时显示刷新选项
支持自动重试机制,超过最大重试次数后显示手动刷新按钮
...@@ -148,6 +148,86 @@ ...@@ -148,6 +148,86 @@
148 } 148 }
149 } 149 }
150 150
151 + // 手动刷新样式
152 + .manual-refresh-container {
153 + position: absolute;
154 + top: 0;
155 + left: 0;
156 + width: 100%;
157 + height: 100vh;
158 + display: flex;
159 + justify-content: center;
160 + align-items: center;
161 + background-color: #f8f9fa;
162 + z-index: 2;
163 + }
164 +
165 + .refresh-content {
166 + text-align: center;
167 + padding: 60rpx 40rpx;
168 + background: white;
169 + border-radius: 16rpx;
170 + box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1);
171 + margin: 0 40rpx;
172 + max-width: 600rpx;
173 + }
174 +
175 + .refresh-icon {
176 + font-size: 80rpx;
177 + margin-bottom: 24rpx;
178 + }
179 +
180 + .refresh-title {
181 + font-size: 36rpx;
182 + font-weight: 600;
183 + color: #333;
184 + margin-bottom: 16rpx;
185 + }
186 +
187 + .refresh-subtitle {
188 + font-size: 28rpx;
189 + color: #666;
190 + margin-bottom: 40rpx;
191 + line-height: 1.5;
192 + }
193 +
194 + .refresh-buttons {
195 + display: flex;
196 + gap: 20rpx;
197 + justify-content: center;
198 + }
199 +
200 + .refresh-button {
201 + flex: 1;
202 + padding: 24rpx 32rpx;
203 + background: linear-gradient(135deg, #007aff, #0056cc);
204 + color: white;
205 + border-radius: 12rpx;
206 + font-size: 32rpx;
207 + font-weight: 600;
208 + text-align: center;
209 +
210 + &:active {
211 + background: linear-gradient(135deg, #0056cc, #003d99);
212 + transform: scale(0.98);
213 + }
214 + }
215 +
216 + .retry-button-small {
217 + flex: 1;
218 + padding: 24rpx 32rpx;
219 + background: #f0f0f0;
220 + color: #666;
221 + border-radius: 12rpx;
222 + font-size: 32rpx;
223 + text-align: center;
224 +
225 + &:active {
226 + background: #e0e0e0;
227 + transform: scale(0.98);
228 + }
229 + }
230 +
151 // 错误提示样式 231 // 错误提示样式
152 .error-container { 232 .error-container {
153 position: absolute; 233 position: absolute;
......
...@@ -12,12 +12,27 @@ ...@@ -12,12 +12,27 @@
12 <view class="skeleton-image"> 12 <view class="skeleton-image">
13 <view class="skeleton-shimmer"></view> 13 <view class="skeleton-shimmer"></view>
14 <view class="skeleton-text"> 14 <view class="skeleton-text">
15 - <view class="loading-title">正在加载精彩内容</view> 15 + <view class="loading-title">
16 + {{ retryCount > 0 ? `正在重试加载 (${retryCount}/${maxRetries})` : '正在加载精彩内容' }}
17 + </view>
16 <view class="loading-subtitle">请稍候...</view> 18 <view class="loading-subtitle">请稍候...</view>
17 </view> 19 </view>
18 </view> 20 </view>
19 </view> 21 </view>
20 22
23 + <!-- 手动刷新提示 -->
24 + <view v-if="showManualRefresh" class="manual-refresh-container">
25 + <view class="refresh-content">
26 + <view class="refresh-icon">⚠️</view>
27 + <view class="refresh-title">加载遇到问题</view>
28 + <view class="refresh-subtitle">网络可能不稳定,请尝试刷新页面</view>
29 + <view class="refresh-buttons">
30 + <view class="refresh-button" @tap="manualRefresh">刷新页面</view>
31 + <view class="retry-button-small" @tap="retryLoadImage">重试</view>
32 + </view>
33 + </view>
34 + </view>
35 +
21 <!-- 背景图片 --> 36 <!-- 背景图片 -->
22 <image 37 <image
23 v-show="!imageLoading && !imageLoadError" 38 v-show="!imageLoading && !imageLoadError"
...@@ -66,6 +81,11 @@ const loading = ref(true); ...@@ -66,6 +81,11 @@ const loading = ref(true);
66 const hasFamily = ref(false); 81 const hasFamily = ref(false);
67 const imageLoading = ref(true); // 图片加载状态 82 const imageLoading = ref(true); // 图片加载状态
68 const imageLoadError = ref(false); // 图片加载错误状态 83 const imageLoadError = ref(false); // 图片加载错误状态
84 +const loadingTimeout = ref(null); // 加载超时定时器
85 +const retryCount = ref(0); // 重试次数
86 +const maxRetries = ref(3); // 最大重试次数
87 +const isTimeout = ref(false); // 是否超时
88 +const showManualRefresh = ref(false); // 是否显示手动刷新按钮
69 89
70 /** 90 /**
71 * 获取广告配置 91 * 获取广告配置
...@@ -126,16 +146,22 @@ const handleImageClick = () => { ...@@ -126,16 +146,22 @@ const handleImageClick = () => {
126 * 图片加载完成处理 146 * 图片加载完成处理
127 */ 147 */
128 const handleImageLoad = () => { 148 const handleImageLoad = () => {
149 + clearLoadingTimeout();
129 imageLoading.value = false; 150 imageLoading.value = false;
130 imageLoadError.value = false; 151 imageLoadError.value = false;
152 + isTimeout.value = false;
153 + showManualRefresh.value = false;
154 + retryCount.value = 0;
131 }; 155 };
132 156
133 /** 157 /**
134 * 图片加载失败处理 158 * 图片加载失败处理
135 */ 159 */
136 const handleImageError = () => { 160 const handleImageError = () => {
161 + clearLoadingTimeout();
137 imageLoading.value = false; 162 imageLoading.value = false;
138 imageLoadError.value = true; 163 imageLoadError.value = true;
164 + handleLoadingTimeout();
139 }; 165 };
140 166
141 /** 167 /**
...@@ -144,15 +170,86 @@ const handleImageError = () => { ...@@ -144,15 +170,86 @@ const handleImageError = () => {
144 const retryLoadImage = () => { 170 const retryLoadImage = () => {
145 imageLoading.value = true; 171 imageLoading.value = true;
146 imageLoadError.value = false; 172 imageLoadError.value = false;
173 + isTimeout.value = false;
174 + showManualRefresh.value = false;
175 +
176 + // 开始超时检测
177 + startLoadingTimeout();
178 +
147 // 重新获取广告配置 179 // 重新获取广告配置
148 fetchAdConfig(); 180 fetchAdConfig();
149 }; 181 };
150 182
151 /** 183 /**
152 - * 页面初始化 184 + * 手动刷新页面
185 + */
186 +const manualRefresh = () => {
187 + // 重置所有状态
188 + retryCount.value = 0;
189 + imageLoading.value = true;
190 + imageLoadError.value = false;
191 + isTimeout.value = false;
192 + showManualRefresh.value = false;
193 + loading.value = true;
194 +
195 + // 重新初始化页面
196 + initializePage();
197 +};
198 +
199 +/**
200 + * 开始加载超时检测
201 + */
202 +const startLoadingTimeout = () => {
203 + // 清除之前的定时器
204 + if (loadingTimeout.value) {
205 + clearTimeout(loadingTimeout.value);
206 + }
207 +
208 + // 设置10秒超时
209 + loadingTimeout.value = setTimeout(() => {
210 + if (imageLoading.value) {
211 + console.warn('图片加载超时');
212 + isTimeout.value = true;
213 + handleLoadingTimeout();
214 + }
215 + }, 10000);
216 +};
217 +
218 +/**
219 + * 处理加载超时
153 */ 220 */
154 -onMounted(async () => { 221 +const handleLoadingTimeout = () => {
222 + if (retryCount.value < maxRetries.value) {
223 + // 自动重试
224 + retryCount.value++;
225 + console.log(`第${retryCount.value}次自动重试加载`);
226 + retryLoadImage();
227 + } else {
228 + // 超过最大重试次数,显示手动刷新选项
229 + imageLoading.value = false;
230 + showManualRefresh.value = true;
231 + console.error('图片加载失败,已达到最大重试次数');
232 + }
233 +};
234 +
235 +/**
236 + * 清除加载超时定时器
237 + */
238 +const clearLoadingTimeout = () => {
239 + if (loadingTimeout.value) {
240 + clearTimeout(loadingTimeout.value);
241 + loadingTimeout.value = null;
242 + }
243 +};
244 +
245 +/**
246 + * 页面初始化逻辑
247 + */
248 +const initializePage = async () => {
155 try { 249 try {
250 + // 开始超时检测
251 + startLoadingTimeout();
252 +
156 // 执行静默授权 253 // 执行静默授权
157 await performSilentAuth(); 254 await performSilentAuth();
158 255
...@@ -163,9 +260,18 @@ onMounted(async () => { ...@@ -163,9 +260,18 @@ onMounted(async () => {
163 ]); 260 ]);
164 } catch (error) { 261 } catch (error) {
165 console.error('页面初始化失败:', error); 262 console.error('页面初始化失败:', error);
263 + // 初始化失败时也要处理超时
264 + handleLoadingTimeout();
166 } finally { 265 } finally {
167 loading.value = false; 266 loading.value = false;
168 } 267 }
268 +};
269 +
270 +/**
271 + * 页面初始化
272 + */
273 +onMounted(() => {
274 + initializePage();
169 }); 275 });
170 276
171 /** 277 /**
......