Yue 2 ماه پیش
والد
کامیت
c280849afd
41فایلهای تغییر یافته به همراه1762 افزوده شده و 326 حذف شده
  1. 2 0
      UI/CF.APP/chicken_farm/.gitignore
  2. 3 0
      UI/CF.APP/chicken_farm/analysis_options.yaml
  3. 39 0
      UI/CF.APP/chicken_farm/lib/apis/_login.dart
  4. 15 0
      UI/CF.APP/chicken_farm/lib/apis/index.dart
  5. 61 0
      UI/CF.APP/chicken_farm/lib/apis/system/_user.dart
  6. 11 0
      UI/CF.APP/chicken_farm/lib/apis/system/index.dart
  7. 103 0
      UI/CF.APP/chicken_farm/lib/core/api/api_client.dart
  8. 9 0
      UI/CF.APP/chicken_farm/lib/core/api/api_option.dart
  9. 179 0
      UI/CF.APP/chicken_farm/lib/core/api/api_service.dart
  10. 31 0
      UI/CF.APP/chicken_farm/lib/core/config/app_config.dart
  11. 1 0
      UI/CF.APP/chicken_farm/lib/core/config/env_config.dart
  12. 19 0
      UI/CF.APP/chicken_farm/lib/core/errors/app_error.dart
  13. 47 0
      UI/CF.APP/chicken_farm/lib/core/errors/error_handler.dart
  14. 24 0
      UI/CF.APP/chicken_farm/lib/core/utils/jwt_token.dart
  15. 28 0
      UI/CF.APP/chicken_farm/lib/core/utils/loading.dart
  16. 16 0
      UI/CF.APP/chicken_farm/lib/core/utils/logger.dart
  17. 48 0
      UI/CF.APP/chicken_farm/lib/core/utils/storage.dart
  18. 47 0
      UI/CF.APP/chicken_farm/lib/core/utils/toast.dart
  19. 29 112
      UI/CF.APP/chicken_farm/lib/main.dart
  20. 43 0
      UI/CF.APP/chicken_farm/lib/modes/auth/auth_model.dart
  21. 31 0
      UI/CF.APP/chicken_farm/lib/modes/auth/login_model.dart
  22. 16 0
      UI/CF.APP/chicken_farm/lib/modes/user/org_model.dart
  23. 17 0
      UI/CF.APP/chicken_farm/lib/modes/user/org_model.g.dart
  24. 37 0
      UI/CF.APP/chicken_farm/lib/modes/user/role_model.dart
  25. 35 0
      UI/CF.APP/chicken_farm/lib/modes/user/role_model.g.dart
  26. 18 0
      UI/CF.APP/chicken_farm/lib/modes/user/user_info_model.dart
  27. 27 0
      UI/CF.APP/chicken_farm/lib/modes/user/user_info_model.g.dart
  28. 59 0
      UI/CF.APP/chicken_farm/lib/modes/user/user_model.dart
  29. 63 0
      UI/CF.APP/chicken_farm/lib/modes/user/user_model.g.dart
  30. 208 0
      UI/CF.APP/chicken_farm/lib/pages/account/login.dart
  31. 37 0
      UI/CF.APP/chicken_farm/lib/pages/home/home.dart
  32. 48 0
      UI/CF.APP/chicken_farm/lib/routes/app_routes.dart
  33. 31 0
      UI/CF.APP/chicken_farm/lib/routes/route_guard.dart
  34. 17 0
      UI/CF.APP/chicken_farm/lib/routes/route_provider.dart
  35. 210 0
      UI/CF.APP/chicken_farm/lib/stores/auth_store.dart
  36. 0 0
      UI/CF.APP/chicken_farm/lib/stores/config_store.dart
  37. 106 0
      UI/CF.APP/chicken_farm/lib/widgets/config_dialog.dart
  38. 27 0
      UI/CF.APP/chicken_farm/lib/widgets/loading_overlay.dart
  39. 2 0
      UI/CF.APP/chicken_farm/macos/Flutter/GeneratedPluginRegistrant.swift
  40. 0 213
      UI/CF.APP/chicken_farm/pubspec.lock
  41. 18 1
      UI/CF.APP/chicken_farm/pubspec.yaml

+ 2 - 0
UI/CF.APP/chicken_farm/.gitignore

@@ -3,6 +3,7 @@
 *.log
 *.pyc
 *.swp
+*.lock
 .DS_Store
 .atom/
 .build/
@@ -43,3 +44,4 @@ app.*.map.json
 /android/app/debug
 /android/app/profile
 /android/app/release
+

+ 3 - 0
UI/CF.APP/chicken_farm/analysis_options.yaml

@@ -7,6 +7,9 @@
 
 # The following line activates a set of recommended lints for Flutter apps,
 # packages, and plugins designed to encourage good coding practices.
+analyzer:
+  errors:
+    constant_identifier_names: ignore
 include: package:flutter_lints/flutter.yaml
 
 linter:

+ 39 - 0
UI/CF.APP/chicken_farm/lib/apis/_login.dart

@@ -0,0 +1,39 @@
+import 'package:chicken_farm/core/api/api_service.dart';
+import 'package:chicken_farm/modes/auth/auth_model.dart';
+import 'package:chicken_farm/modes/auth/login_model.dart';
+import 'package:chicken_farm/modes/user/user_info_model.dart';
+import 'package:dio/dio.dart';
+
+class LoginApi {
+  static final LoginApi _instance = LoginApi._internal();
+
+  factory LoginApi() => _instance;
+
+  LoginApi._internal();
+
+  Future<AuthResultModel> login(LoginModel data) async {
+    final response = await ApiService().post('/auth/login', data: data);
+    return AuthResultModel.fromJson(response);
+  }
+
+  Future<AuthResultModel> refreshToken(String refreshToken) async {
+    final response = await ApiService().post(
+      '/auth/refreshToken',
+      data: {"refreshToken": refreshToken},
+    );
+    return AuthResultModel.fromJson(response);
+  }
+
+  Future<UserInfoModel> getInfo() async {
+    final response = await ApiService().get('/system/user/getInfo');
+    return UserInfoModel.fromJson(response);
+  }
+
+  Future<void> logout() async {
+    return ApiService().post('/auth/logout');
+  }
+
+  Future<dynamic> getRouters() async {
+    return await ApiService().get('/system/menu/getRouters');
+  }
+}

+ 15 - 0
UI/CF.APP/chicken_farm/lib/apis/index.dart

@@ -0,0 +1,15 @@
+import 'package:chicken_farm/apis/_login.dart';
+import 'package:chicken_farm/apis/system/index.dart';
+
+class Apis {
+  static final Apis _instance = Apis._internal();
+
+  factory Apis() => _instance;
+
+  Apis._internal();
+
+  late final LoginApi loginApi = LoginApi();
+  late final SystemApis system = SystemApis();
+}
+
+final apis = Apis();

+ 61 - 0
UI/CF.APP/chicken_farm/lib/apis/system/_user.dart

@@ -0,0 +1,61 @@
+import 'package:chicken_farm/core/api/api_service.dart';
+
+class UserApi {
+  static final UserApi _instance = UserApi._internal();
+
+  factory UserApi() => _instance;
+
+  UserApi._internal();
+
+  Future<dynamic> getUser(int userId) async {
+    return await ApiService().get('/system/user/$userId');
+  }
+
+  Future<dynamic> listUser([Map<String, dynamic>? query]) async {
+    return await ApiService().get('/system/user/list', queryParameters: query);
+  }
+
+  Future<dynamic> addUser(Map<String, dynamic> data) async {
+    return await ApiService().post('/system/user', data: data);
+  }
+
+  Future<dynamic> updateUser(Map<String, dynamic> data) async {
+    return await ApiService().put('/system/user', data: data);
+  }
+
+  Future<dynamic> delUser(String userId) async {
+    return await ApiService().delete('/system/user/$userId');
+  }
+
+  Future<dynamic> resetUserPwd(String userId, String password) async {
+    final data = {
+      'userId': userId,
+      'password': password,
+    };
+    return await ApiService().put('/system/user/resetPwd', data: data);
+  }
+
+  Future<dynamic> changeUserStatus(String userId, dynamic status) async {
+    final data = {
+      'userId': userId,
+      'status': status,
+    };
+    return await ApiService().put('/system/user/changeStatus', data: data);
+  }
+
+  Future<dynamic> getUserProfile() async {
+    return await ApiService().get('/system/user/profile');
+  }
+
+  Future<dynamic> updateUserProfile(Map<String, dynamic> data) async {
+    return await ApiService().put('/system/user/profile', data: data);
+  }
+
+  Future<dynamic> updateUserPwd(String oldPassword, String newPassword) async {
+    final data = {
+      'oldPassword': oldPassword,
+      'newPassword': newPassword,
+    };
+    return await ApiService().put('/system/user/profile/updatePwd', data: data);
+  }
+}

