166 lines
3.9 KiB
TypeScript
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 };
|