Browse Source

Add 初步支持win平台

Yue 5 ngày trước cách đây
mục cha
commit
382bcb520a

+ 4 - 1
UI/CF.APP/chicken_farm/lib/modes/menu_item.dart

@@ -5,11 +5,14 @@ class MenuItem {
   final String routeName;
   final IconData? icon;
   final String? permission;
+  // 平台类型,0:所有平台,1:Android,2:windows
+  final int platform;
 
   const MenuItem({
     required this.name,
     required this.routeName,
     this.icon,
     this.permission,
+    this.platform = 0,
   });
-}
+}

+ 97 - 94
UI/CF.APP/chicken_farm/lib/pages/account/login_page.dart

@@ -49,108 +49,111 @@ class _LoginPageState extends ConsumerState<LoginPage> {
             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,
+                child: ConstrainedBox(
+                  constraints: const BoxConstraints(maxWidth: 400),
+                  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),
+                            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],
                               ),
-                              filled: true,
-                              fillColor: Colors.grey[50],
+                              validator: (v) => v!.isEmpty ? '请输入用户名' : null,
                             ),
-                            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),
+                            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],
                               ),
-                              filled: true,
-                              fillColor: Colors.grey[50],
+                              validator: (v) => v!.length < 6 ? '密码不能少于6位' : null,
                             ),
-                            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(
-                                                  AppRouteNames.home,
-                                                );
-                                              }
-                                            })
-                                            .catchError((error) {
-                                              // 处理登录错误
-                                              logger.e('登录失败: $error');
-                                              if (context.mounted) {
-                                                String errorMessage = '登录失败';
-                                                if (error is Exception) {
-                                                  errorMessage = error
-                                                      .toString();
+                            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(
+                                                    AppRouteNames.home,
+                                                  );
                                                 }
-                                                ToastUtil.error(errorMessage);
-                                              }
-                                            });
-                                      }
-                                    },
-                              style: ElevatedButton.styleFrom(
-                                shape: RoundedRectangleBorder(
-                                  borderRadius: BorderRadius.circular(12),
+                                              })
+                                              .catchError((error) {
+                                                // 处理登录错误
+                                                logger.e('登录失败: $error');
+                                                if (context.mounted) {
+                                                  String errorMessage = '登录失败';
+                                                  if (error is Exception) {
+                                                    errorMessage = error
+                                                        .toString();
+                                                  }
+                                                  ToastUtil.error(errorMessage);
+                                                }
+                                              });
+                                        }
+                                      },
+                                style: ElevatedButton.styleFrom(
+                                  shape: RoundedRectangleBorder(
+                                    borderRadius: BorderRadius.circular(12),
+                                  ),
+                                  textStyle: const TextStyle(fontSize: 16),
                                 ),
-                                textStyle: const TextStyle(fontSize: 16),
+                                child: authState.state == AuthState.loading
+                                    ? const CircularProgressIndicator(
+                                        color: Colors.white,
+                                      )
+                                    : const Text('登录'),
                               ),
-                              child: authState.state == AuthState.loading
-                                  ? const CircularProgressIndicator(
-                                      color: Colors.white,
-                                    )
-                                  : const Text('登录'),
                             ),
-                          ),
-                        ],
+                          ],
+                        ),
                       ),
                     ),
                   ),
@@ -185,4 +188,4 @@ class _LoginPageState extends ConsumerState<LoginPage> {
       ),
     );
   }
-}
+}

+ 273 - 0
UI/CF.APP/chicken_farm/lib/pages/breeding/batch_create_page_win.dart

