import { authService } from './authService'; // API Base URL - 从环境变量获取 // 默认改为 8010,与当前后端一致。若有自定义域名/端口,请在 .env.local 配置 VITE_API_BASE_URL const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:8010'; // 用户信息接口(与后端API对应) export interface User { id: string; username: string; nickname: string; phone: string | null; email: string | null; avatar: string | null; registration_date: string; created_at: string; updated_at: string; apikey?: string; // API密钥字段 } // 注册请求接口 export interface RegisterRequest { username: string; password: string; nickname: string; email?: string; phone?: string; sms_code?: string; } // 登录响应接口 export interface LoginResponse { access_token: string; token_type: string; user: User; } // 更新用户信息请求接口 export interface UpdateUserRequest { nickname?: string; phone?: string; email?: string; avatar?: string; apikey?: string; } // 错误响应接口 export interface ErrorResponse { detail?: string; message?: string; } // Token验证响应接口 export interface TokenVerifyResponse { valid: boolean; user: User; } // 登出响应接口 export interface LogoutResponse { message: string; user_id: string; } /** * 用户API服务类 * 负责与后端用户中心API交互 */ class UserApiService { private baseUrl = `${API_BASE_URL}/api`; /** * 获取请求头(包含鉴权信息) */ private getHeaders(requireAuth: boolean = false): Record { const headers: Record = { 'Content-Type': 'application/json' }; if (requireAuth) { const authHeader = authService.getAuthHeader(); if (authHeader) { headers['Authorization'] = authHeader; } else { throw new Error('未授权:请先登录'); } } return headers; } /** * 处理API响应 */ private async handleResponse(response: Response): Promise { if (!response.ok) { // 尝试解析错误信息 let errorMessage = `请求失败,请稍后重试`; try { const errorData: ErrorResponse = await response.json(); const detail = errorData.detail || errorData.message || ''; // 将后端错误信息转换为用户友好的中文提示 errorMessage = this.translateErrorMessage(detail, response.status); } catch (e) { // 解析失败,使用默认错误信息 } // 401 错误且不是登录接口时,清除登录状态(不调用后端API,因为Token已无效) if (response.status === 401 && !response.url.includes('/auth/login')) { authService.logout(false); } throw new Error(errorMessage); } return response.json(); } /** * 将后端错误信息转换为用户友好的中文提示 */ private translateErrorMessage(detail: string, statusCode: number): string { // 注册相关错误 if (detail === 'Username already exists') { return '该用户名已被注册,请更换用户名'; } if (detail === 'Email already exists') { return '该邮箱已被注册,请更换邮箱或使用该邮箱登录'; } // 登录相关错误 if (detail === 'Invalid username or password') { return '用户名/手机号或者密码错误'; } // 权限相关错误 if (statusCode === 401) { return '登录已过期,请重新登录'; } if (statusCode === 403) { return '没有权限执行此操作'; } if (statusCode === 404) { return '请求的资源不存在'; } if (statusCode === 409) { return '数据冲突,请检查您的输入'; } // 服务器错误 if (statusCode >= 500) { return '服务器繁忙,请稍后重试'; } // 如果有detail且不是英文技术信息,直接返回 if (detail && !/^[A-Z]/.test(detail)) { return detail; } return '请求失败,请稍后重试'; } /** * 用户注册 * POST /api/auth/register */ async register(registerData: RegisterRequest, keyId: string | null = null): Promise { const body = { ...registerData, // encrypted字段不需要传,后端默认为true ...(keyId && { key_id: keyId }) }; const response = await fetch(`${this.baseUrl}/auth/register`, { method: 'POST', headers: this.getHeaders(false), body: JSON.stringify(body), }); return this.handleResponse(response); } /** * 用户登录 * POST /api/auth/login */ async login(username: string, password: string, keyId: string | null = null): Promise { const body: any = { username, password // encrypted字段不需要传,后端默认为true }; if (keyId) { body.key_id = keyId; } const response = await fetch(`${this.baseUrl}/auth/login`, { method: 'POST', headers: this.getHeaders(false), body: JSON.stringify(body), }); return this.handleResponse(response); } /** * 获取当前用户信息 * GET /api/users/me */ async getCurrentUser(): Promise { const response = await fetch(`${this.baseUrl}/users/me`, { method: 'GET', headers: this.getHeaders(true), }); return this.handleResponse(response); } /** * 更新当前用户信息 * PUT /api/users/me */ async updateCurrentUser(updateData: UpdateUserRequest): Promise { const response = await fetch(`${this.baseUrl}/users/me`, { method: 'PUT', headers: this.getHeaders(true), body: JSON.stringify(updateData), }); return this.handleResponse(response); } /** * 删除当前用户(申请注销) * DELETE /api/users/me */ async deleteCurrentUser(): Promise<{ message: string }> { const response = await fetch(`${this.baseUrl}/users/me`, { method: 'DELETE', headers: this.getHeaders(true), }); return this.handleResponse<{ message: string }>(response); } /** * 验证Token是否有效 * GET /api/auth/verify */ async verifyToken(): Promise { const response = await fetch(`${this.baseUrl}/auth/verify`, { method: 'GET', headers: this.getHeaders(true), }); return this.handleResponse(response); } /** * 刷新Token * POST /api/auth/refresh */ async refreshToken(): Promise { const response = await fetch(`${this.baseUrl}/auth/refresh`, { method: 'POST', headers: this.getHeaders(true), }); return this.handleResponse(response); } /** * 用户登出 * POST /api/auth/logout */ async logout(): Promise { const response = await fetch(`${this.baseUrl}/auth/logout`, { method: 'POST', headers: this.getHeaders(true), }); return this.handleResponse(response); } /** * 验证验证码(不删除,供两步流程使用) */ async verifySmsCode(phone: string, sms_code: string): Promise { const response = await fetch(`${API_BASE_URL}/api/sms/verify-code`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone, sms_code }), }); if (!response.ok) { const err = await response.json().catch(() => ({})); throw new Error(err.detail || '验证码错误'); } } /** * 发送短信验证码 */ async sendSmsCode(phone: string, scene: string = 'register'): Promise { const response = await fetch(`${API_BASE_URL}/api/sms/send-code`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone, scene }), }); if (!response.ok) { const err = await response.json().catch(() => ({})); throw new Error(err.detail || '发送失败,请稍后重试'); } } /** * 手机号+验证码登录 */ async loginByPhone(phone: string, sms_code: string): Promise { const response = await fetch(`${this.baseUrl}/auth/login/phone`, { method: 'POST', headers: this.getHeaders(false), body: JSON.stringify({ phone, sms_code }), }); return this.handleResponse(response); } /** * 手机验证码修改密码 */ async resetPasswordByPhone(phone: string, sms_code: string, new_password: string): Promise { const response = await fetch(`${this.baseUrl}/auth/reset-password/phone`, { method: 'POST', headers: this.getHeaders(false), body: JSON.stringify({ phone, sms_code, new_password }), }); if (!response.ok) { const err = await response.json().catch(() => ({})); throw new Error(err.detail || '修改失败'); } } } // 导出单例 export const userApi = new UserApiService();