+ 11 - 0
UI/CF.APP/chicken_farm/lib/apis/system/index.dart

@@ -0,0 +1,11 @@
+import '_user.dart';
+
+class SystemApis {
+  static final SystemApis _instance = SystemApis._internal();
+
+  factory SystemApis() => _instance;
+
+  SystemApis._internal();
+
+  late final UserApi userApi = UserApi();
+}

+ 103 - 0
UI/CF.APP/chicken_farm/lib/core/api/api_client.dart

@@ -0,0 +1,103 @@
+import 'package:chicken_farm/core/utils/jwt_token.dart';
+import 'package:dio/dio.dart';
+import 'package:flutter/foundation.dart';
+import '../config/app_config.dart';
+import '../utils/logger.dart';
+
+class ApiClient {
+  static Dio? _dio;
+
+  // 存储所有的 CancelToken 实例
+  static final List<CancelToken> _cancelTokens = [];
+
+  static Dio get instance {
+    if (_dio == null) {
+      _initDio();
+    }
+    return _dio!;
+  }
+
+  static void _initDio() {
+    _dio = Dio(
+      BaseOptions(
+        baseUrl: AppConfig.baseUrl,
+        connectTimeout: const Duration(milliseconds: 10000),
+        receiveTimeout: const Duration(milliseconds: 10000),
+        sendTimeout: const Duration(milliseconds: 10000),
+        headers: {
+          'Content-Type': 'application/json',
+          'ClientId': AppConfig.clientId,
+        },
+      ),
+    );
+
+    // 添加请求拦截器
+    _dio?.interceptors.add(
+      InterceptorsWrapper(
+        onRequest: (options, handler) async {
+          // 在发送请求之前做一些预处理
+          logger.d('--> ${options.method} ${options.path}');
+          logger.d('Headers: ${options.headers}');
+          if (options.data != null) {
+            logger.d('Request Data: ${options.data}');
+          }
+
+          // 获取并添加 token
+          String? token = await JwtToken.getToken();
+          if (token != null && token.isNotEmpty) {
+            options.headers['Authorization'] = 'Bearer $token';
+          }
+
+          // 创建并添加 CancelToken
+          final cancelToken = CancelToken();
+          options.cancelToken = cancelToken;
+          _cancelTokens.add(cancelToken);
+
+          handler.next(options);
+        },
+        onResponse: (response, handler) {
+          // 在返回响应数据之前做一些预处理
+          logger.d(
+            '<=== ${response.statusCode} ${response.requestOptions.path}',
+          );
+
+          logger.d('响应数据: ${response.data}');
+          handler.next(response);
+        },
+        onError: (DioException e, handler) {
+          // 当请求失败时做一些预处理
+          logger.e('===> ${e.response?.statusCode} ${e.requestOptions.path}');
+          logger.e('Error: ${e.error}');
+          logger.e('Error Message: ${e.message}');
+          if (e.response?.data != null) {
+            logger.e('Error Response Data: ${e.response?.data}');
+          }
+          handler.next(e);
+        },
+      ),
+    );
+
+    // 在 debug 模式下添加日志拦截器
+    if (kDebugMode) {
+      _dio?.interceptors.add(
+        LogInterceptor(responseBody: true, requestBody: true),
+      );
+    }
+  }
+
+  // 修改baseUrl后需要清空 dio
+  static void clearDio() {
+    _dio = null;
+    _initDio();
+  }
+
+  // 取消所有请求
+  static void cancelAllRequests() {
+    for (final token in _cancelTokens) {
+      if (!token.isCancelled) {
+        token.cancel("All requests canceled");
+      }
+    }
+    _cancelTokens.clear();
+  }
+}

+ 9 - 0
UI/CF.APP/chicken_farm/lib/core/api/api_option.dart

@@ -0,0 +1,9 @@
+class ApiOption {
+  bool alert;
+  bool loading;
+
+  ApiOption({this.alert = true, this.loading = true});
+  ApiOption.noLoading({this.alert = true, this.loading = false});
+  ApiOption.noAlert({this.alert = false, this.loading = true});
+  ApiOption.noAlertNoLoading({this.alert = false, this.loading = false});
+}

+ 179 - 0
UI/CF.APP/chicken_farm/lib/core/api/api_service.dart

@@ -0,0 +1,179 @@
+import 'package:chicken_farm/core/api/api_option.dart';
+import 'package:chicken_farm/core/utils/loading.dart';
+import 'package:chicken_farm/core/utils/logger.dart';
+import 'package:chicken_farm/core/utils/toast.dart';
+import 'package:chicken_farm/routes/app_routes.dart';
+import 'package:chicken_farm/routes/route_provider.dart';
+import 'package:dio/dio.dart';
+import 'package:go_router/go_router.dart';
+import 'api_client.dart';
+import '../errors/error_handler.dart';
+
+class ApiService {
+  final Dio _dio = ApiClient.instance;
+
+  Future<dynamic> get(
+    String path, {
+    Map<String, dynamic>? queryParameters,
+    ApiOption? apiOption,
+    Options? options,
+    CancelToken? cancelToken,
+  }) async {
+    final option = apiOption ?? ApiOption();
+    try {
+      if (option.loading) {
+        LoadingUtil.showLoading();
+      }
+      final response = await _dio.get(
+        path,
+        queryParameters: queryParameters,
+        options: options,
+        cancelToken: cancelToken,
+      );
+      return _handleResponse(response, option);
+    } catch (e) {
+      throw ErrorHandler.handleError(e);
+    } finally {
+      if (option.loading) {
+        LoadingUtil.hideLoading();
+      }
+    }
+  }
+
+  Future<dynamic> post(
+    String path, {
+    dynamic data,
+    Map<String, dynamic>? queryParameters,
+    ApiOption? apiOption,
+    Options? options,
+    CancelToken? cancelToken,
+  }) async {
+    final option = apiOption ?? ApiOption();
+    try {
+      if (option.loading) {
+        LoadingUtil.showLoading();
+      }
+      final response = await _dio.post(
+        path,
+        data: data,
+        queryParameters: queryParameters,
+        options: options,
+        cancelToken: cancelToken,
+      );
+      return _handleResponse(response, option);
+    } catch (e) {
+      throw ErrorHandler.handleError(e);
+    } finally {
+      if (option.loading) {
+        LoadingUtil.hideLoading();
+      }
+    }
+  }
+
+  Future<dynamic> put(
+    String path, {
+    dynamic data,
+    Map<String, dynamic>? queryParameters,
+    ApiOption? apiOption,
+    Options? options,
+    CancelToken? cancelToken,
+  }) async {
+    final option = apiOption ?? ApiOption();
+    try {
+      if (option.loading) {
+        LoadingUtil.showLoading();
+      }
+      final response = await _dio.put(
+        path,
+        data: data,
+        queryParameters: queryParameters,
+        options: options,
+        cancelToken: cancelToken,
+      );
+      return _handleResponse(response, option);
+    } catch (e) {
+      throw ErrorHandler.handleError(e);
+    } finally {
+      if (option.loading) {
+        LoadingUtil.hideLoading();
+      }
+    }
+  }
+
+  Future<dynamic> delete(
+    String path, {
+    dynamic data,
+    Map<String, dynamic>? queryParameters,
+    ApiOption? apiOption,
+    Options? options,
+    CancelToken? cancelToken,
+  }) async {
+    final option = apiOption ?? ApiOption();
+    if (option.loading) {
+      LoadingUtil.showLoading();
+    }
+    try {
+      final response = await _dio.delete(
+        path,
+        data: data,
+        queryParameters: queryParameters,
+        options: options,
+        cancelToken: cancelToken,
+      );
+      return _handleResponse(response, option);
+    } catch (e) {
+      throw ErrorHandler.handleError(e);
+    } finally {
+      if (option.loading) {
+        LoadingUtil.hideLoading();
+      }
+    }
+  }
+
+  dynamic _handleResponse(Response response, ApiOption apiOption) {
+    try {
+      if (response.statusCode == 200 || response.statusCode == 201) {
+        // 假设后端返回的数据结构是 { "code": 200, "msg": "success", "data": ... }
+        final data = response.data;
+        final code = data is Map && data.containsKey('code') ? data['code'] : 0;
+        final msg = data is Map && data.containsKey('msg') ? data['msg'] : null;
+        if (code == 200) {
+          final rData = (data is Map && data.containsKey('data'))
+              ? data['data']
+              : data;
+          if (apiOption.alert) {
+            ToastUtils.success(msg ?? '操作成功');
+          }
+          return rData;
+        } else if (code == 401) {
+          if (apiOption.alert) {
+            ToastUtils.error(msg ?? '请先登录!');
+          }
+          rootNavigatorKey.currentContext?.goNamed(AppRoutePaths.login);
+          return null;
+        } else if (code == 403) {
+          if (apiOption.alert) {
+            ToastUtils.error(msg ?? '没有权限!');
+          }
+          return null;
+        } else {
+          if (apiOption.alert) {
+            ToastUtils.error(data['msg'] ?? '操作失败');
+          }
+          return null;
+        }
+      } else {
+        if (apiOption.alert) {
+          ToastUtils.error(response.statusMessage ?? '请求失败');
+        }
+        return null;
+      }
+    } catch (e) {
+      logger.e("数据解析失败:$e");
+      if (apiOption.alert) {
+        ToastUtils.error('数据解析失败');
+      }
+      return null;
+    }
+  }
+}

