individual_query_page.dart 11 KB

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