157 lines
5.0 KiB
TypeScript
157 lines
5.0 KiB
TypeScript
import { HttpUtil } from './HttpUtil';
|
|
import { StorageManager } from './StorageManager';
|
|
import { WxSDK } from './WxSDK';
|
|
import { API_ENDPOINTS, API_TIMEOUT } from '../config/ApiConfig';
|
|
import { ApiEnvelope, WxLoginData, GameData, NextLevelData } from '../types/ApiTypes';
|
|
|
|
/**
|
|
* 认证管理器
|
|
* 单例模式,负责微信登录和 JWT token 管理
|
|
*/
|
|
export class AuthManager {
|
|
private static _instance: AuthManager | null = null;
|
|
|
|
private _userId: string = '';
|
|
private _isLoggedIn: boolean = false;
|
|
/** 服务端返回的已完成关卡数量,用于称号体系计算 */
|
|
private _completedLevelCount: number = 0;
|
|
/** game-data 返回的下一关数据,供 PageLoading 传给 LevelDataManager */
|
|
private _nextLevel: NextLevelData | null = null;
|
|
|
|
static get instance(): AuthManager {
|
|
if (!this._instance) {
|
|
this._instance = new AuthManager();
|
|
}
|
|
return this._instance;
|
|
}
|
|
|
|
private constructor() {}
|
|
|
|
get isLoggedIn(): boolean {
|
|
return this._isLoggedIn;
|
|
}
|
|
|
|
get userId(): string {
|
|
return this._userId;
|
|
}
|
|
|
|
get completedLevelCount(): number {
|
|
return this._completedLevelCount;
|
|
}
|
|
|
|
/** 获取 game-data 返回的下一关数据 */
|
|
get nextLevel(): NextLevelData | null {
|
|
return this._nextLevel;
|
|
}
|
|
|
|
addCompletedLevelCount(delta: number = 1): void {
|
|
this._completedLevelCount = Math.max(0, this._completedLevelCount + delta);
|
|
}
|
|
|
|
/**
|
|
* 初始化认证:尝试恢复 token 或执行微信登录
|
|
*/
|
|
async initialize(): Promise<boolean> {
|
|
const savedToken = StorageManager.getToken();
|
|
if (savedToken) {
|
|
HttpUtil.setAuthToken(savedToken);
|
|
try {
|
|
const valid = await this.validateToken();
|
|
if (valid) {
|
|
console.log('[AuthManager] Token 恢复成功');
|
|
return true;
|
|
}
|
|
} catch {
|
|
console.warn('[AuthManager] 本地 token 无效,重新登录');
|
|
}
|
|
}
|
|
|
|
return this.wxLogin();
|
|
}
|
|
|
|
private async wxLogin(): Promise<boolean> {
|
|
try {
|
|
let code: string;
|
|
|
|
if (WxSDK.isWechat()) {
|
|
code = await WxSDK.login();
|
|
} else {
|
|
console.warn('[AuthManager] 非微信环境,使用开发模式 mock code');
|
|
code = 'dev_mock_code';
|
|
}
|
|
|
|
const response = await HttpUtil.post<ApiEnvelope<WxLoginData>>(
|
|
API_ENDPOINTS.WX_LOGIN,
|
|
{ code },
|
|
API_TIMEOUT.DEFAULT
|
|
);
|
|
|
|
if (!response.success || !response.data) {
|
|
console.error('[AuthManager] 登录失败:', response.message);
|
|
return false;
|
|
}
|
|
|
|
const { token, user } = response.data;
|
|
HttpUtil.setAuthToken(token);
|
|
StorageManager.setToken(token);
|
|
|
|
this._userId = user.id;
|
|
this._isLoggedIn = true;
|
|
|
|
// 登录响应中 stamina 是原始数值(不含实时恢复),先存储默认体力
|
|
// 后续通过 game-data 接口获取完整 StaminaInfo
|
|
console.log(`[AuthManager] 登录成功,用户: ${user.id},体力: ${user.stamina}`);
|
|
|
|
// 获取通关进度和完整体力信息
|
|
await this.fetchGameData();
|
|
|
|
return true;
|
|
} catch (err) {
|
|
console.error('[AuthManager] 登录异常:', err);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private async validateToken(): Promise<boolean> {
|
|
const gameData = await this._fetchGameData();
|
|
if (!gameData) return false;
|
|
|
|
this._userId = gameData.user.id;
|
|
this._isLoggedIn = true;
|
|
StorageManager.setStamina(gameData.user.stamina);
|
|
this._completedLevelCount = gameData.completedLevelCount;
|
|
this._nextLevel = gameData.nextLevel;
|
|
|
|
console.log(`[AuthManager] Token 验证成功,体力: ${gameData.user.stamina.current}/${gameData.user.stamina.max},已完成: ${this._completedLevelCount} 关`);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 登录成功后获取游戏数据(体力 + 通关进度 + 下一关)
|
|
*/
|
|
private async fetchGameData(): Promise<void> {
|
|
const gameData = await this._fetchGameData();
|
|
if (gameData) {
|
|
this._completedLevelCount = gameData.completedLevelCount;
|
|
this._nextLevel = gameData.nextLevel;
|
|
StorageManager.setStamina(gameData.user.stamina);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 从服务端获取游戏数据(共用方法)
|
|
*/
|
|
private async _fetchGameData(): Promise<GameData | null> {
|
|
try {
|
|
const response = await HttpUtil.get<ApiEnvelope<GameData>>(
|
|
API_ENDPOINTS.USER_GAME_DATA,
|
|
API_TIMEOUT.SHORT
|
|
);
|
|
return (response.success && response.data) ? response.data : null;
|
|
} catch {
|
|
console.warn('[AuthManager] 获取游戏数据失败');
|
|
return null;
|
|
}
|
|
}
|
|
}
|