@@ -0,0 +1,273 @@
+import 'package:chicken_farm/core/utils/logger.dart';
+import 'package:chicken_farm/apis/index.dart';
+import 'package:chicken_farm/components/vb_search_select.dart';
+import 'package:chicken_farm/components/vb_select.dart';
+import 'package:chicken_farm/modes/breeding/batch.dart';
+import 'package:chicken_farm/modes/breeding/family.dart';
+import 'package:flutter/material.dart';
+import 'package:chicken_farm/components/vb_app_bar.dart';
+import 'package:chicken_farm/core/utils/toast.dart';
+
+class BatchCreatePageWin extends StatefulWidget {
+  const BatchCreatePageWin({super.key});
+
+  @override
+  State<BatchCreatePageWin> createState() => _BatchCreatePageWinState();
+}
+
+class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
+  final List<String> _rfids = [];
+  String? _selectedBatchNum;
+  String? _selectedFamilyId;
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: const VberAppBar(title: '个体绑定[Windows]', showLeftButton: true),
+      body: Padding(
+        padding: const EdgeInsets.all(16.0),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            // 批次选择
+            _buildBatchSearchSelect(),
+            const SizedBox(height: 10),
+            // 家系号选择
+            _buildFamilySearchSelect(),
+            const SizedBox(height: 20),
+            // 电子编号区域
+            _buildRfidSection(),
+            const SizedBox(height: 20),
+            // 提交按钮
+            SizedBox(
+              width: double.infinity,
+              child: ElevatedButton(
+                onPressed:
+                    _rfids.isNotEmpty &&
+                        _selectedBatchNum != null &&
+                        _selectedFamilyId != null
+                    ? _handleSubmit
+                    : null,
+                style: ElevatedButton.styleFrom(
+                  backgroundColor:
+                      _rfids.isNotEmpty &&
+                          _selectedBatchNum != null &&
+                          _selectedFamilyId != null
+                      ? Colors.blue
+                      : Colors.grey,
+                  foregroundColor: Colors.white,
+                ),
+                child: const Text('提交'),
+              ),
+            ),
+            const SizedBox(height: 20),
+            // 已识别的电子编号列表
+            if (_rfids.isNotEmpty) ...[
+              Row(
+                mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                children: [
+                  const Text(
+                    '已识别的电子编号',
+                    style: TextStyle(fontWeight: FontWeight.bold),
+                  ),
+                  IconButton(
+                    icon: const Icon(Icons.clear, size: 18),
+                    onPressed: _clearRfids,
+                    tooltip: '清空编号',
+                  ),
+                ],
+              ),
+              const SizedBox(height: 10),
+              Expanded(
+                child: Container(
+                  padding: const EdgeInsets.all(10),
+                  decoration: BoxDecoration(
+                    border: Border.all(color: Colors.grey),
+                    borderRadius: BorderRadius.circular(8),
+                  ),
+                  child: ListView.builder(
+                    padding: EdgeInsets.zero,
+                    itemCount: _rfids.length,
+                    itemBuilder: (context, index) {
+                      return ListTile(
+                        visualDensity: VisualDensity.compact,
+                        contentPadding: const EdgeInsets.symmetric(
+                          horizontal: 2,
+                          vertical: 0,
+                        ),
+                        title: Text(_rfids[index]),
+                        trailing: IconButton(
+                          icon: const Icon(
+                            Icons.delete,
+                            size: 18,
+                            color: Colors.red,
+                          ),
+                          onPressed: () => _removeRfid(index),
+                        ),
+                      );
+                    },
+                  ),
+                ),
+              ),
+            ],
+            const SizedBox(height: 20),
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget _buildBatchSearchSelect() {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        const Text('选择批次', style: TextStyle(fontWeight: FontWeight.bold)),
+        const SizedBox(height: 10),
+        Container(
+          padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
+          decoration: BoxDecoration(
+            border: Border.all(color: Colors.grey),
+            borderRadius: BorderRadius.circular(8),
+          ),
+          child: VberSearchSelect<BatchModel>(
+            searchApi: ({required dynamic queryParams}) async {
+              final result = await apis.breeding.queryApi.queryPageBatchs(
+                queryParams,
+              );
+              return {'rows': result.rows, 'total': result.total};
+            },
+            converter: (BatchModel data) {
+              return SelectOption(
+                label: '${data.batchNum}(${data.batchName})',
+                value: data.batchNum,
+                extra: data,
+              );
+            },
+            value: _selectedBatchNum,
+            hint: '批次号',
+            onChanged: (String? value) {
+              setState(() {
+                _selectedBatchNum = value;
+                // 当切换批次时,重置后续选项和数据
+                _selectedFamilyId = null;
+              });
+            },
+            hideUnderline: true,
+          ),
+        ),
+      ],
+    );
+  }
+
+  Widget _buildFamilySearchSelect() {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        const Text('选择家系号', style: TextStyle(fontWeight: FontWeight.bold)),
+        const SizedBox(height: 10),
+        Container(
+          padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
+          decoration: BoxDecoration(
+            border: Border.all(color: Colors.grey),
+            borderRadius: BorderRadius.circular(8),
+          ),
+          child: VberSearchSelect<FamilyModel>(
+            searchApi: ({required dynamic queryParams}) async {
+              final result = await apis.breeding.queryApi.queryPageFamilys(
+                queryParams,
+              );
+              return {'rows': result.rows, 'total': result.total};
+            },
+            converter: (FamilyModel data) {
+              return SelectOption(
+                label: data.familyNum,
+                value: data.id.toString(),
+                extra: data,
+              );
+            },
+            value: _selectedFamilyId,
+            hint: '家系号',
+            onChanged: (String? value) {
+              setState(() {
+                _selectedFamilyId = value;
+              });
+            },
+            hideUnderline: true,
+          ),
+        ),
+      ],
+    );
+  }
+
+  Widget _buildRfidSection() {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        const Text('请输入或扫描RFID', style: TextStyle(fontWeight: FontWeight.bold)),
+        const SizedBox(height: 10),
+        Container(
+          padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
+          decoration: BoxDecoration(border: Border.all(color: Colors.grey)),
+        ),
+      ],
+    );
+  }
+
+  // 移除指定索引的电子编号
+  void _removeRfid(int index) {
+    setState(() {
+      _rfids.removeAt(index);
+    });
+  }
+
+  // 清空所有已识别的电子编号
+  void _clearRfids() {
+    setState(() {
+      _rfids.clear();
+    });
+    ToastUtil.info('已清空所有电子编号');
+  }
+
+  // 提交数据
+  void _handleSubmit() {
+    final data = _rfids.map((rfid) {
+      return {
+        'rfid': rfid,
+        'batchNum': _selectedBatchNum,
+        'familyId': _selectedFamilyId,
+      };
+    }).toList();
+    apis.breeding.submitApi
+        .create(data)
+        .then((_) {
+          if (mounted) {
+            ScaffoldMessenger.of(context).showSnackBar(
+              const SnackBar(
+                content: Text('批量绑定个体成功'),
+                backgroundColor: Colors.green,
+              ),
+            );
+            // 提交后重置表单
+            setState(() {
+              _rfids.clear();
+            });
+          }
+        })
+        .catchError((err) {
+          ToastUtil.error('批量绑定个体失败');
+          if (mounted && err != null) {
+            String errorMessage = err.toString();
+            if (err is Exception) {
+              errorMessage = err.toString();
+            }
+            logger.e(errorMessage);
+            ScaffoldMessenger.of(context).showSnackBar(
+              SnackBar(
+                content: Text(errorMessage),
+                backgroundColor: Colors.red,
+              ),
+            );
+          }
+        });
+  }
+}