+ 31 - 0
UI/CF.APP/chicken_farm/lib/core/config/app_config.dart

@@ -0,0 +1,31 @@
+import 'package:chicken_farm/core/utils/storage.dart';
+
+class AppConfig {
+  static String baseUrl = 'http://192.168.0.81:8380'; // 默认值
+  static String clientId = '9579f8780cf24ae2959d03d11482b18a'; // 默认值
+  static const String baseUrlKey = 'base_url';
+  static const String clientIdKey = 'client_id';
+
+  // 初始化配置
+  static Future<void> init() async {
+    final storedBaseUrl = await StorageUtils.get(baseUrlKey);
+    final storedClientId = await StorageUtils.get(clientIdKey);
+
+    if (storedBaseUrl != null) {
+      baseUrl = storedBaseUrl;
+    }
+
+    if (storedClientId != null) {
+      clientId = storedClientId;
+    }
+  }
+
+  // 保存配置
+  static Future<void> save(String newBaseUrl, String newClientId) async {
+    baseUrl = newBaseUrl;
+    clientId = newClientId;
+
+    await StorageUtils.set(baseUrlKey, newBaseUrl);
+    await StorageUtils.set(clientIdKey, newClientId);
+  }
+}

+ 1 - 0
UI/CF.APP/chicken_farm/lib/core/config/env_config.dart

@@ -0,0 +1 @@
+  

+ 19 - 0
UI/CF.APP/chicken_farm/lib/core/errors/app_error.dart

@@ -0,0 +1,19 @@
+class AppError implements Exception {
+  final String message;
+  final int? statusCode;
+
+  AppError({required this.message, this.statusCode});
+
+  @override
+  String toString() {
+    return 'AppError: $message (Status Code: $statusCode)';
+  }
+}
+
+class NetworkError extends AppError {
+  NetworkError({required super.message, super.statusCode});
+}
+
+class AuthError extends AppError {
+  AuthError({required super.message, super.statusCode});
+}

+ 47 - 0
UI/CF.APP/chicken_farm/lib/core/errors/error_handler.dart

@@ -0,0 +1,47 @@
+import 'package:dio/dio.dart';
+import 'app_error.dart';
+import '../utils/logger.dart';
+
+class ErrorHandler {
+  static AppError handleError(dynamic error) {
+    logger.e('错误详情: $error');
+
+    if (error is DioException) {
+      return _handleDioError(error);
+    } else if (error is AppError) {
+      return error;
+    } else {
+      // 处理其他类型的错误
+      return AppError(message: error.toString());
+    }
+  }
+
+  static AppError _handleDioError(DioException error) {
+    switch (error.type) {
+      case DioExceptionType.connectionTimeout:
+      case DioExceptionType.sendTimeout:
+      case DioExceptionType.receiveTimeout:
+        return NetworkError(message: "连接超时,请检查网络");
+      case DioExceptionType.connectionError:
+        return NetworkError(message: "网络连接错误,请检查网络");
+      case DioExceptionType.badResponse:
+        final statusCode = error.response?.statusCode;
+        final errorMessage = error.response?.data['message'] ?? "服务器错误";
+
+        if (statusCode == 401) {
+          return AuthError(message: "认证失败,请重新登录", statusCode: statusCode);
+        } else if (statusCode == 403) {
+          return AuthError(message: "权限不足", statusCode: statusCode);
+        } else if (statusCode == 404) {
+          return AppError(message: "请求的资源不存在", statusCode: statusCode);
+        } else if (statusCode == 500) {
+          return AppError(message: "服务器内部错误", statusCode: statusCode);
+        }
+        return AppError(message: errorMessage, statusCode: statusCode);
+      case DioExceptionType.cancel:
+        return AppError(message: "请求已取消");
+      default:
+        return AppError(message: "未知错误");
+    }
+  }
+}

+ 24 - 0
UI/CF.APP/chicken_farm/lib/core/utils/jwt_token.dart

@@ -0,0 +1,24 @@
+import 'package:chicken_farm/core/utils/storage.dart';
+
+class JwtToken {
+  static const String tokenKey = "CF_TOKEN";
+  static const String refreshTokenKey = "CF_REFRESH_TOKEN";
+
+  static Future<String?> getToken() async {
+    return await StorageUtils.get(tokenKey);
+  }
+
+  static Future<String?> getRefreshToken() async {
+    return await StorageUtils.get(refreshTokenKey);
+  }
+
+  static Future<void> setToken(String token, String? refreshToken) async {
+    await StorageUtils.set(tokenKey, token);
+    await StorageUtils.set(refreshTokenKey, refreshToken ?? "");
+  }
+
+  static Future<void> clear() async {
+    await StorageUtils.remove(tokenKey);
+    await StorageUtils.remove(refreshTokenKey);
+  }
+}

+ 28 - 0
UI/CF.APP/chicken_farm/lib/core/utils/loading.dart

@@ -0,0 +1,28 @@
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+final loadingProvider = StateProvider<bool>((ref) => false);
+
+class LoadingUtil {
+  static final LoadingUtil _instance = LoadingUtil._internal();
+  static ProviderContainer? _container;
+
+  factory LoadingUtil() => _instance;
+
+  LoadingUtil._internal();
+
+  static void init(ProviderContainer providerContainer) {
+    _container = providerContainer;
+  }
+
+  static void showLoading() {
+    _container?.read(loadingProvider.notifier).state = true;
+  }
+
+  static void hideLoading() {
+    _container?.read(loadingProvider.notifier).state = false;
+  }
+
+  static bool isLoading() {
+    return _container?.read(loadingProvider) ?? false;
+  }
+}

+ 16 - 0
UI/CF.APP/chicken_farm/lib/core/utils/logger.dart

@@ -0,0 +1,16 @@
+import 'package:logger/logger.dart';
+
+final logger = Logger(
+  printer: PrettyPrinter(
+    methodCount: 2,
+    colors: true,
+    printEmojis: true,
+    printTime: false,
+  ),
+);
+
+// 使用示例:
+// logger.d('Debug message');
+// logger.i('Info message');
+// logger.w('Warning message');
+// logger.e('Error message');

+ 48 - 0
UI/CF.APP/chicken_farm/lib/core/utils/storage.dart

@@ -0,0 +1,48 @@
+import 'dart:convert';
+
+import 'package:shared_preferences/shared_preferences.dart';
+
+class StorageUtils {
+  static Future<SharedPreferences> _getInstance() async =>
+      await SharedPreferences.getInstance();
+
+  static Future<void> set(String key, String value) async {
+    final prefs = await _getInstance();
+    await prefs.setString(key, value);
+  }
+
+  static Future<String?> get(String key) async {
+    final prefs = await _getInstance();
+    return prefs.getString(key);
+  }
+
+  static Future<void> setObject<T>(String key, T value) async {
+    final str = json.encode(value);
+    await set(key, str);
+  }
+
+  static Future<T?> getObject<T>(String key) async {
+    final str = await get(key);
+    return str != null ? json.decode(str) as T : null;
+  }
+
+  static Future<void> setBool(String key, bool value) async {
+    final prefs = await _getInstance();
+    await prefs.setBool(key, value);
+  }
+
+  static Future<bool?> getBool(String key) async {
+    final prefs = await _getInstance();
+    return prefs.getBool(key);
+  }
+
+  static Future<void> remove(String key) async {
+    final prefs = await _getInstance();
+    await prefs.remove(key);
+  }
+
+  static Future<void> clear() async {
+    final prefs = await _getInstance();
+    await prefs.clear();
+  }
+}

+ 47 - 0
UI/CF.APP/chicken_farm/lib/core/utils/toast.dart

