机器状态界面增加定时器
This commit is contained in:
@@ -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');
|
||||
|
||||
@@ -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 ======================
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user