+ 242 - 0
UI/CF.APP/chicken_farm/lib/pages/breeding/batch_culling_page_win.dart

@@ -0,0 +1,242 @@
+import 'package:chicken_farm/apis/index.dart';
+import 'package:flutter/material.dart';
+import 'package:chicken_farm/components/vb_app_bar.dart';
+import 'package:chicken_farm/components/vb_dict_select.dart';
+import 'package:chicken_farm/core/utils/toast.dart';
+
+class BatchCullingPageWin extends StatefulWidget {
+  const BatchCullingPageWin({super.key});
+
+  @override
+  State<BatchCullingPageWin> createState() => _BatchCullingPageWinState();
+}
+
+class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
+  final List<String> _rfids = [];
+  String? _cullReason;
+  String? _disposalMethod;
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: const VberAppBar(title: '批量淘汰[Windows]', showLeftButton: true),
+      body: Padding(
+        padding: const EdgeInsets.all(16.0),
+        child: Column(
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: [
+            // 电子编号区域
+            _buildRfidSection(),
+            const SizedBox(height: 20),
+            // 淘汰原因
+            _buildCullReasonSection(),
+            const SizedBox(height: 20),
+            // 处置方式
+            _buildDisposalMethodSection(),
+            const SizedBox(height: 20),
+            // 提交按钮
+            SizedBox(
+              width: double.infinity,
+              child: ElevatedButton(
+                onPressed:
+                    _rfids.isNotEmpty &&
+                        _cullReason != null &&
+                        _disposalMethod != null
+                    ? _handleSubmit
+                    : null,
+                style: ElevatedButton.styleFrom(
+                  backgroundColor:
+                      _rfids.isNotEmpty &&
+                          _cullReason != null &&
+                          _disposalMethod != null
+                      ? Colors.blue
+                      : Colors.grey,
+                  foregroundColor: Colors.white,
+                ),
+                child: const Text('提交'),
+              ),
+            ),
+            const SizedBox(height: 20),
+            // 已识别的电子编号列表
+            if (_rfids.isNotEmpty) ...[
+              Row(
+                mainAxisAlignment: MainAxisAlignment.spaceBetween,
+                children: [
+                  const Text(
+                    '已识别的电子编号',
+                    style: TextStyle(fontWeight: FontWeight.bold),
+                  ),
+                  IconButton(
+                    icon: const Icon(Icons.clear, size: 18),
+                    onPressed: _clearRfids,
+                    tooltip: '清空编号',
+                  ),
+                ],
+              ),
+              const SizedBox(height: 10),
+              Expanded(
+                child: Container(
+                  padding: const EdgeInsets.all(10),
+                  decoration: BoxDecoration(
+                    border: Border.all(color: Colors.grey),
+                    borderRadius: BorderRadius.circular(8),
+                  ),
+                  child: ListView.builder(
+                    padding: EdgeInsets.zero,
+                    itemCount: _rfids.length,
+                    itemBuilder: (context, index) {
+                      return ListTile(
+                        visualDensity: VisualDensity.compact,
+                        contentPadding: const EdgeInsets.symmetric(
+                          horizontal: 2,
+                          vertical: 0,
+                        ),
+                        title: Text(_rfids[index]),
+                        trailing: IconButton(
+                          icon: const Icon(
+                            Icons.delete,
+                            size: 18,
+                            color: Colors.red,
+                          ),
+                          onPressed: () => _removeRfid(index),
+                        ),
+                      );
+                    },
+                  ),
+                ),
+              ),
+            ],
+            const SizedBox(height: 20),
+          ],
+        ),
+      ),
+    );
+  }
+
+  Widget _buildRfidSection() {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        const Text('请输入或扫描RFID', style: TextStyle(fontWeight: FontWeight.bold)),
+        const SizedBox(height: 10),
+        Container(
+          padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
+          decoration: BoxDecoration(border: Border.all(color: Colors.grey)),
+        ),
+      ],
+    );
+  }
+
+  Widget _buildCullReasonSection() {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        const Text('淘汰原因', style: TextStyle(fontWeight: FontWeight.bold)),
+        const SizedBox(height: 10),
+        Container(
+          padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
+          decoration: BoxDecoration(
+            border: Border.all(color: Colors.grey),
+            borderRadius: BorderRadius.circular(8),
+          ),
+          child: VberDictSelect(
+            dictType: 'chicken_cull_reason',
+            value: _cullReason,
+            onChanged: (value) {
+              setState(() {
+                _cullReason = value;
+              });
+            },
+            hint: '请选择淘汰原因',
+            hideUnderline: true,
+          ),
+        ),
+      ],
+    );
+  }
+
+  Widget _buildDisposalMethodSection() {
+    return Column(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        const Text('处置方式', style: TextStyle(fontWeight: FontWeight.bold)),
+        const SizedBox(height: 10),
+        Container(
+          padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
+          decoration: BoxDecoration(
+            border: Border.all(color: Colors.grey),
+            borderRadius: BorderRadius.circular(8),
+          ),
+          child: VberDictSelect(
+            dictType: 'chicken_disposal_method',
+            value: _disposalMethod,
+            onChanged: (value) {
+              setState(() {
+                _disposalMethod = value;
+              });
+            },
+            hint: '请选择处置方式',
+            hideUnderline: true,
+          ),
+        ),
+      ],
+    );
+  }
+
+  // 移除指定索引的电子编号
+  void _removeRfid(int index) {
+    setState(() {
+      _rfids.removeAt(index);
+    });
+  }
+
+  // 清空所有已识别的电子编号
+  void _clearRfids() {
+    setState(() {
+      _rfids.clear();
+    });
+    ToastUtil.info('已清空所有电子编号');
+  }
+
+  // 提交数据
+  void _handleSubmit() {
+    final data = {
+      'rfids': _rfids,
+      'disposal_method': _disposalMethod,
+      'cull_reason': _cullReason,
+    };
+    apis.breeding.submitApi
+        .weight(data)
+        .then((_) {
+          if (mounted) {
+            ScaffoldMessenger.of(context).showSnackBar(
+              const SnackBar(
+                content: Text('批量淘汰提交成功'),
+                backgroundColor: Colors.green,
+              ),
+            );
+            // 提交后重置表单
+            setState(() {
+              _rfids.clear();
+              _disposalMethod = null;
+              _cullReason = null;
+            });
+          }
+        })
+        .catchError((err) {
+          ToastUtil.error('批量淘汰提交失败');
+          if (mounted && err != null) {
+            String errorMessage = err.toString();
+            if (err is Exception) {
+              errorMessage = err.toString();
+            }
+            ScaffoldMessenger.of(context).showSnackBar(
+              SnackBar(
+                content: Text(errorMessage),
+                backgroundColor: Colors.red,
+              ),
+            );
+          }
+        });
+  }
+}

