完成页面对接tcp推送的设备状态数据

完成页面测试解析tcp推送的设备状态数据的UI展示
This commit is contained in:
2026-03-03 19:34:17 +08:00
parent 0a3a062c04
commit 34b4c2bcbc
12 changed files with 676 additions and 230 deletions

View File

@@ -9,6 +9,8 @@ import '../../../../core/di/injection.dart';
import '../../../../core/network/net_message_dispatcher.dart';
import '../../../../core/network/protocol_decoder.dart';
import '../../../devices/presentation/bloc/devices_cubit.dart';
import '../../../devices/presentation/bloc/device_status_bloc.dart'; // 👈 新增导入
import '../../../devices/presentation/bloc/device_status_state.dart'; // 👈 新增导入
class RunningStatusPage extends StatefulWidget {
const RunningStatusPage({super.key});
@@ -18,90 +20,18 @@ class RunningStatusPage extends StatefulWidget {
}
class _RunningStatusPageState extends State<RunningStatusPage> {
final _dispatcher = sl<NetMessageDispatcher>();
late StreamSubscription<RawPacket> _sub;
// 实时设备状态数据
String _yaw = '--';
String _satelliteCnt = '--';
String _qual = '--';
String _leftSpeed = '--';
String _rightSpeed = '--';
String _voltage = '--';
// 实时设备状态数据
String _pitch = '--';
String _roll = '--';
String _latitude = '--';
String _longitude = '--';
String _timeStamp = '--';
String _knifeCuttingSpeed = '--';
String _controlMode = '--';
String _workingArea = '--';
String _battery = '--';
String _obstacleFlag = '--';
// 视图切换状态
bool _isCardView = true;
@override
void initState() {
super.initState();
_sub = _dispatcher.onCommand(0x02).listen(_onDeviceData);
}
void _onDeviceData(RawPacket packet) {
try {
final csv = utf8.decode(packet.payload);
final fields = csv.split(',');
// 至少需 16 个字段(索引 10=航向角, 13=卫星数, 14=定位质量)
if (fields.length >= 16) {
setState(() {
_voltage = fields[0]; // 电压
_leftSpeed = fields[1]; // 左轮目标速度
_rightSpeed = fields[2]; // 右轮目标速度
_pitch = fields[11]; // 俯仰角
_roll = fields[12]; // 翻滚角
_latitude = fields[16]; // 纬度
_longitude = fields[17]; // 经度
_timeStamp = '${fields[16]} ${fields[17]}'; // 时间戳(合并字段)
_knifeCuttingSpeed = fields[19]; // 割刀速度
_controlMode = fields[20]; // 控制模式
_workingArea = fields[21]; // 作业面积
_battery = fields[22]; // 电量
_obstacleFlag = fields[23]; // 障碍物标志
_yaw = fields[10]; // 航向角
_satelliteCnt = fields[13]; // 卫星数
_qual = fields[14]; // 定位质量
});
}
} catch (_) {
// 解析失败时忽略,避免崩溃
}
}
@override
void dispose() {
_sub.cancel();
super.dispose();
}
void _refreshDeviceData() {
final deviceState = context.read<DevicesCubit>().state;
final currentDevice = deviceState.selectedDevice;
if (currentDevice != null) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("数据刷新成功!"), duration: Duration(seconds: 1)));
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("暂无设备,无法刷新"), duration: Duration(seconds: 1)));
}
}
@override
Widget build(BuildContext context) {
final deviceState = context.read<DevicesCubit>().state;
final currentDevice = deviceState.selectedDevice;
if (currentDevice == null) {
return const Scaffold(body: Center(child: Text("加载中...")));
return const Scaffold(
body: Center(child: Text("加载中...")),
);
}
return Scaffold(
@@ -125,20 +55,38 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
),
),
// 2. 状态信息行(动态更新)
SliverToBoxAdapter(
child: Container(
color: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("航向角状态: $_yaw°", style: const TextStyle(fontSize: 14)),
Text("定位质量: $_qual", style: const TextStyle(fontSize: 14)),
Text("卫星数: $_satelliteCnt", style: const TextStyle(fontSize: 14)),
],
),
),
// 2. 状态信息行(动态更新)- 使用 BlocBuilder 监听
BlocBuilder<DeviceStatusBloc, DeviceStatusState>(
builder: (context, state) {
String yaw = '--';
String qual = '--';
String satelliteCnt = '--';
if (state is DeviceStatusUpdated) {
yaw = state.status.yaw.toStringAsFixed(2);
qual = state.status.qual.toString();
satelliteCnt = state.status.satelliteCnt.toString();
} else if (state is DeviceStatusError) {
yaw = '错误';
qual = '-';
satelliteCnt = '-';
}
return SliverToBoxAdapter(
child: Container(
color: Colors.white,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("航向角状态:$yaw°", style: const TextStyle(fontSize: 14)),
Text("定位质量:$qual", style: const TextStyle(fontSize: 14)),
Text("卫星数:$satelliteCnt", style: const TextStyle(fontSize: 14)),
],
),
),
);
},
),
// 3. 选项卡 + 刷新按钮
@@ -180,12 +128,19 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
),
),
// 4. 内容区域
// 4. 内容区域 - 使用 BlocBuilder 监听
SliverFillRemaining(
child: Container(
margin: const EdgeInsets.all(16),
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(8)),
child: _isCardView ? _buildCardContentView() : _buildChartContentView(),
child: BlocBuilder<DeviceStatusBloc, DeviceStatusState>(
builder: (context, state) {
return Container(
margin: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: _isCardView ? _buildCardContentView(state) : _buildChartContentView(),
);
},
),
),
],
@@ -207,33 +162,89 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
);
}
Widget _buildCardContentView() {
return SingleChildScrollView(
// 添加 SingleChildScrollView 使内容可滚动
padding: const EdgeInsets.all(20.0),
Widget _buildCardItem(String title, String value) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title, style: const TextStyle(fontSize: 16, color: Color(0xFF333333))),
Text(value, style: const TextStyle(fontSize: 16, color: Color(0xFF666666))),
],
),
);
}
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) {
final status = state.status;
voltage = status.voltage.toStringAsFixed(2);
leftSpeed = status.leftTargetSpeed.toStringAsFixed(2);
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) {
voltage = '错误';
}
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),
_CardItem(title: "电压", value: "$_voltage V"),
_CardItem(title: "左轮速度", value: "$_leftSpeed rpm"),
_CardItem(title: "右轮速度", value: "$_rightSpeed rpm"),
_CardItem(title: "航向角", value: "$_yaw°"),
_CardItem(title: "俯仰角", value: "$_pitch°"),
_CardItem(title: "翻滚角", value: "$_roll°"),
_CardItem(title: "卫星数", value: _satelliteCnt),
_CardItem(title: "定位质量", value: _qual),
_CardItem(title: "纬度", value: _latitude),
_CardItem(title: "经度", value: _longitude),
_CardItem(title: "时间戳", value: _timeStamp),
_CardItem(title: "割刀速度", value: "$_knifeCuttingSpeed rpm"),
_CardItem(title: "控制模式", value: _controlMode),
_CardItem(title: "作业面积", value: "$_workingArea m²"),
_CardItem(title: "电量", value: "$_battery%"),
_CardItem(title: "障碍物标志", value: _obstacleFlag),
_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),
],
),
),
);
}
@@ -249,25 +260,19 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
),
);
}
}
class _CardItem extends StatelessWidget {
final String title;
final String value;
void _refreshDeviceData() {
final deviceState = context.read<DevicesCubit>().state;
final currentDevice = deviceState.selectedDevice;
const _CardItem({required this.title, required this.value});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title, style: const TextStyle(fontSize: 16, color: Color(0xFF333333))),
Text(value, style: const TextStyle(fontSize: 16, color: Color(0xFF666666))),
],
),
);
if (currentDevice != null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("数据刷新成功!"), duration: Duration(seconds: 1)),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("暂无设备,无法刷新"), duration: Duration(seconds: 1)),
);
}
}
}