完成页面对接tcp推送的设备状态数据
完成页面测试解析tcp推送的设备状态数据的UI展示
This commit is contained in:
@@ -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)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user