import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:dio/dio.dart'; import '../core/api_client.dart'; import '../core/secure_storage.dart'; /// 用户简要信息 class UserInfo { final String id; final String phone; final String? name; final String? avatarUrl; UserInfo({required this.id, required this.phone, this.name, this.avatarUrl}); } /// 认证状态 class AuthState { final UserInfo? user; final bool isLoggedIn; final bool isLoading; const AuthState({this.user, this.isLoggedIn = false, this.isLoading = true}); } /// 认证 Provider final authProvider = NotifierProvider(AuthNotifier.new); final secureStorageProvider = Provider((ref) => SecureStorage()); final apiClientProvider = Provider((ref) { return ApiClient(storage: ref.watch(secureStorageProvider)); }); class AuthNotifier extends Notifier { @override AuthState build() { _checkAuth(); return const AuthState(isLoading: true); } Future _checkAuth() async { final storage = ref.read(secureStorageProvider); final refresh = await storage.readRefreshToken(); if (refresh == null) { state = const AuthState(isLoggedIn: false, isLoading: false); return; } try { final response = await Dio(BaseOptions(baseUrl: baseUrl)) .post('/api/auth/refresh', data: {'refreshToken': refresh}); final data = response.data['data']; if (data != null) { await storage.writeAccessToken(data['accessToken']); await storage.writeRefreshToken(data['refreshToken']); state = AuthState( isLoggedIn: true, isLoading: false, user: UserInfo(id: '', phone: '', name: data['user']?['name']), ); _loadProfile(); } else { state = const AuthState(isLoggedIn: false, isLoading: false); } } catch (_) { state = const AuthState(isLoggedIn: false, isLoading: false); } } Future _loadProfile() async { try { final api = ref.read(apiClientProvider); final response = await api.get('/api/user/profile'); final user = response.data['data']; if (user != null) { state = AuthState( isLoggedIn: true, isLoading: false, user: UserInfo( id: user['id'] ?? '', phone: user['phone'] ?? '', name: user['name'], avatarUrl: user['avatarUrl'], ), ); } } catch (_) {} } /// 发送验证码,返回 (error, devCode) Future<({String? error, String? devCode})> sendSms(String phone) async { try { final api = ref.read(apiClientProvider); final response = await api.post('/api/auth/send-sms', data: {'phone': phone}); final devCode = response.data['data']?['devCode'] as String?; return (error: null, devCode: devCode); } catch (e) { return (error: '发送失败: $e', devCode: null); } } /// 验证码登录 Future login(String phone, String code) async { try { final api = ref.read(apiClientProvider); final response = await api.post('/api/auth/login', data: {'phone': phone, 'smsCode': code}); final data = response.data['data']; if (data == null) return response.data['message'] ?? '登录失败'; await api.saveTokens(data['accessToken'], data['refreshToken']); final user = data['user']; state = AuthState( isLoggedIn: true, isLoading: false, user: UserInfo( id: user['id'] ?? '', phone: user['phone'] ?? '', name: user['name'], avatarUrl: user['avatarUrl'], ), ); return null; } catch (e) { return '登录失败: $e'; } } /// 登出 Future logout() async { final api = ref.read(apiClientProvider); final storage = ref.read(secureStorageProvider); final refresh = await storage.readRefreshToken(); if (refresh != null) { try { await api.post('/api/auth/logout', data: {'refreshToken': refresh}); } catch (_) {} } await api.clearTokens(); state = const AuthState(isLoggedIn: false, isLoading: false); } }