vb_electronic_id_field.dart 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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() {
  93. setState(() {
  94. _isScanning = true;
  95. });
  96. ToastUtil.show('开始识别电子编号', duration: 1);
  97. RfidManager.instance.startScan(isMultiple: _isMultiple);
  98. }
  99. @override
  100. Widget build(BuildContext context) {
  101. return Column(
  102. crossAxisAlignment: CrossAxisAlignment.start,
  103. children: [
  104. Text(widget.label, style: const TextStyle(fontWeight: FontWeight.bold)),
  105. const SizedBox(height: 10),
  106. Container(
  107. padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
  108. decoration: BoxDecoration(
  109. border: Border.all(color: Colors.grey),
  110. borderRadius: BorderRadius.circular(8),
  111. ),
  112. child: Row(
  113. children: [
  114. Expanded(
  115. child: Text(
  116. _getDisplayText(),
  117. style: TextStyle(
  118. color: _hasValue() ? Colors.black : Colors.grey,
  119. fontSize: 16,
  120. ),
  121. ),
  122. ),
  123. IconButton(
  124. icon: _isScanning
  125. ? const SizedBox(
  126. width: 20,
  127. height: 20,
  128. child: CircularProgressIndicator(strokeWidth: 2),
  129. )
  130. : Icon(
  131. widget.multiple ? Icons.add : Icons.qr_code_scanner,
  132. size: 20,
  133. ),
  134. onPressed: _isScanning ? null : _scanRfid,
  135. ),
  136. ],
  137. ),
  138. ),
  139. ],
  140. );
  141. }
  142. /// 获取显示的文本
  143. String _getDisplayText() {
  144. if (widget.multiple) {
  145. if (widget.electronicIds == null || widget.electronicIds!.isEmpty) {
  146. return widget.multiplePlaceholder;
  147. } else {
  148. return widget.multipleFormat.replaceAll(
  149. '%d',
  150. widget.electronicIds!.length.toString(),
  151. );
  152. }
  153. } else {
  154. return widget.electronicId ?? widget.placeholder;
  155. }
  156. }
  157. /// 判断是否有值
  158. bool _hasValue() {
  159. if (widget.multiple) {
  160. return widget.electronicIds != null && widget.electronicIds!.isNotEmpty;
  161. } else {
  162. return widget.electronicId != null;
  163. }
  164. }
  165. }