Files

166 lines
3.9 KiB
TypeScript

interface UserInfo {
_id: string;
openid: string;
unionid: string | null;
nickName: string | null;
avatarUrl: string | null;
totalDownloads: number;
createdAt: string;
lastActiveAt: string;
}
const STORAGE_KEY = 'user_info';
const STORAGE_EXPIRE_KEY = 'user_info_expire';
const EXPIRE_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 天
/** 内存中的用户数据(App 生命周期内有效) */
let currentUser: UserInfo | null = null;
/** 登录进行中的 Promise(防止并发重复调用) */
let loginPromise: Promise<UserInfo> | null = null;
function syncAppGlobalUser(user: UserInfo | null): void {
try {
const app = getApp<IAppOption>();
if (app?.globalData) {
app.globalData.user = user;
}
} catch {
// App 尚未初始化时忽略
}
}
function syncUserState(user: UserInfo, persist = true): UserInfo {
currentUser = user;
if (persist) {
saveToStorage(user);
}
syncAppGlobalUser(user);
return user;
}
/**
* 获取当前用户,优先内存 → Storage → 云函数登录
*/
export async function getUser(): Promise<UserInfo> {
// 1. 内存中有,直接返回
if (currentUser) {
syncAppGlobalUser(currentUser);
return currentUser;
}
// 2. 尝试从 Storage 读取
const cached = loadFromStorage();
if (cached) {
return syncUserState(cached, false);
}
// 3. 静默登录(防止并发)
if (!loginPromise) {
loginPromise = silentLogin().finally(() => {
loginPromise = null;
});
}
return loginPromise;
}
/**
* 静默登录:调用云函数
*/
async function silentLogin(): Promise<UserInfo> {
const res = await wx.cloud.callFunction({
name: 'userLogin',
});
const result = (res?.result as any) || {};
if (result.code !== 0) {
throw new Error('登录失败');
}
const user = result.data as UserInfo;
return syncUserState(user);
}
export function getCachedUser(): UserInfo | null {
if (currentUser) {
syncAppGlobalUser(currentUser);
return currentUser;
}
const cached = loadFromStorage();
if (!cached) return null;
return syncUserState(cached, false);
}
/**
* 从 Storage 读取用户数据(检查过期)
*/
function loadFromStorage(): UserInfo | null {
try {
const expire = wx.getStorageSync(STORAGE_EXPIRE_KEY);
if (!expire || Date.now() > expire) {
wx.removeStorageSync(STORAGE_KEY);
wx.removeStorageSync(STORAGE_EXPIRE_KEY);
return null;
}
const user = wx.getStorageSync(STORAGE_KEY);
return user || null;
} catch {
return null;
}
}
/**
* 写入 Storage
*/
function saveToStorage(user: UserInfo): void {
try {
wx.setStorageSync(STORAGE_KEY, user);
wx.setStorageSync(STORAGE_EXPIRE_KEY, Date.now() + EXPIRE_DURATION);
} catch {
// Storage 写入失败不影响主流程
}
}
/**
* 清除登录状态
*/
export function clearUser(): void {
currentUser = null;
syncAppGlobalUser(null);
wx.removeStorageSync(STORAGE_KEY);
wx.removeStorageSync(STORAGE_EXPIRE_KEY);
}
/**
* 强制刷新用户数据(跳过缓存)
*/
export async function refreshUser(): Promise<UserInfo> {
clearUser();
return await silentLogin();
}
export async function updateUserProfile(payload: {
nickName?: string | null;
avatarUrl?: string | null;
}): Promise<UserInfo> {
await getUser();
const res = await wx.cloud.callFunction({
name: 'userLogin',
data: {
action: 'updateProfile',
...payload,
},
});
const result = (res?.result as any) || {};
if (result.code !== 0 || !result.data) {
throw new Error(result.message || '更新用户资料失败');
}
return syncUserState(result.data as UserInfo);
}
export type { UserInfo };