+ 18 - 2
UI/CF.APP/chicken_farm/lib/pages/home/menu_buttons.dart

@@ -1,3 +1,4 @@
+import 'dart:io' show Platform;
 import 'package:chicken_farm/stores/auth_store.dart';
 import 'package:chicken_farm/stores/menu_store.dart';
 import 'package:flutter/material.dart';
@@ -14,8 +15,23 @@ class MenuButtons extends ConsumerWidget {
 
     final isSuperAdmin = authStore.isSuperAdmin();
 
-    // 根据权限过滤菜单项
+    // 获取当前平台类型
+    // 平台类型,0:所有平台,1:Android手机,2:Windows
+    int currentPlatform = 0;
+    if (Platform.isAndroid) {
+      currentPlatform = 1;
+    } else if (Platform.isWindows) {
+      currentPlatform = 2;
+    }
+
+    // 根据权限和平台类型过滤菜单项
     final visibleMenuItems = MenuStore.menuItems.where((item) {
+      // 平台过滤
+      if (item.platform != 0 && item.platform != currentPlatform) {
+        return false;
+      }
+      
+      // 权限过滤
       if (isSuperAdmin) return true;
       if (item.permission == null) return true;
       return authState.permissions?.contains(item.permission) ?? false;
@@ -54,4 +70,4 @@ class MenuButtons extends ConsumerWidget {
       ),
     );
   }
-}
+}

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

