Files
ai_game/client/js/data/UserManager.js
2026-03-11 12:10:19 +08:00

336 lines
7.5 KiB
JavaScript
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 { get, post, del } from '../utils/http';
export default class UserManager {
constructor() {
this.userId = null;
this.openid = null;
this.nickname = '';
this.avatarUrl = '';
this.token = '';
this.isLoggedIn = false;
}
/**
* 检查是否已登录(只检查本地缓存)
* @returns {boolean} 是否已登录
*/
checkLogin() {
const cached = wx.getStorageSync('userInfo');
if (cached && cached.userId && cached.token) {
this.userId = cached.userId;
this.openid = cached.openid;
this.nickname = cached.nickname || '游客';
this.avatarUrl = cached.avatarUrl || '';
this.token = cached.token;
this.isLoggedIn = true;
return true;
}
return false;
}
/**
* 初始化用户(只恢复缓存,不自动登录)
*/
async init() {
// 只检查本地缓存,不自动登录
this.checkLogin();
}
/**
* 执行登录(供登录按钮调用)
* @param {Object} userInfo - 微信用户信息(头像、昵称等),可选
*/
async doLogin(userInfo = null) {
try {
// 获取登录code
const { code } = await this.wxLogin();
// 调用后端登录接口,传入用户信息
const result = await post('/user/login', {
code,
userInfo: userInfo ? {
nickname: userInfo.nickName,
avatarUrl: userInfo.avatarUrl,
gender: userInfo.gender || 0
} : null
});
this.userId = result.userId;
this.openid = result.openid;
// 优先使用后端返回的,其次用授权获取的
this.nickname = result.nickname || (userInfo?.nickName) || '游客';
this.avatarUrl = result.avatarUrl || (userInfo?.avatarUrl) || '';
this.token = result.token || '';
this.isLoggedIn = true;
// 缓存用户信息(包含 token
wx.setStorageSync('userInfo', {
userId: this.userId,
openid: this.openid,
nickname: this.nickname,
avatarUrl: this.avatarUrl,
token: this.token
});
return {
userId: this.userId,
nickname: this.nickname,
avatarUrl: this.avatarUrl
};
} catch (error) {
console.error('登录失败:', error);
throw error;
}
}
/**
* 退出登录
*/
logout() {
this.userId = null;
this.openid = null;
this.nickname = '';
this.avatarUrl = '';
this.token = '';
this.isLoggedIn = false;
wx.removeStorageSync('userInfo');
}
/**
* 更新用户资料
*/
async updateProfile(nickname, avatarUrl) {
if (!this.isLoggedIn) return false;
try {
await post('/user/profile', {
nickname,
avatarUrl,
gender: 0
}, { params: { userId: this.userId } });
// 更新本地数据
this.nickname = nickname;
this.avatarUrl = avatarUrl;
// 更新缓存(保留 token
wx.setStorageSync('userInfo', {
userId: this.userId,
openid: this.openid,
nickname: this.nickname,
avatarUrl: this.avatarUrl,
token: this.token
});
return true;
} catch (e) {
console.error('更新资料失败:', e);
return false;
}
}
/**
* 微信登录(带超时)
*/
wxLogin() {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error('登录超时'));
}, 5000);
wx.login({
success: (res) => {
clearTimeout(timeout);
if (res.code) {
resolve(res);
} else {
reject(new Error('获取code失败'));
}
},
fail: (err) => {
clearTimeout(timeout);
reject(err);
}
});
});
}
/**
* 获取用户游玩进度
*/
async getProgress(storyId = null) {
if (!this.isLoggedIn) return null;
return await get('/user/progress', { userId: this.userId, storyId });
}
/**
* 保存用户进度
*/
async saveProgress(storyId, currentNodeKey, isCompleted = false, endingReached = '') {
if (!this.isLoggedIn) return;
await post('/user/progress', {
userId: this.userId,
storyId,
currentNodeKey,
isCompleted,
endingReached
});
}
/**
* 点赞故事
*/
async likeStory(storyId, isLiked) {
if (!this.isLoggedIn) return;
await post('/user/like', {
userId: this.userId,
storyId,
isLiked
});
}
/**
* 收藏故事
*/
async collectStory(storyId, isCollected) {
if (!this.isLoggedIn) return;
await post('/user/collect', {
userId: this.userId,
storyId,
isCollected
});
}
/**
* 获取收藏列表
*/
async getCollections() {
if (!this.isLoggedIn) return [];
return await get('/user/collections', { userId: this.userId });
}
/**
* 获取最近游玩的故事
*/
async getRecentPlayed() {
if (!this.isLoggedIn) return [];
try {
return await get('/user/recent-played', { userId: this.userId, limit: 10 });
} catch (e) {
return [];
}
}
/**
* 获取AI创作历史
*/
async getAIHistory() {
if (!this.isLoggedIn) return [];
try {
return await get('/user/ai-history', { userId: this.userId, limit: 20 });
} catch (e) {
return [];
}
}
/**
* 获取AI配额
*/
async getAIQuota() {
if (!this.isLoggedIn) return { daily: 3, used: 0, purchased: 0 };
try {
return await get('/user/ai-quota', { userId: this.userId });
} catch (e) {
return { daily: 3, used: 0, purchased: 0 };
}
}
/**
* 获取我的作品
*/
async getMyWorks() {
if (!this.isLoggedIn) return [];
try {
return await get('/user/my-works', { userId: this.userId });
} catch (e) {
return [];
}
}
/**
* 获取草稿箱
*/
async getDrafts() {
if (!this.isLoggedIn) return [];
try {
return await get('/user/drafts', { userId: this.userId });
} catch (e) {
return [];
}
}
// ========== 游玩记录相关 ==========
/**
* 保存游玩记录
*/
async savePlayRecord(storyId, endingName, endingType, pathHistory) {
if (!this.isLoggedIn) return null;
try {
return await post('/user/play-record', {
userId: this.userId,
storyId,
endingName,
endingType: endingType || '',
pathHistory: pathHistory || []
});
} catch (e) {
console.error('保存游玩记录失败:', e);
return null;
}
}
/**
* 获取游玩记录列表
* @param {number} storyId - 可选指定故事ID获取该故事的所有记录
*/
async getPlayRecords(storyId = null) {
if (!this.isLoggedIn) return [];
try {
const params = { userId: this.userId };
if (storyId) params.storyId = storyId;
return await get('/user/play-records', params);
} catch (e) {
console.error('获取游玩记录失败:', e);
return [];
}
}
/**
* 获取单条记录详情
*/
async getPlayRecordDetail(recordId) {
if (!this.isLoggedIn) return null;
try {
return await get(`/user/play-records/${recordId}`);
} catch (e) {
console.error('获取记录详情失败:', e);
return null;
}
}
// 删除游玩记录
async deletePlayRecord(recordId) {
if (!this.isLoggedIn) return false;
try {
await del(`/user/play-records/${recordId}`);
return true;
} catch (e) {
console.error('删除记录失败:', e);
return false;
}
}
}