import 'package:chicken_farm/apis/index.dart'; import 'package:chicken_farm/core/utils/logger.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/core/services/pda/scan_channel.dart'; import 'package:chicken_farm/components/vb_rfid_field.dart'; class CageChangePage extends StatefulWidget { const CageChangePage({super.key}); @override State createState() => _CageChangePageState(); } class _CageChangePageState extends State { final List _rfids = []; // 添加TextEditingControllers用于控制输入框 final TextEditingController _sourceCageController = TextEditingController(); final TextEditingController _targetCageController = TextEditingController(); // 添加FocusNode用于控制焦点 final FocusNode _sourceCageFocusNode = FocusNode(); final FocusNode _targetCageFocusNode = FocusNode(); // 扫描状态 bool _isScanningSource = false; bool _isScanningTarget = false; int _scanTag = 1; @override void initState() { super.initState(); _sourceCageController.clear(); _targetCageController.clear(); // 监听焦点变化以更新_scanTag值 _sourceCageFocusNode.addListener(() { if (_sourceCageFocusNode.hasFocus) { _scanTag = 1; } }); _targetCageFocusNode.addListener(() { if (_targetCageFocusNode.hasFocus) { _scanTag = 2; } }); ScanChannel.openScanHead().then((success) { if (success) { logger.d("扫描头已打开"); } else { logger.d("扫描头打开失败"); } }); // 初始化监听 ScanChannel.initScanListener( onScanResult: (result) { if (_scanTag == 1) { // 源笼号 setState(() { _sourceCageController.text = result; _isScanningSource = false; }); if (_targetCageController.text.isEmpty) { // 源笼号扫描成功后自动延时扫描目标笼号 ScanChannel.stopSingleScan(); logger.d("自动扫描目标笼号"); _targetCageFocusNode.requestFocus(); _dealyScanCode(2); } } else if (_scanTag == 2) { // 目标笼号 setState(() { _targetCageController.text = result; _isScanningTarget = false; }); } // 扫码成功后停止解码(保留扫描头) ScanChannel.stopSingleScan(); }, onScanError: (error) { logger.d("扫码错误:$error"); setState(() { _isScanningSource = false; }); }, onKeyPress: (bool isDouble, String keyCode) { if (isDouble && keyCode == "KEY_619") { _sourceCageController.clear(); _targetCageController.clear(); _scanTag = 1; ScanChannel.startScan(); } else { logger.d("按键:$isDouble $keyCode"); } }, ); _scanTag = 1; // 进入页面默认使原笼号获取到焦点 // WidgetsBinding.instance.addPostFrameCallback((_) { // _sourceCageFocusNode.requestFocus(); // }); } @override void dispose() { // 释放TextEditingControllers _sourceCageController.dispose(); _targetCageController.dispose(); // 释放FocusNode _sourceCageFocusNode.dispose(); _targetCageFocusNode.dispose(); // 手动关闭扫描头,立即释放资源 ScanChannel.closeScanHead(); // 释放通道 ScanChannel.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: const VberAppBar(title: '换笼管理', showLeftButton: true), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 源笼号区域 _buildCageSection(1), const SizedBox(height: 15), // 目标笼号区域 _buildCageSection(2), const SizedBox(height: 15), // 电子编号区域 _buildRfidSection(), const SizedBox(height: 15), // 提交按钮 SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _sourceCageController.text.isNotEmpty && _targetCageController.text.isNotEmpty && _rfids.isNotEmpty ? _handleSubmit : null, style: ElevatedButton.styleFrom( backgroundColor: (_sourceCageController.text.isNotEmpty && _targetCageController.text.isNotEmpty && _rfids.isNotEmpty) ? 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), Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( border: Border.all(color: Colors.grey), borderRadius: BorderRadius.circular(8), ), child: ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), 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 _buildCageSection(int tag) { String title = '源笼号'; TextEditingController controller = _sourceCageController; FocusNode focusNode = _sourceCageFocusNode; bool isScanning = _isScanningSource; if (tag != 1) { tag = 2; title = '目标笼号'; controller = _targetCageController; focusNode = _targetCageFocusNode; isScanning = _isScanningTarget; } // 确保光标在文本末尾 if (controller.text.isNotEmpty) { controller.selection = TextSelection.fromPosition( TextPosition(offset: controller.text.length), ); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(title, style: const 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: Row( children: [ Expanded( // 将Text替换为TextField child: TextField( focusNode: focusNode, controller: controller, enabled: controller.text.isEmpty, decoration: InputDecoration( border: InputBorder.none, hintText: controller.text.isNotEmpty ? null : '未扫描', hintStyle: TextStyle( color: controller.text.isNotEmpty ? Colors.black : Colors.grey, fontSize: 16, ), ), style: TextStyle( color: controller.text.isNotEmpty ? Colors.black : Colors.grey, fontSize: 16, ), onChanged: (text) { setState(() { // 文本更改由controller自动处理 }); }, ), ), if (controller.text.isNotEmpty) ...[ IconButton( icon: const Icon(Icons.refresh, size: 20), onPressed: () { _handleChangeCageCode(tag); }, ), ] else ...[ IconButton( icon: isScanning ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator(strokeWidth: 2), ) : const Icon(Icons.qr_code_scanner, size: 20), onPressed: () { _handleScanCageCode(tag); }, ), ], ], ), ), ], ); } Widget _buildRfidSection() { return VberRfidField( rfids: _rfids, onRfidScanned: (rfid) { // 检查是否已存在相同的RFID标签 bool isDuplicate = _rfids.any((existingRfid) => existingRfid == rfid); if (isDuplicate) { ToastUtil.info("电子编号已存在"); } else { // 如果不重复,添加到列表中 setState(() { _rfids.insert(0, rfid); }); ToastUtil.success("成功添加新的电子编号"); } }, multiple: true, multipleScan: false, label: '电子编号', multiplePlaceholder: '未识别', multipleFormat: '已识别 %d 枚电子编号', ); } void _dealyScanCode(int scanTag, {int? dealy}) async { dealy ??= 800; _scanTag = scanTag; logger.d("开始扫码: $_scanTag"); await Future.delayed(Duration(milliseconds: dealy)); bool success = await ScanChannel.startScan(); if (!success) { ToastUtil.error("扫码失败"); } } void _handleScanCageCode(int tag) async { if (_isScanningTarget || _isScanningSource) return; setState(() { if (tag == 1) { _isScanningSource = true; } else if (tag == 2) { _isScanningTarget = true; } }); _scanTag = tag; logger.d("开始扫码: $_scanTag"); bool success = await ScanChannel.startScan(); if (!success) { ToastUtil.error("扫码失败"); } } void _handleChangeCageCode(int tag) { setState(() { if (tag == 1) { _sourceCageController.clear(); } else { _targetCageController.clear(); } }); _dealyScanCode(tag); } // 移除指定索引的电子编号 void _removeRfid(int index) { setState(() { _rfids.removeAt(index); }); } // 清空所有已识别的电子编号 void _clearRfids() { setState(() { _rfids.clear(); }); ToastUtil.info('已清空所有电子编号'); } // 提交数据 void _handleSubmit() { final data = { 'source_cage': _sourceCageController.text, 'target_cage': _targetCageController.text, 'rfids': _rfids, }; apis.breeding.submitApi .cageChange(data) .then((_) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('换笼提交成功'), backgroundColor: Colors.green, ), ); // 提交后重置表单 setState(() { _sourceCageController.clear(); _targetCageController.clear(); _rfids.clear(); }); } }) .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, ), ); } }); } }