Ver Fonte

Add 增加离线脱机模式的支持,完善鉴权,个人中心等

Yue há 5 dias atrás
pai
commit
34db2646bb

+ 14 - 0
UI/CF.APP/chicken_farm/lib/core/permissions/permission_keys.dart

@@ -0,0 +1,14 @@
+// 权限标识
+class PermissionKeys {
+  // 养殖相关权限
+  static const String bindChicken = 'breeding:bind:chicken';
+  static const String cageChange = 'breeding:cage:change';
+  static const String individualWeighing = 'breeding:individual:weighing';
+  static const String individualCulling = 'breeding:individual:culling';
+  static const String batchCulling = 'breeding:batch:culling';
+
+  // 实验相关权限
+  static const String sampleQuery = 'experiment:sample:query';
+  // 设备相关权限
+  static const String inspectionCheckin = 'device:inspection:checkin';
+}

+ 14 - 11
UI/CF.APP/chicken_farm/lib/pages/home/_profile/user_info_card.dart

@@ -1,3 +1,4 @@
+import 'package:chicken_farm/core/config/app_config.dart';
 import 'package:chicken_farm/modes/user/user_model.dart';
 import 'package:flutter/material.dart';
 
@@ -28,16 +29,18 @@ class UserInfoCard extends StatelessWidget {
               ),
               subtitle: Text('用户名: ${user.userName}'),
             ),
-            const Divider(),
-            const Text('基本信息', style: TextStyle(fontWeight: FontWeight.bold)),
-            const SizedBox(height: 10),
-            _buildInfoRow('手机号码', user.phonenumber ?? '未填写'),
-            _buildInfoRow('邮箱地址', user.email ?? '未填写'),
-            _buildInfoRow('部门', user.orgName ?? '未分配'),
-            _buildInfoRow(
-              '角色',
-              (user.roles?.map((r) => r.roleName).join(', ')) ?? '未分配',
-            ),
+            if (!AppConfig.isOffline) ...[
+              const Divider(),
+              const Text('基本信息', style: TextStyle(fontWeight: FontWeight.bold)),
+              const SizedBox(height: 10),
+              _buildInfoRow('手机号码', user.phonenumber ?? '未填写'),
+              _buildInfoRow('邮箱地址', user.email ?? '未填写'),
+              _buildInfoRow('部门', user.orgName ?? '未分配'),
+              _buildInfoRow(
+                '角色',
+                (user.roles?.map((r) => r.roleName).join(', ')) ?? '未分配',
+              ),
+            ],
           ],
         ),
       ),
@@ -61,4 +64,4 @@ class UserInfoCard extends StatelessWidget {
       ),
     );
   }
-}
+}

+ 18 - 11
UI/CF.APP/chicken_farm/lib/pages/home/profile.dart

@@ -1,3 +1,4 @@
+import 'package:chicken_farm/core/config/app_config.dart';
 import 'package:chicken_farm/stores/auth_store.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -32,17 +33,23 @@ class ProfilePage extends ConsumerWidget {
                     children: [
                       UserInfoCard(user: authState.user!),
                       const SizedBox(height: 20),
-                      const UploadDataButton(),
-                      const SizedBox(height: 20),
-                      const ClearCacheButton(),
-                      const SizedBox(height: 20),
-                      const ConfigButton(),
-                      const SizedBox(height: 20),
-                      // const RfidConfigButton(),
-                      // const SizedBox(height: 20),
-                      // const ScannerLightButton(),
-                      // const SizedBox(height: 20),
-                      const LogoutButton(),
+                      if (AppConfig.isOffline) ...[
+                        const ClearCacheButton(),
+                        const SizedBox(height: 20),
+                      ] else ...[
+                        const UploadDataButton(),
+                        const SizedBox(height: 20),
+                        const ClearCacheButton(),
+                        const SizedBox(height: 20),
+                        const ConfigButton(),
+                        const SizedBox(height: 20),
+                        // const RfidConfigButton(),
+                        // const SizedBox(height: 20),
+                        // const ScannerLightButton(),
+                        // const SizedBox(height: 20),
+                        const LogoutButton(),
+                        const SizedBox(height: 20),
+                      ],
                     ],
                   ),
                 ),

