vb_electronic_id_field.dart 6.7 KB

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