机器状态界面增加定时器

This commit is contained in:
mmc
2026-03-07 20:03:33 +08:00
parent 7705361098
commit 04e54871c9
3 changed files with 140 additions and 24 deletions

View File

@@ -22,7 +22,6 @@ class PathHttpDatasourceImpl implements PathHttpDatasource {
// 2. 格式化打印JSON(带缩进,清晰展示嵌套结构)
final jsonString = const JsonEncoder.withIndent(' ').convert(body);
print('完整JSON请求体:\n$jsonString');
final _jsonString = jsonEncode(body);
print('完整JSON请求体:\n$jsonString');

View File

@@ -18,6 +18,9 @@ import '../../../devices/presentation/bloc/devices_cubit.dart';
import '../../../devices/presentation/bloc/device_status_bloc.dart';
import '../../../devices/presentation/bloc/device_status_state.dart';
// 配置:数据超时时间(5秒)
const int DATA_TIMEOUT_SECONDS = 5;
class RunningStatusPage extends StatefulWidget {
const RunningStatusPage({super.key});
@@ -48,6 +51,41 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
double _timeIndex = 0;
// 新增:超时检测相关变量
Timer? _dataTimeoutTimer;
bool _isDataTimeout = false; // 标记是否数据超时
@override
void initState() {
super.initState();
// 初始化超时计时器
_startDataTimeoutTimer();
}
@override
void dispose() {
// 销毁计时器,防止内存泄漏
_dataTimeoutTimer?.cancel();
super.dispose();
}
// 启动/重置数据超时计时器
void _startDataTimeoutTimer() {
// 先取消现有计时器
_dataTimeoutTimer?.cancel();
// 启动新计时器:超过指定时间未收到数据则标记为超时
_dataTimeoutTimer = Timer(Duration(seconds: DATA_TIMEOUT_SECONDS), () {
if (mounted) {
setState(() {
_isDataTimeout = true;
// 超时后清空历史图表数据(可选)
_resetChartData();
});
}
});
}
// 核心修复:数据点X轴坐标强制映射为0-5(对应6个标签),保证一一对应
List<FlSpot> _getMappedSpots(List<FlSpot> data) {
final List<FlSpot> mapped = [];
@@ -74,6 +112,11 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
if (currentDevice != null) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("数据刷新成功!"), duration: Duration(seconds: 1)));
// 刷新后重置超时状态
if (_isDataTimeout) {
setState(() => _isDataTimeout = false);
}
_startDataTimeoutTimer();
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("暂无设备,无法刷新"), duration: Duration(seconds: 1)));
}
@@ -375,6 +418,11 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
// ====================== 图表视图 ======================
Widget _buildChartContentView(DeviceStatusState state) {
// 新增:如果数据超时,直接显示loading
if (_isDataTimeout) {
return const Center(child: CircularProgressIndicator(color: Color(0xFF1677FF), strokeWidth: 4));
}
if (state is! DeviceStatusUpdated) {
return const Center(
child: CircularProgressIndicator(
@@ -602,6 +650,11 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
// ====================== 卡片视图 ======================
Widget _buildCardContentView(DeviceStatusState state) {
// 新增:如果数据超时,直接显示loading
if (_isDataTimeout) {
return const Center(child: CircularProgressIndicator(color: Color(0xFF1677FF), strokeWidth: 4));
}
if (state is DeviceStatusUpdated) {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
@@ -766,11 +819,12 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
BlocBuilder<DeviceStatusBloc, DeviceStatusState>(
builder: (context, state) {
String qual = '--';
String satelliteCnt = '--';
String headingStatus = "--";
// 新增:超时状态下显示--
String qual = _isDataTimeout ? '--' : '--';
String satelliteCnt = _isDataTimeout ? '--' : '--';
String headingStatus = _isDataTimeout ? "--" : "--";
if (state is DeviceStatusUpdated) {
if (!_isDataTimeout && state is DeviceStatusUpdated) {
headingStatus = state.status.headingStatus == 0 ? '未初始化' : '已初始化';
int qualValue = 0;
try {
@@ -780,7 +834,13 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
}
qual = LocationUtils.parseLocationQuality(qualValue);
satelliteCnt = state.status.satelliteCnt.toString();
} else if (state is DeviceStatusError) {
// 收到新数据,重置超时计时器和状态
_startDataTimeoutTimer();
if (_isDataTimeout) {
setState(() => _isDataTimeout = false);
}
} else if (!_isDataTimeout && state is DeviceStatusError) {
qual = '-';
satelliteCnt = '-';
headingStatus = '-';
@@ -873,7 +933,7 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
});
}
if (state is DeviceStatusUpdated) {
if (!_isDataTimeout && state is DeviceStatusUpdated) {
debugPrint('📈 [UI] 检测到 Updated 状态,准备追加图表数据');
_appendChartData(state);
}
@@ -886,7 +946,21 @@ class _RunningStatusPageState extends State<RunningStatusPage> {
);
}
void _resetChartData() {}
// 新增:清空图表历史数据
void _resetChartData() {
_leftMeasureHistory.clear();
_rightMeasureHistory.clear();
_leftTargetHistory.clear();
_rightTargetHistory.clear();
_leftCurrentHistory.clear();
_rightCurrentHistory.clear();
_leftTempHistory.clear();
_rightTempHistory.clear();
_knifeHistory.clear();
_chipTempHistory.clear();
_voltageHistory.clear();
_timeIndex = 0;
}
}
// ====================== 带动画的圆形仪表盘 Widget ======================

View File

@@ -70,7 +70,6 @@ class MapPageEnterprise extends StatefulWidget {
class _MapPageEnterpriseState extends State<MapPageEnterprise> {
final _dispatcher = sl<NetMessageDispatcher>();
late StreamSubscription<RawPacket> _sub;
bool _isRefreshing = false; // 新增:页面刷新状态标志
bool _isVideoDialogOpen = false; // 控制视频弹窗显示
String _videoStreamUrl = "";
@@ -180,14 +179,21 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
// 计算边界
final bounds = calculateBounds(points);
if (bounds == null) return;
final currentZoom = _mapController.camera?.zoom ?? 18.0;
// 移动地图到边界中心(自动适配缩放级别)
_mapController.fitBounds(
bounds,
options: FitBoundsOptions(
padding: const EdgeInsets.all(50), // 边缘留白(避免内容贴边)
//maxZoom: 18, // 最大缩放级别(防止过度放大)
),
//_mapController.fitBounds(
// bounds,
// options: FitBoundsOptions(
// padding: const EdgeInsets.all(50), // 边缘留白(避免内容贴边)
// //maxZoom: 18, // 最大缩放级别(防止过度放大)
// ),
//);
_mapController.move(
bounds.center, // 边界中心点
currentZoom, // 保留当前缩放比例
);
print('地图已移动到绘制内容中心,边界范围:$bounds');
@@ -204,6 +210,17 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
return null;
}
bool __isValidLatLng(LatLng? latLng) {
if (latLng == null) return false;
// 排除赤道0,0坐标,同时校验经纬度范围(避免非法值)
return latLng.latitude != 0.0 &&
latLng.longitude != 0.0 &&
latLng.latitude >= -90 &&
latLng.latitude <= 90 &&
latLng.longitude >= -180 &&
latLng.longitude <= 180;
}
bool _isValidLatLng(double lat, double lng) {
return lat != 0 && lng != 0 && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180;
}
@@ -820,7 +837,6 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
_positionSub?.cancel();
_traceManager.reset();
_mapController.dispose();
_sub.cancel();
super.dispose();
}
@@ -1160,20 +1176,20 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
}
final gcjPoint = wgs84ToGcj02(lat, lng);
// 关键:判断Widget是否还挂载,避免空指针
final initCenter = bd09ToGcj02(
'120.81992468426961', // 经度
'32.04532826114155',
);
_currentLatLng = gcjPoint; // ✅ 状态变量在setState内更新
return FlutterMap(
mapController: _mapController,
options: MapOptions(
initialCenter: _currentLatLng ?? const LatLng(39.9042, 116.4074),
initialCenter: __isValidLatLng(_currentLatLng) ? _currentLatLng! : initCenter,
initialZoom: 18,
// 1. 调整最大缩放级别(匹配高德实际支持的上限)
maxZoom: 18,
// 2. 增加最小缩放级别(可选,提升体验)
minZoom: 3,
// 3. 启用连续缩放(支持滚轮精细缩放)
enableScrollWheel: true,
// 禁止地图点击事件(避免和中心标冲突)
onTap: (_, __) {}, // 空实现,禁用地图点击响应
),
children: [
@@ -1283,10 +1299,10 @@ class _MapPageEnterpriseState extends State<MapPageEnterprise> {
);
}).toList(),
),
if (gctracePoint!.isNotEmpty)
//开始作业之后
if (gctracePoint!.isNotEmpty && isStartWork)
PolylineLayer(
polylines: [
// 已绘制的障碍物点连线
for (int i = 0; i < gctracePoint!.length - 1; i++)
Polyline(
points: [gctracePoint![i], gctracePoint![i + 1]],
@@ -2309,6 +2325,33 @@ List<LatLng> batchWgs84ToGcj02(List<LatLng> wgs84Points) {
}).toList();
}
LatLng bd09ToGcj02(dynamic bdLng, dynamic bdLat) {
// 1. 先将字符串转为double(兼容你的初始值格式)
double lng = _safeToDouble(bdLng);
double lat = _safeToDouble(bdLat);
// 2. BD09转GCJ02核心公式
double x = lng - 0.0065;
double y = lat - 0.006;
double z = math.sqrt(x * x + y * y) - 0.00002 * math.sin(y * _pi);
double theta = math.atan2(y, x) - 0.000003 * math.cos(x * _pi);
double gcjLng = z * math.cos(theta);
double gcjLat = z * math.sin(theta);
return LatLng(gcjLat, gcjLng);
}
double _safeToDouble(dynamic value) {
if (value == null) return 0.0;
if (value is double) return value;
if (value is int) return value.toDouble();
if (value is String) {
// 字符串转数字,失败返回0.0
return double.tryParse(value) ?? 0.0;
}
return 0.0;
}
LatLng gcj02ToWgs84(double lat, double lon) {
if (_outOfChina(lat, lon)) {
return LatLng(lat, lon);