feat: 支持加载进度提示和 API 重试机制

- 添加 ProgressTips 节点到 PageLoading 展示加载状态消息
- 连接 statusLabel 到 ProgressTips 组件
- LevelDataManager 添加 API 请求重试机制(重试 2 次)
- 优化进度消息:正在请求服务端数据、正在加载游戏必备资源等
- 初始化失败时显示"网络异常,请重新打开游戏"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
richarjiang
2026-03-30 09:14:10 +08:00
parent 8794a3495c
commit e0d2ff5d57
8 changed files with 239 additions and 34 deletions

View File

@@ -22,6 +22,9 @@ export class LevelDataManager {
/** 请求超时时间(毫秒) */
private readonly REQUEST_TIMEOUT = 8000;
/** API 请求重试次数 */
private readonly API_RETRY_COUNT = 2;
/** API 返回的原始关卡数据 */
private _apiData: ApiLevelData[] = [];
@@ -62,12 +65,12 @@ export class LevelDataManager {
try {
// 阶段1: 获取 API 数据 (0-30%)
onProgress?.(0, '正在获取关卡数据...');
const apiData = await this._fetchApiData();
onProgress?.(0, '正在请求服务端数据...');
const apiData = await this._fetchApiData(onProgress);
if (!apiData || apiData.length === 0) {
console.warn('[LevelDataManager] API 返回空数据');
onProgress?.(0.3, 'API 数据为空,使用本地配置');
onProgress?.(0.3, '网络异常,请重新打开游戏');
return false;
}
@@ -78,7 +81,7 @@ export class LevelDataManager {
// 阶段2: 只预加载第一关图片 (30-80%)
const firstLevel = apiData[0];
onProgress?.(0.3, '正在加载第一关资源...');
onProgress?.(0.3, '正在加载游戏必备资源...');
const spriteFrame = await this._loadImage(firstLevel.imageUrl);
if (spriteFrame) {
@@ -86,12 +89,12 @@ export class LevelDataManager {
}
console.log('[LevelDataManager] 初始化完成,第一关资源已加载');
onProgress?.(0.8, '第一关资源加载完成');
onProgress?.(0.8, '游戏资源加载完成');
return true;
} catch (error) {
console.error('[LevelDataManager] 初始化失败:', error);
onProgress?.(0.3, '获取数据失败,使用本地配置');
onProgress?.(0.3, '网络异常,请重新打开游戏');
return false;
}
}
@@ -205,22 +208,44 @@ export class LevelDataManager {
}
/**
* 从 API 获取关卡数据
* 从 API 获取关卡数据(带重试机制)
* @param onProgress 进度回调
*/
private async _fetchApiData(): Promise<ApiLevelData[] | null> {
try {
const response = await HttpUtil.get<ApiResponse>(this.API_URL, this.REQUEST_TIMEOUT);
private async _fetchApiData(onProgress?: ProgressCallback): Promise<ApiLevelData[] | null> {
let lastError: Error | null = null;
if (!response.success) {
console.warn(`[LevelDataManager] API 返回失败, 消息: ${response.message}`);
return null;
for (let attempt = 1; attempt <= this.API_RETRY_COUNT; attempt++) {
const progress = (attempt - 1) / this.API_RETRY_COUNT * 0.3;
try {
onProgress?.(progress, `正在请求服务端数据 (第${attempt}次)...`);
const response = await HttpUtil.get<ApiResponse>(this.API_URL, this.REQUEST_TIMEOUT);
if (!response.success) {
console.warn(`[LevelDataManager] API 返回失败, 消息: ${response.message}`);
lastError = new Error(response.message || 'API 返回失败');
} else {
return response.data.levels;
}
} catch (error) {
console.warn(`[LevelDataManager] 第${attempt}次请求失败:`, error);
lastError = error as Error;
}
return response.data.levels;
} catch (error) {
console.error('[LevelDataManager] API 请求失败:', error);
return null;
// 重试逻辑(无论是 response.success 为 false 还是抛出异常)
if (attempt < this.API_RETRY_COUNT) {
onProgress?.(progress + 0.05, `请求失败,正在重试...`);
await this._delay(1000);
}
}
console.error('[LevelDataManager] API 请求重试全部失败:', lastError);
return null;
}
private _delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
/**