import 'package:dio/dio.dart'; import '../../core/network/api_client.dart'; import '../../core/storage/storage_service.dart'; import '../../core/constants/app_constants.dart'; import '../../core/errors/app_error.dart'; import '../models/api_response.dart'; import '../models/user_model.dart'; /// 认证服务 class AuthService { static final AuthService _instance = AuthService._internal(); factory AuthService() => _instance; AuthService._internal(); final ApiClient _apiClient = ApiClient.instance; /// 用户注册 Future> register({ required String username, required String email, required String password, required String nickname, String? phone, }) async { try { final response = await _apiClient.post( '/auth/register', data: { 'username': username, 'email': email, 'password': password, 'nickname': nickname, if (phone != null) 'phone': phone, }, ); if (response.statusCode == 201) { final authResponse = AuthResponse.fromJson(response.data['data']); await _saveTokens(authResponse); return ApiResponse.success( message: response.data['message'] ?? '注册成功', data: authResponse, ); } else { return ApiResponse.failure( message: response.data['message'] ?? '注册失败', code: response.statusCode, ); } } on DioException catch (e) { return _handleDioError(e); } catch (e) { return ApiResponse.failure( message: '注册失败:$e', error: e.toString(), ); } } /// 用户登录 Future> login({ required String account, // 用户名或邮箱 required String password, bool rememberMe = false, }) async { try { final response = await _apiClient.post( '/auth/login', data: { 'account': account, 'password': password, }, ); if (response.statusCode == 200) { final authResponse = AuthResponse.fromJson(response.data['data']); await _saveTokens(authResponse); return ApiResponse.success( message: response.data['message'] ?? '登录成功', data: authResponse, ); } else { return ApiResponse.failure( message: response.data['message'] ?? '登录失败', code: response.statusCode, ); } } on DioException catch (e) { return _handleDioError(e); } catch (e) { return ApiResponse.failure( message: '登录失败:$e', error: e.toString(), ); } } /// 刷新Token Future> refreshToken() async { try { final refreshToken = StorageService.getString(AppConstants.refreshTokenKey); if (refreshToken == null) { return ApiResponse.failure( message: 'Refresh token not found', code: 401, ); } final response = await _apiClient.post( '/auth/refresh', data: { 'refresh_token': refreshToken, }, ); if (response.statusCode == 200) { final authResponse = AuthResponse.fromJson(response.data['data']); await _saveTokens(authResponse); return ApiResponse.success( message: 'Token refreshed successfully', data: authResponse, ); } else { return ApiResponse.failure( message: response.data['message'] ?? 'Token refresh failed', code: response.statusCode, ); } } on DioException catch (e) { return _handleDioError(e); } catch (e) { return ApiResponse.failure( message: 'Token refresh failed: $e', error: e.toString(), ); } } /// 用户登出 Future> logout() async { try { final response = await _apiClient.post('/auth/logout'); // 无论服务器响应如何,都清除本地token await _clearTokens(); if (response.statusCode == 200) { return ApiResponse.success( message: response.data['message'] ?? '登出成功', ); } else { return ApiResponse.success( message: '登出成功', ); } } on DioException catch (e) { // 即使请求失败,也清除本地token await _clearTokens(); return ApiResponse.success( message: '登出成功', ); } catch (e) { await _clearTokens(); return ApiResponse.success( message: '登出成功', ); } } /// 获取当前用户信息 Future> getCurrentUser() async { try { final response = await _apiClient.get('/auth/me'); if (response.statusCode == 200) { final user = UserModel.fromJson(response.data['data']); await StorageService.setObject(AppConstants.userInfoKey, user.toJson()); return ApiResponse.success( message: 'User info retrieved successfully', data: user, ); } else { return ApiResponse.failure( message: response.data['message'] ?? 'Failed to get user info', code: response.statusCode, ); } } on DioException catch (e) { return _handleDioError(e); } catch (e) { return ApiResponse.failure( message: 'Failed to get user info: $e', error: e.toString(), ); } } /// 更新用户信息 Future> updateProfile({ String? nickname, String? avatar, String? phone, DateTime? birthday, String? gender, String? bio, String? learningLevel, String? targetLanguage, String? nativeLanguage, int? dailyGoal, }) async { try { final data = {}; if (nickname != null) data['nickname'] = nickname; if (avatar != null) data['avatar'] = avatar; if (phone != null) data['phone'] = phone; if (birthday != null) data['birthday'] = birthday.toIso8601String(); if (gender != null) data['gender'] = gender; if (bio != null) data['bio'] = bio; if (learningLevel != null) data['learning_level'] = learningLevel; if (targetLanguage != null) data['target_language'] = targetLanguage; if (nativeLanguage != null) data['native_language'] = nativeLanguage; if (dailyGoal != null) data['daily_goal'] = dailyGoal; final response = await _apiClient.put('/auth/profile', data: data); if (response.statusCode == 200) { final user = UserModel.fromJson(response.data['data']); await StorageService.setObject(AppConstants.userInfoKey, user.toJson()); return ApiResponse.success( message: response.data['message'] ?? '个人信息更新成功', data: user, ); } else { return ApiResponse.failure( message: response.data['message'] ?? '个人信息更新失败', code: response.statusCode, ); } } on DioException catch (e) { return _handleDioError(e); } catch (e) { return ApiResponse.failure( message: '个人信息更新失败:$e', error: e.toString(), ); } } /// 修改密码 Future> changePassword({ required String currentPassword, required String newPassword, required String confirmPassword, }) async { try { final response = await _apiClient.put( '/auth/change-password', data: { 'current_password': currentPassword, 'new_password': newPassword, 'confirm_password': confirmPassword, }, ); if (response.statusCode == 200) { return ApiResponse.success( message: response.data['message'] ?? '密码修改成功', ); } else { return ApiResponse.failure( message: response.data['message'] ?? '密码修改失败', code: response.statusCode, ); } } on DioException catch (e) { return _handleDioError(e); } catch (e) { return ApiResponse.failure( message: '密码修改失败:$e', error: e.toString(), ); } } /// 检查是否已登录 bool isLoggedIn() { final token = StorageService.getString(AppConstants.accessTokenKey); return token != null && token.isNotEmpty; } /// 获取本地存储的用户信息 UserModel? getCachedUser() { final userJson = StorageService.getObject(AppConstants.userInfoKey); if (userJson != null) { try { return UserModel.fromJson(userJson); } catch (e) { print('Error parsing cached user: $e'); return null; } } return null; } /// 保存tokens Future _saveTokens(AuthResponse authResponse) async { await StorageService.setString( AppConstants.accessTokenKey, authResponse.accessToken, ); await StorageService.setString( AppConstants.refreshTokenKey, authResponse.refreshToken, ); if (authResponse.user != null) { await StorageService.setObject( AppConstants.userInfoKey, authResponse.user!, ); } } /// 清除tokens Future _clearTokens() async { await StorageService.remove(AppConstants.accessTokenKey); await StorageService.remove(AppConstants.refreshTokenKey); await StorageService.remove(AppConstants.userInfoKey); } /// 处理Dio错误 ApiResponse _handleDioError(DioException e) { switch (e.type) { case DioExceptionType.connectionTimeout: case DioExceptionType.sendTimeout: case DioExceptionType.receiveTimeout: return ApiResponse.failure( message: '请求超时,请检查网络连接', error: 'TIMEOUT', ); case DioExceptionType.badResponse: final statusCode = e.response?.statusCode; final message = e.response?.data?['message'] ?? '请求失败'; return ApiResponse.failure( message: message, code: statusCode, error: 'BAD_RESPONSE', ); case DioExceptionType.cancel: return ApiResponse.failure( message: '请求已取消', error: 'CANCELLED', ); case DioExceptionType.connectionError: return ApiResponse.failure( message: '网络连接失败,请检查网络设置', error: 'CONNECTION_ERROR', ); default: return ApiResponse.failure( message: '未知错误:${e.message}', error: 'UNKNOWN', ); } } }