|
|
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
|
|
|
import 'package:chicken_farm/components/vb_app_bar.dart';
|
|
|
import 'package:chicken_farm/core/utils/toast.dart';
|
|
|
import 'package:chicken_farm/components/vb_rfid_field.dart';
|
|
|
+import 'package:chicken_farm/core/utils/logger.dart';
|
|
|
+import 'dart:async';
|
|
|
|
|
|
class IndividualWeighingPage extends StatefulWidget {
|
|
|
const IndividualWeighingPage({super.key});
|
|
|
@@ -15,6 +17,26 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
|
|
|
double? _weight;
|
|
|
bool _isReadingWeight = false;
|
|
|
|
|
|
+ // 添加TextController和FocusNode用于重量输入框
|
|
|
+ final TextEditingController _weightController = TextEditingController();
|
|
|
+ final FocusNode _weightFocusNode = FocusNode();
|
|
|
+
|
|
|
+ // 添加Timer用于延迟处理输入
|
|
|
+ Timer? _inputDebounceTimer;
|
|
|
+ // 添加超时Timer
|
|
|
+ Timer? _timeoutTimer;
|
|
|
+
|
|
|
+ @override
|
|
|
+ void dispose() {
|
|
|
+ // 释放TextEditingController和FocusNode
|
|
|
+ _weightController.dispose();
|
|
|
+ _weightFocusNode.dispose();
|
|
|
+ // 取消定时器
|
|
|
+ _inputDebounceTimer?.cancel();
|
|
|
+ _timeoutTimer?.cancel();
|
|
|
+ super.dispose();
|
|
|
+ }
|
|
|
+
|
|
|
@override
|
|
|
Widget build(BuildContext context) {
|
|
|
return Scaffold(
|
|
|
@@ -62,6 +84,7 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
|
|
|
_rfid = rfid;
|
|
|
});
|
|
|
ToastUtil.success('电子编号识别成功');
|
|
|
+ _handleReadWeight();
|
|
|
},
|
|
|
label: '电子编号',
|
|
|
placeholder: '未识别',
|
|
|
@@ -83,24 +106,79 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
|
|
|
child: Row(
|
|
|
children: [
|
|
|
Expanded(
|
|
|
- child: Text(
|
|
|
- _weight != null ? _weight!.toStringAsFixed(2) : '未读取',
|
|
|
+ child: TextField(
|
|
|
+ focusNode: _weightFocusNode,
|
|
|
+ controller: _weightController,
|
|
|
+ enabled: _weight == null,
|
|
|
+ decoration: InputDecoration(
|
|
|
+ border: InputBorder.none,
|
|
|
+ hintText: _weight != null
|
|
|
+ ? null
|
|
|
+ : _isReadingWeight
|
|
|
+ ? "正在读取重量"
|
|
|
+ : '请读取重量',
|
|
|
+ hintStyle: TextStyle(
|
|
|
+ color: _isReadingWeight
|
|
|
+ ? Colors.red
|
|
|
+ : _weight != null
|
|
|
+ ? Colors.black
|
|
|
+ : Colors.grey,
|
|
|
+ fontSize: 16,
|
|
|
+ ),
|
|
|
+ ),
|
|
|
style: TextStyle(
|
|
|
color: _weight != null ? Colors.black : Colors.grey,
|
|
|
fontSize: 16,
|
|
|
),
|
|
|
+ keyboardType: TextInputType.numberWithOptions(decimal: true),
|
|
|
+ onChanged: (text) {
|
|
|
+ // 取消之前的定时器
|
|
|
+ _inputDebounceTimer?.cancel();
|
|
|
+ // 设置新的定时器,延时处理输入
|
|
|
+ _inputDebounceTimer = Timer(
|
|
|
+ const Duration(milliseconds: 500),
|
|
|
+ () {
|
|
|
+ if (text.isEmpty) {
|
|
|
+ setState(() {
|
|
|
+ _weight = null;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ try {
|
|
|
+ final parsedValue = double.tryParse(text);
|
|
|
+ if (parsedValue != null) {
|
|
|
+ setState(() {
|
|
|
+ _weight = parsedValue;
|
|
|
+ });
|
|
|
+ ToastUtil.success('重量读取成功');
|
|
|
+ }
|
|
|
+ _isReadingWeight = false;
|
|
|
+ } catch (e) {
|
|
|
+ // 输入无效时不更新_weight
|
|
|
+ logger.e('解析重量值失败: $e');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ );
|
|
|
+ },
|
|
|
),
|
|
|
),
|
|
|
- IconButton(
|
|
|
- icon: _isReadingWeight
|
|
|
- ? const SizedBox(
|
|
|
- width: 20,
|
|
|
- height: 20,
|
|
|
- child: CircularProgressIndicator(strokeWidth: 2),
|
|
|
- )
|
|
|
- : const Icon(Icons.sync, size: 20),
|
|
|
- onPressed: _simulateReadWeight,
|
|
|
- ),
|
|
|
+ if (_weight != null) ...[
|
|
|
+ IconButton(
|
|
|
+ icon: const Icon(Icons.refresh, size: 20),
|
|
|
+ onPressed: _handleReadWeight,
|
|
|
+ ),
|
|
|
+ ] else ...[
|
|
|
+ IconButton(
|
|
|
+ icon: _isReadingWeight
|
|
|
+ ? const SizedBox(
|
|
|
+ width: 20,
|
|
|
+ height: 20,
|
|
|
+ child: CircularProgressIndicator(strokeWidth: 2),
|
|
|
+ )
|
|
|
+ : const Icon(Icons.sync, size: 20),
|
|
|
+ onPressed: _handleReadWeight,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
],
|
|
|
),
|
|
|
),
|
|
|
@@ -108,24 +186,29 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
|
|
|
);
|
|
|
}
|
|
|
|
|
|
- // 模拟读取重量
|
|
|
- void _simulateReadWeight() {
|
|
|
- if (_isReadingWeight) return;
|
|
|
-
|
|
|
+ void _handleReadWeight() {
|
|
|
setState(() {
|
|
|
+ _weight = null;
|
|
|
+ _weightController.clear();
|
|
|
_isReadingWeight = true;
|
|
|
});
|
|
|
-
|
|
|
- // 模拟读取重量过程
|
|
|
- Future.delayed(const Duration(seconds: 1), () {
|
|
|
+ // 重置后输入框获得焦点
|
|
|
+ WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
|
if (mounted) {
|
|
|
+ _weightFocusNode.requestFocus();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 设置3秒超时
|
|
|
+ _timeoutTimer?.cancel(); // 取消之前的超时定时器
|
|
|
+ _timeoutTimer = Timer(const Duration(seconds: 15), () {
|
|
|
+ if (mounted && _isReadingWeight == true) {
|
|
|
setState(() {
|
|
|
- _weight = double.parse(
|
|
|
- (5.0 + DateTime.now().millisecond % 50 / 10).toStringAsFixed(2),
|
|
|
- );
|
|
|
+ _weight = null;
|
|
|
_isReadingWeight = false;
|
|
|
+ _weightFocusNode.unfocus();
|
|
|
});
|
|
|
- ToastUtil.success('重量读取成功');
|
|
|
+ ToastUtil.error('读取重量超时');
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
@@ -141,6 +224,7 @@ class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
|
|
|
setState(() {
|
|
|
_rfid = null;
|
|
|
_weight = null;
|
|
|
+ _weightController.clear();
|
|
|
});
|
|
|
}
|
|
|
}
|