@@ -0,0 +1,47 @@
+import 'package:flutter/material.dart';
+import 'package:fluttertoast/fluttertoast.dart';
+
+class ToastUtils {
+  static void success(
+    String message, [
+    Toast? toastLength = Toast.LENGTH_SHORT,
+    ToastGravity? gravity = ToastGravity.TOP,
+    Color? textColor = Colors.white,
+    double? fontSize = 16.0,
+  ]) => show(message, Colors.green, toastLength, gravity, textColor, fontSize);
+
+  static void error(
+    String message, [
+    Toast? toastLength = Toast.LENGTH_LONG,
+    ToastGravity? gravity = ToastGravity.CENTER,
+    Color? textColor = Colors.white,
+    double? fontSize = 16.0,
+  ]) => show(message, Colors.red, toastLength, gravity, textColor, fontSize);
+
+  static void info(
+    String message, [
+    Toast? toastLength = Toast.LENGTH_LONG,
+    ToastGravity? gravity = ToastGravity.CENTER,
+    Color? textColor = Colors.white,
+    double? fontSize = 16.0,
+  ]) => show(message, Colors.blue, toastLength, gravity, textColor, fontSize);
+
+  static void show(
+    String message, [
+    Color? backgroundColor = Colors.blue,
+    Toast? toastLength = Toast.LENGTH_SHORT,
+    ToastGravity? gravity = ToastGravity.CENTER,
+    Color? textColor = Colors.white,
+    double? fontSize = 16.0,
+  ]) {
+    Fluttertoast.showToast(
+      msg: message,
+      toastLength: toastLength,
+      gravity: gravity,
+      timeInSecForIosWeb: 1,
+      backgroundColor: backgroundColor,
+      textColor: textColor,
+      fontSize: fontSize,
+    );
+  }
+}

+ 29 - 112
UI/CF.APP/chicken_farm/lib/main.dart

@@ -1,122 +1,39 @@
+import 'package:chicken_farm/core/config/app_config.dart';
+import 'package:chicken_farm/core/utils/loading.dart';
+import 'package:chicken_farm/routes/route_provider.dart';
 import 'package:flutter/material.dart';
