individual_query_page.dart 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. import 'dart:async';
  2. import 'dart:io';
  3. import 'package:chicken_farm/components/vb_dict_label.dart';
  4. import 'package:chicken_farm/core/utils/logger.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:chicken_farm/apis/breeding/_query.dart';
  7. import 'package:chicken_farm/components/vb_electronic_id_field.dart';
  8. import 'package:chicken_farm/components/vb_win_electronic_id_field.dart';
  9. import 'package:chicken_farm/core/utils/toast.dart';
  10. import 'package:chicken_farm/modes/breeding/chicken.dart';
  11. import 'package:intl/intl.dart';
  12. class IndividualQueryPage extends StatefulWidget {
  13. const IndividualQueryPage({super.key});
  14. @override
  15. State<IndividualQueryPage> createState() => _IndividualQueryPageState();
  16. }
  17. class _IndividualQueryPageState extends State<IndividualQueryPage> {
  18. final BreedQueryApi _breedQueryApi = BreedQueryApi();
  19. ChickenModel? _chicken;
  20. String? _electronicId;
  21. bool _isLoading = false;
  22. final TextEditingController _idController = TextEditingController();
  23. Timer? _debounceTimer; // 添加Timer变量用于管理延时操作
  24. // 添加手动模式状态
  25. bool _isManualMode = false;
  26. @override
  27. void initState() {
  28. super.initState();
  29. }
  30. @override
  31. void dispose() {
  32. // 取消任何待处理的计时器
  33. if (_debounceTimer != null) {
  34. _debounceTimer!.cancel();
  35. }
  36. _idController.dispose();
  37. super.dispose();
  38. }
  39. void _queryChickenOnce(String id) {
  40. if (_debounceTimer != null) {
  41. _debounceTimer!.cancel();
  42. }
  43. _debounceTimer = Timer(Duration(milliseconds: 800), () {
  44. _queryChicken(id);
  45. });
  46. }
  47. Future<void> _queryChicken(String id) async {
  48. if (id.isEmpty) {
  49. ToastUtil.warning('请输入电子编号');
  50. return;
  51. }
  52. setState(() {
  53. _isLoading = true;
  54. });
  55. try {
  56. final chicken = await _breedQueryApi.queryChicken(id.trim());
  57. if (chicken != null) {
  58. if (mounted) {
  59. // 遵循Flutter异步操作与UI更新安全规范
  60. setState(() {
  61. _chicken = chicken;
  62. });
  63. }
  64. } else {
  65. if (mounted) {
  66. // 遵循Flutter异步操作与UI更新安全规范
  67. ToastUtil.error('未找到该编号对应的个体信息');
  68. setState(() {
  69. _chicken = null;
  70. });
  71. }
  72. }
  73. } catch (e) {
  74. if (mounted) {
  75. // 遵循Flutter异步操作与UI更新安全规范
  76. ToastUtil.error('查询失败: $e');
  77. logger.e(e);
  78. setState(() {
  79. _chicken = null;
  80. });
  81. }
  82. } finally {
  83. if (mounted) {
  84. // 遵循Flutter异步操作与UI更新安全规范
  85. setState(() {
  86. _isLoading = false;
  87. });
  88. }
  89. }
  90. }
  91. // 手动查询方法
  92. void _manualQueryChicken() {
  93. if (_idController.text.isEmpty) {
  94. ToastUtil.warning('请输入电子编号');
  95. return;
  96. }
  97. _queryChicken(_idController.text);
  98. }
  99. @override
  100. Widget build(BuildContext context) {
  101. return Scaffold(
  102. appBar: AppBar(title: const Text('个体查询')),
  103. body: Padding(
  104. padding: const EdgeInsets.all(16.0),
  105. child: Column(
  106. children: [
  107. // 按钮行 - 手动/自动切换按钮
  108. Row(
  109. mainAxisAlignment: MainAxisAlignment.end, // 靠右对齐
  110. children: [
  111. // 手动/自动切换按钮
  112. SizedBox(
  113. // 设置固定宽度
  114. width: 120,
  115. child: ElevatedButton(
  116. onPressed: () {
  117. setState(() {
  118. _isManualMode = !_isManualMode;
  119. _idController.clear();
  120. _chicken = null;
  121. _electronicId = null;
  122. });
  123. },
  124. style: ElevatedButton.styleFrom(
  125. backgroundColor: _isManualMode
  126. ? Colors.blue
  127. : Colors.orange,
  128. foregroundColor: Colors.white,
  129. ),
  130. child: Text(_isManualMode ? '识别查询' : '手动查询'),
  131. ),
  132. ),
  133. ],
  134. ),
  135. const SizedBox(height: 8), // 添加一点间距
  136. // 电子标签输入区域 - 根据模式动态显示
  137. if (!_isManualMode) ...[
  138. _buildPlatformSpecificField(),
  139. ] else ...[
  140. // 手动输入模式
  141. Row(
  142. children: [
  143. Expanded(
  144. child: TextField(
  145. controller: _idController,
  146. decoration: const InputDecoration(
  147. labelText: '电子编号',
  148. border: OutlineInputBorder(),
  149. hintText: '请输入电子编号',
  150. ),
  151. ),
  152. ),
  153. const SizedBox(width: 8),
  154. ElevatedButton(
  155. onPressed: _manualQueryChicken,
  156. style: ElevatedButton.styleFrom(
  157. backgroundColor: Colors.green,
  158. foregroundColor: Colors.white,
  159. ),
  160. child: const Text('查询'),
  161. ),
  162. ],
  163. ),
  164. ],
  165. const SizedBox(height: 16),
  166. // 个体信息展示区域
  167. if (_chicken != null) ...[
  168. Expanded(
  169. child: SingleChildScrollView(
  170. child: Card(
  171. child: Padding(
  172. padding: const EdgeInsets.all(16.0),
  173. child: Column(
  174. crossAxisAlignment: CrossAxisAlignment.start,
  175. children: [
  176. // 基本信息
  177. const Text(
  178. '基本信息',
  179. style: TextStyle(
  180. fontSize: 18,
  181. fontWeight: FontWeight.bold,
  182. ),
  183. ),
  184. const SizedBox(height: 10),
  185. _buildInfoRow('电子编号:', _chicken!.electronicId),
  186. _buildInfoRow('批次号:', _chicken!.batchNum),
  187. _buildInfoRow('家系编号:', _chicken!.familyNum),
  188. _buildInfoRow('笼号:', _chicken!.cageNum ?? '无'),
  189. _buildInfoRow2(
  190. '性别:',
  191. VberDictLabel(
  192. dictType: "chicken_gender",
  193. value: _chicken!.gender.toString(),
  194. ),
  195. ),
  196. _buildInfoRow(
  197. '孵化日期:',
  198. DateFormat(
  199. 'yyyy-MM-dd',
  200. ).format(_chicken!.hatchDate),
  201. ),
  202. if (_chicken!.currentAge != null)
  203. _buildInfoRow('当前日龄:', '${_chicken!.currentAge} 天'),
  204. _buildInfoRow2(
  205. '养殖状态:',
  206. VberDictLabel(
  207. dictType: "chicken_status",
  208. value: _chicken!.status.toString(),
  209. ),
  210. ),
  211. if (_chicken!.cullReason != null)
  212. _buildInfoRow2(
  213. '淘汰原因:',
  214. VberDictLabel(
  215. dictType: "chicken_cull_reason",
  216. value: _chicken!.cullReason.toString(),
  217. ),
  218. ),
  219. if (_chicken!.disposalMethod != null)
  220. _buildInfoRow2(
  221. '处理方式:',
  222. VberDictLabel(
  223. dictType: "chicken_disposal_method",
  224. value: _chicken!.disposalMethod.toString(),
  225. ),
  226. ),
  227. if (_chicken!.cullTime != null)
  228. _buildInfoRow(
  229. '淘汰时间:',
  230. DateFormat(
  231. 'yyyy-MM-dd HH:mm:ss',
  232. ).format(_chicken!.cullTime!),
  233. ),
  234. const SizedBox(height: 20),
  235. // SOP信息
  236. // const Text(
  237. // 'SOP信息',
  238. // style: TextStyle(
  239. // fontSize: 18,
  240. // fontWeight: FontWeight.bold,
  241. // ),
  242. // ),
  243. // const SizedBox(height: 10),
  244. // _buildInfoRow('饲料SOP:', _chicken!.feedSopName ?? '无'),
  245. // _buildInfoRow('用药SOP:', _chicken!.drugSopName ?? '无'),
  246. // _buildInfoRow(
  247. // '疫苗SOP:',
  248. // _chicken!.vaccineSopName ?? '无',
  249. // ),
  250. ],
  251. ),
  252. ),
  253. ),
  254. ),
  255. ),
  256. ] else if (!_isLoading)
  257. Expanded(
  258. child: Center(
  259. child: Text(
  260. '请${_isManualMode ? "输入" : "识别"}电子编号查询',
  261. style: Theme.of(
  262. context,
  263. ).textTheme.titleMedium?.copyWith(color: Colors.grey[600]),
  264. ),
  265. ),
  266. ),
  267. ],
  268. ),
  269. ),
  270. );
  271. }
  272. // 根据平台构建特定字段组件
  273. Widget _buildPlatformSpecificField() {
  274. return VberElectronicIdsField(
  275. electronicId: _electronicId,
  276. scanMilliseconds: 1000,
  277. onIdScanned: (id) {
  278. setState(() {
  279. _electronicId = id;
  280. });
  281. _queryChickenOnce(id);
  282. },
  283. label: '电子编号',
  284. placeholder: '未识别',
  285. );
  286. }
  287. Widget _buildInfoRow(String label, String value) {
  288. return Padding(
  289. padding: const EdgeInsets.only(bottom: 8.0),
  290. child: Row(
  291. crossAxisAlignment: CrossAxisAlignment.start,
  292. children: [
  293. SizedBox(
  294. width: 80,
  295. child: Text(
  296. label,
  297. style: const TextStyle(fontWeight: FontWeight.w500),
  298. ),
  299. ),
  300. Expanded(
  301. child: Text(value, style: const TextStyle(color: Colors.black87)),
  302. ),
  303. ],
  304. ),
  305. );
  306. }
  307. Widget _buildInfoRow2(String label, Widget value) {
  308. return Padding(
  309. padding: const EdgeInsets.only(bottom: 8.0),
  310. child: Row(
  311. crossAxisAlignment: CrossAxisAlignment.start,
  312. children: [
  313. SizedBox(
  314. width: 80,
  315. child: Text(
  316. label,
  317. style: const TextStyle(fontWeight: FontWeight.w500),
  318. ),
  319. ),
  320. value,
  321. ],
  322. ),
  323. );
  324. }
  325. }