| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- import 'package:chicken_farm/apis/index.dart';
- 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});
- @override
- State<IndividualWeighingPage> createState() => _IndividualWeighingPageState();
- }
- class _IndividualWeighingPageState extends State<IndividualWeighingPage> {
- String? _rfid;
- 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(
- appBar: const VberAppBar(title: '个体称重', showLeftButton: true),
- body: Padding(
- padding: const EdgeInsets.all(16.0),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- // 电子编号区域
- _buildRfidSection(),
- const SizedBox(height: 20),
- // 重量区域
- _buildWeightSection(),
- const SizedBox(height: 30),
- // 提交按钮
- SizedBox(
- width: double.infinity,
- child: ElevatedButton(
- onPressed: _rfid != null && _weight != null
- ? _handleSubmit
- : null,
- style: ElevatedButton.styleFrom(
- backgroundColor: _rfid != null && _weight != null
- ? Colors.blue
- : Colors.grey,
- foregroundColor: Colors.white,
- ),
- child: const Text('提交'),
- ),
- ),
- ],
- ),
- ),
- );
- }
- Widget _buildRfidSection() {
- return VberRfidField(
- rfid: _rfid,
- onRfidScanned: (rfid) {
- setState(() {
- _rfid = rfid;
- });
- ToastUtil.success('电子编号识别成功');
- _handleReadWeight();
- },
- label: '电子编号',
- placeholder: '未识别',
- );
- }
- Widget _buildWeightSection() {
- return Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- const Text('重量(kg)', style: TextStyle(fontWeight: FontWeight.bold)),
- const SizedBox(height: 10),
- Container(
- padding: const EdgeInsets.fromLTRB(16, 2, 16, 2),
- decoration: BoxDecoration(
- border: Border.all(color: Colors.grey),
- borderRadius: BorderRadius.circular(8),
- ),
- child: Row(
- children: [
- Expanded(
- 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');
- }
- }
- },
- );
- },
- ),
- ),
- 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,
- ),
- ],
- ],
- ),
- ),
- ],
- );
- }
- void _handleReadWeight() {
- setState(() {
- _weight = null;
- _weightController.clear();
- _isReadingWeight = true;
- });
- // 重置后输入框获得焦点
- WidgetsBinding.instance.addPostFrameCallback((_) {
- if (mounted) {
- _weightFocusNode.requestFocus();
- }
- });
- // 设置3秒超时
- _timeoutTimer?.cancel(); // 取消之前的超时定时器
- _timeoutTimer = Timer(const Duration(seconds: 15), () {
- if (mounted && _isReadingWeight == true) {
- setState(() {
- _weight = null;
- _isReadingWeight = false;
- _weightFocusNode.unfocus();
- });
- ToastUtil.error('读取重量超时');
- }
- });
- }
- // 提交数据
- void _handleSubmit() {
- final data = {"rfid": _rfid, "weight": _weight};
- apis.breeding.submitApi
- .weight(data)
- .then((_) {
- if (mounted) {
- ScaffoldMessenger.of(context).showSnackBar(
- const SnackBar(
- content: Text('称重提交成功'),
- backgroundColor: Colors.green,
- ),
- );
- // 提交后重置表单
- setState(() {
- _rfid = null;
- _weight = null;
- _weightController.clear();
- });
- }
- })
- .catchError((err) {
- ToastUtil.error('称重提交失败');
- if (mounted && err != null) {
- String errorMessage = err.toString();
- if (err is Exception) {
- errorMessage = err.toString();
- }
- ScaffoldMessenger.of(context).showSnackBar(
- SnackBar(
- content: Text(errorMessage),
- backgroundColor: Colors.red,
- ),
- );
- }
- });
- }
- }
|