-
-void main() {
-  runApp(const MyApp());
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+void main() async {
+  WidgetsFlutterBinding.ensureInitialized();
+  await AppConfig.init(); // 初始化配置
+  
+  final container = ProviderContainer();
+  // 初始化LoadingUtil
+  LoadingUtil.init(container);
+  
+  runApp(
+    ProviderScope(
+      child: MyApp(),
+    ),
+  );
 }
 
-class MyApp extends StatelessWidget {
+class MyApp extends ConsumerWidget {
   const MyApp({super.key});
 
-  // This widget is the root of your application.
   @override
-  Widget build(BuildContext context) {
-    return MaterialApp(
-      title: 'Flutter Demo',
-      theme: ThemeData(
-        // This is the theme of your application.
-        //
-        // TRY THIS: Try running your application with "flutter run". You'll see
-        // the application has a purple toolbar. Then, without quitting the app,
-        // try changing the seedColor in the colorScheme below to Colors.green
-        // and then invoke "hot reload" (save your changes or press the "hot
-        // reload" button in a Flutter-supported IDE, or press "r" if you used
-        // the command line to start the app).
-        //
-        // Notice that the counter didn't reset back to zero; the application
-        // state is not lost during the reload. To reset the state, use hot
-        // restart instead.
-        //
-        // This works for code too, not just values: Most code changes can be
-        // tested with just a hot reload.
-        colorScheme: .fromSeed(seedColor: Colors.deepPurple),
-      ),
-      home: const MyHomePage(title: 'Flutter Demo Home Page'),
-    );
-  }
-}
+  Widget build(BuildContext context, WidgetRef ref) {
+    final goRouter = ref.watch(goRouterProvider);
 
-class MyHomePage extends StatefulWidget {
-  const MyHomePage({super.key, required this.title});
-
-  // This widget is the home page of your application. It is stateful, meaning
-  // that it has a State object (defined below) that contains fields that affect
-  // how it looks.
-
-  // This class is the configuration for the state. It holds the values (in this
-  // case the title) provided by the parent (in this case the App widget) and
-  // used by the build method of the State. Fields in a Widget subclass are
-  // always marked "final".
-
-  final String title;
-
-  @override
-  State<MyHomePage> createState() => _MyHomePageState();
-}
-
-class _MyHomePageState extends State<MyHomePage> {
-  int _counter = 0;
-
-  void _incrementCounter() {
-    setState(() {
-      // This call to setState tells the Flutter framework that something has
-      // changed in this State, which causes it to rerun the build method below
-      // so that the display can reflect the updated values. If we changed
-      // _counter without calling setState(), then the build method would not be
-      // called again, and so nothing would appear to happen.
-      _counter++;
-    });
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    // This method is rerun every time setState is called, for instance as done
-    // by the _incrementCounter method above.
-    //
-    // The Flutter framework has been optimized to make rerunning build methods
-    // fast, so that you can just rebuild anything that needs updating rather
-    // than having to individually change instances of widgets.
-    return Scaffold(
-      appBar: AppBar(
-        // TRY THIS: Try changing the color here to a specific color (to
-        // Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
-        // change color while the other colors stay the same.
-        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
-        // Here we take the value from the MyHomePage object that was created by
-        // the App.build method, and use it to set our appbar title.
-        title: Text(widget.title),
-      ),
-      body: Center(
-        // Center is a layout widget. It takes a single child and positions it
-        // in the middle of the parent.
-        child: Column(
-          // Column is also a layout widget. It takes a list of children and
-          // arranges them vertically. By default, it sizes itself to fit its
-          // children horizontally, and tries to be as tall as its parent.
-          //
-          // Column has various properties to control how it sizes itself and
-          // how it positions its children. Here we use mainAxisAlignment to
-          // center the children vertically; the main axis here is the vertical
-          // axis because Columns are vertical (the cross axis would be
-          // horizontal).
-          //
-          // TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
-          // action in the IDE, or press "p" in the console), to see the
-          // wireframe for each widget.
-          mainAxisAlignment: .center,
-          children: [
-            const Text('You have pushed the button this many times:'),
-            Text(
-              '$_counter',
-              style: Theme.of(context).textTheme.headlineMedium,
-            ),
-          ],
-        ),
-      ),
-      floatingActionButton: FloatingActionButton(
-        onPressed: _incrementCounter,
-        tooltip: 'Increment',
-        child: const Icon(Icons.add),
+    return MaterialApp.router(
+      title: 'Chicken Farm',
+      debugShowCheckedModeBanner: false,
+      theme: ThemeData(
+        useMaterial3: true,
+        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
       ),
+      routerConfig: goRouter,
     );
   }
-}
+}

+ 43 - 0
UI/CF.APP/chicken_farm/lib/modes/auth/auth_model.dart

@@ -0,0 +1,43 @@
+class AuthResultModel {
+  String? scope;
+  String? openid;
+  String accessToken;
+  int? expireIn;
+  String? refreshToken;
+  int? refreshExpireIn;
+  String? clientId;
+
+  AuthResultModel({
+    required this.accessToken,
+    this.expireIn,
+    this.refreshToken,
+    this.refreshExpireIn,
+    this.clientId,
+    this.scope,
+    this.openid,
+  });
+
+  factory AuthResultModel.fromJson(Map<String, dynamic> json) {
+    return AuthResultModel(
+      accessToken: json['access_token'],
+      expireIn: json['expires_in'],
+      refreshToken: json['refresh_token'],
+      refreshExpireIn: json['refresh_expires_in'],
+      clientId: json['client_id'],
+      scope: json['scope'],
+      openid: json['openid'],
+    );
+  }
+
+  Map<String, dynamic> toJson() {
+    return {
+      'access_token': accessToken,
+      'expires_in': expireIn,
+      'refresh_token': refreshToken,
+      'refresh_expires_in': refreshExpireIn,
+      'client_id': clientId,
+      'scope': scope,
+      'openid': openid,
+    };
+  }
+}

+ 31 - 0
UI/CF.APP/chicken_farm/lib/modes/auth/login_model.dart

@@ -0,0 +1,31 @@
+class LoginModel {
+  String username;
+  String password;
+  String clientId;
+  String grantType;
+
+  LoginModel({
+    required this.username,
+    required this.password,
+    this.clientId = "",
+    this.grantType = "password",
+  });
+
+  factory LoginModel.fromJson(Map<String, dynamic> json) {
+    return LoginModel(
+      username: json['username'],
+      password: json['password'],
+      clientId: json['clientId'],
+      grantType: json['grantType'],
+    );
+  }
+
+  Map<String, dynamic> toJson() {
+    return {
+      'username': username,
+      'password': password,
+      'clientId': clientId,
+      'grantType': grantType,
+    };
+  }
+}

+ 16 - 0
UI/CF.APP/chicken_farm/lib/modes/user/org_model.dart

@@ -0,0 +1,16 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'org_model.g.dart';
+
+@JsonSerializable()
+class OrgModel {
+  int? orgId;
+  String? orgName;
+
+  OrgModel({this.orgId, this.orgName});
+
+  factory OrgModel.fromJson(Map<String, dynamic> json) =>
+      _$OrgModelFromJson(json);
+
+  Map<String, dynamic> toJson() => _$OrgModelToJson(this);
+}

+ 17 - 0
UI/CF.APP/chicken_farm/lib/modes/user/org_model.g.dart

@@ -0,0 +1,17 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'org_model.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+OrgModel _$OrgModelFromJson(Map<String, dynamic> json) => OrgModel(
+  orgId: (json['orgId'] as num?)?.toInt(),
+  orgName: json['orgName'] as String?,
+);
+
+Map<String, dynamic> _$OrgModelToJson(OrgModel instance) => <String, dynamic>{
+  'orgId': instance.orgId,
+  'orgName': instance.orgName,
+};

+ 37 - 0
UI/CF.APP/chicken_farm/lib/modes/user/role_model.dart

@@ -0,0 +1,37 @@
+import 'package:json_annotation/json_annotation.dart';
+
+part 'role_model.g.dart';
+
+@JsonSerializable()
+class RoleModel {
+  int? roleId;
+  String? roleName;
+  String? roleKey;
+  int? roleSort;
+  String? dataScope;
+  bool? menuCheckStrictly;
+  bool? orgCheckStrictly;
+  String? status;
+  String? createTime;
+  bool? flag;
+  bool? superAdmin;
+
+  RoleModel({
+    this.roleId,
+    this.roleName,
+    this.roleKey,
+    this.roleSort,
+    this.dataScope,
+    this.menuCheckStrictly,
+    this.orgCheckStrictly,
+    this.status,
+    this.createTime,
+    this.flag,
+    this.superAdmin,
+  });
+
+  factory RoleModel.fromJson(Map<String, dynamic> json) =>
+      _$RoleModelFromJson(json);
+
+  Map<String, dynamic> toJson() => _$RoleModelToJson(this);
+}

+ 35 - 0
UI/CF.APP/chicken_farm/lib/modes/user/role_model.g.dart

@@ -0,0 +1,35 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'role_model.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+RoleModel _$RoleModelFromJson(Map<String, dynamic> json) => RoleModel(
+  roleId: (json['roleId'] as num?)?.toInt(),
+  roleName: json['roleName'] as String?,
+  roleKey: json['roleKey'] as String?,
+  roleSort: (json['roleSort'] as num?)?.toInt(),
+  dataScope: json['dataScope'] as String?,
+  menuCheckStrictly: json['menuCheckStrictly'] as bool?,
+  orgCheckStrictly: json['orgCheckStrictly'] as bool?,
+  status: json['status'] as String?,
+  createTime: json['createTime'] as String?,
+  flag: json['flag'] as bool?,
+  superAdmin: json['superAdmin'] as bool?,
+);
+
+Map<String, dynamic> _$RoleModelToJson(RoleModel instance) => <String, dynamic>{
+  'roleId': instance.roleId,
+  'roleName': instance.roleName,
+  'roleKey': instance.roleKey,
+  'roleSort': instance.roleSort,
+  'dataScope': instance.dataScope,
+  'menuCheckStrictly': instance.menuCheckStrictly,
+  'orgCheckStrictly': instance.orgCheckStrictly,
+  'status': instance.status,
+  'createTime': instance.createTime,
+  'flag': instance.flag,
+  'superAdmin': instance.superAdmin,
+};

+ 18 - 0
UI/CF.APP/chicken_farm/lib/modes/user/user_info_model.dart

@@ -0,0 +1,18 @@
+import 'package:chicken_farm/modes/user/user_model.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'user_info_model.g.dart';
+
+@JsonSerializable()
+class UserInfoModel {
+  UserModel? user;
+  List<String>? permissions;
+  List<String>? roles;
+
+  UserInfoModel({this.user, this.permissions, this.roles});
+
+  factory UserInfoModel.fromJson(Map<String, dynamic> json) =>
+      _$UserInfoModelFromJson(json);
+
+  Map<String, dynamic> toJson() => _$UserInfoModelToJson(this);
+}

+ 27 - 0
UI/CF.APP/chicken_farm/lib/modes/user/user_info_model.g.dart

@@ -0,0 +1,27 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'user_info_model.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+UserInfoModel _$UserInfoModelFromJson(Map<String, dynamic> json) =>
+    UserInfoModel(
+      user: json['user'] == null
+          ? null
+          : UserModel.fromJson(json['user'] as Map<String, dynamic>),
+      permissions: (json['permissions'] as List<dynamic>?)
+          ?.map((e) => e as String)
+          .toList(),
+      roles: (json['roles'] as List<dynamic>?)
+          ?.map((e) => e as String)
+          .toList(),
+    );
+
+Map<String, dynamic> _$UserInfoModelToJson(UserInfoModel instance) =>
+    <String, dynamic>{
+      'user': instance.user,
+      'permissions': instance.permissions,
+      'roles': instance.roles,
+    };

+ 59 - 0
UI/CF.APP/chicken_farm/lib/modes/user/user_model.dart

@@ -0,0 +1,59 @@
+import 'package:chicken_farm/modes/user/org_model.dart';
+import 'package:chicken_farm/modes/user/role_model.dart';
+import 'package:json_annotation/json_annotation.dart';
+
+part 'user_model.g.dart';
+
+@JsonSerializable()
+class UserModel {
+  int? userId;
+  String? tenantId;
+  int? orgId;
+  String? userName;
+  String? nickName;
+  String? userType;
+  String? email;
+  String? phonenumber;
+  String? sex;
+  String? avatar;
+  String? status;
+  String? leaderName;
+  String? loginIp;
+  String? loginDate;
+  String? remark;
+  String? createTime;
+  OrgModel? org;
+  String? orgName;
+  List<RoleModel>? roles;
+  List<int>? roleIds;
+  List<int>? postIds;
+
+  UserModel({
+    this.userId,
+    this.tenantId,
+    this.orgId,
+    this.userName,
+    this.nickName,
+    this.userType,
+    this.email,
+    this.phonenumber,
+    this.sex,
+    this.avatar,
+    this.status,
+    this.leaderName,
+    this.loginIp,
+    this.loginDate,
+    this.remark,
+    this.createTime,
+    this.org,
+    this.orgName,
+    this.roles,
+    this.roleIds,
+    this.postIds,
+  });
+
+  factory UserModel.fromJson(Map<String, dynamic> json) =>
+      _$UserModelFromJson(json);
+
+  Map<String, dynamic> toJson() => _$UserModelToJson(this);
+}

+ 63 - 0
UI/CF.APP/chicken_farm/lib/modes/user/user_model.g.dart

@@ -0,0 +1,63 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'user_model.dart';
+
+// **************************************************************************
+// JsonSerializableGenerator
+// **************************************************************************
+
+UserModel _$UserModelFromJson(Map<String, dynamic> json) => UserModel(
+  userId: (json['userId'] as num?)?.toInt(),
+  tenantId: json['tenantId'] as String?,
+  orgId: (json['orgId'] as num?)?.toInt(),
+  userName: json['userName'] as String?,
+  nickName: json['nickName'] as String?,
+  userType: json['userType'] as String?,
+  email: json['email'] as String?,
+  phonenumber: json['phonenumber'] as String?,
+  sex: json['sex'] as String?,
+  avatar: json['avatar'] as String?,
+  status: json['status'] as String?,
+  leaderName: json['leaderName'] as String?,
+  loginIp: json['loginIp'] as String?,
+  loginDate: json['loginDate'] as String?,
+  remark: json['remark'] as String?,
+  createTime: json['createTime'] as String?,
+  org: json['org'] == null
+      ? null
+      : OrgModel.fromJson(json['org'] as Map<String, dynamic>),
+  orgName: json['orgName'] as String?,
+  roles: (json['roles'] as List<dynamic>?)
+      ?.map((e) => RoleModel.fromJson(e as Map<String, dynamic>))
+      .toList(),
+  roleIds: (json['roleIds'] as List<dynamic>?)
+      ?.map((e) => (e as num).toInt())
+      .toList(),
+  postIds: (json['postIds'] as List<dynamic>?)
+      ?.map((e) => (e as num).toInt())
+      .toList(),
+);
+
+Map<String, dynamic> _$UserModelToJson(UserModel instance) => <String, dynamic>{
+  'userId': instance.userId,
+  'tenantId': instance.tenantId,
+  'orgId': instance.orgId,
+  'userName': instance.userName,
+  'nickName': instance.nickName,
+  'userType': instance.userType,
+  'email': instance.email,
+  'phonenumber': instance.phonenumber,
+  'sex': instance.sex,
+  'avatar': instance.avatar,
+  'status': instance.status,
+  'leaderName': instance.leaderName,
+  'loginIp': instance.loginIp,
+  'loginDate': instance.loginDate,
+  'remark': instance.remark,
+  'createTime': instance.createTime,
+  'org': instance.org,
+  'orgName': instance.orgName,
+  'roles': instance.roles,
+  'roleIds': instance.roleIds,
+  'postIds': instance.postIds,
+};

+ 208 - 0
UI/CF.APP/chicken_farm/lib/pages/account/login.dart

@@ -0,0 +1,208 @@
+import 'package:chicken_farm/core/utils/logger.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:go_router/go_router.dart';
+import 'package:chicken_farm/core/utils/toast.dart';
+import 'package:chicken_farm/modes/auth/login_model.dart';
+import 'package:chicken_farm/routes/app_routes.dart';
+import 'package:chicken_farm/stores/auth_store.dart';
+import 'package:chicken_farm/widgets/config_dialog.dart';
+
+class LoginPage extends ConsumerStatefulWidget {
+  const LoginPage({super.key});
+
+  @override
+  ConsumerState<LoginPage> createState() => _LoginPageState();
+}
+
+class _LoginPageState extends ConsumerState<LoginPage> {
+  final _formKey = GlobalKey<FormState>();
+  final _usernameCtrl = TextEditingController(text: 'admin');
+  final _passwordCtrl = TextEditingController(text: '123iwb');
+
+  @override
+  void dispose() {
+    _usernameCtrl.dispose();
+    _passwordCtrl.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final authState = ref.watch(authStoreProvider);
+    final authStore = ref.read(authStoreProvider.notifier);
+
+    // 监听认证状态变化,如果已认证则跳转到主页
+    WidgetsBinding.instance.addPostFrameCallback((_) {
+      if (authState.state == AuthState.authenticated && context.mounted) {
+        context.goNamed(AppRoutePaths.home);
+      }
+    });
+
+    ref.listen<AuthInfo>(authStoreProvider, (previous, next) {
+      if (next.state == AuthState.authenticated) {
+        // 登录成功,跳转到主页
+        if (context.mounted) {
+          context.goNamed(AppRoutePaths.home);
+        }
+      }
+    });
+
+    return Scaffold(
+      appBar: AppBar(
+        title: const Text('用户登录'),
+        backgroundColor: Theme.of(context).colorScheme.primary,
+        foregroundColor: Colors.white,
+      ),
+      body: Stack(
+        children: [
+          Container(
+            decoration: BoxDecoration(
+              gradient: LinearGradient(
+                begin: Alignment.topCenter,
+                end: Alignment.bottomCenter,
+                colors: [
+                  Theme.of(context).colorScheme.primary.withValues(alpha: 0.1),
+                  Theme.of(context).colorScheme.surface,
+                ],
+              ),
+            ),
+            child: Center(
+              child: SingleChildScrollView(
+                padding: const EdgeInsets.all(24.0),
+                child: Card(
+                  elevation: 8,
+                  shape: RoundedRectangleBorder(
+                    borderRadius: BorderRadius.circular(16),
+                  ),
+                  child: Padding(
+                    padding: const EdgeInsets.all(24.0),
+                    child: Form(
+                      key: _formKey,
+                      child: Column(
+                        mainAxisSize: MainAxisSize.min,
+                        children: [
+                          Text(
+                            '养殖场管理系统',
+                            style: TextStyle(
+                              fontSize: 24,
+                              fontWeight: FontWeight.bold,
+                              color: Theme.of(context).colorScheme.primary,
+                            ),
+                          ),
+                          const SizedBox(height: 24),
+                          TextFormField(
+                            controller: _usernameCtrl,
+                            decoration: InputDecoration(
+                              labelText: '用户名',
+                              prefixIcon: const Icon(Icons.person),
+                              border: OutlineInputBorder(
+                                borderRadius: BorderRadius.circular(12),
+                              ),
+                              filled: true,
+                              fillColor: Colors.grey[50],
+                            ),
+                            validator: (v) => v!.isEmpty ? '请输入用户名' : null,
+                          ),
+                          const SizedBox(height: 16),
+                          TextFormField(
+                            controller: _passwordCtrl,
+                            obscureText: true,
+                            decoration: InputDecoration(
+                              labelText: '密码',
+                              prefixIcon: const Icon(Icons.lock),
+                              border: OutlineInputBorder(
+                                borderRadius: BorderRadius.circular(12),
+                              ),
+                              filled: true,
+                              fillColor: Colors.grey[50],
+                            ),
+                            validator: (v) => v!.length < 6 ? '密码不能少于6位' : null,
+                          ),
+                          const SizedBox(height: 24),
+                          SizedBox(
+                            width: double.infinity,
+                            height: 50,
+                            child: ElevatedButton(
+                              onPressed: authState.state == AuthState.loading
+                                  ? null
+                                  : () {
+                                      if (_formKey.currentState!.validate()) {
+                                        authStore
+                                            .login(
+                                              LoginModel(
+                                                username: _usernameCtrl.text,
+                                                password: _passwordCtrl.text,
+                                              ),
+                                            )
+                                            .then((_) async {
+                                              // 登录成功后跳转到主页
+                                              if (context.mounted) {
+                                                logger.d('登录成功');
+                                                context.goNamed(
+                                                  AppRoutePaths.home,
+                                                );
+                                              }
+                                            })
+                                            .catchError((error) {
+                                              // 处理登录错误
+                                              logger.e('登录失败: $error');
+                                              if (context.mounted) {
+                                                String errorMessage = '登录失败';
+                                                if (error is Exception) {
+                                                  errorMessage = error.toString();
+                                                }
+                                                ToastUtils.error(errorMessage);
+                                              }
+                                            });
+                                      }
+                                    },
+                              style: ElevatedButton.styleFrom(
+                                shape: RoundedRectangleBorder(
+                                  borderRadius: BorderRadius.circular(12),
+                                ),
+                                textStyle: const TextStyle(fontSize: 16),
+                              ),
+                              child: authState.state == AuthState.loading
+                                  ? const CircularProgressIndicator(
+                                      color: Colors.white,
+                                    )
+                                  : const Text('登录'),
+                            ),
+                          ),
+                        ],
+                      ),
+                    ),
+                  ),
+                ),
+              ),
+            ),
+          ),
+          Positioned(
+            bottom: 16,
+            right: 16,
+            child: IconButton(
+              icon: const Icon(Icons.settings),
+              onPressed: () async {
+                final result = await showDialog(
+                  context: context,
+                  builder: (context) => const ConfigDialog(),
+                );
+                // 如果配置发生了变化,显示提示
+                if (result == true && context.mounted) {
+                  // ScaffoldMessenger.of(context).showSnackBar(
+                  //   const SnackBar(
+                  //     content: Text('配置已保存'),
+                  //     duration: Duration(seconds: 2),
+                  //   ),
+                  // );
+                  ToastUtils.success('配置已保存');
+                }
+              },
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}

+ 37 - 0
UI/CF.APP/chicken_farm/lib/pages/home/home.dart

@@ -0,0 +1,37 @@
+import 'package:chicken_farm/stores/auth_store.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+
+class HomePage extends ConsumerWidget {
+  const HomePage({super.key});
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final authState = ref.watch(authStoreProvider);
+    final authStore = ref.read(authStoreProvider.notifier);
+
+    return Scaffold(
+      appBar: AppBar(
+        title: const Text('主页'),
+        actions: [
+          IconButton(
+            icon: const Icon(Icons.logout),
+            onPressed: () => authStore.logout(),
+          ),
+        ],
+      ),
+      body: Center(child: _buildContent(authState)),
+    );
+  }
+
+  Widget _buildContent(AuthInfo authState) {
+    switch (authState.state) {
+      case AuthState.loading:
+        return const CircularProgressIndicator();
+      case AuthState.unauthenticated:
+        return const Text('未登录');
+      case AuthState.authenticated:
+        return Text('欢迎回来, ${authState.user?.nickName ?? '访客'}!');
+    }
+  }
+}

+ 48 - 0
UI/CF.APP/chicken_farm/lib/routes/app_routes.dart

@@ -0,0 +1,48 @@
+import 'package:chicken_farm/stores/auth_store.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:go_router/go_router.dart';
+import '../pages/account/login.dart';
+import '../pages/home/home.dart';
+
+class AppRoutePaths {
+  static const String splash = '/';
+  static const String login = '/login';
+  static const String home = '/home';
+}
+
+class AppRoutes {
+  static final List<GoRoute> routes = [
+    GoRoute(
+      path: AppRoutePaths.splash,
+      builder: (context, state) => const SplashScreen(),
+    ),
+    GoRoute(
+      path: AppRoutePaths.login,
+      name: AppRoutePaths.login,
+      builder: (context, state) => const LoginPage(),
+    ),
+    GoRoute(
+      path: AppRoutePaths.home,
+      name: AppRoutePaths.home,
+      builder: (context, state) => const HomePage(),
+    ),
+  ];
+}
+
+// 启动屏
+class SplashScreen extends ConsumerWidget {
+  const SplashScreen({super.key});
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    ref.listen(authStoreProvider, (previous, next) {
+      if (next.state == AuthState.authenticated) {
+        context.goNamed(AppRoutePaths.home);
+      } else if (next.state != AuthState.loading) {
+        context.goNamed(AppRoutePaths.login);
+      }
+    });
+    return const Scaffold(body: Center(child: CircularProgressIndicator()));
+  }
+}

+ 31 - 0
UI/CF.APP/chicken_farm/lib/routes/route_guard.dart

@@ -0,0 +1,31 @@
+import 'package:chicken_farm/core/utils/logger.dart';
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:chicken_farm/stores/auth_store.dart';
+
+class RouteGuard {
+  static String? redirectLogic(BuildContext context, GoRouterState state) {
+    final container = ProviderScope.containerOf(context);
+    final authState = container.read(authStoreProvider);
+    final isGoingToLogin = state.matchedLocation == '/login';
+    logger.d(
+      "-- redirect -- path: ${state.matchedLocation} state: ${authState.state}",
+    );
+    if (authState.state == AuthState.loading) return null; // 加载中不跳转
+
+    // // 如果已经认证,且当前不在主页,则跳转到主页
+    // if (authState.state == AuthState.authenticated && isGoingToLogin) {
+    //   return '/home';
+    // }
+
+    // 如果未认证,且不是前往登录页或启动页,则跳转到登录页
+    if (authState.state != AuthState.authenticated &&
+        !isGoingToLogin &&
+        state.matchedLocation != '/') {
+      return '/login';
+    }
+
+    return null;
+  }
+}

+ 17 - 0
UI/CF.APP/chicken_farm/lib/routes/route_provider.dart

@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:go_router/go_router.dart';
+import 'app_routes.dart';
+import 'route_guard.dart';
+
+/// 全局导航键,用于在没有BuildContext的情况下进行导航
+final GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>();
+
+final goRouterProvider = Provider<GoRouter>((ref) {
+  return GoRouter(
+    navigatorKey: rootNavigatorKey,
+    routes: AppRoutes.routes,
+    redirect: RouteGuard.redirectLogic,
+    initialLocation: AppRoutePaths.splash,
+  );
+});

+ 210 - 0
UI/CF.APP/chicken_farm/lib/stores/auth_store.dart

@@ -0,0 +1,210 @@
+import 'package:chicken_farm/apis/index.dart';
+import 'package:chicken_farm/core/config/app_config.dart';
+import 'package:chicken_farm/core/utils/jwt_token.dart';
+import 'package:chicken_farm/core/utils/logger.dart';
+import 'package:chicken_farm/modes/auth/login_model.dart';
+import 'package:chicken_farm/modes/user/user_model.dart';
+import 'package:chicken_farm/routes/app_routes.dart';
+import 'package:chicken_farm/routes/route_provider.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:go_router/go_router.dart';
+
+/// 认证状态枚举
+enum AuthState { authenticated, unauthenticated, loading }
+
+/// 用户认证信息状态
+class AuthInfo {
+  final AuthState state;
+  final String? token;
+  final UserModel? user;
+  final List<String>? permissions;
+  final List<String>? roles;
+
+  AuthInfo({
+    required this.state,
+    this.token,
+    this.user,
+    this.permissions,
+    this.roles,
+  });
+
+  /// 创建已认证状态
+  AuthInfo.authenticated({
+    required String token,
+    required UserModel user,
+    List<String>? permissions,
+    List<String>? roles,
+  }) : this(
+         state: AuthState.authenticated,
+         token: token,
+         user: user,
+         permissions: permissions,
+         roles: roles,
+       );
+
+  /// 创建未认证状态
+  AuthInfo.unauthenticated()
+    : this(
+        state: AuthState.unauthenticated,
+        token: null,
+        user: null,
+        permissions: const [],
+        roles: const [],
+      );
+
+  /// 创建加载状态
+  AuthInfo.loading()
+    : this(
+        state: AuthState.loading,
+        token: null,
+        user: null,
+        permissions: const [],
+        roles: const [],
+      );
+
+  /// 复制对象并更新部分字段
+  AuthInfo copyWith({
+    AuthState? state,
+    String? token,
+    UserModel? user,
+    List<String>? permissions,
+    List<String>? roles,
+  }) {
+    return AuthInfo(
+      state: state ?? this.state,
+      token: token ?? this.token,
+      user: user ?? this.user,
+      permissions: permissions ?? this.permissions,
+      roles: roles ?? this.roles,
+    );
+  }
+}
+
+class AuthStore extends StateNotifier<AuthInfo> {
+  AuthStore() : super(AuthInfo.unauthenticated()) {
+    _init();
+  }
+
+  /// 初始化认证状态
+  Future<void> _init() async {
+    state = AuthInfo.loading();
+    try {
+      final token = await JwtToken.getToken();
+      if (token != null) {
+        // 如果有token,则设置为已认证状态
+        // 尝试获取用户信息以验证token有效性
+        try {
+          final userInfo = await apis.loginApi.getInfo();
+          state = AuthInfo.authenticated(
+            token: token,
+            user: userInfo.user!,
+            permissions: userInfo.permissions,
+            roles: userInfo.roles,
+          );
+          logger.i('已登录 state: $state');
+        } catch (e) {
+          // Token无效,清除本地存储
+          await JwtToken.clear();
+          state = AuthInfo.unauthenticated();
+        }
+      } else {
+        state = AuthInfo.unauthenticated();
+      }
+    } catch (e) {
+      state = AuthInfo.unauthenticated();
+    }
+  }
+
+  /// 登录操作
+  Future<void> login(LoginModel loginModel) async {
+    state = AuthInfo.loading();
+    try {
+      loginModel.clientId = AppConfig.clientId;
+      final authResult = await apis.loginApi.login(loginModel);
+      final token = authResult.accessToken;
+      await JwtToken.setToken(token, authResult.refreshToken);
+      // 获取用户信息
+      final userInfo = await apis.loginApi.getInfo();
+      state = AuthInfo.authenticated(
+        token: token,
+        user: userInfo.user!,
+        permissions: userInfo.permissions,
+        roles: userInfo.roles,
+      );
+      logger.i('登录成功 state: $state');
+    } catch (e) {
+      await JwtToken.clear();
+      state = AuthInfo.unauthenticated();
+    }
+  }
+
+  /// 登出操作
+  Future<void> logout() async {
+    try {
+      await apis.loginApi.logout();
+    } catch (e) {
+      // 即使API调用失败也要清除本地状态
+      logger.e('Logout API call failed: $e');
+    } finally {
+      await JwtToken.clear();
+      state = AuthInfo.unauthenticated();
+      if (rootNavigatorKey.currentState != null &&
+          rootNavigatorKey.currentContext != null) {
+        rootNavigatorKey.currentContext!.goNamed(AppRoutePaths.login);
+      }
+    }
+  }
+
+  /// 刷新token
+  Future<void> refreshToken() async {
+    try {
+      final refreshToken = await JwtToken.getRefreshToken();
+      if (refreshToken != null) {
+        final authResult = await apis.loginApi.refreshToken(refreshToken);
+        final newToken = authResult.accessToken;
+        await JwtToken.setToken(newToken, authResult.refreshToken);
+        state = state.copyWith(token: newToken);
+      }
+    } catch (e) {
+      // 刷新失败则登出
+      await logout();
+      rethrow;
+    }
+  }
+
+  /// 重新获取用户信息
+  Future<void> getUserInfo() async {
+    try {
+      final userInfo = await apis.loginApi.getInfo();
+      state = state.copyWith(
+        user: userInfo.user,
+        permissions: userInfo.permissions,
+        roles: userInfo.roles,
+      );
+    } catch (e) {
+      rethrow;
+    }
+  }
+
+  /// 检查是否有特定权限
+  bool hasPermission(String permission) {
+    return state.permissions?.contains(permission) ?? false;
+  }
+
+  /// 检查是否有特定角色
+  bool hasRole(String role) {
+    return state.roles?.contains(role) ?? false;
+  }
+
+  /// 是否是超级管理员
+  bool isSuperAdmin() {
+    if (state.user == null) return false;
+    return state.user!.userName == "admin" ||
+        (state.roles?.contains("super_admin") ?? false);
+  }
+}
+
+// 添加 Provider 实例
+final authStoreProvider = StateNotifierProvider<AuthStore, AuthInfo>(
+  (ref) => AuthStore(),
+);

+ 0 - 0
UI/CF.APP/chicken_farm/lib/stores/config_store.dart


+ 106 - 0
UI/CF.APP/chicken_farm/lib/widgets/config_dialog.dart

@@ -0,0 +1,106 @@
+import 'package:chicken_farm/core/api/api_client.dart';
+import 'package:chicken_farm/core/config/app_config.dart';
+import 'package:flutter/material.dart';
+
+class ConfigDialog extends StatefulWidget {
+  const ConfigDialog({super.key});
+
+  @override
+  State<ConfigDialog> createState() => _ConfigDialogState();
+}
+
+class _ConfigDialogState extends State<ConfigDialog> {
+  final _formKey = GlobalKey<FormState>();
+  late TextEditingController _baseUrlController;
+  late TextEditingController _clientIdController;
+
+  @override
+  void initState() {
+    super.initState();
+    _baseUrlController = TextEditingController(text: AppConfig.baseUrl);
+    _clientIdController = TextEditingController(text: AppConfig.clientId);
+  }
+
+  @override
+  void dispose() {
+    _baseUrlController.dispose();
+    _clientIdController.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return AlertDialog(
+      title: const Text('配置服务器'),
+      content: SizedBox(
+        width: MediaQuery.of(context).size.width * 0.8,
+        child: Form(
+          key: _formKey,
+          child: Column(
+            mainAxisSize: MainAxisSize.min,
+            children: [
+              TextFormField(
+                controller: _baseUrlController,
+                decoration: const InputDecoration(
+                  labelText: 'Base URL',
+                  hintText: '例如: http://localhost:8080',
+                  border: OutlineInputBorder(),
+                ),
+                validator: (value) {
+                  if (value == null || value.isEmpty) {
+                    return '请输入Base URL';
+                  }
+                  if (!value.startsWith('http')) {
+                    return '请输入有效的URL地址';
+                  }
+                  return null;
+                },
+              ),
+              const SizedBox(height: 16),
+              TextFormField(
+                controller: _clientIdController,
+                decoration: const InputDecoration(
+                  labelText: 'Client ID',
+                  border: OutlineInputBorder(),
+                ),
+                validator: (value) {
+                  if (value == null || value.isEmpty) {
+                    return '请输入Client ID';
+                  }
+                  return null;
+                },
+              ),
+            ],
+          ),
+        ),
+      ),
+      actions: [
+        TextButton(
+          onPressed: () {
+            Navigator.of(context).pop();
+          },
+          child: const Text('取消'),
+        ),
+        ElevatedButton(
+          onPressed: () async {
+            if (_formKey.currentState!.validate()) {
+              // 保存配置
+              await AppConfig.save(
+                _baseUrlController.text.trim(),
+                _clientIdController.text.trim(),
+              );
+              
+              // 重新初始化API客户端
+              ApiClient.clearDio();
+              
+              if (context.mounted) {
+                Navigator.of(context).pop(true);
+              }
+            }
+          },
+          child: const Text('保存'),
+        ),
+      ],
+    );
+  }
+}

+ 27 - 0
UI/CF.APP/chicken_farm/lib/widgets/loading_overlay.dart

@@ -0,0 +1,27 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:chicken_farm/core/utils/loading.dart';
+
+class LoadingOverlay extends ConsumerWidget {
+  final Widget child;
+
+  const LoadingOverlay({super.key, required this.child});
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final isLoading = ref.watch(loadingProvider);
+    
+    return Stack(
+      children: [
+        child,
+        if (isLoading)
+          Container(
+            color: Colors.black.withValues(alpha: 0.5),
+            child: const Center(
+              child: CircularProgressIndicator(),
+            ),
+          ),
+      ],
+    );
+  }
+}

+ 2 - 0
UI/CF.APP/chicken_farm/macos/Flutter/GeneratedPluginRegistrant.swift

@@ -5,6 +5,8 @@
 import FlutterMacOS
 import Foundation
 
+import shared_preferences_foundation
 
 func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
+  SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
 }

+ 0 - 213
UI/CF.APP/chicken_farm/pubspec.lock

@@ -1,213 +0,0 @@
-# Generated by pub
-# See https://dart.dev/tools/pub/glossary#lockfile
-packages:
-  async:
-    dependency: transitive
-    description:
-      name: async
-      sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "2.13.0"
-  boolean_selector:
-    dependency: transitive
-    description:
-      name: boolean_selector
-      sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "2.1.2"
-  characters:
-    dependency: transitive
-    description:
-      name: characters
-      sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.4.0"
-  clock:
-    dependency: transitive
-    description:
-      name: clock
-      sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.1.2"
-  collection:
-    dependency: transitive
-    description:
-      name: collection
-      sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.19.1"
-  cupertino_icons:
-    dependency: "direct main"
-    description:
-      name: cupertino_icons
-      sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.0.8"
-  fake_async:
-    dependency: transitive
-    description:
-      name: fake_async
-      sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.3.3"
-  flutter:
-    dependency: "direct main"
-    description: flutter
-    source: sdk
-    version: "0.0.0"
-  flutter_lints:
-    dependency: "direct dev"
-    description:
-      name: flutter_lints
-      sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "6.0.0"
-  flutter_test:
-    dependency: "direct dev"
-    description: flutter
-    source: sdk
-    version: "0.0.0"
-  leak_tracker:
-    dependency: transitive
-    description:
-      name: leak_tracker
-      sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "11.0.2"
-  leak_tracker_flutter_testing:
-    dependency: transitive
-    description:
-      name: leak_tracker_flutter_testing
-      sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "3.0.10"
-  leak_tracker_testing:
-    dependency: transitive
-    description:
-      name: leak_tracker_testing
-      sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "3.0.2"
-  lints:
-    dependency: transitive
-    description:
-      name: lints
-      sha256: a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "6.0.0"
-  matcher:
-    dependency: transitive
-    description:
-      name: matcher
-      sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "0.12.17"
-  material_color_utilities:
-    dependency: transitive
-    description:
-      name: material_color_utilities
-      sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "0.11.1"
-  meta:
-    dependency: transitive
-    description:
-      name: meta
-      sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.17.0"
-  path:
-    dependency: transitive
-    description:
-      name: path
-      sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.9.1"
-  sky_engine:
-    dependency: transitive
-    description: flutter
-    source: sdk
-    version: "0.0.0"
-  source_span:
-    dependency: transitive
-    description:
-      name: source_span
-      sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.10.1"
-  stack_trace:
-    dependency: transitive
-    description:
-      name: stack_trace
-      sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.12.1"
-  stream_channel:
-    dependency: transitive
-    description:
-      name: stream_channel
-      sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "2.1.4"
-  string_scanner:
-    dependency: transitive
-    description:
-      name: string_scanner
-      sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.4.1"
-  term_glyph:
-    dependency: transitive
-    description:
-      name: term_glyph
-      sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "1.2.2"
-  test_api:
-    dependency: transitive
-    description:
-      name: test_api
-      sha256: ab2726c1a94d3176a45960b6234466ec367179b87dd74f1611adb1f3b5fb9d55
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "0.7.7"
-  vector_math:
-    dependency: transitive
-    description:
-      name: vector_math
-      sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "2.2.0"
-  vm_service:
-    dependency: transitive
-    description:
-      name: vm_service
-      sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60"
-      url: "https://mirrors.tuna.tsinghua.edu.cn/dart-pub/"
-    source: hosted
-    version: "15.0.2"
-sdks:
-  dart: ">=3.10.1 <4.0.0"
-  flutter: ">=3.18.0-18.0.pre.54"

+ 18 - 1
UI/CF.APP/chicken_farm/pubspec.yaml

@@ -33,7 +33,21 @@ dependencies:
 
   # The following adds the Cupertino Icons font to your application.
   # Use with the CupertinoIcons class for iOS style icons.
-  cupertino_icons: ^1.0.8
+   # 状态管理
+  flutter_riverpod: ^2.3.0
+  riverpod_annotation: ^2.1.1
+
+  # 网络请求
+  dio: ^5.4.0
+
+  # 路由管理
+  go_router: ^12.1.0
+
+  # 工具
+  json_annotation: ^4.9.0 # JSON 序列化
+  logger: ^1.1.0         # 日志
+  fluttertoast: ^8.2.2   # 弹窗
+  shared_preferences: ^2.2.2 # 本地存储
 
 dev_dependencies:
   flutter_test:
@@ -45,6 +59,9 @@ dev_dependencies:
   # package. See that file for information about deactivating specific lint
   # rules and activating additional ones.
   flutter_lints: ^6.0.0
+  build_runner: ^2.4.4
+  json_serializable: ^6.7.0
+  riverpod_generator: ^2.2.3
 
 # For information on the generic Dart part of this file, see the
 # following page: https://dart.dev/tools/pub/pubspec