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; real_name?: string | null; is_verified?: string; verified_at?: 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; email_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 VerifyUserRequest { real_name: string; id_card: 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 { // ── 精确英文 detail 映射 ────────────────────────────────────────── const exactMap: Record = { 'Username already exists': '该用户名已被注册,请更换用户名', 'Email already exists': '该邮箱已被注册,请更换邮箱或使用该邮箱登录', 'Invalid username or password': '用户名/手机号或者密码错误', 'User not found': '用户不存在', 'Authentication required': '请先登录', '该邮箱未绑定任何账户': '该邮箱未绑定任何账户,请先注册或绑定邮箱', } if (exactMap[detail]) return exactMap[detail]; // ── 中文 detail 直接透传(后端已是中文的直接用)────────────────── if (detail && !/^[A-Za-z]/.test(detail)) return detail; // ── 按状态码兜底 ───────────────────────────────────────────────── if (statusCode === 400) return detail || '请求参数有误,请检查后重试'; if (statusCode === 401) return '登录已过期,请重新登录'; if (statusCode === 403) return detail || '没有权限执行此操作'; if (statusCode === 404) return detail || '请求的资源不存在'; if (statusCode === 409) return detail || '数据冲突,请检查您的输入'; if (statusCode === 429) return detail || '操作太频繁,请稍后再试'; if (statusCode >= 500) return '服务器繁忙,请稍后重试'; return detail || '请求失败,请稍后重试'; } /** * 用户注册 * 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); } /** * 获取RSA公钥 * GET /api/users/rsa-public-key */ async getRSAPublicKey(): Promise<{ public_key: string }> { const response = await fetch(`${this.baseUrl}/users/rsa-public-key`, { method: 'GET', headers: this.getHeaders(false), }); return this.handleResponse<{ public_key: string }>(response); } /** * 提交实名认证(发送加密数据) * POST /api/users/me/verify */ async submitVerification(encryptedData: string): Promise { const response = await fetch(`${this.baseUrl}/users/me/verify`, { method: 'POST', headers: this.getHeaders(true), body: JSON.stringify({ encrypted_data: encryptedData }), }); return this.handleResponse(response); } /** * 获取公开配置 * GET /api/users/config/public */ async getPublicConfig(): Promise<{ enable_verification_reminder: boolean }> { const response = await fetch(`${this.baseUrl}/users/config/public`, { method: 'GET', headers: this.getHeaders(false), }); return this.handleResponse<{ enable_verification_reminder: boolean }>(response); } /** 发送短信验证码 */ 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 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 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 || '修改失败'); } } /** 发送邮箱验证码 */ async sendEmailCode(email: string, scene: string = 'register'): Promise { const response = await fetch(`${API_BASE_URL}/api/email/send-code`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, scene }), }); if (!response.ok) { const err = await response.json().catch(() => ({})); throw new Error(err.detail || '发送失败,请稍后重试'); } } /** 验证邮箱验证码(不删除,供两步流程第一步使用) */ async verifyEmailCode(email: string, email_code: string): Promise { const response = await fetch(`${API_BASE_URL}/api/email/verify-code`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email, email_code }), }); if (!response.ok) { const err = await response.json().catch(() => ({})); throw new Error(err.detail || '验证码错误'); } } /** 邮箱验证码修改密码 */ async resetPasswordByEmail(email: string, email_code: string, new_password: string): Promise { const response = await fetch(`${this.baseUrl}/auth/reset-password/email`, { method: 'POST', headers: this.getHeaders(false), body: JSON.stringify({ email, email_code, new_password }), }); if (!response.ok) { const err = await response.json().catch(() => ({})); throw new Error(err.detail || '修改失败'); } } } // 导出单例 export const userApi = new UserApiService();