@@ -10,10 +10,12 @@ import '../pages/checkin/checkin_record_page.dart';
 import '../pages/sample/sample_query_page.dart';
 import '../pages/sample/sample_detail_page.dart';
 import '../pages/breeding/batch_create_page.dart';
+import '../pages/breeding/batch_create_page_win.dart';
 import '../pages/breeding/cage_change_page.dart';
 import '../pages/breeding/individual_weighing_page.dart';
 import '../pages/breeding/individual_culling_page.dart';
 import '../pages/breeding/batch_culling_page.dart';
+import '../pages/breeding/batch_culling_page_win.dart';
 import '../pages/upload/upload_page.dart';
 
 class AppRouteNames {
@@ -23,10 +25,12 @@ class AppRouteNames {
   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 cageChange = '/cage_change';
   static const String individualWeighing = '/individual_weighing';
   static const String individualCulling = '/individual_culling';
   static const String batchCulling = '/batch_culling';
+  static const String batchCullingWin = '/batch_culling_win'; // Windows平台批量淘汰
   static const String sample = '/sample';
   static const String sampleDetail = '/sample/detail';
   static const String rfidConfig = '/rfid-config';
@@ -100,6 +104,16 @@ class AppRoutes {
       name: AppRouteNames.batchCulling,
       builder: (context, state) => const BatchCullingPage(),
     ),
+    GoRoute(
+      path: AppRouteNames.bindwingTagNumWin,
+      name: AppRouteNames.bindwingTagNumWin,
+      builder: (context, state) => const BatchCreatePageWin(),
+    ),
+    GoRoute(
+      path: AppRouteNames.batchCullingWin,
+      name: AppRouteNames.batchCullingWin,
+      builder: (context, state) => const BatchCullingPageWin(),
+    ),
     GoRoute(
       path: AppRouteNames.rfidConfig,
       name: AppRouteNames.rfidConfig,

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

@@ -9,42 +9,63 @@ class MenuStore {
       routeName: AppRouteNames.bindwingTagNum,
       icon: Icons.tag_outlined,
       permission: 'device:device:query',
+      platform: 1,
     ),
     MenuItem(
       name: '换笼管理',
       routeName: AppRouteNames.cageChange,
       icon: Icons.compare_arrows,
       permission: 'breeding:cage:change',
+      platform: 1,
     ),
     MenuItem(
       name: '个体称重',
       routeName: AppRouteNames.individualWeighing,
       icon: Icons.scale,
       permission: 'breeding:individual:weighing',
+      platform: 1,
     ),
     MenuItem(
       name: '个体淘汰',
       routeName: AppRouteNames.individualCulling,
       icon: Icons.person_remove,
       permission: 'breeding:individual:culling',
+      platform: 1,
     ),
     MenuItem(
       name: '批量淘汰',
       routeName: AppRouteNames.batchCulling,
       icon: Icons.group_remove,
       permission: 'breeding:batch:culling',
+      platform: 1,
     ),
     MenuItem(
       name: '点检签到',
       routeName: AppRouteNames.checkin,
       icon: Icons.check_circle_outline,
       permission: 'device:inspection:checkin',
+      platform: 0,
     ),
     MenuItem(
       name: '样品查询',
       routeName: AppRouteNames.sample,
       icon: Icons.search,
       permission: 'experiment:sample:query',
+      platform: 0,
+    ),
+    MenuItem(
+      name: '个体绑定',
+      routeName: AppRouteNames.bindwingTagNumWin,
+      icon: Icons.tag_outlined,
+      permission: 'device:device:query',
+      platform: 2,
+    ),
+    MenuItem(
+      name: '批量淘汰',
+      routeName: AppRouteNames.batchCullingWin,
+      icon: Icons.group_remove,
+      permission: 'breeding:batch:culling',
+      platform: 2,
     ),
   ];
 }