Commit 6d1704c6 authored by akari's avatar akari
parents 47ea47f1 0c5d8ff9
...@@ -10,6 +10,9 @@ class BluetoothReadModel extends Equatable { ...@@ -10,6 +10,9 @@ class BluetoothReadModel extends Equatable {
final int? oxygenConcentration; final int? oxygenConcentration;
final int? co2Measurement; final int? co2Measurement;
final DateTime? updatedAt; final DateTime? updatedAt;
final int? totalTime;
final double? ambientTemperature;
final int? o2SupplyTime;
const BluetoothReadModel({ const BluetoothReadModel({
this.sn, this.sn,
...@@ -18,6 +21,9 @@ class BluetoothReadModel extends Equatable { ...@@ -18,6 +21,9 @@ class BluetoothReadModel extends Equatable {
this.oxygenConcentration, this.oxygenConcentration,
this.co2Measurement, this.co2Measurement,
this.updatedAt, this.updatedAt,
this.totalTime,
this.ambientTemperature,
this.o2SupplyTime,
}); });
factory BluetoothReadModel.fromMcuReport(McuReport report) { factory BluetoothReadModel.fromMcuReport(McuReport report) {
...@@ -30,6 +36,10 @@ class BluetoothReadModel extends Equatable { ...@@ -30,6 +36,10 @@ class BluetoothReadModel extends Equatable {
report.oxygenConcentration < 0 ? null : report.oxygenConcentration, report.oxygenConcentration < 0 ? null : report.oxygenConcentration,
co2Measurement: report.co2Measurement < 0 ? null : report.co2Measurement, co2Measurement: report.co2Measurement < 0 ? null : report.co2Measurement,
updatedAt: DateTime.now(), updatedAt: DateTime.now(),
totalTime: report.totalTime < 0 ? null : report.totalTime,
ambientTemperature:
report.ambientTemperature.isNaN ? null : report.ambientTemperature,
o2SupplyTime: report.o2SupplyTime < 0 ? null : report.o2SupplyTime,
); );
} }
...@@ -42,6 +52,9 @@ class BluetoothReadModel extends Equatable { ...@@ -42,6 +52,9 @@ class BluetoothReadModel extends Equatable {
int? oxygenConcentration, int? oxygenConcentration,
int? co2Measurement, int? co2Measurement,
DateTime? updatedAt, DateTime? updatedAt,
int? totalTime,
double? ambientTemperature,
int? o2SupplyTime,
bool clearSn = false, bool clearSn = false,
}) { }) {
return BluetoothReadModel( return BluetoothReadModel(
...@@ -51,6 +64,9 @@ class BluetoothReadModel extends Equatable { ...@@ -51,6 +64,9 @@ class BluetoothReadModel extends Equatable {
oxygenConcentration: oxygenConcentration ?? this.oxygenConcentration, oxygenConcentration: oxygenConcentration ?? this.oxygenConcentration,
co2Measurement: co2Measurement ?? this.co2Measurement, co2Measurement: co2Measurement ?? this.co2Measurement,
updatedAt: updatedAt ?? this.updatedAt, updatedAt: updatedAt ?? this.updatedAt,
totalTime: totalTime ?? this.totalTime,
ambientTemperature: ambientTemperature ?? this.ambientTemperature,
o2SupplyTime: o2SupplyTime ?? this.o2SupplyTime,
); );
} }
...@@ -62,5 +78,8 @@ class BluetoothReadModel extends Equatable { ...@@ -62,5 +78,8 @@ class BluetoothReadModel extends Equatable {
oxygenConcentration, oxygenConcentration,
co2Measurement, co2Measurement,
updatedAt, updatedAt,
totalTime,
ambientTemperature,
o2SupplyTime,
]; ];
} }
...@@ -6,6 +6,9 @@ class MonitoringMetricBO extends Equatable { ...@@ -6,6 +6,9 @@ class MonitoringMetricBO extends Equatable {
/// 指标数值 /// 指标数值
final String value; final String value;
/// 设定值(温度/湿度/氧气为设定值,CO₂为告警阈值)
final String setValue;
/// 指标单位 /// 指标单位
final String unit; final String unit;
...@@ -22,6 +25,7 @@ class MonitoringMetricBO extends Equatable { ...@@ -22,6 +25,7 @@ class MonitoringMetricBO extends Equatable {
required this.value, required this.value,
required this.unit, required this.unit,
required this.label, required this.label,
this.setValue = '--',
this.borderColorValue = 0xFF999999, this.borderColorValue = 0xFF999999,
this.backgroundColorValue = 0x1A999999, this.backgroundColorValue = 0x1A999999,
}); });
...@@ -29,6 +33,7 @@ class MonitoringMetricBO extends Equatable { ...@@ -29,6 +33,7 @@ class MonitoringMetricBO extends Equatable {
factory MonitoringMetricBO.fromJson(Map<String, dynamic> json) { factory MonitoringMetricBO.fromJson(Map<String, dynamic> json) {
return MonitoringMetricBO( return MonitoringMetricBO(
value: json['value'] as String? ?? '', value: json['value'] as String? ?? '',
setValue: json['setValue'] as String? ?? '--',
unit: json['unit'] as String? ?? '', unit: json['unit'] as String? ?? '',
label: json['label'] as String? ?? '', label: json['label'] as String? ?? '',
borderColorValue: json['borderColorValue'] as int? ?? 0xFF999999, borderColorValue: json['borderColorValue'] as int? ?? 0xFF999999,
...@@ -39,6 +44,7 @@ class MonitoringMetricBO extends Equatable { ...@@ -39,6 +44,7 @@ class MonitoringMetricBO extends Equatable {
@override @override
List<Object?> get props => [ List<Object?> get props => [
value, value,
setValue,
unit, unit,
label, label,
borderColorValue, borderColorValue,
......
...@@ -18,46 +18,67 @@ class MonitoringTopStatusBar extends StatelessWidget { ...@@ -18,46 +18,67 @@ class MonitoringTopStatusBar extends StatelessWidget {
), ),
), ),
padding: EdgeInsets.only(left: 32.w, bottom: 22.h), padding: EdgeInsets.only(left: 32.w, bottom: 22.h),
child: Row( child: BlocBuilder<BluetoothReadBloc, BluetoothReadState>(
children: [ builder: (context, state) {
Text( final info = state.info;
'总运行时长:9999h',
style: TextStyle(
color: Colors.white,
fontSize: 25.sp,
),
),
SizedBox(width: 32.w),
Text(
'环境温度:30.68',
style: TextStyle(
color: Colors.white,
fontSize: 25.sp,
),
),
SizedBox(width: 32.w),
Text(
'总制氧时长:500h',
style: TextStyle(
color: Colors.white,
fontSize: 25.sp,
),
),
SizedBox(width: 32.w), String totalTimeText;
BlocBuilder<BluetoothReadBloc, BluetoothReadState>( if (info.totalTime != null) {
builder: (context, state) { totalTimeText = '${info.totalTime}h';
final sn = state.info.sn; } else {
return Text( totalTimeText = '--';
'sn:${sn ?? ''}', }
String ambientTempText;
if (info.ambientTemperature != null) {
ambientTempText = info.ambientTemperature!.toStringAsFixed(2);
} else {
ambientTempText = '--';
}
String o2SupplyTimeText;
if (info.o2SupplyTime != null) {
o2SupplyTimeText = '${info.o2SupplyTime}h';
} else {
o2SupplyTimeText = '--';
}
return Row(
children: [
Text(
'总运行时长:$totalTimeText',
style: TextStyle(
color: Colors.white,
fontSize: 25.sp,
),
),
SizedBox(width: 32.w),
Text(
'环境温度:$ambientTempText',
style: TextStyle(
color: Colors.white,
fontSize: 25.sp,
),
),
SizedBox(width: 32.w),
Text(
'制氧时长:$o2SupplyTimeText',
style: TextStyle(
color: Colors.white,
fontSize: 25.sp,
),
),
SizedBox(width: 32.w),
Text(
'sn:${info.sn ?? ''}',
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 25.sp, fontSize: 25.sp,
), ),
); ),
}, ],
), );
], },
), ),
); );
} }
......
...@@ -54,9 +54,6 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -54,9 +54,6 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
bool _isMqttConnecting = false; bool _isMqttConnecting = false;
String? _mqttDeviceSn; String? _mqttDeviceSn;
/// 已收到的摄像头告警 eventId 集合,用于去重
final Set<String> _seenAlarmEventIds = {};
/// 记录已请求过舱详情的 SN,避免每个 BLE 数据帧都重复请求接口 /// 记录已请求过舱详情的 SN,避免每个 BLE 数据帧都重复请求接口
String? _lastFetchedCabinSn; String? _lastFetchedCabinSn;
bool _isFetchingCabinDetail = false; bool _isFetchingCabinDetail = false;
...@@ -703,7 +700,6 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -703,7 +700,6 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
latestBluetoothRawHex: '', latestBluetoothRawHex: '',
cameraAlerts: const [], cameraAlerts: const [],
)); ));
_seenAlarmEventIds.clear();
_isManualUnbindingBluetooth = false; _isManualUnbindingBluetooth = false;
} }
...@@ -904,10 +900,6 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -904,10 +900,6 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
final alarm = CameraAlarmBO.fromJson(json); final alarm = CameraAlarmBO.fromJson(json);
// 按 eventId 去重
if (_seenAlarmEventIds.contains(alarm.eventId)) return;
_seenAlarmEventIds.add(alarm.eventId);
final timeStr = _formatTimestamp(alarm.timestamp); final timeStr = _formatTimestamp(alarm.timestamp);
final behaviorTitle = alarm.titleByBehaviorCode; final behaviorTitle = alarm.titleByBehaviorCode;
final petName = alarm.petName; final petName = alarm.petName;
...@@ -923,9 +915,19 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -923,9 +915,19 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
alarmId: alarm.alarmId, alarmId: alarm.alarmId,
); );
emit(state.copyWith( // 按告警标题去重:相同标题 → 原地覆盖;不同标题 → 插入头部
cameraAlerts: [alert, ...state.cameraAlerts], final existingIndex = state.cameraAlerts.indexWhere((a) => a.title == title);
)); if (existingIndex >= 0) {
// 已存在相同标题 → 原地替换
final updatedAlerts = List<AlertInfoBO>.from(state.cameraAlerts);
updatedAlerts[existingIndex] = alert;
emit(state.copyWith(cameraAlerts: updatedAlerts));
} else {
// 不存在 → 插入头部
emit(state.copyWith(
cameraAlerts: [alert, ...state.cameraAlerts],
));
}
} }
/// 处理 MQTT pet/bind 宠物绑定消息 /// 处理 MQTT pet/bind 宠物绑定消息
...@@ -1045,24 +1047,28 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -1045,24 +1047,28 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
'舱内温度', '舱内温度',
_formatReportTemperatureOrKeep(report.mainTemperature, '舱内温度'), _formatReportTemperatureOrKeep(report.mainTemperature, '舱内温度'),
fallbackUnit: '℃', fallbackUnit: '℃',
setValue: _formatSetTemperature(report.temperatureSetting),
baseMetrics: metrics, baseMetrics: metrics,
), ),
'舱内湿度': _replaceMetricValue( '舱内湿度': _replaceMetricValue(
'舱内湿度', '舱内湿度',
_formatReportIntOrKeep(report.humidity, '舱内湿度'), _formatReportIntOrKeep(report.humidity, '舱内湿度'),
fallbackUnit: 'RH', fallbackUnit: 'RH',
setValue: _formatSetInt(report.humiditySetting),
baseMetrics: metrics, baseMetrics: metrics,
), ),
'氧气浓度': _replaceMetricValue( '氧气浓度': _replaceMetricValue(
'氧气浓度', '氧气浓度',
_formatReportIntOrKeep(report.oxygenConcentration, '氧气浓度'), _formatReportIntOrKeep(report.oxygenConcentration, '氧气浓度'),
fallbackUnit: '%', fallbackUnit: '%',
setValue: _formatSetInt(report.oxygenSetting),
baseMetrics: metrics, baseMetrics: metrics,
), ),
'二氧化碳': _replaceMetricValue( '二氧化碳': _replaceMetricValue(
'二氧化碳', '二氧化碳',
_formatReportIntOrKeep(report.co2Measurement, '二氧化碳'), _formatReportIntOrKeep(report.co2Measurement, '二氧化碳'),
fallbackUnit: 'ppm', fallbackUnit: 'ppm',
setValue: _formatSetInt(report.co2Setting),
baseMetrics: metrics, baseMetrics: metrics,
), ),
}; };
...@@ -1134,6 +1140,7 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -1134,6 +1140,7 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
String label, String label,
String value, { String value, {
required String fallbackUnit, required String fallbackUnit,
String? setValue,
List<MonitoringMetricBO>? baseMetrics, List<MonitoringMetricBO>? baseMetrics,
}) { }) {
final metrics = baseMetrics ?? state.metrics; final metrics = baseMetrics ?? state.metrics;
...@@ -1147,12 +1154,14 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -1147,12 +1154,14 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
if (existing == null) { if (existing == null) {
return MonitoringMetricBO( return MonitoringMetricBO(
value: value, value: value,
setValue: setValue ?? '--',
unit: fallbackUnit, unit: fallbackUnit,
label: label, label: label,
); );
} }
return MonitoringMetricBO( return MonitoringMetricBO(
value: value, value: value,
setValue: setValue ?? existing.setValue,
unit: existing.unit.isEmpty ? fallbackUnit : existing.unit, unit: existing.unit.isEmpty ? fallbackUnit : existing.unit,
label: existing.label, label: existing.label,
borderColorValue: existing.borderColorValue, borderColorValue: existing.borderColorValue,
...@@ -1171,6 +1180,16 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -1171,6 +1180,16 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
return _existingMetricValue(label) ?? '--'; return _existingMetricValue(label) ?? '--';
} }
String _formatSetTemperature(double value) {
if (value.isNaN) return '--';
final fixed = value.toStringAsFixed(1);
return fixed.endsWith('.0') ? fixed.substring(0, fixed.length - 2) : fixed;
}
String _formatSetInt(int value) {
return value < 0 ? '--' : '$value';
}
String _formatReportIntOrKeep(int value, String label) { String _formatReportIntOrKeep(int value, String label) {
if (value >= 0) return '$value'; if (value >= 0) return '$value';
return _existingMetricValue(label) ?? '--'; return _existingMetricValue(label) ?? '--';
......
...@@ -148,7 +148,7 @@ class MonitoringMetricCard extends StatelessWidget { ...@@ -148,7 +148,7 @@ class MonitoringMetricCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'设定24${metric.unit}', '设定${metric.setValue}${metric.unit}',
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
fontSize: 24.sp, fontSize: 24.sp,
......
...@@ -173,7 +173,7 @@ class MonitoringPetInfoCard extends StatelessWidget { ...@@ -173,7 +173,7 @@ class MonitoringPetInfoCard extends StatelessWidget {
SizedBox(height: 30.h), SizedBox(height: 30.h),
_buildCareLevelBlock(info), _buildCareLevelBlock(info),
SizedBox(height: 25.h), SizedBox(height: 25.h),
_buildExitButton(), // _buildExitButton(),
], ],
); );
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment