Files
frontend/src/services/authService.ts

495 lines
14 KiB
TypeScript
Raw Normal View History

/**
*
*
*/
import { api } from './api';
import { User } from '../types';
export function resolveAuthApiError(error: any, fallback = '操作失败,请稍后重试'): string {
const code: number = error?.code ?? 0;
const msg: string = String(error?.message ?? '').toLowerCase();
if (msg.includes('network request failed') || msg.includes('failed to fetch')) {
return '网络连接失败,请检查网络后重试';
}
if (code === 429 || msg.includes('too frequently')) {
return '验证码发送过于频繁,请稍后再试';
}
if (msg.includes('verification code expired')) {
return '验证码已过期,请重新获取';
}
if (msg.includes('invalid verification code')) {
return '验证码错误,请重新输入';
}
if (msg.includes('email already exists')) {
return '该邮箱已被注册,请直接登录';
}
if (msg.includes('email not bound')) {
return '当前账号未绑定邮箱,请先完成邮箱绑定验证';
}
if (msg.includes('user not found')) {
return '该邮箱尚未注册';
}
if (msg.includes('email service unavailable')) {
return '邮件服务暂不可用,请稍后再试';
}
if (msg.includes('invalid email')) {
return '邮箱格式不正确';
}
if (msg.includes('invalid username or password')) {
return '账号或密码错误';
}
if (typeof error?.message === 'string' && error.message.trim().length > 0) {
return error.message;
}
return fallback;
}
// 登录请求参数
export interface LoginRequest {
username?: string;
account?: string;
password: string;
}
// 注册请求参数
export interface RegisterRequest {
username: string;
password: string;
nickname: string;
email: string;
verification_code: string;
phone?: string;
}
export interface SendEmailCodeRequest {
email: string;
}
export interface ResetPasswordRequest {
email: string;
verification_code: string;
new_password: string;
}
export interface VerifyCurrentUserEmailRequest {
email: string;
verification_code: string;
}
// 认证响应
export interface AuthResponse {
token: string;
refreshToken?: string;
refresh_token?: string; // 兼容后端的snake_case
user: User;
}
// 刷新Token响应
export interface RefreshTokenResponse {
token: string;
refreshToken?: string;
refresh_token?: string; // 兼容后端的snake_case
}
// 用户信息响应 - API直接返回User对象不需要包装
export type UserResponse = User;
// 更新用户信息请求
export interface UpdateUserRequest {
nickname?: string;
avatar?: string;
bio?: string;
website?: string;
location?: string;
phone?: string;
email?: string;
}
export interface BlockedUserListResponse {
list: User[];
total: number;
page: number;
page_size: number;
total_pages: number;
}
export interface BlockStatusResponse {
is_blocked: boolean;
}
// 认证服务类
// 职责:纯 HTTP 层 + Token 管理,不涉及 SQLite
// SQLite 的读写编排由各领域 Manager/store 统一负责
class AuthService {
// ── 内部辅助:从服务器获取用户 ──
private async refreshCurrentUserFromServer(): Promise<User | null> {
try {
const response = await api.get<UserResponse>('/users/me');
return response.data;
} catch (error) {
console.error('[AuthService] 获取当前用户失败:', error);
return null;
}
}
private async refreshUserByIdFromServer(userId: string): Promise<User | null> {
try {
const response = await api.get<UserResponse>(`/users/${userId}`);
return response.data;
} catch (error) {
console.error('[AuthService] 获取用户信息失败:', error);
return null;
}
}
// ── 公开 API仅做 HTTP 请求 + Token 存储,不碰 SQLite ──
// 用户登录(只管 API + TokenDB 操作交给 authStore
async login(data: LoginRequest): Promise<AuthResponse> {
const response = await api.post<AuthResponse>('/auth/login', data);
if (response.data.token) {
await api.setToken(response.data.token);
}
const refreshToken = response.data.refresh_token || response.data.refreshToken;
if (refreshToken) {
await api.setRefreshToken(refreshToken);
}
return response.data;
}
// 用户注册(只管 API + TokenDB 操作交给 authStore
async register(data: RegisterRequest): Promise<AuthResponse> {
const response = await api.post<AuthResponse>('/auth/register', data);
if (response.data.token) {
await api.setToken(response.data.token);
}
const refreshToken = response.data.refresh_token || response.data.refreshToken;
if (refreshToken) {
await api.setRefreshToken(refreshToken);
}
return response.data;
}
// 发送注册验证码
async sendRegisterCode(email: string): Promise<boolean> {
const response = await api.post<{ success: boolean }>('/auth/register/send-code', { email } as SendEmailCodeRequest);
return response.code === 0;
}
// 发送找回密码验证码
async sendPasswordResetCode(email: string): Promise<boolean> {
const response = await api.post<{ success: boolean }>('/auth/password/send-code', { email } as SendEmailCodeRequest);
return response.code === 0;
}
// 找回密码重置
async resetPassword(data: ResetPasswordRequest): Promise<boolean> {
const response = await api.post<{ success: boolean }>('/auth/password/reset', data);
return response.code === 0;
}
// 已登录用户发送邮箱验证验证码
async sendCurrentUserEmailVerifyCode(email: string): Promise<boolean> {
const response = await api.post<{ success: boolean }>('/users/me/email/send-code', { email } as SendEmailCodeRequest);
return response.code === 0;
}
// 已登录用户提交邮箱验证码
async verifyCurrentUserEmail(data: VerifyCurrentUserEmailRequest): Promise<boolean> {
const response = await api.post<{ success: boolean }>('/users/me/email/verify', data);
return response.code === 0;
}
// 用户登出(只管 API + TokenDB/缓存清理交给 authStore
async logout(): Promise<void> {
try {
await api.post('/auth/logout');
} catch (error) {
console.error('[AuthService] 登出 API 失败:', error);
} finally {
await api.clearToken();
}
}
// 纯 API 获取当前用户(无任何 DB 依赖,供冷启动校验 Token 时使用)
async fetchCurrentUserFromAPI(): Promise<User | null> {
try {
const response = await api.get<UserResponse>('/users/me');
return response.data;
} catch (error) {
console.error('[AuthService] fetchCurrentUserFromAPI 失败:', error);
return null;
}
}
// 刷新Token
async refreshToken(): Promise<RefreshTokenResponse | null> {
try {
const response = await api.post<RefreshTokenResponse>('/auth/refresh');
if (response.data.token) {
await api.setToken(response.data.token);
}
if (response.data.refreshToken) {
await api.setRefreshToken(response.data.refreshToken);
}
return response.data;
} catch (error) {
console.error('刷新Token失败:', error);
await api.clearToken();
return null;
}
}
// 获取当前用户信息(兼容旧调用,始终走服务端)
async getCurrentUser(): Promise<User | null> {
return this.refreshCurrentUserFromServer();
}
// 强制从服务器获取当前用户信息(别名,保留兼容)
async fetchCurrentUserFresh(): Promise<User | null> {
return this.fetchCurrentUserFromAPI();
}
async fetchUserByIdFromAPI(userId: string): Promise<User | null> {
return this.refreshUserByIdFromServer(userId);
}
// 获取用户信息根据用户ID
async getUserById(userId: string, forceRefresh = false): Promise<User | null> {
void forceRefresh; // 兼容旧签名:缓存由 userManager 统一编排
return this.refreshUserByIdFromServer(userId);
}
// 更新用户信息
async updateUser(data: UpdateUserRequest): Promise<User | null> {
try {
const response = await api.put<UserResponse>('/users/me', data);
return response.data;
} catch (error) {
console.error('更新用户信息失败:', error);
return null;
}
}
// 修改密码
async sendChangePasswordCode(): Promise<boolean> {
const response = await api.post<{ success: boolean }>('/users/change-password/send-code');
return response.code === 0;
}
// 修改密码(需要邮箱验证码)
async changePassword(oldPassword: string, newPassword: string, verificationCode: string): Promise<boolean> {
try {
const response = await api.post('/users/change-password', {
old_password: oldPassword,
new_password: newPassword,
verification_code: verificationCode,
});
return response.code === 0;
} catch (error) {
console.error('修改密码失败:', error);
return false;
}
}
// 检查用户名是否可用
async checkUsernameAvailable(username: string): Promise<boolean> {
try {
const response = await api.get<{ available: boolean }>('/auth/check-username', {
username,
});
return response.data.available;
} catch (error) {
console.error('检查用户名失败:', error);
return false;
}
}
// 关注用户
async followUser(userId: string): Promise<boolean> {
try {
const response = await api.post(`/users/${userId}/follow`);
return response.code === 0;
} catch (error) {
console.error('关注用户失败:', error);
return false;
}
}
// 取消关注用户
async unfollowUser(userId: string): Promise<boolean> {
try {
const response = await api.delete(`/users/${userId}/follow`);
return response.code === 0;
} catch (error) {
console.error('取消关注用户失败:', error);
return false;
}
}
// 获取用户关注列表
async getFollowingList(userId: string, page = 1, pageSize = 20): Promise<User[]> {
try {
const response = await api.get<{ list: User[] }>(`/users/${userId}/following`, {
page,
page_size: pageSize,
});
return response.data.list;
} catch (error) {
console.error('获取关注列表失败:', error);
return [];
}
}
// 获取用户粉丝列表
async getFollowersList(userId: string, page = 1, pageSize = 20): Promise<User[]> {
try {
const response = await api.get<{ list: User[] }>(`/users/${userId}/followers`, {
page,
page_size: pageSize,
});
return response.data.list;
} catch (error) {
console.error('获取粉丝列表失败:', error);
return [];
}
}
// 拉黑用户
async blockUser(userId: string): Promise<boolean> {
try {
const response = await api.post(`/users/${userId}/block`);
return response.code === 0;
} catch (error) {
console.error('拉黑用户失败:', error);
return false;
}
}
// 取消拉黑
async unblockUser(userId: string): Promise<boolean> {
try {
const response = await api.delete(`/users/${userId}/block`);
return response.code === 0;
} catch (error) {
console.error('取消拉黑失败:', error);
return false;
}
}
// 获取黑名单
async getBlockedUsers(page = 1, pageSize = 20): Promise<BlockedUserListResponse> {
try {
const response = await api.get<BlockedUserListResponse>('/users/blocks', {
page,
page_size: pageSize,
});
return response.data;
} catch (error) {
console.error('获取黑名单失败:', error);
return {
list: [],
total: 0,
page,
page_size: pageSize,
total_pages: 0,
};
}
}
// 获取拉黑状态
async getBlockStatus(userId: string): Promise<boolean> {
try {
const response = await api.get<BlockStatusResponse>(`/users/${userId}/block-status`);
return !!response.data.is_blocked;
} catch (error) {
console.error('获取拉黑状态失败:', error);
return false;
}
}
// 搜索用户
async searchUsers(keyword: string, page = 1, pageSize = 20): Promise<{ list: User[]; total: number }> {
try {
const response = await api.get<{ list: User[]; total: number }>('/users/search', {
keyword,
page,
page_size: pageSize,
});
return response.data;
} catch (error) {
console.error('搜索用户失败:', error);
return { list: [], total: 0 };
}
}
}
// ── 二维码登录相关接口 ──
export interface QRCodeSession {
session_id: string;
qrcode_url: string;
expires_in: number;
expires_at: number;
}
export interface ScanResponse {
user: {
id: string;
nickname: string;
avatar: string;
};
}
// 二维码登录 API扩展 AuthService
export const qrcodeApi = {
/**
*
*/
getQRCode: async (): Promise<QRCodeSession> => {
const response = await api.get<QRCodeSession>('/auth/qrcode');
return response.data;
},
/**
*
*/
scan: async (sessionId: string): Promise<ScanResponse> => {
const response = await api.post<ScanResponse>('/auth/qrcode/scan', {
session_id: sessionId,
});
return response.data;
},
/**
*
*/
confirm: async (sessionId: string): Promise<{ success: boolean }> => {
const response = await api.post<{ success: boolean }>('/auth/qrcode/confirm', {
session_id: sessionId,
});
return response.data;
},
/**
*
*/
cancel: async (sessionId: string): Promise<{ success: boolean }> => {
const response = await api.post<{ success: boolean }>('/auth/qrcode/cancel', {
session_id: sessionId,
});
return response.data;
},
};
// 导出认证服务实例
export const authService = new AuthService();