+ 15 - 6
UI/CF.APP/chicken_farm/lib/routes/app_routes.dart

@@ -24,8 +24,9 @@ class AppRouteNames {
   static const String home = '/home';
   static const String checkin = '/checkin';
   static const String checkinRecord = '/checkin_record';
-  static const String bindwingTagNum = '/bind_wing_tag_num';
-  static const String bindwingTagNumWin = '/bind_wing_tag_num_win'; // Windows平台个体绑定
+  static const String bindChicken = '/bind_wing_tag_num';
+  static const String bindwingTagNumWin =
+      '/bind_wing_tag_num_win'; // Windows平台个体绑定
   static const String cageChange = '/cage_change';
   static const String individualWeighing = '/individual_weighing';
   static const String individualCulling = '/individual_culling';
@@ -80,8 +81,8 @@ class AppRoutes {
       },
     ),
     GoRoute(
-      path: AppRouteNames.bindwingTagNum,
-      name: AppRouteNames.bindwingTagNum,
+      path: AppRouteNames.bindChicken,
+      name: AppRouteNames.bindChicken,
       builder: (context, state) => const BatchCreatePage(),
     ),
     GoRoute(
@@ -136,9 +137,17 @@ class SplashScreen extends ConsumerWidget {
   Widget build(BuildContext context, WidgetRef ref) {
     ref.listen(authStoreProvider, (previous, next) {
       if (next.state == AuthState.authenticated) {
-        context.goNamed(AppRouteNames.home);
+        WidgetsBinding.instance.addPostFrameCallback((_) {
+          if (context.mounted) {
+            context.goNamed(AppRouteNames.home);
+          }
+        });
       } else if (next.state != AuthState.loading) {
-        context.goNamed(AppRouteNames.login);
+        WidgetsBinding.instance.addPostFrameCallback((_) {
+          if (context.mounted) {
+            context.goNamed(AppRouteNames.login);
+          }
+        });
       }
     });
     return const Scaffold(body: Center(child: CircularProgressIndicator()));

+ 7 - 5
UI/CF.APP/chicken_farm/lib/routes/route_guard.dart

@@ -3,6 +3,7 @@ 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';
+import 'package:chicken_farm/routes/app_routes.dart';
 
 class RouteGuard {
   static String? redirectLogic(BuildContext context, GoRouterState state) {
@@ -14,10 +15,11 @@ class RouteGuard {
     );
     if (authState.state == AuthState.loading) return null; // 加载中不跳转
 
-    // // 如果已经认证,且当前不在主页,则跳转到主页
-    // if (authState.state == AuthState.authenticated && isGoingToLogin) {
-    //   return '/home';
-    // }
+    // 如果已经认证,且当前在登录页或启动页,则跳转到主页
+    if (authState.state == AuthState.authenticated && 
+        (isGoingToLogin || state.matchedLocation == '/')) {
+      return AppRouteNames.home;
+    }
 
     // 如果未认证,且不是前往登录页或启动页,则跳转到登录页
     if (authState.state != AuthState.authenticated &&
@@ -28,4 +30,4 @@ class RouteGuard {
 
     return null;
   }
-}
+}

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

@@ -1,5 +1,6 @@
 import 'package:chicken_farm/apis/index.dart';
 import 'package:chicken_farm/core/config/app_config.dart';
+import 'package:chicken_farm/core/permissions/permission_keys.dart';
 import 'package:chicken_farm/core/services/navigation_service.dart';
 import 'package:chicken_farm/core/utils/jwt_token.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
@@ -89,7 +90,35 @@ class AuthStore extends StateNotifier<AuthInfo> {
   /// 初始化认证状态
   Future<void> _init() async {
     state = AuthInfo.loading();
+
     try {
+      // 检查是否启用了离线模式
+      if (AppConfig.isOffline) {
+        // 在离线模式下,创建一个具有养殖相关权限的虚拟用户
+        final offlineUser = UserModel()
+          ..userId = 0
+          ..userName = 'offline_user'
+          ..nickName = '离线用户';
+
+        // 设置养殖相关的权限
+        final breedingPermissions = [
+          PermissionKeys.bindChicken,
+          PermissionKeys.cageChange,
+          PermissionKeys.individualWeighing,
+          PermissionKeys.individualCulling,
+          PermissionKeys.batchCulling,
+        ];
+
+        state = AuthInfo.authenticated(
+          token: 'offline_token',
+          user: offlineUser,
+          permissions: breedingPermissions,
+          roles: ['breeding_operator'],
+        );
+        logger.i('离线模式已启用,创建离线用户: $state');
+        return;
+      }
+
       final token = await JwtToken.getToken();
       if (token != null) {
         // 检查网络连接状态

+ 11 - 10
UI/CF.APP/chicken_farm/lib/stores/menu_store.dart

@@ -1,70 +1,71 @@
 import 'package:chicken_farm/modes/menu_item.dart';
 import 'package:chicken_farm/routes/app_routes.dart';
 import 'package:flutter/material.dart';
+import 'package:chicken_farm/core/permissions/permission_keys.dart';
 
 class MenuStore {
   static const List<MenuItem> menuItems = [
     MenuItem(
       name: '个体绑定',
-      routeName: AppRouteNames.bindwingTagNum,
+      routeName: AppRouteNames.bindChicken,
       icon: Icons.tag_outlined,
-      permission: 'device:device:query',
+      permission: PermissionKeys.bindChicken,
       platform: 1,
     ),
     MenuItem(
       name: '换笼管理',
       routeName: AppRouteNames.cageChange,
       icon: Icons.compare_arrows,
-      permission: 'breeding:cage:change',
+      permission: PermissionKeys.cageChange,
       platform: 1,
     ),
     MenuItem(
       name: '个体称重',
       routeName: AppRouteNames.individualWeighing,
       icon: Icons.scale,
-      permission: 'breeding:individual:weighing',
+      permission: PermissionKeys.individualWeighing,
       platform: 1,
     ),
     MenuItem(
       name: '个体淘汰',
       routeName: AppRouteNames.individualCulling,
       icon: Icons.person_remove,
-      permission: 'breeding:individual:culling',
+      permission: PermissionKeys.individualCulling,
       platform: 1,
     ),
     MenuItem(
       name: '批量淘汰',
       routeName: AppRouteNames.batchCulling,
       icon: Icons.group_remove,
-      permission: 'breeding:batch:culling',
+      permission: PermissionKeys.batchCulling,
       platform: 1,
     ),
     MenuItem(
       name: '点检签到',
       routeName: AppRouteNames.checkin,
       icon: Icons.check_circle_outline,
-      permission: 'device:inspection:checkin',
+      permission: PermissionKeys.inspectionCheckin,
       platform: 0,
     ),
     MenuItem(
       name: '样品查询',
       routeName: AppRouteNames.sample,
       icon: Icons.search,
-      permission: 'experiment:sample:query',
+      permission: PermissionKeys.sampleQuery,
       platform: 0,
     ),
     MenuItem(
       name: '个体绑定',
       routeName: AppRouteNames.bindwingTagNumWin,
       icon: Icons.tag_outlined,
-      permission: 'device:device:query',
+      permission: PermissionKeys.bindChicken,
       platform: 2,
     ),
     MenuItem(
       name: '批量淘汰',
       routeName: AppRouteNames.batchCullingWin,
       icon: Icons.group_remove,
-      permission: 'breeding:batch:culling',
+      permission: PermissionKeys.batchCulling,
       platform: 2,
     ),
   ];