Browse Source

Update Api接口,字段和后台进行统一

Yue 1 month ago
parent
commit
62a0e874c3

+ 22 - 214
UI/CF.APP/chicken_farm/lib/apis/breeding/_query.dart

@@ -1,8 +1,6 @@
-import 'dart:math';
-
+import 'package:chicken_farm/core/api/api_service.dart';
 import 'package:chicken_farm/modes/breeding/batch.dart';
 import 'package:chicken_farm/modes/breeding/family.dart';
-import 'package:chicken_farm/modes/breeding/wing_tag_num.dart';
 import 'package:chicken_farm/modes/api/page_model.dart';
 
 class BreedQueryApi {
@@ -12,229 +10,39 @@ class BreedQueryApi {
 
   BreedQueryApi._internal();
 
-  // 预生成的批次模拟数据,仅包含必填字段
-  static final List<BatchModel> _mockBatchData = [
-    BatchModel(batchNum: 'BATCH001', batchName: '批次一号'),
-    BatchModel(batchNum: 'BATCH002', batchName: '批次二号'),
-    BatchModel(batchNum: 'BATCH003', batchName: '批次三号'),
-    BatchModel(batchNum: 'BATCH004', batchName: '批次四号'),
-    BatchModel(batchNum: 'BATCH005', batchName: '批次五号'),
-    BatchModel(batchNum: 'BATCH006', batchName: '批次六号'),
-    BatchModel(batchNum: 'BATCH007', batchName: '批次七号'),
-    BatchModel(batchNum: 'BATCH008', batchName: '批次八号'),
-    BatchModel(batchNum: 'BATCH009', batchName: '批次九号'),
-    BatchModel(batchNum: 'BATCH010', batchName: '批次十号'),
-    BatchModel(batchNum: 'BATCH011', batchName: '批次十一号'),
-    BatchModel(batchNum: 'BATCH012', batchName: '批次十二号'),
-    BatchModel(batchNum: 'BATCH013', batchName: '批次十三号'),
-    BatchModel(batchNum: 'BATCH014', batchName: '批次十四号'),
-    BatchModel(batchNum: 'BATCH015', batchName: '批次十五号'),
-    BatchModel(batchNum: 'BATCH016', batchName: '批次十六号'),
-    BatchModel(batchNum: 'BATCH017', batchName: '批次十七号'),
-    BatchModel(batchNum: 'BATCH018', batchName: '批次十八号'),
-    BatchModel(batchNum: 'BATCH019', batchName: '批次十九号'),
-    BatchModel(batchNum: 'BATCH020', batchName: '批次二十号'),
-  ];
-
-  // 预生成的翅号模拟数据,仅包含必填字段
-  static final List<WingTagNumModel> _mockWingTagData = [
-    WingTagNumModel(wingTagNum: 'WING0001'),
-    WingTagNumModel(wingTagNum: 'WING0002'),
-    WingTagNumModel(wingTagNum: 'WING0003'),
-    WingTagNumModel(wingTagNum: 'WING0004'),
-    WingTagNumModel(wingTagNum: 'WING0005'),
-    WingTagNumModel(wingTagNum: 'WING0006'),
-    WingTagNumModel(wingTagNum: 'WING0007'),
-    WingTagNumModel(wingTagNum: 'WING0008'),
-    WingTagNumModel(wingTagNum: 'WING0009'),
-    WingTagNumModel(wingTagNum: 'WING0010'),
-    WingTagNumModel(wingTagNum: 'WING0011'),
-    WingTagNumModel(wingTagNum: 'WING0012'),
-    WingTagNumModel(wingTagNum: 'WING0013'),
-    WingTagNumModel(wingTagNum: 'WING0014'),
-    WingTagNumModel(wingTagNum: 'WING0015'),
-    WingTagNumModel(wingTagNum: 'WING0016'),
-    WingTagNumModel(wingTagNum: 'WING0017'),
-    WingTagNumModel(wingTagNum: 'WING0018'),
-    WingTagNumModel(wingTagNum: 'WING0019'),
-    WingTagNumModel(wingTagNum: 'WING0020'),
-  ];
-
-  // 预生成的家系模拟数据,仅包含必填字段
-  static final List<FamilyModel> _mockFamilyData = [
-    FamilyModel(id: 1, familyNum: 'FAM001'),
-    FamilyModel(id: 2, familyNum: 'FAM002'),
-    FamilyModel(id: 3, familyNum: 'FAM003'),
-    FamilyModel(id: 4, familyNum: 'FAM004'),
-    FamilyModel(id: 5, familyNum: 'FAM005'),
-    FamilyModel(id: 6, familyNum: 'FAM006'),
-    FamilyModel(id: 7, familyNum: 'FAM007'),
-    FamilyModel(id: 8, familyNum: 'FAM008'),
-    FamilyModel(id: 9, familyNum: 'FAM009'),
-    FamilyModel(id: 10, familyNum: 'FAM010'),
-    FamilyModel(id: 11, familyNum: 'FAM011'),
-    FamilyModel(id: 12, familyNum: 'FAM012'),
-    FamilyModel(id: 13, familyNum: 'FAM013'),
-    FamilyModel(id: 14, familyNum: 'FAM014'),
-    FamilyModel(id: 15, familyNum: 'FAM015'),
-    FamilyModel(id: 16, familyNum: 'FAM016'),
-    FamilyModel(id: 17, familyNum: 'FAM017'),
-    FamilyModel(id: 18, familyNum: 'FAM018'),
-    FamilyModel(id: 19, familyNum: 'FAM019'),
-    FamilyModel(id: 20, familyNum: 'FAM020'),
-  ];
+  static final String apiPrefix = '/app/breeding';
 
   Future<PageResultModel<BatchModel>> queryPageBatchs(dynamic query) async {
-    // 模拟数据 - 注释掉原来的API调用
-    /*final response = await ApiService().get(
-      '/app/breeding/listBatch',
+    final result = await ApiService().get(
+      '$apiPrefix/listBatch/${query['keyword']}',
       queryParameters: query,
     );
-    if (response == null) return PageResultModel.empty();
-    final List<BatchModel> rows = (response['rows'] as List)
-        .map((e) => BatchModel.fromJson(e))
-        .toList();
-    return PageResultModel<BatchModel>(rows: rows, total: response['total']);*/
-
-    // 使用预生成的模拟数据
-    // 根据keyword筛选数据
-    List<BatchModel> filteredData = _mockBatchData;
-    if (query != null &&
-        query['keyword'] != null &&
-        query['keyword'].toString().isNotEmpty) {
-      final keyword = query['keyword'].toString().toLowerCase();
-      filteredData = _mockBatchData
-          .where((batch) => batch.batchNum.toLowerCase().contains(keyword))
+    if (result.success) {
+      final List<BatchModel> rows = (result.data['rows'] as List)
+          .map((e) => BatchModel.fromJson(e))
           .toList();
+      return PageResultModel<BatchModel>(
+        rows: rows,
+        total: result.data['total'],
+      );
     }
-
-    int page = query != null && query['pageNum'] != null
-        ? query['pageNum'] as int
-        : 1;
-    int pageSize = query != null && query['pageSize'] != null
-        ? query['pageSize'] as int
-        : 10;
-    int startIndex = (page - 1) * pageSize;
-    int endIndex = startIndex + pageSize < filteredData.length
-        ? startIndex + pageSize
-        : filteredData.length;
-
-    List<BatchModel> pageRows = startIndex < filteredData.length
-        ? filteredData.sublist(startIndex, endIndex)
-        : [];
-
-    return PageResultModel<BatchModel>(
-      rows: pageRows,
-      total: filteredData.length,
-    );
-  }
-
-  Future<PageResultModel<WingTagNumModel>> queryPageWingTags(
-    dynamic query,
-  ) async {
-    // 模拟数据 - 注释掉原来的API调用
-    /*final response = await ApiService().get(
-      '/app/breeding/listWingTag',
-      queryParameters: query,
-    );
-    if (response == null) return PageResultModel.empty();
-    final List<WingTagNumModel> rows = (response['rows'] as List)
-        .map((e) => WingTagNumModel.fromJson(e))
-        .toList();
-    return PageResultModel<WingTagNumModel>(
-      rows: rows,
-      total: response['total'],
-    );*/
-
-    // 使用预生成的模拟数据
-    int page = query != null && query['pageNum'] != null
-        ? query['pageNum'] as int
-        : 1;
-    int pageSize = query != null && query['pageSize'] != null
-        ? query['pageSize'] as int
-        : 10;
-    int startIndex = (page - 1) * pageSize;
-    int endIndex = startIndex + pageSize < _mockWingTagData.length
-        ? startIndex + pageSize
-        : _mockWingTagData.length;
-
-    List<WingTagNumModel> pageRows = startIndex < _mockWingTagData.length
-        ? _mockWingTagData.sublist(startIndex, endIndex)
-        : [];
-
-    return PageResultModel<WingTagNumModel>(
-      rows: pageRows,
-      total: _mockWingTagData.length,
-    );
-  }
-
-  Future<List<WingTagNumModel>> queryWingTags(dynamic query) async {
-    // 模拟数据 - 注释掉原来的API调用
-    /*final response = await ApiService().get(
-      '/app/breeding/listWingTag',
-      queryParameters: query,
-    );
-    if (response == null) return [];
-    return response
-        .map<WingTagNumModel>((e) => WingTagNumModel.fromJson(e))
-        .toList();*/
-
-    // 使用预生成的模拟数据,随机返回5-10条
-    final random = Random();
-    final count = 5 + random.nextInt(6); // 5到10之间的随机数
-    final indices = <int>{};
-
-    // 随机选择不重复的索引
-    while (indices.length < count) {
-      indices.add(random.nextInt(_mockWingTagData.length));
-    }
-
-    // 根据索引获取数据
-    return indices.map((index) => _mockWingTagData[index]).toList();
+    return PageResultModel.empty();
   }
 
   Future<PageResultModel<FamilyModel>> queryPageFamilys(dynamic query) async {
-    // 模拟数据 - 注释掉原来的API调用
-    /*final response = await ApiService().get(
-      '/app/breeding/listFamily',
+    final result = await ApiService().get(
+      '$apiPrefix/listFamily/${query['keyword']}',
       queryParameters: query,
     );
-    if (response == null) return PageResultModel.empty();
-    final List<FamilyModel> rows = (response['rows'] as List)
-        .map((e) => FamilyModel.fromJson(e))
-        .toList();
-    return PageResultModel<FamilyModel>(rows: rows, total: response['total']);*/
-
-    // 使用预生成的模拟数据
-    // 根据keyword筛选数据
-    List<FamilyModel> filteredData = _mockFamilyData;
-    if (query != null &&
-        query['keyword'] != null &&
-        query['keyword'].toString().isNotEmpty) {
-      final keyword = query['keyword'].toString().toLowerCase();
-      filteredData = _mockFamilyData
-          .where((family) => family.familyNum.toLowerCase().contains(keyword))
+    if (result.success) {
+      final List<FamilyModel> rows = (result.data['rows'] as List)
+          .map((e) => FamilyModel.fromJson(e))
           .toList();
+      return PageResultModel<FamilyModel>(
+        rows: rows,
+        total: result.data['total'],
+      );
     }
-
-    int page = query != null && query['pageNum'] != null
-        ? query['pageNum'] as int
-        : 1;
-    int pageSize = query != null && query['pageSize'] != null
-        ? query['pageSize'] as int
-        : 10;
-    int startIndex = (page - 1) * pageSize;
-    int endIndex = startIndex + pageSize < filteredData.length
-        ? startIndex + pageSize
-        : filteredData.length;
-
-    List<FamilyModel> pageRows = startIndex < filteredData.length
-        ? filteredData.sublist(startIndex, endIndex)
-        : [];
-
-    return PageResultModel<FamilyModel>(
-      rows: pageRows,
-      total: filteredData.length,
-    );
+    return PageResultModel.empty();
   }
 }

+ 45 - 44
UI/CF.APP/chicken_farm/lib/apis/breeding/_submit.dart

@@ -13,23 +13,25 @@ class BreedSubmitApi {
 
   BreedSubmitApi._internal();
   final BreedingDataService _breedingDataService = BreedingDataService();
+  static final String apiPrefix = '/app/breeding';
 
-  final String bindChickenUrl = '/app/breeding/bind/';
-  final String cageChangeUrl = '/app/breeding/cageChange/';
-  final String weightUrl = '/app/breeding/weight/';
-  final String cullUrl = '/app/breeding/cull/';
+  final String bindChickenUrl = '$apiPrefix/batchAddChicken';
+  final String cageChangeUrl = '$apiPrefix/batchChangeCage';
+  final String weightUrl = '$apiPrefix/chickenWeight';
+  final String cullUrl = '$apiPrefix/batchCullChicken';
 
   Future<ResultModel> bindChicken(dynamic data) async {
     try {
-      List<String> ids = data['rfids'];
+      List<String> ids = data['electronicIds'];
       // 保存到本地数据库
       List<Map<String, dynamic>> list = ids.map<Map<String, dynamic>>((id) {
         return {
-          'rfid': id,
-          'batch_num': data['batchNum'],
-          'family_id': data['familyId'],
-          'date': data['date'],
-          'is_export': 0,
+          'electronicId': id,
+          'batchNum': data['batchNum'],
+          'familyNum': data['familyNum'],
+          // 'cageNum': data['cageNum'],
+          // 'gender': data['gender'] ?? 2,
+          'isExport': 0,
         };
       }).toList();
       ResultModel result = ResultModel.offline();
@@ -56,13 +58,13 @@ class BreedSubmitApi {
 
   Future<ResultModel> cageChange(dynamic data) async {
     try {
-      final ids = data['rfids'] as List<String>;
+      final ids = data['electronicIds'] as List<String>;
       List<Map<String, dynamic>> list = ids.map<Map<String, dynamic>>((id) {
         return {
-          'rfid': id,
-          'target_cage': data['targetCage'],
-          'date': data['date'],
-          'is_export': 0,
+          'electronicId': id,
+          'targetCageNum': data['targetCage'],
+          'bindTime': data['date'],
+          'isExport': 0,
         };
       }).toList();
       ResultModel result = ResultModel.offline();
@@ -90,10 +92,10 @@ class BreedSubmitApi {
   Future<ResultModel> weight(dynamic data) async {
     try {
       Map<String, dynamic> weightData = {
-        'rfid': data['rfid'],
-        'weight': data['weight'],
-        'date': data['date'],
-        'is_export': 0,
+        'electronicId': data['electronicId'],
+        'weightValue': data['weight'],
+        'recordDate': data['date'],
+        'isExport': 0,
       };
       ResultModel result = ResultModel.offline();
       if (!AppConfig.isOffline &&
@@ -121,11 +123,11 @@ class BreedSubmitApi {
     try {
       List<Map<String, dynamic>> list = [
         {
-          'rfid': data['rfid'],
-          'cull_reason': data['cullReason'],
-          'disposal_method': data['disposalMethod'],
-          'date': data['date'],
-          'is_export': 0,
+          'electronicId': data['electronicId'],
+          'cullReason': data['cullReason'],
+          'disposalMethod': data['disposalMethod'],
+          'cullTime': data['date'],
+          'isExport': 0,
         },
       ];
       ResultModel result = ResultModel.offline();
@@ -149,14 +151,14 @@ class BreedSubmitApi {
 
   Future<ResultModel> batchCull(dynamic data) async {
     try {
-      List<String> ids = data['rfids'];
+      List<String> ids = data['electronicIds'];
       List<Map<String, dynamic>> list = ids.map<Map<String, dynamic>>((id) {
         return {
-          'rfid': id,
-          'cull_reason': data['cullReason'],
-          'disposal_method': data['disposalMethod'],
-          'date': data['date'],
-          'is_export': 0,
+          'electronicId': data['electronicId'],
+          'cullReason': data['cullReason'],
+          'disposalMethod': data['disposalMethod'],
+          'cullTime': data['date'],
+          'isExport': 0,
         };
       }).toList();
       ResultModel result = ResultModel.offline();
@@ -196,20 +198,19 @@ class BreedSubmitApi {
       return ResultModel(success: false, message: e.toString(), data: null);
     }
   }
-}
 
-String getUrl(String type) {
-  final prefix = '/app/breeding/';
-  switch (type) {
-    case BreedConfig.chicken:
-      return '${prefix}bindChicken/';
-    case BreedConfig.cageChange:
-      return '${prefix}cageChange/';
-    case BreedConfig.weight:
-      return '${prefix}weight/';
-    case BreedConfig.cull:
-      return '${prefix}cull/';
-    default:
-      return '';
+  String getUrl(String type) {
+    switch (type) {
+      case BreedConfig.chicken:
+        return '$apiPrefix/bindChicken';
+      case BreedConfig.cageChange:
+        return '$apiPrefix/cageChange';
+      case BreedConfig.weight:
+        return '$apiPrefix/weight';
+      case BreedConfig.cull:
+        return '$apiPrefix/cull';
+      default:
+        return '';
+    }
   }
 }

+ 21 - 21
UI/CF.APP/chicken_farm/lib/components/vb_rfid_field.dart → UI/CF.APP/chicken_farm/lib/components/vb_electronic_id_field.dart

@@ -8,11 +8,11 @@ import 'package:chicken_farm/core/utils/toast.dart';
 ///
 /// 当[multiple]为true时,显示已识别的RFID数量
 /// 当[multiple]为false时,显示单个RFID的具体值
-class VberRfidField extends StatefulWidget {
-  final List<String>? rfids;
-  final String? rfid;
-  final ValueChanged<String>? onRfidScanned; // RFID识别成功回调
-  final ValueChanged<List<RfidModel>>? onRfidsScanned; // RFID识别成功回调
+class VberElectronicIdsField extends StatefulWidget {
+  final List<String>? electronicIds;
+  final String? electronicId;
+  final ValueChanged<String>? onIdScanned; // RFID识别成功回调
+  final ValueChanged<List<RfidModel>>? onIdsScanned; // RFID识别成功回调
   final ValueChanged<String>? onKeyPress; // 按键事件
   final bool multiple;
   final bool? multipleScan;
@@ -22,12 +22,12 @@ class VberRfidField extends StatefulWidget {
   final String multiplePlaceholder; // 多个模式下未识别时显示的占位符文本
   final String multipleFormat; // 多个模式下有值时的显示格式,包含一个%d占位符表示数量
 
-  const VberRfidField({
+  const VberElectronicIdsField({
     super.key,
-    this.rfids,
-    this.rfid,
-    this.onRfidScanned,
-    this.onRfidsScanned,
+    this.electronicIds,
+    this.electronicId,
+    this.onIdScanned,
+    this.onIdsScanned,
     this.onKeyPress,
     this.multiple = false,
     this.multipleScan,
@@ -39,10 +39,10 @@ class VberRfidField extends StatefulWidget {
   });
 
   @override
-  State<VberRfidField> createState() => _VberRfidFieldState();
+  State<VberElectronicIdsField> createState() => _VberElectronicIdsFieldState();
 }
 
-class _VberRfidFieldState extends State<VberRfidField> {
+class _VberElectronicIdsFieldState extends State<VberElectronicIdsField> {
   late final RfidManager _rfidManager;
   bool _isScanning = false; // 内部管理识别状态
   bool _isMultiple = false; // 内部管理识别状态
@@ -71,8 +71,8 @@ class _VberRfidFieldState extends State<VberRfidField> {
     setState(() {
       _isScanning = false;
     });
-    if (widget.onRfidScanned != null) {
-      widget.onRfidScanned!(rfid);
+    if (widget.onIdScanned != null) {
+      widget.onIdScanned!(rfid);
     }
   }
 
@@ -81,8 +81,8 @@ class _VberRfidFieldState extends State<VberRfidField> {
     setState(() {
       _isScanning = false;
     });
-    if (widget.onRfidsScanned != null) {
-      widget.onRfidsScanned!(rfidList);
+    if (widget.onIdsScanned != null) {
+      widget.onIdsScanned!(rfidList);
     }
   }
 
@@ -154,25 +154,25 @@ class _VberRfidFieldState extends State<VberRfidField> {
   /// 获取显示的文本
   String _getDisplayText() {
     if (widget.multiple) {
-      if (widget.rfids == null || widget.rfids!.isEmpty) {
+      if (widget.electronicIds == null || widget.electronicIds!.isEmpty) {
         return widget.multiplePlaceholder;
       } else {
         return widget.multipleFormat.replaceAll(
           '%d',
-          widget.rfids!.length.toString(),
+          widget.electronicIds!.length.toString(),
         );
       }
     } else {
-      return widget.rfid ?? widget.placeholder;
+      return widget.electronicId ?? widget.placeholder;
     }
   }
 
   /// 判断是否有值
   bool _hasValue() {
     if (widget.multiple) {
-      return widget.rfids != null && widget.rfids!.isNotEmpty;
+      return widget.electronicIds != null && widget.electronicIds!.isNotEmpty;
     } else {
-      return widget.rfid != null;
+      return widget.electronicId != null;
     }
   }
 }

+ 17 - 13
UI/CF.APP/chicken_farm/lib/core/config/excel_header_map.dart

@@ -3,23 +3,27 @@ import 'package:chicken_farm/core/config/breed_config.dart';
 class ExcelHeaderMap {
   static final Map<String, Map<String, String>> templates = {
     BreedConfig.chicken: {
-      '批次号': 'batch_num',
-      '家系号': 'family_id',
-      '电子编号': 'rfid',
-      '创建时间': 'date',
+      '电子编号': 'electronicId',
+      '批次号': 'batchNum',
+      '家系编号': 'familyNum',
+      // '笼编号': 'cageNum',
+      // '性别': 'gender',
     },
     BreedConfig.cageChange: {
-      '源笼号': 'source_cage',
-      '目标笼号': 'target_cage',
-      '电子编号': 'rfid',
-      '创建时间': 'date',
+      '电子编号': 'electronicId',
+      '目标笼号': 'targetCageNum',
+      '绑定时间': 'bindTime',
+    },
+    BreedConfig.weight: {
+      '电子编号': 'electronicId',
+      '体重': 'weightValue',
+      '记录日期': 'recordDate',
     },
-    BreedConfig.weight: {'体重': 'weight', '电子编号': 'rfid', '创建时间': 'date'},
     BreedConfig.cull: {
-      '淘汰原因': 'cull_reason',
-      '处置方式': 'disposal_method',
-      '电子编号': 'rfid',
-      '创建时间': 'date',
+      '电子编号': 'electronicId',
+      '淘汰原因': 'cullReason',
+      '处置方式': 'disposalMethod',
+      '淘汰时间': 'cullTime',
     },
   };
 }

+ 17 - 18
UI/CF.APP/chicken_farm/lib/core/db/table_config.dart

@@ -15,11 +15,10 @@ class TableConfig {
             '''
           CREATE TABLE IF NOT EXISTS ${TableConfig.chicken} (
             id INTEGER PRIMARY KEY AUTOINCREMENT,
-            rfid TEXT,
-            batch_num TEXT,
-            family_id TEXT,
-            is_export INTEGER,
-            date TEXT,
+            electronicId TEXT,
+            batchNum TEXT,
+            familyNum TEXT,
+            isExport INTEGER,
             create_time TEXT,
             update_time TEXT
           )
@@ -33,10 +32,10 @@ class TableConfig {
             '''
           CREATE TABLE IF NOT EXISTS ${TableConfig.weight} (
             id INTEGER PRIMARY KEY AUTOINCREMENT,
-            rfid TEXT,
-            weight TEXT,
-            is_export INTEGER,
-            date TEXT,
+            electronicId TEXT,
+            weightValue TEXT,
+            isExport INTEGER,
+            recordDate TEXT,
             create_time TEXT,
             update_time TEXT
           )
@@ -50,10 +49,10 @@ class TableConfig {
             '''
           CREATE TABLE IF NOT EXISTS ${TableConfig.cageChange} (
             id INTEGER PRIMARY KEY AUTOINCREMENT,
-            rfid TEXT,
-            target_cage TEXT,
-            is_export INTEGER,
-            date TEXT,
+            electronicId TEXT,
+            targetCageNum TEXT,
+            isExport INTEGER,
+            bindTime TEXT,
             create_time TEXT,
             update_time TEXT
           )
@@ -67,11 +66,11 @@ class TableConfig {
             '''
           CREATE TABLE IF NOT EXISTS ${TableConfig.cull} (
             id INTEGER PRIMARY KEY AUTOINCREMENT,
-            rfid TEXT,
-            cull_reason TEXT,
-            disposal_method TEXT,
-            is_export INTEGER,
-            date TEXT,
+            electronicId TEXT,
+            cullReason TEXT,
+            disposalMethod TEXT,
+            isExport INTEGER,
+            cullTime TEXT,
             create_time TEXT,
             update_time TEXT
           )

+ 5 - 5
UI/CF.APP/chicken_farm/lib/core/services/breeding_data_service.dart

@@ -42,7 +42,7 @@ class BreedingDataService {
 
   Future<List<Map<String, dynamic>>> query(
     String table, {
-    String? where = 'is_export = 0',
+    String? where = 'isExport = 0',
     List<dynamic>? whereArgs,
   }) async {
     try {
@@ -62,7 +62,7 @@ class BreedingDataService {
   Future<int> queryCount(String tableName) async {
     final count = await _sqliteManager.queryCount(
       tableName,
-      where: "is_export = 0",
+      where: "isExport = 0",
     );
     return count;
   }
@@ -143,15 +143,15 @@ class BreedingDataService {
     try {
       List<Map<String, dynamic>> listData = await _sqliteManager.query(
         table: tableName,
-        where: 'is_export = 0',
+        where: 'isExport = 0',
       );
       if (listData.isNotEmpty) {
         String path = await ExcelExportUtil.export(templateKey, listData);
         if (path.isNotEmpty) {
           int r = await _sqliteManager.update(
             table: tableName,
-            data: {'is_export': 1},
-            where: 'is_export = 0',
+            data: {'isExport': 1},
+            where: 'isExport = 0',
           );
           if (r > 0) {
             result.message = path;

+ 0 - 2
UI/CF.APP/chicken_farm/lib/core/services/upload_service.dart

@@ -5,7 +5,6 @@ import 'package:chicken_farm/core/db/table_config.dart';
 import 'package:chicken_farm/core/services/breeding_data_service.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:chicken_farm/core/utils/service_checker.dart';
-import 'package:chicken_farm/apis/breeding/_submit.dart';
 import 'package:chicken_farm/modes/api/result_model.dart';
 import 'package:flutter_riverpod/flutter_riverpod.dart';
 
@@ -25,7 +24,6 @@ class UploadService {
 
   final container = ProviderContainer();
   final BreedingDataService _bdService = BreedingDataService();
-  final BreedSubmitApi _breedSubmitApi = BreedSubmitApi();
   bool _isUploading = false;
   bool isHideUpload = false;
   bool isAuthErr = false;

+ 63 - 62
UI/CF.APP/chicken_farm/lib/pages/breeding/batch_create_page.dart

@@ -2,7 +2,7 @@ import 'package:chicken_farm/core/config/app_config.dart';
 import 'package:chicken_farm/core/utils/datetime_util.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:chicken_farm/apis/index.dart';
-import 'package:chicken_farm/components/vb_rfid_field.dart';
+import 'package:chicken_farm/components/vb_electronic_id_field.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';
@@ -20,15 +20,15 @@ class BatchCreatePage extends StatefulWidget {
 }
 
 class _BatchCreatePageState extends State<BatchCreatePage> {
-  final List<String> _rfids = [];
+  final List<String> _electronicIds = [];
   String? _batchNum;
-  String? _familyId;
+  String? _familyNum;
 
   @override
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: const VberAppBar(title: '个体绑定', showLeftButton: true),
-      body: Padding(
+      body: SingleChildScrollView(
         padding: const EdgeInsets.all(16.0),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
@@ -40,21 +40,23 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
             _buildFamilyInput(),
             const SizedBox(height: 20),
             // 电子编号区域
-            _buildRfidSection(),
+            _buildElectronicIdsSection(),
             const SizedBox(height: 20),
             // 提交按钮
             SizedBox(
               width: double.infinity,
               child: ElevatedButton(
                 onPressed:
-                    _rfids.isNotEmpty && _batchNum != null && _familyId != null
+                    _electronicIds.isNotEmpty &&
+                        _batchNum != null &&
+                        _familyNum != null
                     ? _handleSubmit
                     : null,
                 style: ElevatedButton.styleFrom(
                   backgroundColor:
-                      _rfids.isNotEmpty &&
+                      _electronicIds.isNotEmpty &&
                           _batchNum != null &&
-                          _familyId != null
+                          _familyNum != null
                       ? Colors.blue
                       : Colors.grey,
                   foregroundColor: Colors.white,
@@ -64,7 +66,7 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
             ),
             const SizedBox(height: 20),
             // 已识别的电子编号列表
-            if (_rfids.isNotEmpty) ...[
+            if (_electronicIds.isNotEmpty) ...[
               Row(
                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
                 children: [
@@ -80,35 +82,34 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
                 ],
               ),
               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),
+              Container(
+                height: 200, // 固定高度以支持滚动
+                padding: const EdgeInsets.all(10),
+                decoration: BoxDecoration(
+                  border: Border.all(color: Colors.grey),
+                  borderRadius: BorderRadius.circular(8),
+                ),
+                child: ListView.builder(
+                  padding: EdgeInsets.zero,
+                  itemCount: _electronicIds.length,
+                  itemBuilder: (context, index) {
+                    return ListTile(
+                      visualDensity: VisualDensity.compact,
+                      contentPadding: const EdgeInsets.symmetric(
+                        horizontal: 2,
+                        vertical: 0,
+                      ),
+                      title: Text(_electronicIds[index]),
+                      trailing: IconButton(
+                        icon: const Icon(
+                          Icons.delete,
+                          size: 18,
+                          color: Colors.red,
                         ),
-                      );
-                    },
-                  ),
+                        onPressed: () => _removeRfid(index),
+                      ),
+                    );
+                  },
                 ),
               ),
             ],
@@ -174,7 +175,7 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
               ),
               onChanged: (value) {
                 setState(() {
-                  _familyId = value.isNotEmpty ? value : null;
+                  _familyNum = value.isNotEmpty ? value : null;
                 });
               },
             ),
@@ -219,7 +220,7 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
               setState(() {
                 _batchNum = value;
                 // 当切换批次时,重置后续选项和数据
-                _familyId = null;
+                _familyNum = null;
               });
 
               // // 获取翅号数据
@@ -261,11 +262,11 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
                 extra: data,
               );
             },
-            value: _familyId,
+            value: _familyNum,
             hint: '家系号',
             onChanged: (String? value) {
               setState(() {
-                _familyId = value;
+                _familyNum = value;
               });
             },
             hideUnderline: true,
@@ -275,36 +276,36 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
     );
   }
 
-  Widget _buildRfidSection() {
-    return VberRfidField(
-      rfids: _rfids,
-      onRfidsScanned: (List<RfidModel> scannedRfids) {
+  Widget _buildElectronicIdsSection() {
+    return VberElectronicIdsField(
+      electronicIds: _electronicIds,
+      onIdsScanned: (List<RfidModel> idList) {
         // 过滤出未存在的RFID
-        final newRfids = scannedRfids
-            .where((rfid) => !_rfids.contains(rfid.uid))
+        final newIds = idList
+            .where((id) => !_electronicIds.contains(id.uid))
             .toList();
 
-        if (newRfids.isNotEmpty) {
+        if (newIds.isNotEmpty) {
           setState(() {
-            // 将新的RFID添加到列表中
-            for (var rfid in newRfids) {
-              _rfids.insert(0, rfid.uid);
+            // 将新的ElectronicId添加到列表中
+            for (var id in newIds) {
+              _electronicIds.insert(0, id.uid);
             }
           });
           ScaffoldMessenger.of(context).showSnackBar(
             SnackBar(
-              content: Text("新增 ${newRfids.length} 枚电子编号"),
+              content: Text("新增 ${newIds.length} 枚电子编号"),
               backgroundColor: Colors.green,
             ),
           );
-          // ToastUtil.success("新增 ${newRfids.length} 枚电子编号");
-          // if (newRfids.length == scannedRfids.length) {
+          // ToastUtil.success("新增 ${newIds.length} 枚电子编号");
+          // if (newIds.length == idList.length) {
           //   // 全都是新添加的
-          //   ToastUtil.success("成功添加 ${newRfids.length} 枚新的电子编号");
+          //   ToastUtil.success("成功添加 ${newIds.length} 枚新的电子编号");
           // } else {
           //   // 部分是重复的
-          //   ToastUtil.info("新增 ${newRfids.length} 枚电子编号");
-          //   // ,${scannedRfids.length - newRfids.length} 枚已存在
+          //   ToastUtil.info("新增 ${newIds.length} 枚电子编号");
+          //   // ,${idList.length - newIds.length} 枚已存在
           // }
         } else {
           // 所有RFID都已存在
@@ -327,14 +328,14 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
   // 移除指定索引的电子编号
   void _removeRfid(int index) {
     setState(() {
-      _rfids.removeAt(index);
+      _electronicIds.removeAt(index);
     });
   }
 
   // 清空所有已识别的电子编号
   void _clearRfids() {
     setState(() {
-      _rfids.clear();
+      _electronicIds.clear();
     });
     ToastUtil.info('已清空所有电子编号');
   }
@@ -342,9 +343,9 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
   // 提交数据
   void _handleSubmit() {
     final data = {
-      'rfids': _rfids,
+      'electronicIds': _electronicIds,
       'batchNum': _batchNum,
-      'familyId': _familyId,
+      'familyNum': _familyNum,
       'date': DateTimeUtil.format(DateTime.now()),
     };
     apis.breeding.submitApi.bindChicken(data).then((res) {
@@ -361,7 +362,7 @@ class _BatchCreatePageState extends State<BatchCreatePage> {
           );
           // 提交后重置表单
           setState(() {
-            _rfids.clear();
+            _electronicIds.clear();
           });
         }
       } else {

+ 56 - 57
UI/CF.APP/chicken_farm/lib/pages/breeding/batch_create_page_win.dart

@@ -17,15 +17,15 @@ class BatchCreatePageWin extends StatefulWidget {
 }
 
 class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
-  final List<String> _rfids = [];
-  String? _selectedBatchNum;
-  String? _selectedFamilyId;
+  final List<String> _electronicIds = [];
+  String? _batchNum;
+  String? _familyNum;
 
   @override
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: const VberAppBar(title: '个体绑定[Windows]', showLeftButton: true),
-      body: Padding(
+      body: SingleChildScrollView(
         padding: const EdgeInsets.all(16.0),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
@@ -37,23 +37,23 @@ class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
             _buildFamilySearchSelect(),
             const SizedBox(height: 20),
             // 电子编号区域
-            _buildRfidSection(),
+            _buildElectronicIdSection(),
             const SizedBox(height: 20),
             // 提交按钮
             SizedBox(
               width: double.infinity,
               child: ElevatedButton(
                 onPressed:
-                    _rfids.isNotEmpty &&
-                        _selectedBatchNum != null &&
-                        _selectedFamilyId != null
+                    _electronicIds.isNotEmpty &&
+                        _batchNum != null &&
+                        _familyNum != null
                     ? _handleSubmit
                     : null,
                 style: ElevatedButton.styleFrom(
                   backgroundColor:
-                      _rfids.isNotEmpty &&
-                          _selectedBatchNum != null &&
-                          _selectedFamilyId != null
+                      _electronicIds.isNotEmpty &&
+                          _batchNum != null &&
+                          _familyNum != null
                       ? Colors.blue
                       : Colors.grey,
                   foregroundColor: Colors.white,
@@ -63,7 +63,7 @@ class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
             ),
             const SizedBox(height: 20),
             // 已识别的电子编号列表
-            if (_rfids.isNotEmpty) ...[
+            if (_electronicIds.isNotEmpty) ...[
               Row(
                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
                 children: [
@@ -73,41 +73,40 @@ class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
                   ),
                   IconButton(
                     icon: const Icon(Icons.clear, size: 18),
-                    onPressed: _clearRfids,
+                    onPressed: _clearElectronicIds,
                     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),
+              Container(
+                height: 200, // 固定高度以支持滚动
+                padding: const EdgeInsets.all(10),
+                decoration: BoxDecoration(
+                  border: Border.all(color: Colors.grey),
+                  borderRadius: BorderRadius.circular(8),
+                ),
+                child: ListView.builder(
+                  padding: EdgeInsets.zero,
+                  itemCount: _electronicIds.length,
+                  itemBuilder: (context, index) {
+                    return ListTile(
+                      visualDensity: VisualDensity.compact,
+                      contentPadding: const EdgeInsets.symmetric(
+                        horizontal: 2,
+                        vertical: 0,
+                      ),
+                      title: Text(_electronicIds[index]),
+                      trailing: IconButton(
+                        icon: const Icon(
+                          Icons.delete,
+                          size: 18,
+                          color: Colors.red,
                         ),
-                      );
-                    },
-                  ),
+                        onPressed: () => _removeElectronicId(index),
+                      ),
+                    );
+                  },
                 ),
               ),
             ],
@@ -144,13 +143,13 @@ class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
                 extra: data,
               );
             },
-            value: _selectedBatchNum,
+            value: _batchNum,
             hint: '批次号',
             onChanged: (String? value) {
               setState(() {
-                _selectedBatchNum = value;
+                _batchNum = value;
                 // 当切换批次时,重置后续选项和数据
-                _selectedFamilyId = null;
+                _familyNum = null;
               });
             },
             hideUnderline: true,
@@ -186,11 +185,11 @@ class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
                 extra: data,
               );
             },
-            value: _selectedFamilyId,
+            value: _familyNum,
             hint: '家系号',
             onChanged: (String? value) {
               setState(() {
-                _selectedFamilyId = value;
+                _familyNum = value;
               });
             },
             hideUnderline: true,
@@ -200,11 +199,11 @@ class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
     );
   }
 
-  Widget _buildRfidSection() {
+  Widget _buildElectronicIdSection() {
     return Column(
       crossAxisAlignment: CrossAxisAlignment.start,
       children: [
-        const Text('请输入或扫描RFID', style: TextStyle(fontWeight: FontWeight.bold)),
+        const Text('请输入或扫描电子编号', style: TextStyle(fontWeight: FontWeight.bold)),
         const SizedBox(height: 10),
         Container(
           padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
@@ -215,27 +214,27 @@ class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
   }
 
   // 移除指定索引的电子编号
-  void _removeRfid(int index) {
+  void _removeElectronicId(int index) {
     setState(() {
-      _rfids.removeAt(index);
+      _electronicIds.removeAt(index);
     });
   }
 
   // 清空所有已识别的电子编号
-  void _clearRfids() {
+  void _clearElectronicIds() {
     setState(() {
-      _rfids.clear();
+      _electronicIds.clear();
     });
     ToastUtil.info('已清空所有电子编号');
   }
 
   // 提交数据
   void _handleSubmit() {
-    final data = _rfids.map((rfid) {
+    final data = _electronicIds.map((id) {
       return {
-        'rfid': rfid,
-        'batchNum': _selectedBatchNum,
-        'familyId': _selectedFamilyId,
+        'electronicId': id,
+        'batchNum': _batchNum,
+        'familyNum': _familyNum,
         'date': DateTimeUtil.format(DateTime.now()),
       };
     }).toList();
@@ -256,7 +255,7 @@ class _BatchCreatePageWinState extends State<BatchCreatePageWin> {
           );
           // 提交后重置表单
           setState(() {
-            _rfids.clear();
+            _electronicIds.clear();
           });
         }
       } else {

+ 50 - 51
UI/CF.APP/chicken_farm/lib/pages/breeding/batch_culling_page.dart

@@ -1,5 +1,5 @@
 import 'package:chicken_farm/apis/index.dart';
-import 'package:chicken_farm/components/vb_rfid_field.dart';
+import 'package:chicken_farm/components/vb_electronic_id_field.dart';
 import 'package:chicken_farm/core/utils/datetime_util.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'package:chicken_farm/modes/rfid/rfid_model.dart';
@@ -16,7 +16,7 @@ class BatchCullingPage extends StatefulWidget {
 }
 
 class _BatchCullingPageState extends State<BatchCullingPage> {
-  final List<String> _rfids = [];
+  final List<String> _electronicIds = [];
   String? _cullReason;
   String? _disposalMethod;
 
@@ -24,13 +24,13 @@ class _BatchCullingPageState extends State<BatchCullingPage> {
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: const VberAppBar(title: '批量淘汰', showLeftButton: true),
-      body: Padding(
+      body: SingleChildScrollView(
         padding: const EdgeInsets.all(16.0),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
             // 电子编号区域
-            _buildRfidSection(),
+            _buildElectronicIdSection(),
             const SizedBox(height: 20),
             // 淘汰原因
             _buildCullReasonSection(),
@@ -43,14 +43,14 @@ class _BatchCullingPageState extends State<BatchCullingPage> {
               width: double.infinity,
               child: ElevatedButton(
                 onPressed:
-                    _rfids.isNotEmpty &&
+                    _electronicIds.isNotEmpty &&
                         _cullReason != null &&
                         _disposalMethod != null
                     ? _handleSubmit
                     : null,
                 style: ElevatedButton.styleFrom(
                   backgroundColor:
-                      _rfids.isNotEmpty &&
+                      _electronicIds.isNotEmpty &&
                           _cullReason != null &&
                           _disposalMethod != null
                       ? Colors.blue
@@ -62,7 +62,7 @@ class _BatchCullingPageState extends State<BatchCullingPage> {
             ),
             const SizedBox(height: 20),
             // 已识别的电子编号列表
-            if (_rfids.isNotEmpty) ...[
+            if (_electronicIds.isNotEmpty) ...[
               Row(
                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
                 children: [
@@ -78,35 +78,34 @@ class _BatchCullingPageState extends State<BatchCullingPage> {
                 ],
               ),
               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),
+              Container(
+                height: 200, // 固定高度以支持滚动
+                padding: const EdgeInsets.all(10),
+                decoration: BoxDecoration(
+                  border: Border.all(color: Colors.grey),
+                  borderRadius: BorderRadius.circular(8),
+                ),
+                child: ListView.builder(
+                  padding: EdgeInsets.zero,
+                  itemCount: _electronicIds.length,
+                  itemBuilder: (context, index) {
+                    return ListTile(
+                      visualDensity: VisualDensity.compact,
+                      contentPadding: const EdgeInsets.symmetric(
+                        horizontal: 2,
+                        vertical: 0,
+                      ),
+                      title: Text(_electronicIds[index]),
+                      trailing: IconButton(
+                        icon: const Icon(
+                          Icons.delete,
+                          size: 18,
+                          color: Colors.red,
                         ),
-                      );
-                    },
-                  ),
+                        onPressed: () => _removeRfid(index),
+                      ),
+                    );
+                  },
                 ),
               ),
             ],
@@ -117,26 +116,26 @@ class _BatchCullingPageState extends State<BatchCullingPage> {
     );
   }
 
-  Widget _buildRfidSection() {
-    return VberRfidField(
-      rfids: _rfids,
-      onRfidsScanned: (List<RfidModel> scannedRfids) {
-        // 过滤出未存在的RFID
-        final newRfids = scannedRfids
-            .where((rfid) => !_rfids.contains(rfid.uid))
+  Widget _buildElectronicIdSection() {
+    return VberElectronicIdsField(
+      electronicIds: _electronicIds,
+      onIdsScanned: (List<RfidModel> idList) {
+        // 过滤出未存在的ID
+        final ids = idList
+            .where((id) => !_electronicIds.contains(id.uid))
             .toList();
 
-        if (newRfids.isNotEmpty) {
+        if (ids.isNotEmpty) {
           setState(() {
-            // 将新的RFID添加到列表中
-            for (var rfid in newRfids) {
-              _rfids.insert(0, rfid.uid);
+            // 将新的ID添加到列表中
+            for (var id in ids) {
+              _electronicIds.insert(0, id.uid);
             }
           });
           // ToastUtil.success("新增 ${newRfids.length} 枚电子编号");
           ScaffoldMessenger.of(context).showSnackBar(
             SnackBar(
-              content: Text("新增 ${newRfids.length} 枚电子编号"),
+              content: Text("新增 ${ids.length} 枚电子编号"),
               backgroundColor: Colors.green,
             ),
           );
@@ -217,14 +216,14 @@ class _BatchCullingPageState extends State<BatchCullingPage> {
   // 移除指定索引的电子编号
   void _removeRfid(int index) {
     setState(() {
-      _rfids.removeAt(index);
+      _electronicIds.removeAt(index);
     });
   }
 
   // 清空所有已识别的电子编号
   void _clearRfids() {
     setState(() {
-      _rfids.clear();
+      _electronicIds.clear();
     });
     ToastUtil.info('已清空所有电子编号');
   }
@@ -232,7 +231,7 @@ class _BatchCullingPageState extends State<BatchCullingPage> {
   // 提交数据
   void _handleSubmit() {
     final data = {
-      'rfids': _rfids,
+      'electronicIds': _electronicIds,
       'disposalMethod': _disposalMethod,
       'cullReason': _cullReason,
       'date': DateTimeUtil.format(DateTime.now()),
@@ -251,7 +250,7 @@ class _BatchCullingPageState extends State<BatchCullingPage> {
           );
           // 提交后重置表单
           setState(() {
-            _rfids.clear();
+            _electronicIds.clear();
             // _cullReason = null;
             // _disposalMethod = null;
           });

+ 42 - 43
UI/CF.APP/chicken_farm/lib/pages/breeding/batch_culling_page_win.dart

@@ -14,7 +14,7 @@ class BatchCullingPageWin extends StatefulWidget {
 }
 
 class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
-  final List<String> _rfids = [];
+  final List<String> _electronicIds = [];
   String? _cullReason;
   String? _disposalMethod;
 
@@ -22,13 +22,13 @@ class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: const VberAppBar(title: '批量淘汰[Windows]', showLeftButton: true),
-      body: Padding(
+      body: SingleChildScrollView(
         padding: const EdgeInsets.all(16.0),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
             // 电子编号区域
-            _buildRfidSection(),
+            _buildElectronicIdSection(),
             const SizedBox(height: 20),
             // 淘汰原因
             _buildCullReasonSection(),
@@ -41,14 +41,14 @@ class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
               width: double.infinity,
               child: ElevatedButton(
                 onPressed:
-                    _rfids.isNotEmpty &&
+                    _electronicIds.isNotEmpty &&
                         _cullReason != null &&
                         _disposalMethod != null
                     ? _handleSubmit
                     : null,
                 style: ElevatedButton.styleFrom(
                   backgroundColor:
-                      _rfids.isNotEmpty &&
+                      _electronicIds.isNotEmpty &&
                           _cullReason != null &&
                           _disposalMethod != null
                       ? Colors.blue
@@ -60,7 +60,7 @@ class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
             ),
             const SizedBox(height: 20),
             // 已识别的电子编号列表
-            if (_rfids.isNotEmpty) ...[
+            if (_electronicIds.isNotEmpty) ...[
               Row(
                 mainAxisAlignment: MainAxisAlignment.spaceBetween,
                 children: [
@@ -70,41 +70,40 @@ class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
                   ),
                   IconButton(
                     icon: const Icon(Icons.clear, size: 18),
-                    onPressed: _clearRfids,
+                    onPressed: _clearElectronicIds,
                     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),
+              Container(
+                height: 200, // 固定高度以支持滚动
+                padding: const EdgeInsets.all(10),
+                decoration: BoxDecoration(
+                  border: Border.all(color: Colors.grey),
+                  borderRadius: BorderRadius.circular(8),
+                ),
+                child: ListView.builder(
+                  padding: EdgeInsets.zero,
+                  itemCount: _electronicIds.length,
+                  itemBuilder: (context, index) {
+                    return ListTile(
+                      visualDensity: VisualDensity.compact,
+                      contentPadding: const EdgeInsets.symmetric(
+                        horizontal: 2,
+                        vertical: 0,
+                      ),
+                      title: Text(_electronicIds[index]),
+                      trailing: IconButton(
+                        icon: const Icon(
+                          Icons.delete,
+                          size: 18,
+                          color: Colors.red,
                         ),
-                      );
-                    },
-                  ),
+                        onPressed: () => _removeElectronicId(index),
+                      ),
+                    );
+                  },
                 ),
               ),
             ],
@@ -115,11 +114,11 @@ class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
     );
   }
 
-  Widget _buildRfidSection() {
+  Widget _buildElectronicIdSection() {
     return Column(
       crossAxisAlignment: CrossAxisAlignment.start,
       children: [
-        const Text('请输入或扫描RFID', style: TextStyle(fontWeight: FontWeight.bold)),
+        const Text('请输入或扫描电子编号', style: TextStyle(fontWeight: FontWeight.bold)),
         const SizedBox(height: 10),
         Container(
           padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
@@ -186,16 +185,16 @@ class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
   }
 
   // 移除指定索引的电子编号
-  void _removeRfid(int index) {
+  void _removeElectronicId(int index) {
     setState(() {
-      _rfids.removeAt(index);
+      _electronicIds.removeAt(index);
     });
   }
 
   // 清空所有已识别的电子编号
-  void _clearRfids() {
+  void _clearElectronicIds() {
     setState(() {
-      _rfids.clear();
+      _electronicIds.clear();
     });
     ToastUtil.info('已清空所有电子编号');
   }
@@ -203,7 +202,7 @@ class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
   // 提交数据
   void _handleSubmit() {
     final data = {
-      'rfids': _rfids,
+      'electronicIds': _electronicIds,
       'disposal_method': _disposalMethod,
       'cull_reason': _cullReason,
       'date': DateTimeUtil.format(DateTime.now()),
@@ -222,7 +221,7 @@ class _BatchCullingPageWinState extends State<BatchCullingPageWin> {
           );
           // 提交后重置表单
           setState(() {
-            _rfids.clear();
+            _electronicIds.clear();
             // _cullReason = null;
             // _disposalMethod = null;
           });

+ 47 - 40
UI/CF.APP/chicken_farm/lib/pages/breeding/cage_change_page.dart

@@ -5,7 +5,7 @@ import 'package:flutter/material.dart';
 import 'package:chicken_farm/components/vb_app_bar.dart';
 import 'package:chicken_farm/core/utils/toast.dart';
 import 'package:chicken_farm/core/services/pda/scan_channel.dart';
-import 'package:chicken_farm/components/vb_rfid_field.dart';
+import 'package:chicken_farm/components/vb_electronic_id_field.dart';
 import 'package:go_router/go_router.dart';
 
 class CageChangePage extends StatefulWidget {
@@ -16,7 +16,7 @@ class CageChangePage extends StatefulWidget {
 }
 
 class _CageChangePageState extends State<CageChangePage> {
-  final List<String> _rfids = [];
+  final List<String> _electronicIds = [];
 
   // 添加TextEditingControllers用于控制输入框
   // final TextEditingController _sourceCageController = TextEditingController();
@@ -167,7 +167,7 @@ class _CageChangePageState extends State<CageChangePage> {
               _buildCageSection(),
               const SizedBox(height: 15),
               // 电子编号区域
-              _buildRfidSection(),
+              _buildElectronicIdSection(),
               const SizedBox(height: 15),
 
               // 提交按钮
@@ -196,12 +196,14 @@ class _CageChangePageState extends State<CageChangePage> {
                 width: double.infinity,
                 child: ElevatedButton(
                   onPressed:
-                      _cageController.text.isNotEmpty && _rfids.isNotEmpty
+                      _cageController.text.isNotEmpty &&
+                          _electronicIds.isNotEmpty
                       ? _handleSubmit
                       : null,
                   style: ElevatedButton.styleFrom(
                     backgroundColor:
-                        (_cageController.text.isNotEmpty && _rfids.isNotEmpty)
+                        (_cageController.text.isNotEmpty &&
+                            _electronicIds.isNotEmpty)
                         ? Colors.blue
                         : Colors.grey,
                     foregroundColor: Colors.white,
@@ -212,7 +214,7 @@ class _CageChangePageState extends State<CageChangePage> {
 
               const SizedBox(height: 20),
               // 已识别的电子编号列表
-              if (_rfids.isNotEmpty) ...[
+              if (_electronicIds.isNotEmpty) ...[
                 Row(
                   mainAxisAlignment: MainAxisAlignment.spaceBetween,
                   children: [
@@ -222,7 +224,7 @@ class _CageChangePageState extends State<CageChangePage> {
                     ),
                     IconButton(
                       icon: const Icon(Icons.clear, size: 18),
-                      onPressed: _clearRfids,
+                      onPressed: _clearElectronicIds,
                       tooltip: '清空编号',
                     ),
                   ],
@@ -238,7 +240,7 @@ class _CageChangePageState extends State<CageChangePage> {
                     shrinkWrap: true,
                     physics: const NeverScrollableScrollPhysics(),
                     padding: EdgeInsets.zero,
-                    itemCount: _rfids.length,
+                    itemCount: _electronicIds.length,
                     itemBuilder: (context, index) {
                       return ListTile(
                         visualDensity: VisualDensity.compact,
@@ -246,14 +248,14 @@ class _CageChangePageState extends State<CageChangePage> {
                           horizontal: 2,
                           vertical: 0,
                         ),
-                        title: Text(_rfids[index]),
+                        title: Text(_electronicIds[index]),
                         trailing: IconButton(
                           icon: const Icon(
                             Icons.delete,
                             size: 18,
                             color: Colors.red,
                           ),
-                          onPressed: () => _removeRfid(index),
+                          onPressed: () => _removeElectronicId(index),
                         ),
                       );
                     },
@@ -433,12 +435,12 @@ class _CageChangePageState extends State<CageChangePage> {
     );
   }
 
-  Widget _buildRfidSection() {
-    return VberRfidField(
-      rfids: _rfids,
-      onRfidScanned: (rfid) {
-        // 检查是否已存在相同的RFID标签
-        bool isDuplicate = _rfids.any((existingRfid) => existingRfid == rfid);
+  Widget _buildElectronicIdSection() {
+    return VberElectronicIdsField(
+      electronicIds: _electronicIds,
+      onIdScanned: (id) {
+        // 检查是否已存在相同的ID标签
+        bool isDuplicate = _electronicIds.any((v) => v == id);
         if (isDuplicate) {
           ScaffoldMessenger.of(context).showSnackBar(
             const SnackBar(
@@ -449,7 +451,7 @@ class _CageChangePageState extends State<CageChangePage> {
         } else {
           // 如果不重复,添加到列表中
           setState(() {
-            _rfids.insert(0, rfid);
+            _electronicIds.insert(0, id);
           });
           ScaffoldMessenger.of(context).showSnackBar(
             const SnackBar(
@@ -506,15 +508,6 @@ class _CageChangePageState extends State<CageChangePage> {
   //   _dealyScanCode(tag);
   // }
 
-  void _dealyScanCode({int? dealy}) async {
-    dealy ??= 600;
-    await Future.delayed(Duration(milliseconds: dealy));
-    bool success = await ScanChannel.startScan();
-    if (!success) {
-      ToastUtil.error("扫码失败");
-    }
-  }
-
   void _handleScanCageCode() async {
     if (_isScanningCode) return;
     setState(() {
@@ -526,36 +519,50 @@ class _CageChangePageState extends State<CageChangePage> {
     }
   }
 
-  void _handleChangeCageCode() {
-    _dealyScanCode();
+  void _handleChangeCageCode() async {
+    if (!await ScanChannel.isScanHeadOpened()) {
+      logger.w("扫描头未打开,正在重新打开");
+      await ScanChannel.openScanHead().then((success) async {
+        if (success) {
+          success = await ScanChannel.startScan();
+          if (!success) {
+            ToastUtil.error("扫码失败");
+          }
+        } else {
+          ToastUtil.errorAlert("扫描头打开失败");
+          if (mounted) {
+            context.pop();
+          }
+        }
+      });
+    } else {
+      bool success = await ScanChannel.startScan();
+      if (!success) {
+        ToastUtil.error("扫码失败");
+      }
+    }
   }
 
   // 移除指定索引的电子编号
-  void _removeRfid(int index) {
+  void _removeElectronicId(int index) {
     setState(() {
-      _rfids.removeAt(index);
+      _electronicIds.removeAt(index);
     });
   }
 
   // 清空所有已识别的电子编号
-  void _clearRfids() {
+  void _clearElectronicIds() {
     setState(() {
-      _rfids.clear();
+      _electronicIds.clear();
     });
     ToastUtil.info('已清空所有电子编号');
   }
 
   // 提交数据
   void _handleSubmit() {
-    // final data = {
-    //   'sourceCage': _sourceCageController.text,
-    //   'targetCage': _targetCageController.text,
-    //   'rfids': _rfids,
-    //   'date': DateTimeUtil.format(DateTime.now()),
-    // };
     final data = {
       'targetCage': _cageController.text,
-      'rfids': _rfids,
+      'electronicIds': _electronicIds,
       'date': DateTimeUtil.format(DateTime.now()),
     };
     apis.breeding.submitApi.cageChange(data).then((res) {
@@ -575,7 +582,7 @@ class _CageChangePageState extends State<CageChangePage> {
             // _sourceCageController.clear();
             // _targetCageController.clear();
             _cageController.clear();
-            _rfids.clear();
+            _electronicIds.clear();
           });
         }
       } else {

+ 14 - 14
UI/CF.APP/chicken_farm/lib/pages/breeding/individual_culling_page.dart

@@ -5,7 +5,7 @@ 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';
-import 'package:chicken_farm/components/vb_rfid_field.dart';
+import 'package:chicken_farm/components/vb_electronic_id_field.dart';
 
 class IndividualCullingPage extends StatefulWidget {
   const IndividualCullingPage({super.key});
@@ -15,7 +15,7 @@ class IndividualCullingPage extends StatefulWidget {
 }
 
 class _IndividualCullingPageState extends State<IndividualCullingPage> {
-  String? _rfid;
+  String? _electronicId;
   String? _cullReason;
   String? _disposalMethod;
 
@@ -23,13 +23,13 @@ class _IndividualCullingPageState extends State<IndividualCullingPage> {
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: const VberAppBar(title: '个体淘汰', showLeftButton: true),
-      body: Padding(
+      body: SingleChildScrollView(
         padding: const EdgeInsets.all(16.0),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
             // 电子编号区域
-            _buildRfidSection(),
+            _buildElectronicIdSection(),
             const SizedBox(height: 20),
             // 淘汰原因
             _buildCullReasonSection(),
@@ -42,14 +42,14 @@ class _IndividualCullingPageState extends State<IndividualCullingPage> {
               width: double.infinity,
               child: ElevatedButton(
                 onPressed:
-                    _rfid != null &&
+                    _electronicId != null &&
                         _cullReason != null &&
                         _disposalMethod != null
                     ? _handleSubmit
                     : null,
                 style: ElevatedButton.styleFrom(
                   backgroundColor:
-                      _rfid != null &&
+                      _electronicId != null &&
                           _cullReason != null &&
                           _disposalMethod != null
                       ? Colors.blue
@@ -65,11 +65,11 @@ class _IndividualCullingPageState extends State<IndividualCullingPage> {
     );
   }
 
-  Widget _buildRfidSection() {
-    return VberRfidField(
-      rfid: _rfid,
-      onRfidScanned: (rfid) {
-        if (rfid == _rfid) {
+  Widget _buildElectronicIdSection() {
+    return VberElectronicIdsField(
+      electronicId: _electronicId,
+      onIdScanned: (id) {
+        if (id == _electronicId) {
           ScaffoldMessenger.of(context).showSnackBar(
             const SnackBar(
               content: Text('电子编号未改变'),
@@ -78,7 +78,7 @@ class _IndividualCullingPageState extends State<IndividualCullingPage> {
           );
         } else {
           setState(() {
-            _rfid = rfid;
+            _electronicId = id;
           });
           // ToastUtil.success('电子编号识别成功');
           ScaffoldMessenger.of(context).showSnackBar(
@@ -153,7 +153,7 @@ class _IndividualCullingPageState extends State<IndividualCullingPage> {
   // 提交数据
   void _handleSubmit() {
     final data = {
-      "rfid": _rfid,
+      "electronicId": _electronicId,
       "cullReason": _cullReason,
       "disposalMethod": _disposalMethod,
       'date': DateTimeUtil.format(DateTime.now()),
@@ -172,7 +172,7 @@ class _IndividualCullingPageState extends State<IndividualCullingPage> {
           );
           // 提交后重置表单
           setState(() {
-            _rfid = null;
+            _electronicId = null;
             // _cullReason = null;
             // _disposalMethod = null;
           });

+ 14 - 14
UI/CF.APP/chicken_farm/lib/pages/breeding/individual_weighing_page.dart

@@ -3,7 +3,7 @@ import 'package:chicken_farm/core/utils/datetime_util.dart';
 import 'package:flutter/material.dart';
 import 'package:chicken_farm/components/vb_app_bar.dart';
 import 'package:chicken_farm/core/utils/toast.dart';
-import 'package:chicken_farm/components/vb_rfid_field.dart';
+import 'package:chicken_farm/components/vb_electronic_id_field.dart';
 import 'package:chicken_farm/core/utils/logger.dart';
 import 'dart:async';
 
@@ -15,7 +15,7 @@ class IndividualWeighingPage extends StatefulWidget {
 }
 
 class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
-  String? _rfid;
+  String? _electronicId;
   double? _weight;
   bool _isReadingWeight = false;
 
@@ -43,13 +43,13 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
   Widget build(BuildContext context) {
     return Scaffold(
       appBar: const VberAppBar(title: '个体称重', showLeftButton: true),
-      body: Padding(
+      body: SingleChildScrollView(
         padding: const EdgeInsets.all(16.0),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: [
             // 电子编号区域
-            _buildRfidSection(),
+            _buildElectronicIdSection(),
             const SizedBox(height: 20),
 
             // 重量区域
@@ -60,11 +60,11 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
             SizedBox(
               width: double.infinity,
               child: ElevatedButton(
-                onPressed: _rfid != null && _weight != null
+                onPressed: _electronicId != null && _weight != null
                     ? _handleSubmit
                     : null,
                 style: ElevatedButton.styleFrom(
-                  backgroundColor: _rfid != null && _weight != null
+                  backgroundColor: _electronicId != null && _weight != null
                       ? Colors.blue
                       : Colors.grey,
                   foregroundColor: Colors.white,
@@ -78,11 +78,11 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
     );
   }
 
-  Widget _buildRfidSection() {
-    return VberRfidField(
-      rfid: _rfid,
-      onRfidScanned: (rfid) {
-        if (rfid == _rfid) {
+  Widget _buildElectronicIdSection() {
+    return VberElectronicIdsField(
+      electronicId: _electronicId,
+      onIdScanned: (id) {
+        if (id == _electronicId) {
           ScaffoldMessenger.of(context).showSnackBar(
             const SnackBar(
               content: Text('电子编号未改变'),
@@ -91,7 +91,7 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
           );
         } else {
           setState(() {
-            _rfid = rfid;
+            _electronicId = id;
           });
           // ToastUtil.success('电子编号识别成功');
           ScaffoldMessenger.of(context).showSnackBar(
@@ -239,7 +239,7 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
   // 提交数据
   void _handleSubmit() {
     final data = {
-      "rfid": _rfid,
+      "electronicId": _electronicId,
       "weight": _weight,
       'date': DateTimeUtil.format(DateTime.now()),
     };
@@ -257,7 +257,7 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
           );
           // 提交后重置表单
           setState(() {
-            _rfid = null;
+            _electronicId = null;
             _weight = null;
             _weightController.clear();
           });