优化和路径规划新适配

This commit is contained in:
2026-07-11 16:46:53 +08:00
parent 2124f3bc02
commit 1a4d0aedfd
43 changed files with 2454 additions and 685 deletions

View File

@@ -70,7 +70,10 @@ class _DroneOsdCardState extends State<DroneOsdCard> {
_subscription = _dataSource.droneOsdStream.listen((osd) {
if (!mounted) return;
debugPrint('📥 [DroneOsdCard] 收到无人机 OSD 数据');
// 🔥 打印完整的 MQTT 原始数据(不做任何解析)
debugPrint('\n========== 📥 [无人机OSD] 完整原始数据 ==========');
debugPrint('${osd.rawData}');
debugPrint('===========================================\n');
setState(() {
_currentOsd = osd;
@@ -115,7 +118,9 @@ class _DroneOsdCardState extends State<DroneOsdCard> {
return;
}
debugPrint('📊 [DroneOsdCard] 数据键: ${droneData.keys.toList()}');
// 🔥 打印完整原始数据(用于调试)
debugPrint('📊 [DroneOsdCard] drone/host 数据键: ${droneData.keys.toList()}');
debugPrint('📊 [DroneOsdCard] 完整原始数据: $droneData');
// ========== 1. 基础飞行信息 ==========
// 无人机高度(height / altitude)
@@ -321,28 +326,28 @@ class _DroneOsdCardState extends State<DroneOsdCard> {
? const Color(0xFF00B42A)
: const Color(0xFFFF7D00),
},
{
'icon': Icons.signal_cellular_alt,
'label': '遥控信号',
'key': 'rcSignal',
'newValue': rcSignal != null ? '$rcSignal%' : null,
'color': rcSignal != null && rcSignal > 80
? const Color(0xFF00B42A)
: rcSignal != null && rcSignal > 50
? const Color(0xFFFF7D00)
: const Color(0xFFF53F3F),
},
{
'icon': Icons.video_label,
'label': '图传信号',
'key': 'videoSignal',
'newValue': videoSignal != null ? '$videoSignal%' : null,
'color': videoSignal != null && videoSignal > 80
? const Color(0xFF00B42A)
: videoSignal != null && videoSignal > 50
? const Color(0xFFFF7D00)
: const Color(0xFFF53F3F),
},
// {
// 'icon': Icons.signal_cellular_alt,
// 'label': '遥控信号',
// 'key': 'rcSignal',
// 'newValue': rcSignal != null ? '$rcSignal%' : null,
// 'color': rcSignal != null && rcSignal > 80
// ? const Color(0xFF00B42A)
// : rcSignal != null && rcSignal > 50
// ? const Color(0xFFFF7D00)
// : const Color(0xFFF53F3F),
// },
// {
// 'icon': Icons.video_label,
// 'label': '图传信号',
// 'key': 'videoSignal',
// 'newValue': videoSignal != null ? '$videoSignal%' : null,
// 'color': videoSignal != null && videoSignal > 80
// ? const Color(0xFF00B42A)
// : videoSignal != null && videoSignal > 50
// ? const Color(0xFFFF7D00)
// : const Color(0xFFF53F3F),
// },
{
'icon': Icons.flight,
'label': '飞行模式',
@@ -350,22 +355,22 @@ class _DroneOsdCardState extends State<DroneOsdCard> {
'newValue': flightMode,
'color': const Color(0xFF165DFF),
},
{
'icon': Icons.radio_button_checked,
'label': '任务进度',
'key': 'mission',
'newValue': missionProgress != null ? '$missionProgress%' : null,
'color': const Color(0xFF00B42A),
},
{
'icon': Icons.map,
'label': '航点',
'key': 'waypoint',
'newValue': (currentWaypoint != null && waypointCount != null)
? '$currentWaypoint/$waypointCount'
: null,
'color': const Color(0xFF722ED1),
},
// {
// 'icon': Icons.radio_button_checked,
// 'label': '任务进度',
// 'key': 'mission',
// 'newValue': missionProgress != null ? '$missionProgress%' : null,
// 'color': const Color(0xFF00B42A),
// },
// {
// 'icon': Icons.map,
// 'label': '航点',
// 'key': 'waypoint',
// 'newValue': (currentWaypoint != null && waypointCount != null)
// ? '$currentWaypoint/$waypointCount'
// : null,
// 'color': const Color(0xFF722ED1),
// },
];
// 应用缓存逻辑:有新值则更新缓存,否则使用旧值

View File

@@ -135,10 +135,9 @@ class DroneStationItemCard extends StatelessWidget {
// ],
],
),
//
// const SizedBox(height: 12),
//
// // 电量卡片
const SizedBox(height: 12),
// 🔥 电量状态 - 已隐藏
// _buildInfoCard(
// title: '电量状态',
// icon: Icons.battery_full_rounded,
@@ -146,10 +145,10 @@ class DroneStationItemCard extends StatelessWidget {
// value: station.capacityPercent != null ? '${station.capacityPercent}%' : '未知',
// progressValue: station.capacityPercent,
// ),
//
// const SizedBox(height: 12),
//
// // 环境信息卡片
// 🔥 环境监测 - 已隐藏
// _buildSectionCard(
// title: '环境监测',
// icon: Icons.thermostat_rounded,

View File

@@ -66,7 +66,10 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
_subscription = _dataSource.stationOsdStream.listen((osd) {
if (!mounted) return;
//debugPrint('📥 [DroneStationOsdCard] 收到机场 OSD 原始数据');
// 🔥 打印完整的 MQTT 原始数据(不做任何解析)
debugPrint('\n========== 📥 [机场OSD] 完整原始数据 ==========');
debugPrint('${osd.rawData}');
debugPrint('===========================================\n');
setState(() {
_currentOsd = osd;
@@ -95,8 +98,11 @@ class _DroneStationOsdCardState extends State<DroneStationOsdCard> {
return;
}
// debugPrint('📊 [DroneStationOsdCard] 开始解析 OSD 数据...');
//debugPrint('📊 [DroneStationOsdCard] host 数据键: ${hostData.keys.toList()}');
// 🔥 打印完整的 host 数据键,查看所有可用字段
debugPrint('📊 [DroneStationOsdCard] host 数据键: ${hostData.keys.toList()}');
// 🔥 打印完整原始数据(用于调试)
debugPrint('📊 [DroneStationOsdCard] 完整原始数据: $hostData');
// ========== 1. 电池相关 ==========
// 提取无人机电量(从 drone_battery_maintenance_info.batteries[0].capacity_percent)

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:maibu_satabot_v2/core/app/app_user_cubit.dart';
import 'package:maibu_satabot_v2/core/app/app_user_state.dart'; // 🔥 导入 AppUserState
import 'package:maibu_satabot_v2/core/consts/tcp_consts.dart';
import 'package:maibu_satabot_v2/features/remote_control/presentation/widgets/webrtc/webrtc_local_player.dart';
@@ -15,7 +16,6 @@ class RobotHeaderCard extends StatefulWidget {
}
class _RobotHeaderCardState extends State<RobotHeaderCard> {
String _videoStreamUrl = '';
int _currentViewIndex = 0; // 0=前, 1=后, 2=左, 3=右, 4=上
// 视角配置
@@ -30,30 +30,7 @@ class _RobotHeaderCardState extends State<RobotHeaderCard> {
@override
void initState() {
super.initState();
_initVideoUrl();
}
/// 初始化视频流 URL
void _initVideoUrl() {
final userState = context.read<AppUserCubit>().state;
final deviceId = widget.robot['id'] as String?;
debugPrint(' [RobotHeaderCard] 开始初始化视频URL');
debugPrint('🎬 [RobotHeaderCard] deviceId: $deviceId');
debugPrint('🎬 [RobotHeaderCard] user: ${userState.user}');
debugPrint('🎬 [RobotHeaderCard] token: ${userState.user?.token}');
if (deviceId != null && deviceId.isNotEmpty && userState.user != null && userState.user!.token != null) {
setState(() {
_videoStreamUrl = "webrtc://${TCPConsts.TCP_IP}/live/livestream/$deviceId?token=${userState.user!.token}";
});
debugPrint('✅ [RobotHeaderCard] 视频URL初始化成功: $_videoStreamUrl');
} else {
debugPrint('❌ [RobotHeaderCard] 视频URL初始化失败');
debugPrint(' - deviceId.isEmpty: ${deviceId == null || deviceId.isEmpty}');
debugPrint(' - user == null: ${userState.user == null}');
debugPrint(' - token == null: ${userState.user?.token == null}');
}
debugPrint('🎬 [RobotHeaderCard] 初始化 - robot: ${widget.robot}');
}
@override
@@ -147,26 +124,59 @@ class _RobotHeaderCardState extends State<RobotHeaderCard> {
aspectRatio: 16 / 9,
child: Container(
color: Colors.black, // 🔥 强制整个视频区域为黑色背景
child: _videoStreamUrl.isNotEmpty
? WebRTCLocalPlayer(
streamUrl: _videoStreamUrl,
showLeftPip: false, // 不显示悬浮小窗
showRightPip: false,
isFrontMain: _currentViewIndex == 0, // 根据当前视角决定主画面
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.videocam_off, size: 48, color: Colors.white54),
const SizedBox(height: 12),
Text(
'无视频信号',
style: TextStyle(color: Colors.white70, fontSize: 14, fontWeight: FontWeight.w500),
child: BlocBuilder<AppUserCubit, AppUserState>(
builder: (context, userState) {
final deviceId = widget.robot['name'] as String?; // 🔥 使用 name 字段(长序列号)
String videoStreamUrl = '';
debugPrint('🎬 [RobotHeaderCard] BlocBuilder 重建');
debugPrint(' - deviceId (name): $deviceId');
debugPrint(' - user != null: ${userState.user != null}');
debugPrint(' - token != null: ${userState.user?.token != null}');
debugPrint(' - TCP_IP: ${TCPConsts.TCP_IP}');
if (deviceId != null &&
deviceId.isNotEmpty &&
userState.user != null &&
userState.user!.token != null) {
videoStreamUrl = "webrtc://${TCPConsts.TCP_IP}/live/livestream/$deviceId?token=${userState.user!.token}";
debugPrint('✅ [RobotHeaderCard] 视频URL构建成功: $videoStreamUrl');
} else {
debugPrint('❌ [RobotHeaderCard] 视频URL构建失败');
if (deviceId == null || deviceId.isEmpty) {
debugPrint(' - 原因: deviceId 为空');
}
if (userState.user == null) {
debugPrint(' - 原因: user 为 null');
}
if (userState.user?.token == null) {
debugPrint(' - 原因: token 为 null');
}
}
return videoStreamUrl.isNotEmpty
? WebRTCLocalPlayer(
key: ValueKey(videoStreamUrl),
streamUrl: videoStreamUrl,
showLeftPip: false,
showRightPip: false,
mainViewAlignment: _viewConfigs[_currentViewIndex]['alignment'] as Alignment,
)
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.videocam_off, size: 48, color: Colors.white54),
const SizedBox(height: 12),
Text(
'暂无视频',
style: TextStyle(color: Colors.white70, fontSize: 14, fontWeight: FontWeight.w500),
),
],
),
],
),
),
);
},
),
),
),
@@ -224,3 +234,5 @@ class _RobotHeaderCardState extends State<RobotHeaderCard> {
);
}
}

View File

@@ -73,7 +73,7 @@ class RobotItemCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
name,
alias != null && alias!.isNotEmpty ? alias! : '暂无别名',
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
@@ -84,13 +84,13 @@ class RobotItemCard extends StatelessWidget {
),
const SizedBox(height: 4),
Text(
alias != null && alias!.isNotEmpty
? '别名: $alias'
: 'ID: $id',
name, // 🔥 显示完整的长序列号 (deviceName)
style: const TextStyle(
fontSize: 12,
fontSize: 11,
color: Color(0xFF86909C),
),
maxLines: 2,
softWrap: true,
),
],
),