Files
mp-xieyingeng/assets/scripts/utils/AuthManager.ts
2026-04-05 13:37:58 +08:00

147 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { HttpUtil } from './HttpUtil';
import { StorageManager } from './StorageManager';
import { WxSDK } from './WxSDK';
import { API_ENDPOINTS, API_TIMEOUT } from '../config/ApiConfig';
import { ApiEnvelope, WxLoginData, GameData } from '../types/ApiTypes';
/**
* 认证管理器
* 单例模式,负责微信登录和 JWT token 管理
*/
export class AuthManager {
private static _instance: AuthManager | null = null;
private _userId: string = '';
private _isLoggedIn: boolean = false;
/** 服务端返回的已完成关卡 ID登录后暂存等 LevelDataManager 就绪后同步) */
private _completedLevelIds: string[] = [];
/** 服务端返回的已完成关卡 ID登录后暂存等 LevelDataManager 就绪后同步) */
private _completedLevelIds: string[] = [];
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 completedLevelIds(): string[] {
return this._completedLevelIds;
}
/**
* 初始化认证:尝试恢复 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;
StorageManager.setPoints(user.points);
// 获取通关进度
await this.fetchCompletedLevels();
console.log(`[AuthManager] 登录成功,用户: ${user.id},积分: ${user.points}`);
return true;
} catch (err) {
console.error('[AuthManager] 登录异常:', err);
return false;
}
}
private async validateToken(): Promise<boolean> {
try {
const response = await HttpUtil.get<ApiEnvelope<GameData>>(
API_ENDPOINTS.USER_GAME_DATA,
API_TIMEOUT.SHORT
);
if (!response.success || !response.data) {
return false;
}
this._userId = response.data.user.id;
this._isLoggedIn = true;
StorageManager.setPoints(response.data.user.points);
this._completedLevelIds = response.data.completedLevelIds;
console.log(`[AuthManager] Token 验证成功,积分: ${response.data.user.points},已完成: ${this._completedLevelIds.length}`);
return true;
} catch {
return false;
}
}
/**
* 登录成功后获取通关进度
*/
private async fetchCompletedLevels(): Promise<void> {
try {
const response = await HttpUtil.get<ApiEnvelope<GameData>>(
API_ENDPOINTS.USER_GAME_DATA,
API_TIMEOUT.SHORT
);
if (response.success && response.data) {
this._completedLevelIds = response.data.completedLevelIds;
// 同步最新积分
StorageManager.setPoints(response.data.user.points);
}
} catch {
console.warn('[AuthManager] 获取通关进度失败');
}
}
}