cage_change_page.dart 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. import 'package:flutter/material.dart';
  2. import 'package:chicken_farm/components/vb_app_bar.dart';
  3. import 'package:chicken_farm/core/utils/toast.dart';
  4. import 'package:chicken_farm/core/services/pda/pda_scanner_service.dart';
  5. class CageChangePage extends StatefulWidget {
  6. const CageChangePage({super.key});
  7. @override
  8. State<CageChangePage> createState() => _CageChangePageState();
  9. }
  10. class _CageChangePageState extends State<CageChangePage> {
  11. String? _sourceCageId;
  12. String? _targetCageId;
  13. final List<String> _rfids = [];
  14. // 扫描状态
  15. bool _isScanningSource = false;
  16. bool _isScanningTarget = false;
  17. bool _isScanningRfid = false;
  18. @override
  19. Widget build(BuildContext context) {
  20. return Scaffold(
  21. appBar: const VberAppBar(title: '换笼管理', showLeftButton: true),
  22. body: Padding(
  23. padding: const EdgeInsets.all(16.0),
  24. child: Column(
  25. crossAxisAlignment: CrossAxisAlignment.start,
  26. children: [
  27. // 源笼号区域
  28. _buildCageSection(
  29. title: '源笼号',
  30. value: _sourceCageId,
  31. isScanning: _isScanningSource,
  32. onScanPressed: _scanSourceCage,
  33. onChangePressed: _handleChangeSourceCage,
  34. ),
  35. const SizedBox(height: 15),
  36. // 目标笼号区域
  37. _buildCageSection(
  38. title: '目标笼号',
  39. value: _targetCageId,
  40. isScanning: _isScanningTarget,
  41. onScanPressed: _scanTargetCage,
  42. onChangePressed: _handleChangeTargetCage,
  43. ),
  44. const SizedBox(height: 15),
  45. // 电子编号区域
  46. _buildRfidSection(),
  47. const SizedBox(height: 15),
  48. // 提交按钮
  49. SizedBox(
  50. width: double.infinity,
  51. child: ElevatedButton(
  52. onPressed:
  53. _sourceCageId != null &&
  54. _targetCageId != null &&
  55. _rfids.isNotEmpty
  56. ? _handleSubmit
  57. : null,
  58. style: ElevatedButton.styleFrom(
  59. backgroundColor:
  60. (_sourceCageId != null &&
  61. _targetCageId != null &&
  62. _rfids.isNotEmpty)
  63. ? Colors.blue
  64. : Colors.grey,
  65. foregroundColor: Colors.white,
  66. ),
  67. child: const Text('提交'),
  68. ),
  69. ),
  70. const SizedBox(height: 20),
  71. // 已扫描的电子编号列表
  72. if (_rfids.isNotEmpty) ...[
  73. const Text(
  74. '已扫描的电子编号',
  75. style: TextStyle(fontWeight: FontWeight.bold),
  76. ),
  77. const SizedBox(height: 10),
  78. Expanded(
  79. child: Container(
  80. padding: const EdgeInsets.all(10),
  81. decoration: BoxDecoration(
  82. border: Border.all(color: Colors.grey),
  83. borderRadius: BorderRadius.circular(8),
  84. ),
  85. child: ListView.builder(
  86. padding: EdgeInsets.zero,
  87. itemCount: _rfids.length,
  88. itemBuilder: (context, index) {
  89. return ListTile(
  90. visualDensity: VisualDensity.compact,
  91. contentPadding: const EdgeInsets.symmetric(
  92. horizontal: 2,
  93. vertical: 0,
  94. ),
  95. title: Text(_rfids[index]),
  96. trailing: IconButton(
  97. icon: const Icon(
  98. Icons.delete,
  99. size: 18,
  100. color: Colors.red,
  101. ),
  102. onPressed: () => _removeRfid(index),
  103. ),
  104. );
  105. },
  106. ),
  107. ),
  108. ),
  109. ],
  110. const SizedBox(height: 20),
  111. ],
  112. ),
  113. ),
  114. );
  115. }
  116. Widget _buildCageSection({
  117. required String title,
  118. String? value,
  119. required bool isScanning,
  120. required VoidCallback onScanPressed,
  121. required VoidCallback onChangePressed,
  122. }) {
  123. return Column(
  124. crossAxisAlignment: CrossAxisAlignment.start,
  125. children: [
  126. Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
  127. const SizedBox(height: 10),
  128. Container(
  129. padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
  130. decoration: BoxDecoration(
  131. border: Border.all(color: Colors.grey),
  132. borderRadius: BorderRadius.circular(8),
  133. ),
  134. child: Row(
  135. children: [
  136. Expanded(
  137. child: Text(
  138. value ?? '未扫描',
  139. style: TextStyle(
  140. color: value != null ? Colors.black : Colors.grey,
  141. fontSize: 16,
  142. ),
  143. ),
  144. ),
  145. if (value != null) ...[
  146. IconButton(
  147. icon: const Icon(Icons.refresh, size: 20),
  148. onPressed: onChangePressed,
  149. ),
  150. ] else ...[
  151. IconButton(
  152. icon: isScanning
  153. ? const SizedBox(
  154. width: 20,
  155. height: 20,
  156. child: CircularProgressIndicator(strokeWidth: 2),
  157. )
  158. : const Icon(Icons.qr_code_scanner, size: 20),
  159. onPressed: onScanPressed,
  160. ),
  161. ],
  162. ],
  163. ),
  164. ),
  165. ],
  166. );
  167. }
  168. Widget _buildRfidSection() {
  169. return Column(
  170. crossAxisAlignment: CrossAxisAlignment.start,
  171. children: [
  172. const Text('鸡数量', style: TextStyle(fontWeight: FontWeight.bold)),
  173. const SizedBox(height: 10),
  174. Container(
  175. padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
  176. decoration: BoxDecoration(
  177. border: Border.all(color: Colors.grey),
  178. borderRadius: BorderRadius.circular(8),
  179. ),
  180. child: Row(
  181. children: [
  182. Expanded(
  183. child: Text(
  184. _rfids.isEmpty ? '未扫描' : '已扫描 ${_rfids.length} 只鸡',
  185. style: TextStyle(
  186. color: _rfids.isNotEmpty ? Colors.black : Colors.grey,
  187. fontSize: 16,
  188. ),
  189. ),
  190. ),
  191. IconButton(
  192. icon: _isScanningRfid
  193. ? const SizedBox(
  194. width: 20,
  195. height: 20,
  196. child: CircularProgressIndicator(strokeWidth: 2),
  197. )
  198. : const Icon(Icons.add, size: 20),
  199. onPressed: _scanRfid,
  200. ),
  201. ],
  202. ),
  203. ),
  204. ],
  205. );
  206. }
  207. // 扫描源笼号
  208. void _scanSourceCage() async {
  209. if (_isScanningSource) return;
  210. setState(() {
  211. _isScanningSource = true;
  212. });
  213. try {
  214. final result = await PdaScannerService.scanBarcode();
  215. if (mounted) {
  216. setState(() {
  217. _sourceCageId = result;
  218. _isScanningSource = false;
  219. });
  220. ToastUtil.success('源笼号扫描成功');
  221. }
  222. } catch (e) {
  223. if (mounted) {
  224. setState(() {
  225. _isScanningSource = false;
  226. });
  227. ToastUtil.error('扫描失败: $e');
  228. }
  229. }
  230. }
  231. // 扫描目标笼号
  232. void _scanTargetCage() async {
  233. if (_isScanningTarget) return;
  234. setState(() {
  235. _isScanningTarget = true;
  236. });
  237. try {
  238. final result = await PdaScannerService.scanBarcode();
  239. if (mounted) {
  240. setState(() {
  241. _targetCageId = result;
  242. _isScanningTarget = false;
  243. });
  244. ToastUtil.success('目标笼号扫描成功');
  245. }
  246. } catch (e) {
  247. if (mounted) {
  248. setState(() {
  249. _isScanningTarget = false;
  250. });
  251. ToastUtil.error('扫描失败: $e');
  252. }
  253. }
  254. }
  255. // 扫描电子编号
  256. void _scanRfid() async {
  257. if (_isScanningRfid) return;
  258. setState(() {
  259. _isScanningRfid = true;
  260. });
  261. try {
  262. // 使用实际的RFID读取功能
  263. final result = await PdaScannerService.readRfid();
  264. if (mounted) {
  265. setState(() {
  266. // 每次添加一个新的电子编号到数组开头(模拟按一次实体按钮扫描一个电子编号)
  267. _rfids.insert(0, result);
  268. _isScanningRfid = false;
  269. });
  270. ToastUtil.success('鸡扫描成功');
  271. }
  272. } catch (e) {
  273. if (mounted) {
  274. setState(() {
  275. _isScanningRfid = false;
  276. });
  277. ToastUtil.error('RFID读取失败: $e');
  278. }
  279. }
  280. }
  281. // 重新扫描源笼号
  282. void _handleChangeSourceCage() {
  283. setState(() {
  284. _sourceCageId = null;
  285. });
  286. }
  287. // 重新扫描目标笼号
  288. void _handleChangeTargetCage() {
  289. setState(() {
  290. _targetCageId = null;
  291. });
  292. }
  293. // 移除指定索引的电子编号
  294. void _removeRfid(int index) {
  295. setState(() {
  296. _rfids.removeAt(index);
  297. });
  298. }
  299. // 提交数据
  300. void _handleSubmit() {
  301. // 在实际应用中,这里会发送数据到服务器
  302. ScaffoldMessenger.of(context).showSnackBar(
  303. const SnackBar(content: Text('换笼操作提交成功'), backgroundColor: Colors.green),
  304. );
  305. // 提交后重置表单
  306. setState(() {
  307. _sourceCageId = null;
  308. _targetCageId = null;
  309. _rfids.clear();
  310. });
  311. }
  312. }