机器状态 优化
This commit is contained in:
@@ -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. 进入已登录状态
|
||||||
|
|||||||
@@ -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)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user