vb_electronic_id_field.dart 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import 'package:chicken_farm/core/utils/logger.dart';
  2. import 'package:chicken_farm/modes/rfid/rfid_model.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:chicken_farm/core/services/pda/rfid_manager.dart';
  5. import 'package:chicken_farm/core/utils/toast.dart';
  6. /// RFID字段组件,支持单个或多个RFID显示
  7. ///
  8. /// 当[multiple]为true时,显示已识别的RFID数量
  9. /// 当[multiple]为false时,显示单个RFID的具体值
  10. class VberElectronicIdsField extends StatefulWidget {
  11. final List<String>? electronicIds;
  12. final String? electronicId;
  13. final ValueChanged<String>? onIdScanned; // RFID识别成功回调
  14. final ValueChanged<List<RfidModel>>? onIdsScanned; // RFID识别成功回调
  15. final ValueChanged<String>? onKeyPress; // 按键事件
  16. final bool multiple;
  17. final bool? multipleScan;
  18. final ValueChanged<int>? onDeleteRfid; // 仅在multiple模式下使用
  19. final String label; // 显示的标签文本
  20. final String placeholder; // 未识别时显示的占位符文本
  21. final String multiplePlaceholder; // 多个模式下未识别时显示的占位符文本
  22. final String multipleFormat; // 多个模式下有值时的显示格式,包含一个%d占位符表示数量
  23. const VberElectronicIdsField({
  24. super.key,
  25. this.electronicIds,
  26. this.electronicId,
  27. this.onIdScanned,
  28. this.onIdsScanned,
  29. this.onKeyPress,
  30. this.multiple = false,
  31. this.multipleScan,
  32. this.onDeleteRfid,
  33. this.label = '电子编号',
  34. this.placeholder = '未识别',
  35. this.multiplePlaceholder = '未识别',
  36. this.multipleFormat = '已识别 %d 枚电子编号',
  37. });
  38. @override
  39. State<VberElectronicIdsField> createState() => _VberElectronicIdsFieldState();
  40. }
  41. class _VberElectronicIdsFieldState extends State<VberElectronicIdsField> {
  42. bool _isScanning = false; // 内部管理识别状态
  43. bool _isMultiple = false; // 内部管理识别状态
  44. @override
  45. void initState() {
  46. super.initState();
  47. RfidManager.instance.registerCallbacks(
  48. onTagScanned: _handleRfidsScanned,
  49. onRFIDScanned: _handleRfidScanned,
  50. onKeyPress: _handleKeyPress,
  51. onErrorScanned: _handleScanError,
  52. onConnectSuccess: () {
  53. ToastUtil.show('读卡器连接成功', duration: 1, bgColor: Colors.green);
  54. },
  55. );
  56. _isMultiple = widget.multipleScan ?? widget.multiple;
  57. }
  58. @override
  59. void dispose() {
  60. RfidManager.instance.disposeRfid();
  61. super.dispose();
  62. }
  63. void _handleRfidScanned(String rfid) {
  64. logger.d('识别成功,已识别电子编号:$rfid');
  65. setState(() {
  66. _isScanning = false;
  67. });
  68. if (widget.onIdScanned != null) {
  69. widget.onIdScanned!(rfid);
  70. }
  71. }
  72. void _handleRfidsScanned(List<RfidModel> rfidList) {
  73. logger.d('识别成功,已识别枚${rfidList.length}电子编号');
  74. setState(() {
  75. _isScanning = false;
  76. });
  77. if (widget.onIdsScanned != null) {
  78. widget.onIdsScanned!(rfidList);
  79. }
  80. }
  81. void _handleScanError(String error) {
  82. ToastUtil.error(error);
  83. setState(() {
  84. _isScanning = false;
  85. });
  86. }
  87. void _handleKeyPress(String keyCode) {
  88. if (keyCode == 'KEY_619') {
  89. _scanRfid();
  90. }
  91. }
  92. void _scanRfid() async {
  93. setState(() {
  94. _isScanning = true;
  95. });
  96. ToastUtil.show('开始识别电子编号', duration: 1);
  97. int result = await RfidManager.instance.startRead(isMultiple: _isMultiple);
  98. if (result == 1) {
  99. ToastUtil.errorAlert('读卡器已自动断开连接!\n现在正在连接中,请稍后重试!');
  100. setState(() {
  101. _isScanning = false;
  102. });
  103. } else if (result == 2) {
  104. ToastUtil.errorAlert('读卡器读取失败,请检查读卡器是否正常');
  105. setState(() {
  106. _isScanning = false;
  107. });
  108. }
  109. }
  110. @override
  111. Widget build(BuildContext context) {
  112. return Column(
  113. crossAxisAlignment: CrossAxisAlignment.start,
  114. children: [
  115. Text(widget.label, style: const TextStyle(fontWeight: FontWeight.bold)),
  116. const SizedBox(height: 10),
  117. Container(
  118. padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
  119. decoration: BoxDecoration(
  120. border: Border.all(color: Colors.grey),
  121. borderRadius: BorderRadius.circular(8),
  122. ),
  123. child: Row(
  124. children: [
  125. Expanded(
  126. child: Text(
  127. _getDisplayText(),
  128. style: TextStyle(
  129. color: _hasValue() ? Colors.black : Colors.grey,
  130. fontSize: 16,
  131. ),
  132. ),
  133. ),
  134. IconButton(
  135. icon: _isScanning
  136. ? const SizedBox(
  137. width: 20,
  138. height: 20,
  139. child: CircularProgressIndicator(strokeWidth: 2),
  140. )
  141. : Icon(
  142. widget.multiple ? Icons.add : Icons.qr_code_scanner,
  143. size: 20,
  144. ),
  145. onPressed: _isScanning ? null : _scanRfid,
  146. ),
  147. ],
  148. ),
  149. ),
  150. ],
  151. );
  152. }
  153. /// 获取显示的文本
  154. String _getDisplayText() {
  155. if (widget.multiple) {
  156. if (widget.electronicIds == null || widget.electronicIds!.isEmpty) {
  157. return widget.multiplePlaceholder;
  158. } else {
  159. return widget.multipleFormat.replaceAll(
  160. '%d',
  161. widget.electronicIds!.length.toString(),
  162. );
  163. }
  164. } else {
  165. return widget.electronicId ?? widget.placeholder;
  166. }
  167. }
  168. /// 判断是否有值
  169. bool _hasValue() {
  170. if (widget.multiple) {
  171. return widget.electronicIds != null && widget.electronicIds!.isNotEmpty;
  172. } else {
  173. return widget.electronicId != null;
  174. }
  175. }
  176. }