97 lines
2.7 KiB
TypeScript
97 lines
2.7 KiB
TypeScript
import Taro from '@tarojs/taro';
|
|
import { config } from '../config';
|
|
import { post, get } from '../utils/request';
|
|
|
|
export interface UserProfile {
|
|
id: string;
|
|
phone?: string;
|
|
email?: string;
|
|
nickname?: string;
|
|
kycLevel: number;
|
|
avatarUrl?: string;
|
|
}
|
|
|
|
interface AuthResponse {
|
|
user: UserProfile;
|
|
tokens: { accessToken: string; refreshToken: string; expiresIn: number };
|
|
}
|
|
|
|
/**
|
|
* Auth 状态管理(简单模块模式,不依赖额外状态库)
|
|
*/
|
|
let _user: UserProfile | null = null;
|
|
let _listeners: Array<() => void> = [];
|
|
|
|
function notify() {
|
|
_listeners.forEach((fn) => fn());
|
|
}
|
|
|
|
export const authStore = {
|
|
/** 获取当前用户 */
|
|
getUser(): UserProfile | null {
|
|
if (!_user) {
|
|
try {
|
|
const saved = Taro.getStorageSync(config.USER_KEY);
|
|
if (saved) _user = JSON.parse(saved);
|
|
} catch {}
|
|
}
|
|
return _user;
|
|
},
|
|
|
|
/** 是否已登录 */
|
|
isLoggedIn(): boolean {
|
|
return !!Taro.getStorageSync(config.TOKEN_KEY);
|
|
},
|
|
|
|
/** 手机号+验证码登录 */
|
|
async loginByPhone(phone: string, smsCode: string): Promise<void> {
|
|
const resp = await post<AuthResponse>('/api/v1/auth/login-phone', { phone, smsCode }, false);
|
|
Taro.setStorageSync(config.TOKEN_KEY, resp.tokens.accessToken);
|
|
Taro.setStorageSync(config.USER_KEY, JSON.stringify(resp.user));
|
|
_user = resp.user;
|
|
notify();
|
|
},
|
|
|
|
/** 发送短信验证码 (支持类型) */
|
|
async sendSmsCode(phone: string, type: 'REGISTER' | 'LOGIN' | 'RESET_PASSWORD' | 'CHANGE_PHONE' = 'LOGIN'): Promise<void> {
|
|
await post('/api/v1/auth/sms/send', { phone, type }, false);
|
|
},
|
|
|
|
/** 微信一键登录 */
|
|
async loginByWechat(): Promise<void> {
|
|
const { code } = await Taro.login();
|
|
const resp = await post<AuthResponse>('/api/v1/auth/login-wechat', { code }, false);
|
|
Taro.setStorageSync(config.TOKEN_KEY, resp.tokens.accessToken);
|
|
Taro.setStorageSync(config.USER_KEY, JSON.stringify(resp.user));
|
|
_user = resp.user;
|
|
notify();
|
|
},
|
|
|
|
/** 获取用户资料 */
|
|
async fetchProfile(): Promise<UserProfile> {
|
|
const profile = await get<UserProfile>('/api/v1/users/me');
|
|
_user = profile;
|
|
Taro.setStorageSync(config.USER_KEY, JSON.stringify(profile));
|
|
notify();
|
|
return profile;
|
|
},
|
|
|
|
/** 登出 */
|
|
logout(): void {
|
|
post('/api/v1/auth/logout').catch(() => {});
|
|
Taro.removeStorageSync(config.TOKEN_KEY);
|
|
Taro.removeStorageSync(config.USER_KEY);
|
|
_user = null;
|
|
notify();
|
|
Taro.reLaunch({ url: '/pages/login/index' });
|
|
},
|
|
|
|
/** 订阅状态变化 */
|
|
subscribe(listener: () => void): () => void {
|
|
_listeners.push(listener);
|
|
return () => {
|
|
_listeners = _listeners.filter((fn) => fn !== listener);
|
|
};
|
|
},
|
|
};
|