机器状态 优化

This commit is contained in:
mmc
2026-03-04 10:09:58 +08:00
parent 34b4c2bcbc
commit d44493b256
2 changed files with 143 additions and 105 deletions

View File

@@ -39,7 +39,7 @@ class AuthCubit extends Cubit<AuthState> {
if (user != null) { if (user != null) {
// 1. 建立 TCP 连接 (远程控制) // 1. 建立 TCP 连接 (远程控制)
tcp.connect(host: TCPConsts.TCP_IP, port: TCPConsts.TCP_PORT); tcp.connect(host: TCPConsts.TCP_IP, port: TCPConsts.TCP_PORT);
await _authTcpDatasource.sendAuthPacket();//包括发送认证包和获取列表和切换函数 //await _authTcpDatasource.sendAuthPacket();//包括发送认证包和获取列表和切换函数
// 2. 同步全局 App 状态 // 2. 同步全局 App 状态
appCubit.setAuth(user); appCubit.setAuth(user);
// 3. 进入已登录状态 // 3. 进入已登录状态

View File

@@ -9,8 +9,8 @@ import '../../../../core/di/injection.dart';
import '../../../../core/network/net_message_dispatcher.dart'; import '../../../../core/network/net_message_dispatcher.dart';
import '../../../../core/network/protocol_decoder.dart'; import '../../../../core/network/protocol_decoder.dart';
import '../../../devices/presentation/bloc/devices_cubit.dart'; import '../../../devices/presentation/bloc/devices_cubit.dart';
import '../../../devices/presentation/bloc/device_status_bloc.dart'; // 👈 新增导入 import '../../../devices/presentation/bloc/device_status_bloc.dart';
import '../../../devices/presentation/bloc/device_status_state.dart'; // 👈 新增导入 import '../../../devices/presentation/bloc/device_status_state.dart';
class RunningStatusPage extends StatefulWidget { class RunningStatusPage extends StatefulWidget {
const RunningStatusPage({super.key}); const RunningStatusPage({super.key});
@@ -20,18 +20,33 @@ class RunningStatusPage extends StatefulWidget {
} }
class _RunningStatusPageState extends State<RunningStatusPage> { class _RunningStatusPageState extends State<RunningStatusPage> {
// 视图切换状态
bool _isCardView = true; bool _isCardView = true;
// 解析定位质量数值为文字描述
String _parseLocationQuality(int locationValue) {
switch (locationValue) {
case 0:
return '无效';
case 1:
return 'GPS 单点定位';
case 2:
return 'DGPS 伪距差分或 SBAS';
case 4:
return 'RTK 固定解';
case 5:
return 'RTK 浮点解';
default:
return '未知($locationValue)'; // 处理未定义的数值,避免显示空值
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final deviceState = context.read<DevicesCubit>().state; final deviceState = context.read<DevicesCubit>().state;
final currentDevice = deviceState.selectedDevice; final currentDevice = deviceState.selectedDevice;
if (currentDevice == null) { if (currentDevice == null) {
return const Scaffold( return const Scaffold(body: Center(child: Text("加载中...")));
body: Center(child: Text("加载中...")),
);
} }
return Scaffold( return Scaffold(
@@ -39,7 +54,6 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
body: CustomScrollView( body: CustomScrollView(
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
slivers: [ slivers: [
// 1. 顶部导航栏
SliverAppBar( SliverAppBar(
backgroundColor: const Color(0xFF1677FF), backgroundColor: const Color(0xFF1677FF),
pinned: true, pinned: true,
@@ -55,21 +69,21 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
), ),
), ),
// 2. 状态信息行(动态更新)- 使用 BlocBuilder 监听
BlocBuilder<DeviceStatusBloc, DeviceStatusState>( BlocBuilder<DeviceStatusBloc, DeviceStatusState>(
builder: (context, state) { builder: (context, state) {
String yaw = '--';
String qual = '--'; String qual = '--';
String satelliteCnt = '--'; String satelliteCnt = '--';
String headingStatus = "--";
if (state is DeviceStatusUpdated) { if (state is DeviceStatusUpdated) {
yaw = state.status.yaw.toStringAsFixed(2); headingStatus = state.status.headingStatus == 0 ? '未初始化' : '已初始化';
qual = state.status.qual.toString(); qual = _parseLocationQuality(state.status.qual);
qual = int.parse(state.status.qual.toString());
satelliteCnt = state.status.satelliteCnt.toString(); satelliteCnt = state.status.satelliteCnt.toString();
} else if (state is DeviceStatusError) { } else if (state is DeviceStatusError) {
yaw = '错误';
qual = '-'; qual = '-';
satelliteCnt = '-'; satelliteCnt = '-';
headingStatus = '-';
} }
return SliverToBoxAdapter( return SliverToBoxAdapter(
@@ -79,7 +93,7 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text("航向角状态:$yaw°", style: const TextStyle(fontSize: 14)), Text("航向角状态:$headingStatus", style: const TextStyle(fontSize: 14)),
Text("定位质量:$qual", style: const TextStyle(fontSize: 14)), Text("定位质量:$qual", style: const TextStyle(fontSize: 14)),
Text("卫星数:$satelliteCnt", style: const TextStyle(fontSize: 14)), Text("卫星数:$satelliteCnt", style: const TextStyle(fontSize: 14)),
], ],
@@ -89,7 +103,6 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
}, },
), ),
// 3. 选项卡 + 刷新按钮
SliverToBoxAdapter( SliverToBoxAdapter(
child: Container( child: Container(
color: Colors.white, color: Colors.white,
@@ -98,7 +111,6 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
// 切换选项卡
Row( Row(
children: [ children: [
GestureDetector( GestureDetector(
@@ -112,7 +124,6 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
), ),
], ],
), ),
// 刷新按钮
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF1677FF), backgroundColor: const Color(0xFF1677FF),
@@ -128,16 +139,12 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
), ),
), ),
// 4. 内容区域 - 使用 BlocBuilder 监听
SliverFillRemaining( SliverFillRemaining(
child: BlocBuilder<DeviceStatusBloc, DeviceStatusState>( child: BlocBuilder<DeviceStatusBloc, DeviceStatusState>(
builder: (context, state) { builder: (context, state) {
return Container( return Container(
margin: const EdgeInsets.all(16), margin: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: _isCardView ? _buildCardContentView(state) : _buildChartContentView(), child: _isCardView ? _buildCardContentView(state) : _buildChartContentView(),
); );
}, },
@@ -153,7 +160,7 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
title, title,
style: TextStyle( style: TextStyle(
color: isActive ? const Color(0xFF1677FF) : const Color(0xFF666666), color: isActive ? const Color(0xFF1677FF) : const Color(0xFF666666),
fontSize: 16, fontSize: 18,
fontWeight: isActive ? FontWeight.bold : FontWeight.normal, fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
decoration: isActive ? TextDecoration.underline : null, decoration: isActive ? TextDecoration.underline : null,
decorationColor: const Color(0xFF1677FF), decorationColor: const Color(0xFF1677FF),
@@ -162,90 +169,123 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
); );
} }
Widget _buildCardItem(String title, String value) { // 电机参数表格
return Padding( Widget _buildMotorTable(DeviceStatusUpdated state) {
padding: const EdgeInsets.symmetric(vertical: 10), final status = state.status;
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, return Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Text(title, style: const TextStyle(fontSize: 16, color: Color(0xFF333333))), children: [
Text(value, style: const TextStyle(fontSize: 16, color: Color(0xFF666666))), const Padding(
], padding: EdgeInsets.symmetric(vertical: 12),
child: Text("电机参数", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
),
Table(
border: TableBorder.all(color: const Color(0xFFE5E5E5)),
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [
TableRow(
decoration: const BoxDecoration(color: Color(0xFFF5F5F5)),
children: [const SizedBox(), _buildTableCell("左轮", isHeader: true), _buildTableCell("右轮", isHeader: true)],
),
TableRow(
children: [
_buildTableCell("目标速度\n(rpm)"),
_buildTableCell(status.leftTargetSpeed.toStringAsFixed(2)),
_buildTableCell(status.rightTargetSpeed.toStringAsFixed(2)),
],
),
TableRow(
children: [
_buildTableCell("测量速度\n(rpm)"),
_buildTableCell(status.leftTargetSpeed.toStringAsFixed(2)),
_buildTableCell(status.rightTargetSpeed.toStringAsFixed(2)),
//_buildTableCell(status.leftMeasuredSpeed.toStringAsFixed(2)),
//_buildTableCell(status.rightMeasuredSpeed.toStringAsFixed(2)),
],
),
TableRow(
children: [
_buildTableCell("电流(A)"),
_buildTableCell(status.leftCurrent.toStringAsFixed(2)),
_buildTableCell(status.rightCurrent.toStringAsFixed(2)),
],
),
TableRow(
children: [
_buildTableCell("电机温度(°C)"),
_buildTableCell(status.leftMotorTemp.toStringAsFixed(2)),
_buildTableCell(status.rightMotorTemp.toStringAsFixed(2)),
],
),
],
),
],
);
}
// 其他参数表格
Widget _buildOtherParamsTable(DeviceStatusUpdated state) {
final status = state.status;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.symmetric(vertical: 12),
child: Text("其他参数", style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
),
Table(
border: TableBorder.all(color: const Color(0xFFE5E5E5)),
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [
TableRow(
decoration: const BoxDecoration(color: Color(0xFFF5F5F5)),
children: [_buildTableCell("名称", isHeader: true), _buildTableCell("数值", isHeader: true)],
),
TableRow(children: [_buildTableCell("俯仰角(°)"), _buildTableCell(status.pitch.toStringAsFixed(2))]),
TableRow(children: [_buildTableCell("翻滚角(°)"), _buildTableCell(status.roll.toStringAsFixed(2))]),
TableRow(children: [_buildTableCell("航向角(°)"), _buildTableCell(status.yaw.toStringAsFixed(2))]),
TableRow(children: [_buildTableCell("电量(%)"), _buildTableCell(status.battery)]),
TableRow(children: [_buildTableCell("芯片温度(°C)"), _buildTableCell(status.chipTemp.toStringAsFixed(2))]),
TableRow(children: [_buildTableCell("割刀速度(rpm)"), _buildTableCell(status.knifeCuttingSpeed)]),
TableRow(children: [_buildTableCell("纬度(°)"), _buildTableCell(status.latitude.toStringAsFixed(6))]),
],
),
],
);
}
Widget _buildTableCell(String text, {bool isHeader = false}) {
return TableCell(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
child: Text(
text,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16,
color: isHeader ? const Color(0xFF333333) : const Color(0xFF666666),
fontWeight: isHeader ? FontWeight.bold : FontWeight.normal,
),
),
), ),
); );
} }
Widget _buildCardContentView(DeviceStatusState state) { Widget _buildCardContentView(DeviceStatusState state) {
// 从 Bloc 状态中提取数据
String voltage = '--';
String leftSpeed = '--';
String rightSpeed = '--';
String yaw = '--';
String pitch = '--';
String roll = '--';
String satelliteCnt = '--';
String qual = '--';
String latitude = '--';
String longitude = '--';
String timeStamp = '--';
String knifeCuttingSpeed = '--';
String controlMode = '--';
String workingArea = '--';
String battery = '--';
String obstacleFlag = '--';
if (state is DeviceStatusUpdated) { if (state is DeviceStatusUpdated) {
final status = state.status; return SingleChildScrollView(
voltage = status.voltage.toStringAsFixed(2); padding: const EdgeInsets.all(16),
leftSpeed = status.leftTargetSpeed.toStringAsFixed(2); child: Column(children: [_buildMotorTable(state), const SizedBox(height: 20), _buildOtherParamsTable(state)]),
rightSpeed = status.rightTargetSpeed.toStringAsFixed(2); );
yaw = status.yaw.toStringAsFixed(2);
pitch = status.pitch.toStringAsFixed(2);
roll = status.roll.toStringAsFixed(2);
satelliteCnt = status.satelliteCnt.toString();
qual = status.qual.toString();
latitude = status.latitude.toStringAsFixed(8);
longitude = status.longitude.toStringAsFixed(8);
timeStamp = '${status.latitude} ${status.longitude}';
knifeCuttingSpeed = status.knifeCuttingSpeed;
controlMode = status.controlMode;
workingArea = status.workingArea;
battery = status.battery;
obstacleFlag = status.obstacleFlag;
} else if (state is DeviceStatusError) { } else if (state is DeviceStatusError) {
voltage = '错误'; return const Center(
child: Text("数据加载失败", style: TextStyle(color: Colors.red, fontSize: 16)),
);
} else {
return const Center(child: CircularProgressIndicator());
} }
return Padding(
padding: const EdgeInsets.all(20.0),child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("设备实时状态", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
const SizedBox(height: 16),
_buildCardItem("电压", "$voltage V"),
_buildCardItem("左轮速度", "$leftSpeed rpm"),
_buildCardItem( "右轮速度", "$rightSpeed rpm"),
_buildCardItem( "航向角", "$yaw°"),
_buildCardItem( "俯仰角", "$pitch°"),
_buildCardItem( "翻滚角", "$roll°"),
_buildCardItem( "卫星数", satelliteCnt),
_buildCardItem( "定位质量", qual),
_buildCardItem( "纬度", latitude),
_buildCardItem( "经度", longitude),
/* //_buildCardItem( "时间戳", timeStamp),*/
_buildCardItem( "割刀速度", "$knifeCuttingSpeed rpm"),
_buildCardItem( "控制模式", controlMode),
_buildCardItem( "作业面积", "$workingArea m²"),
_buildCardItem( "电量", "$battery%"),
_buildCardItem( "障碍物标志", obstacleFlag),
],
),
),
);
} }
Widget _buildChartContentView() { Widget _buildChartContentView() {
@@ -266,13 +306,11 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
final currentDevice = deviceState.selectedDevice; final currentDevice = deviceState.selectedDevice;
if (currentDevice != null) { if (currentDevice != null) {
ScaffoldMessenger.of(context).showSnackBar( // 这里可以触发 Bloc 事件来刷新数据
const SnackBar(content: Text("数据刷新成功!"), duration: Duration(seconds: 1)), // context.read<DeviceStatusBloc>().add(RefreshDeviceStatus(deviceId: currentDevice.id));
); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("数据刷新成功!"), duration: Duration(seconds: 1)));
} else { } else {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("暂无设备,无法刷新"), duration: Duration(seconds: 1)));
const SnackBar(content: Text("暂无设备,无法刷新"), duration: Duration(seconds: 1)),
);
} }
} }
} }