소스 검색

ADD 完成功能菜单和个人中心

Yue 2 주 전
부모
커밋
b38504fa23

+ 2 - 2
UI/CF.APP/chicken_farm/android/app/build.gradle.kts

@@ -6,7 +6,7 @@ plugins {
 }
 
 android {
-    namespace = "com.example.chicken_farm"
+    namespace = "com.vber.chicken_farm"
     compileSdk = flutter.compileSdkVersion
     ndkVersion = flutter.ndkVersion
 
@@ -21,7 +21,7 @@ android {
 
     defaultConfig {
         // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
-        applicationId = "com.example.chicken_farm"
+        applicationId = "com.vber.chicken_farm"
         // You can update the following values to match your application needs.
         // For more information, see: https://flutter.dev/to/review-gradle-config.
         minSdk = flutter.minSdkVersion

+ 1 - 1
UI/CF.APP/chicken_farm/android/app/src/main/kotlin/com/example/chicken_farm/MainActivity.kt

@@ -1,4 +1,4 @@
-package com.example.chicken_farm
+package com.vber.chicken_farm
 
 import io.flutter.embedding.android.FlutterActivity
 

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

@@ -2,7 +2,6 @@ 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();

+ 45 - 0
UI/CF.APP/chicken_farm/lib/components/custom_app_bar.dart

@@ -0,0 +1,45 @@
+import 'package:flutter/material.dart';
+import 'package:go_router/go_router.dart';
+
+class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
+  final String title;
+  final bool showBackButton;
+  final List<Widget>? actions;
+  final VoidCallback? onBack;
+
+  const CustomAppBar({
+    super.key,
+    required this.title,
+    this.showBackButton = true,
+    this.actions,
+    this.onBack,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return AppBar(
+      title: Text(title),
+      centerTitle: true,
+      leading: showBackButton
+          ? IconButton(
+              icon: const Icon(Icons.arrow_back),
+              onPressed: () {
+                if (onBack != null) {
+                  onBack!();
+                } else if (context.canPop()) {
+                  // 如果可以返回,则返回上一页
+                  context.pop();
+                } else {
+                  // 如果无法返回,则导航到首页
+                  context.go('/');
+                }
+              },
+            )
+          : null,
+      actions: actions,
+    );
+  }
+
+  @override
+  Size get preferredSize => const Size.fromHeight(kToolbarHeight);
+}

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


+ 0 - 0
UI/CF.APP/chicken_farm/lib/widgets/config_dialog.dart → UI/CF.APP/chicken_farm/lib/pages/account/config_dialog.dart


+ 5 - 7
UI/CF.APP/chicken_farm/lib/pages/account/login.dart

@@ -1,3 +1,4 @@
+import 'package:chicken_farm/components/custom_app_bar.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -6,7 +7,7 @@ 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';
+import 'package:chicken_farm/pages/account/config_dialog.dart';
 
 class LoginPage extends ConsumerStatefulWidget {
   const LoginPage({super.key});
@@ -49,11 +50,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
     });
 
     return Scaffold(
-      appBar: AppBar(
-        title: const Text('用户登录'),
-        backgroundColor: Theme.of(context).colorScheme.primary,
-        foregroundColor: Colors.white,
-      ),
+      appBar: const CustomAppBar(title: '用户登录', showBackButton: false),
       body: Stack(
         children: [
           Container(
@@ -150,7 +147,8 @@ class _LoginPageState extends ConsumerState<LoginPage> {
                                               if (context.mounted) {
                                                 String errorMessage = '登录失败';
                                                 if (error is Exception) {
-                                                  errorMessage = error.toString();
+                                                  errorMessage = error
+                                                      .toString();
                                                 }
                                                 ToastUtils.error(errorMessage);
                                               }

+ 17 - 0
UI/CF.APP/chicken_farm/lib/pages/checkin/checkin_page.dart

@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'package:chicken_farm/components/custom_app_bar.dart';
+
+class CheckinPage extends StatelessWidget {
+  const CheckinPage({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: const CustomAppBar(
+        title: '点检签到',
+        showBackButton: true, // 子页面显示返回按钮
+      ),
+      body: const Center(child: Text('点检签到页面')),
+    );
+  }
+}

+ 46 - 19
UI/CF.APP/chicken_farm/lib/pages/home/home.dart

@@ -1,37 +1,64 @@
+import 'package:chicken_farm/components/custom_app_bar.dart';
+import 'package:chicken_farm/pages/home/menu_buttons.dart';
 import 'package:chicken_farm/stores/auth_store.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'profile.dart';
 
-class HomePage extends ConsumerWidget {
+class HomePage extends ConsumerStatefulWidget {
   const HomePage({super.key});
 
   @override
-  Widget build(BuildContext context, WidgetRef ref) {
+  ConsumerState<HomePage> createState() => _HomePageState();
+}
+
+class _HomePageState extends ConsumerState<HomePage> {
+  int _selectedIndex = 0;
+
+  static const List<String> _titles = ['功能菜单', '个人中心'];
+
+  @override
+  Widget build(BuildContext context) {
     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(),
+      appBar: CustomAppBar(
+        title: _titles[_selectedIndex],
+        showBackButton: false, // 主页不显示返回按钮
+      ),
+      body: _buildBody(_selectedIndex, authState),
+      bottomNavigationBar: BottomNavigationBar(
+        type: BottomNavigationBarType.fixed,
+        currentIndex: _selectedIndex,
+        onTap: (index) {
+          setState(() {
+            _selectedIndex = index;
+          });
+        },
+        items: const [
+          BottomNavigationBarItem(
+            icon: Icon(Icons.home_outlined),
+            activeIcon: Icon(Icons.home),
+            label: '功能菜单',
+          ),
+          BottomNavigationBarItem(
+            icon: Icon(Icons.person_outline),
+            activeIcon: Icon(Icons.person),
+            label: '个人中心',
           ),
         ],
       ),
-      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 ?? '访客'}!');
+  Widget _buildBody(int selectedIndex, AuthInfo authState) {
+    switch (selectedIndex) {
+      case 0:
+        return const Center(child: MenuButtons());
+      case 1:
+        return const ProfilePage();
+      default:
+        return const Center(child: Text('页面不存在'));
     }
   }
-}
+}

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

@@ -0,0 +1,55 @@
+import 'package:chicken_farm/routes/app_routes.dart';
+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';
+
+class MenuButtons extends ConsumerWidget {
+  const MenuButtons({super.key});
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final authState = ref.watch(authStoreProvider);
+    final authStore = ref.watch(authStoreProvider.notifier);
+
+    final isSuperAdmin = authStore.isSuperAdmin();
+
+    // 根据权限判断是否显示按钮
+    final showCheckIn =
+        isSuperAdmin || (authState.permissions?.contains('checkin') ?? false);
+    final showSampleTransfer =
+        isSuperAdmin ||
+        (authState.permissions?.contains('sample_transfer') ?? false);
+
+    return Column(
+      mainAxisAlignment: MainAxisAlignment.center,
+      children: [
+        if (showCheckIn)
+          SizedBox(
+            width: 200,
+            height: 50,
+            child: ElevatedButton.icon(
+              onPressed: () {
+                context.pushNamed(AppRoutePaths.checkin);
+              },
+              icon: const Icon(Icons.check_circle_outline),
+              label: const Text('点检签到'),
+            ),
+          ),
+        const SizedBox(height: 20),
+        if (showSampleTransfer)
+          SizedBox(
+            width: 200,
+            height: 50,
+            child: ElevatedButton.icon(
+              onPressed: () {
+                context.pushNamed(AppRoutePaths.sampleTransfer);
+              },
+              icon: const Icon(Icons.swap_horiz),
+              label: const Text('样品流转'),
+            ),
+          ),
+      ],
+    );
+  }
+}

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

@@ -0,0 +1,108 @@
+import 'package:chicken_farm/stores/auth_store.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:getwidget/getwidget.dart';
+
+class ProfilePage extends ConsumerWidget {
+  const ProfilePage({super.key});
+
+  @override
+  Widget build(BuildContext context, WidgetRef ref) {
+    final authState = ref.watch(authStoreProvider);
+    final authStore = ref.read(authStoreProvider.notifier);
+
+    return Scaffold(
+      body: Padding(
+        padding: const EdgeInsets.all(16.0),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            const SizedBox(height: 20),
+            if (authState.state == AuthState.authenticated &&
+                authState.user != null) ...[
+              Card(
+                child: Padding(
+                  padding: const EdgeInsets.all(16.0),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      ListTile(
+                        leading: const CircleAvatar(
+                          radius: 30,
+                          child: Icon(Icons.person, size: 30),
+                        ),
+                        title: Text(
+                          authState.user!.nickName ?? '未设置昵称',
+                          style: const TextStyle(
+                            fontSize: 20,
+                            fontWeight: FontWeight.bold,
+                          ),
+                        ),
+                        subtitle: Text('用户名: ${authState.user!.userName}'),
+                      ),
+                      const Divider(),
+                      const Text(
+                        '基本信息',
+                        style: TextStyle(fontWeight: FontWeight.bold),
+                      ),
+                      const SizedBox(height: 10),
+                      _buildInfoRow(
+                        '手机号码',
+                        authState.user!.phonenumber ?? '未填写',
+                      ),
+                      _buildInfoRow('邮箱地址', authState.user!.email ?? '未填写'),
+                      _buildInfoRow('部门', authState.user!.orgName ?? '未分配'),
+                      _buildInfoRow(
+                        '角色',
+                        (authState.user!.roles
+                                ?.map((r) => r.roleName)
+                                .join(', ')) ??
+                            '未分配',
+                      ),
+                    ],
+                  ),
+                ),
+              ),
+              const SizedBox(height: 20),
+              SizedBox(
+                width: double.infinity,
+                child: ElevatedButton.icon(
+                  onPressed: () => authStore.logout(),
+                  icon: const Icon(Icons.logout),
+                  label: const Text('退出登录'),
+                  style: ElevatedButton.styleFrom(
+                    padding: const EdgeInsets.symmetric(
+                      horizontal: 30,
+                      vertical: 15,
+                    ),
+                    textStyle: const TextStyle(fontSize: 16),
+                  ),
+                ),
+              ),
+            ] else ...[
+              const Center(child: Text('加载中...')),
+            ],
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget _buildInfoRow(String label, String value) {
+    return Padding(
+      padding: const EdgeInsets.symmetric(vertical: 4.0),
+      child: Row(
+        children: [
+          SizedBox(
+            width: 80,
+            child: Text(
+              '$label:',
+              style: const TextStyle(fontWeight: FontWeight.w500),
+            ),
+          ),
+          Expanded(child: Text(value)),
+        ],
+      ),
+    );
+  }
+}

+ 17 - 0
UI/CF.APP/chicken_farm/lib/pages/sample_transfer/sample_transfer_page.dart

@@ -0,0 +1,17 @@
+import 'package:flutter/material.dart';
+import 'package:chicken_farm/components/custom_app_bar.dart';
+
+class SampleTransferPage extends StatelessWidget {
+  const SampleTransferPage({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: const CustomAppBar(
+        title: '样品流转',
+        showBackButton: true, // 子页面显示返回按钮
+      ),
+      body: const Center(child: Text('样品流转页面')),
+    );
+  }
+}

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

@@ -4,11 +4,15 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
 import 'package:go_router/go_router.dart';
 import '../pages/account/login.dart';
 import '../pages/home/home.dart';
+import '../pages/checkin/checkin_page.dart';
+import '../pages/sample_transfer/sample_transfer_page.dart';
 
 class AppRoutePaths {
   static const String splash = '/';
   static const String login = '/login';
   static const String home = '/home';
+  static const String checkin = '/checkin';
+  static const String sampleTransfer = '/sample_transfer';
 }
 
 class AppRoutes {
@@ -27,6 +31,16 @@ class AppRoutes {
       name: AppRoutePaths.home,
       builder: (context, state) => const HomePage(),
     ),
+    GoRoute(
+      path: AppRoutePaths.checkin,
+      name: AppRoutePaths.checkin,
+      builder: (context, state) => const CheckinPage(),
+    ),
+    GoRoute(
+      path: AppRoutePaths.sampleTransfer,
+      name: AppRoutePaths.sampleTransfer,
+      builder: (context, state) => const SampleTransferPage(),
+    ),
   ];
 }
 
@@ -45,4 +59,4 @@ class SplashScreen extends ConsumerWidget {
     });
     return const Scaffold(body: Center(child: CircularProgressIndicator()));
   }
-}
+}

+ 1 - 1
UI/CF.APP/chicken_farm/linux/CMakeLists.txt

@@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
 set(BINARY_NAME "chicken_farm")
 # The unique GTK application identifier for this application. See:
 # https://wiki.gnome.org/HowDoI/ChooseApplicationID
-set(APPLICATION_ID "com.example.chicken_farm")
+set(APPLICATION_ID "com.vber.chicken_farm")
 
 # Explicitly opt in to modern CMake behaviors to avoid warnings with recent
 # versions of CMake.

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

@@ -48,6 +48,7 @@ dependencies:
   logger: ^1.1.0         # 日志
   fluttertoast: ^8.2.2   # 弹窗
   shared_preferences: ^2.2.2 # 本地存储
+  getwidget: ^7.0.0
 
 dev_dependencies:
   flutter_test: