Commit 5dc83081 authored by akari's avatar akari

fix: 修复部分蓝牙逻辑

parent 6d1704c6
...@@ -15,6 +15,8 @@ import 'package:laki_icu_app/utils/logger.dart'; ...@@ -15,6 +15,8 @@ import 'package:laki_icu_app/utils/logger.dart';
import 'package:laki_icu_app/utils/mqtt/index.dart'; import 'package:laki_icu_app/utils/mqtt/index.dart';
import 'package:laki_icu_app/utils/storage/storage_service.dart'; import 'package:laki_icu_app/utils/storage/storage_service.dart';
enum _LightTarget { check, illumination, blue, red }
/// 用途:设备控制Bloc /// 用途:设备控制Bloc
/// 涉及页面:设备控制页面 /// 涉及页面:设备控制页面
/// 说明:提供各个子模块的获取和设置方法,方便MCU单元调用 /// 说明:提供各个子模块的获取和设置方法,方便MCU单元调用
...@@ -228,24 +230,30 @@ class DeviceControlBloc ...@@ -228,24 +230,30 @@ class DeviceControlBloc
sn: report.sn.isEmpty ? state.data.sn : report.sn, sn: report.sn.isEmpty ? state.data.sn : report.sn,
cabinTemp: state.data.cabinTemp.copyWith( cabinTemp: state.data.cabinTemp.copyWith(
currentValue: _formatTemperature(report.mainTemperature), currentValue: _formatTemperature(report.mainTemperature),
setValue: _formatTemperatureOrKeep( setValue: state.data.cabinTemp.isOn
report.temperatureSetting, ? _formatTemperatureOrKeep(
state.data.cabinTemp.setValue, report.temperatureSetting,
), state.data.cabinTemp.setValue,
)
: _preservedCabinTempSetValue,
), ),
cabinHumidity: state.data.cabinHumidity.copyWith( cabinHumidity: state.data.cabinHumidity.copyWith(
currentValue: _formatInt(report.humidity), currentValue: _formatInt(report.humidity),
setValue: _formatIntOrKeep( setValue: state.data.cabinHumidity.isOn
report.humiditySetting, ? _formatIntOrKeep(
state.data.cabinHumidity.setValue, report.humiditySetting,
), state.data.cabinHumidity.setValue,
)
: _preservedCabinHumiditySetValue,
), ),
oxygenConcentration: state.data.oxygenConcentration.copyWith( oxygenConcentration: state.data.oxygenConcentration.copyWith(
currentValue: _formatInt(report.oxygenConcentration), currentValue: _formatInt(report.oxygenConcentration),
setValue: _formatIntOrKeep( setValue: state.data.oxygenConcentration.isOn
report.oxygenSetting, ? _formatIntOrKeep(
state.data.oxygenConcentration.setValue, report.oxygenSetting,
), state.data.oxygenConcentration.setValue,
)
: _preservedOxygenConcentrationSetValue,
), ),
co2Concentration: state.data.co2Concentration.copyWith( co2Concentration: state.data.co2Concentration.copyWith(
currentValue: _formatInt(report.co2Measurement), currentValue: _formatInt(report.co2Measurement),
...@@ -302,8 +310,12 @@ class DeviceControlBloc ...@@ -302,8 +310,12 @@ class DeviceControlBloc
final humiLower = humidity != null && humidity < config.humidityMin; final humiLower = humidity != null && humidity < config.humidityMin;
final oxyUpper = oxygen != null && oxygen > config.oxygenMax; final oxyUpper = oxygen != null && oxygen > config.oxygenMax;
final oxyLower = oxygen != null && oxygen < config.oxygenMin; final oxyLower = oxygen != null && oxygen < config.oxygenMin;
final hasAnyAlarm = final hasAnyAlarm = tempUpper ||
tempUpper || tempLower || humiUpper || humiLower || oxyUpper || oxyLower; tempLower ||
humiUpper ||
humiLower ||
oxyUpper ||
oxyLower;
// MQTT 上行(仅存在告警时才发送) // MQTT 上行(仅存在告警时才发送)
final mqttClient = globalMqttClient; final mqttClient = globalMqttClient;
...@@ -439,10 +451,10 @@ class DeviceControlBloc ...@@ -439,10 +451,10 @@ class DeviceControlBloc
} }
/// [用户操作] 设置舱内温度开关(发送给MCU)—— 持久化 /// [用户操作] 设置舱内温度开关(发送给MCU)—— 持久化
void _onCabinTempSwitchChanged( Future<void> _onCabinTempSwitchChanged(
DeviceControlCabinTempSwitchChanged event, DeviceControlCabinTempSwitchChanged event,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) { ) async {
final newData = state.data.copyWith( final newData = state.data.copyWith(
cabinTemp: state.data.cabinTemp.copyWith( cabinTemp: state.data.cabinTemp.copyWith(
isOn: event.isOn, isOn: event.isOn,
...@@ -453,7 +465,13 @@ class DeviceControlBloc ...@@ -453,7 +465,13 @@ class DeviceControlBloc
userSettings: state.userSettings.copyWith(cabinTempIsOn: event.isOn), userSettings: state.userSettings.copyWith(cabinTempIsOn: event.isOn),
clearError: true, clearError: true,
)); ));
// TODO: 发送设置到MCU await _writeControlValueToBluetooth(
identifier: 0x02,
setValue: event.isOn ? _preservedCabinTempSetValue : '10',
errorPrefix: '舱内温度${event.isOn ? '开启' : '关闭'}',
emit: emit,
scale: event.isOn ? 10 : 1,
);
} }
// ==================== 舱内湿度控制事件处理 ==================== // ==================== 舱内湿度控制事件处理 ====================
...@@ -520,10 +538,10 @@ class DeviceControlBloc ...@@ -520,10 +538,10 @@ class DeviceControlBloc
} }
/// [用户操作] 设置舱内湿度开关(发送给MCU)—— 持久化 /// [用户操作] 设置舱内湿度开关(发送给MCU)—— 持久化
void _onCabinHumiditySwitchChanged( Future<void> _onCabinHumiditySwitchChanged(
DeviceControlCabinHumiditySwitchChanged event, DeviceControlCabinHumiditySwitchChanged event,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) { ) async {
final newData = state.data.copyWith( final newData = state.data.copyWith(
cabinHumidity: state.data.cabinHumidity.copyWith( cabinHumidity: state.data.cabinHumidity.copyWith(
isOn: event.isOn, isOn: event.isOn,
...@@ -534,7 +552,12 @@ class DeviceControlBloc ...@@ -534,7 +552,12 @@ class DeviceControlBloc
userSettings: state.userSettings.copyWith(cabinHumidityIsOn: event.isOn), userSettings: state.userSettings.copyWith(cabinHumidityIsOn: event.isOn),
clearError: true, clearError: true,
)); ));
// TODO: 发送设置到MCU await _writeControlValueToBluetooth(
identifier: 0x04,
setValue: event.isOn ? _preservedCabinHumiditySetValue : '100',
errorPrefix: '舱内湿度${event.isOn ? '开启' : '关闭'}',
emit: emit,
);
} }
// ==================== 氧气浓度控制事件处理 ==================== // ==================== 氧气浓度控制事件处理 ====================
...@@ -567,7 +590,7 @@ class DeviceControlBloc ...@@ -567,7 +590,7 @@ class DeviceControlBloc
) async { ) async {
final currentValue = final currentValue =
int.tryParse(state.data.oxygenConcentration.setValue) ?? 0; int.tryParse(state.data.oxygenConcentration.setValue) ?? 0;
final nextValue = (currentValue + event.step).clamp(0, 100); final nextValue = (currentValue + event.step).clamp(0, _oxygenSetValueMax);
Log.warn( Log.warn(
'🔥🔥🔥 BLE_WRITE_DEBUG oxygen_concentration_adjust ' '🔥🔥🔥 BLE_WRITE_DEBUG oxygen_concentration_adjust '
'current=$currentValue step=${event.step} next=$nextValue', 'current=$currentValue step=${event.step} next=$nextValue',
...@@ -579,45 +602,55 @@ class DeviceControlBloc ...@@ -579,45 +602,55 @@ class DeviceControlBloc
String setValue, String setValue,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) async { ) async {
final safeSetValue = _clampIntString(setValue, 0, _oxygenSetValueMax);
final newData = state.data.copyWith( final newData = state.data.copyWith(
oxygenConcentration: state.data.oxygenConcentration.copyWith( oxygenConcentration: state.data.oxygenConcentration.copyWith(
setValue: setValue, setValue: safeSetValue,
), ),
); );
emit(state.copyWith( emit(state.copyWith(
data: newData, data: newData,
userSettings: userSettings: state.userSettings
state.userSettings.copyWith(oxygenConcentrationSetValue: setValue), .copyWith(oxygenConcentrationSetValue: safeSetValue),
clearError: true, clearError: true,
)); ));
Log.warn( Log.warn(
'🔥🔥🔥 BLE_WRITE_DEBUG oxygen_concentration_set_value value=$setValue', '🔥🔥🔥 BLE_WRITE_DEBUG oxygen_concentration_set_value value=$safeSetValue',
); );
await _writeControlValueToBluetooth( await _writeControlValueToBluetooth(
identifier: 0x05, identifier: 0x05,
setValue: setValue, setValue: safeSetValue,
errorPrefix: '氧气浓度设定', errorPrefix: '氧气浓度设定',
emit: emit, emit: emit,
); );
} }
/// [用户操作] 设置氧气浓度开关(发送给MCU)—— 持久化 /// [用户操作] 设置氧气浓度开关(发送给MCU)—— 持久化
void _onOxygenConcentrationSwitchChanged( Future<void> _onOxygenConcentrationSwitchChanged(
DeviceControlOxygenConcentrationSwitchChanged event, DeviceControlOxygenConcentrationSwitchChanged event,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) { ) async {
final safeSetValue = _preservedOxygenConcentrationSetValue;
final newData = state.data.copyWith( final newData = state.data.copyWith(
oxygenConcentration: state.data.oxygenConcentration.copyWith( oxygenConcentration: state.data.oxygenConcentration.copyWith(
isOn: event.isOn, isOn: event.isOn,
setValue: safeSetValue,
), ),
); );
emit(state.copyWith( emit(state.copyWith(
data: newData, data: newData,
userSettings: userSettings: state.userSettings.copyWith(
state.userSettings.copyWith(oxygenConcentrationIsOn: event.isOn), oxygenConcentrationIsOn: event.isOn,
oxygenConcentrationSetValue: safeSetValue,
),
clearError: true, clearError: true,
)); ));
// TODO: 发送设置到MCU await _writeControlValueToBluetooth(
identifier: 0x05,
setValue: event.isOn ? _preservedOxygenConcentrationSetValue : '20',
errorPrefix: '氧气浓度${event.isOn ? '开启' : '关闭'}',
emit: emit,
);
} }
// ==================== 二氧化碳浓度控制事件处理 ==================== // ==================== 二氧化碳浓度控制事件处理 ====================
...@@ -650,7 +683,7 @@ class DeviceControlBloc ...@@ -650,7 +683,7 @@ class DeviceControlBloc
) async { ) async {
final currentValue = final currentValue =
int.tryParse(state.data.co2Concentration.alarmThreshold) ?? 0; int.tryParse(state.data.co2Concentration.alarmThreshold) ?? 0;
final nextValue = (currentValue + event.step).clamp(0, 9999); final nextValue = (currentValue + event.step).clamp(4000, 5000);
Log.warn( Log.warn(
'🔥🔥🔥 BLE_WRITE_DEBUG co2_alarm_threshold_adjust ' '🔥🔥🔥 BLE_WRITE_DEBUG co2_alarm_threshold_adjust '
'current=$currentValue step=${event.step} next=$nextValue', 'current=$currentValue step=${event.step} next=$nextValue',
...@@ -662,24 +695,25 @@ class DeviceControlBloc ...@@ -662,24 +695,25 @@ class DeviceControlBloc
String alarmThreshold, String alarmThreshold,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) async { ) async {
final safeAlarmThreshold = _clampIntString(alarmThreshold, 4000, 5000);
final newData = state.data.copyWith( final newData = state.data.copyWith(
co2Concentration: state.data.co2Concentration.copyWith( co2Concentration: state.data.co2Concentration.copyWith(
alarmThreshold: alarmThreshold, alarmThreshold: safeAlarmThreshold,
), ),
); );
emit(state.copyWith( emit(state.copyWith(
data: newData, data: newData,
userSettings: userSettings:
state.userSettings.copyWith(co2AlarmThreshold: alarmThreshold), state.userSettings.copyWith(co2AlarmThreshold: safeAlarmThreshold),
clearError: true, clearError: true,
)); ));
Log.warn( Log.warn(
'🔥🔥🔥 BLE_WRITE_DEBUG co2_alarm_threshold_set_value ' '🔥🔥🔥 BLE_WRITE_DEBUG co2_alarm_threshold_set_value '
'value=$alarmThreshold', 'value=$safeAlarmThreshold',
); );
await _writeControlValueToBluetooth( await _writeControlValueToBluetooth(
identifier: 0x31, identifier: 0x31,
setValue: alarmThreshold, setValue: safeAlarmThreshold,
errorPrefix: '二氧化碳浓度设定', errorPrefix: '二氧化碳浓度设定',
emit: emit, emit: emit,
); );
...@@ -740,6 +774,10 @@ class DeviceControlBloc ...@@ -740,6 +774,10 @@ class DeviceControlBloc
DeviceControlWindSpeedModeChanged event, DeviceControlWindSpeedModeChanged event,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) async { ) async {
if (event.mode == WindSpeedMode.off && state.data.cabinTemp.isOn) {
emit(state.copyWith(error: '舱内温度开启时风速不能关闭'));
return;
}
final newData = state.data.copyWith( final newData = state.data.copyWith(
windSpeed: state.data.windSpeed.copyWith( windSpeed: state.data.windSpeed.copyWith(
currentMode: event.mode, currentMode: event.mode,
...@@ -817,14 +855,37 @@ class DeviceControlBloc ...@@ -817,14 +855,37 @@ class DeviceControlBloc
DeviceControlOpenOxygenSwitchChanged event, DeviceControlOpenOxygenSwitchChanged event,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) async { ) async {
final oxygenSetValue = event.isOn
? state.data.oxygenConcentration.setValue
: _clampIntString(state.data.oxygenConcentration.setValue, 0, 60);
final newData = state.data.copyWith( final newData = state.data.copyWith(
openOxygen: state.data.openOxygen.copyWith( openOxygen: state.data.openOxygen.copyWith(
isOn: event.isOn, isOn: event.isOn,
), ),
oxygenConcentration: state.data.oxygenConcentration.copyWith(
setValue: oxygenSetValue,
),
circulationMode: event.isOn
? state.data.circulationMode.copyWith(
currentMode: CirculationMode.external,
)
: null,
windSpeed: event.isOn
? state.data.windSpeed.copyWith(currentMode: WindSpeedMode.off)
: null,
); );
emit(state.copyWith( emit(state.copyWith(
data: newData, data: newData,
userSettings: state.userSettings.copyWith(openOxygenIsOn: event.isOn), userSettings: state.userSettings.copyWith(
openOxygenIsOn: event.isOn,
oxygenConcentrationSetValue: oxygenSetValue,
circulationModeValue: event.isOn
? CirculationMode.external
: state.userSettings.circulationModeValue,
windSpeedModeValue: event.isOn
? WindSpeedMode.off
: state.userSettings.windSpeedModeValue,
),
clearError: true, clearError: true,
)); ));
await _writeSwitchValueToBluetooth( await _writeSwitchValueToBluetooth(
...@@ -906,20 +967,9 @@ class DeviceControlBloc ...@@ -906,20 +967,9 @@ class DeviceControlBloc
DeviceControlCheckLightSwitchChanged event, DeviceControlCheckLightSwitchChanged event,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) async { ) async {
final newData = state.data.copyWith( await _setExclusiveLight(
lightControl: state.data.lightControl.copyWith( target: _LightTarget.check,
checkLightOn: event.isOn,
),
);
emit(state.copyWith(
data: newData,
userSettings: state.userSettings.copyWith(checkLightOn: event.isOn),
clearError: true,
));
await _writeSwitchValueToBluetooth(
identifier: 0x0A,
isOn: event.isOn, isOn: event.isOn,
errorPrefix: '检查灯',
emit: emit, emit: emit,
); );
} }
...@@ -929,20 +979,9 @@ class DeviceControlBloc ...@@ -929,20 +979,9 @@ class DeviceControlBloc
DeviceControlIlluminationLightSwitchChanged event, DeviceControlIlluminationLightSwitchChanged event,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) async { ) async {
final newData = state.data.copyWith( await _setExclusiveLight(
lightControl: state.data.lightControl.copyWith( target: _LightTarget.illumination,
illuminationOn: event.isOn,
),
);
emit(state.copyWith(
data: newData,
userSettings: state.userSettings.copyWith(illuminationOn: event.isOn),
clearError: true,
));
await _writeSwitchValueToBluetooth(
identifier: 0x09,
isOn: event.isOn, isOn: event.isOn,
errorPrefix: '照明灯',
emit: emit, emit: emit,
); );
} }
...@@ -952,20 +991,9 @@ class DeviceControlBloc ...@@ -952,20 +991,9 @@ class DeviceControlBloc
DeviceControlBlueLightSwitchChanged event, DeviceControlBlueLightSwitchChanged event,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) async { ) async {
final newData = state.data.copyWith( await _setExclusiveLight(
lightControl: state.data.lightControl.copyWith( target: _LightTarget.blue,
blueLightOn: event.isOn,
),
);
emit(state.copyWith(
data: newData,
userSettings: state.userSettings.copyWith(blueLightOn: event.isOn),
clearError: true,
));
await _writeSwitchValueToBluetooth(
identifier: 0x1E,
isOn: event.isOn, isOn: event.isOn,
errorPrefix: '蓝光',
emit: emit, emit: emit,
); );
} }
...@@ -975,20 +1003,9 @@ class DeviceControlBloc ...@@ -975,20 +1003,9 @@ class DeviceControlBloc
DeviceControlRedLightSwitchChanged event, DeviceControlRedLightSwitchChanged event,
Emitter<DeviceControlState> emit, Emitter<DeviceControlState> emit,
) async { ) async {
final newData = state.data.copyWith( await _setExclusiveLight(
lightControl: state.data.lightControl.copyWith( target: _LightTarget.red,
redLightOn: event.isOn,
),
);
emit(state.copyWith(
data: newData,
userSettings: state.userSettings.copyWith(redLightOn: event.isOn),
clearError: true,
));
await _writeSwitchValueToBluetooth(
identifier: 0x1F,
isOn: event.isOn, isOn: event.isOn,
errorPrefix: '红光',
emit: emit, emit: emit,
); );
} }
...@@ -1037,6 +1054,199 @@ class DeviceControlBloc ...@@ -1037,6 +1054,199 @@ class DeviceControlBloc
// TODO: 发送重置指令到MCU // TODO: 发送重置指令到MCU
} }
int get _oxygenSetValueMax => state.data.openOxygen.isOn ? 80 : 60;
String get _preservedCabinTempSetValue {
final savedValue = state.userSettings.cabinTempSetValue;
if (savedValue != null) return savedValue;
final value = state.data.cabinTemp.setValue;
if (!state.data.cabinTemp.isOn && value == '1') {
return '24';
}
return value;
}
String get _preservedCabinHumiditySetValue {
final savedValue = state.userSettings.cabinHumiditySetValue;
if (savedValue != null) return savedValue;
final value = state.data.cabinHumidity.setValue;
if (!state.data.cabinHumidity.isOn && value == '100') {
return '50';
}
return value;
}
String get _preservedOxygenConcentrationSetValue {
final savedValue = state.userSettings.oxygenConcentrationSetValue;
final value = savedValue ?? state.data.oxygenConcentration.setValue;
if (savedValue == null &&
!state.data.oxygenConcentration.isOn &&
value == '20') {
return '60';
}
return _clampIntString(
value,
0,
_oxygenSetValueMax,
);
}
String _clampIntString(String value, int min, int max) {
final parsed = int.tryParse(value);
if (parsed == null) return '$min';
return '${parsed.clamp(min, max)}';
}
Future<void> _setExclusiveLight({
required _LightTarget target,
required bool isOn,
required Emitter<DeviceControlState> emit,
}) async {
final current = state.data.lightControl;
final nextLightControl = isOn
? _lightControlForTurnOn(current, target)
: current.copyWith(
checkLightOn: target == _LightTarget.check ? false : null,
illuminationOn: target == _LightTarget.illumination ? false : null,
blueLightOn: target == _LightTarget.blue ? false : null,
redLightOn: target == _LightTarget.red ? false : null,
);
final newData = state.data.copyWith(lightControl: nextLightControl);
emit(state.copyWith(
data: newData,
userSettings: state.userSettings.copyWith(
checkLightOn: nextLightControl.checkLightOn,
illuminationOn: nextLightControl.illuminationOn,
blueLightOn: nextLightControl.blueLightOn,
redLightOn: nextLightControl.redLightOn,
),
clearError: true,
));
final List<_LightTarget> lightsToClose = [];
if (isOn) {
for (final light in _lightsToCloseBeforeTurnOn(target)) {
if (_isLightOn(current, light)) lightsToClose.add(light);
}
}
for (final light in lightsToClose) {
await _writeLightToBluetooth(light, false, emit);
await Future<void>.delayed(const Duration(milliseconds: 300));
}
await _writeLightToBluetooth(target, isOn, emit);
}
LightControlBO _lightControlForTurnOn(
LightControlBO current,
_LightTarget target,
) {
switch (target) {
case _LightTarget.check:
return current.copyWith(
checkLightOn: true,
blueLightOn: false,
redLightOn: false,
);
case _LightTarget.illumination:
return current.copyWith(
illuminationOn: true,
blueLightOn: false,
redLightOn: false,
);
case _LightTarget.blue:
return const LightControlBO(
checkLightOn: false,
illuminationOn: false,
blueLightOn: true,
redLightOn: false,
);
case _LightTarget.red:
return const LightControlBO(
checkLightOn: false,
illuminationOn: false,
blueLightOn: false,
redLightOn: true,
);
}
}
List<_LightTarget> _lightsToCloseBeforeTurnOn(_LightTarget target) {
switch (target) {
case _LightTarget.check:
case _LightTarget.illumination:
return const [_LightTarget.blue, _LightTarget.red];
case _LightTarget.blue:
return const [
_LightTarget.check,
_LightTarget.illumination,
_LightTarget.red,
];
case _LightTarget.red:
return const [
_LightTarget.check,
_LightTarget.illumination,
_LightTarget.blue,
];
}
}
bool _isLightOn(LightControlBO lightControl, _LightTarget target) {
switch (target) {
case _LightTarget.check:
return lightControl.checkLightOn;
case _LightTarget.illumination:
return lightControl.illuminationOn;
case _LightTarget.blue:
return lightControl.blueLightOn;
case _LightTarget.red:
return lightControl.redLightOn;
}
}
Future<void> _writeLightToBluetooth(
_LightTarget target,
bool isOn,
Emitter<DeviceControlState> emit,
) {
return _writeSwitchValueToBluetooth(
identifier: _lightIdentifier(target),
isOn: isOn,
errorPrefix: _lightName(target),
emit: emit,
);
}
int _lightIdentifier(_LightTarget target) {
switch (target) {
case _LightTarget.check:
return 0x0A;
case _LightTarget.illumination:
return 0x09;
case _LightTarget.blue:
return 0x1E;
case _LightTarget.red:
return 0x1F;
}
}
String _lightName(_LightTarget target) {
switch (target) {
case _LightTarget.check:
return '检查灯';
case _LightTarget.illumination:
return '照明灯';
case _LightTarget.blue:
return '蓝光';
case _LightTarget.red:
return '红光';
}
}
Future<void> _writeControlValueToBluetooth({ Future<void> _writeControlValueToBluetooth({
required int identifier, required int identifier,
required String setValue, required String setValue,
...@@ -1098,6 +1308,8 @@ class DeviceControlBloc ...@@ -1098,6 +1308,8 @@ class DeviceControlBloc
int _windSpeedProtocolValue(WindSpeedMode mode) { int _windSpeedProtocolValue(WindSpeedMode mode) {
switch (mode) { switch (mode) {
case WindSpeedMode.off:
return 3;
case WindSpeedMode.comfort: case WindSpeedMode.comfort:
return 0; return 0;
case WindSpeedMode.strong: case WindSpeedMode.strong:
......
...@@ -21,7 +21,7 @@ const DeviceControlBO _defaultDeviceControlBO = DeviceControlBO( ...@@ -21,7 +21,7 @@ const DeviceControlBO _defaultDeviceControlBO = DeviceControlBO(
), ),
oxygenConcentration: OxygenConcentrationBO( oxygenConcentration: OxygenConcentrationBO(
currentValue: '--', currentValue: '--',
setValue: '90', setValue: '60',
unit: '%', unit: '%',
isOn: true, isOn: true,
), ),
...@@ -41,10 +41,10 @@ const DeviceControlBO _defaultDeviceControlBO = DeviceControlBO( ...@@ -41,10 +41,10 @@ const DeviceControlBO _defaultDeviceControlBO = DeviceControlBO(
currentMode: WindSpeedMode.sleep, currentMode: WindSpeedMode.sleep,
), ),
nebulizationTime: NebulizationTimeBO( nebulizationTime: NebulizationTimeBO(
setMinutes: '00', setMinutes: '30',
), ),
disinfectionTime: DisinfectionTimeBO( disinfectionTime: DisinfectionTimeBO(
setMinutes: '14', setMinutes: '30',
), ),
openOxygen: OpenOxygenControlBO( openOxygen: OpenOxygenControlBO(
isOn: false, isOn: false,
......
...@@ -121,7 +121,8 @@ class DeviceControlBO extends Equatable { ...@@ -121,7 +121,8 @@ class DeviceControlBO extends Equatable {
environmentTemp: json['environmentTemp'] as String? ?? '25.0℃', environmentTemp: json['environmentTemp'] as String? ?? '25.0℃',
totalOxygenTime: json['totalOxygenTime'] as String? ?? '0h', totalOxygenTime: json['totalOxygenTime'] as String? ?? '0h',
cabinTemp: json['cabinTemp'] != null cabinTemp: json['cabinTemp'] != null
? TemperatureControlBO.fromJson(json['cabinTemp'] as Map<String, dynamic>) ? TemperatureControlBO.fromJson(
json['cabinTemp'] as Map<String, dynamic>)
: const TemperatureControlBO( : const TemperatureControlBO(
currentValue: '24', currentValue: '24',
setValue: '24', setValue: '24',
...@@ -129,7 +130,8 @@ class DeviceControlBO extends Equatable { ...@@ -129,7 +130,8 @@ class DeviceControlBO extends Equatable {
isOn: false, isOn: false,
), ),
cabinHumidity: json['cabinHumidity'] != null cabinHumidity: json['cabinHumidity'] != null
? HumidityControlBO.fromJson(json['cabinHumidity'] as Map<String, dynamic>) ? HumidityControlBO.fromJson(
json['cabinHumidity'] as Map<String, dynamic>)
: const HumidityControlBO( : const HumidityControlBO(
currentValue: '24', currentValue: '24',
setValue: '50', setValue: '50',
...@@ -137,22 +139,25 @@ class DeviceControlBO extends Equatable { ...@@ -137,22 +139,25 @@ class DeviceControlBO extends Equatable {
isOn: false, isOn: false,
), ),
oxygenConcentration: json['oxygenConcentration'] != null oxygenConcentration: json['oxygenConcentration'] != null
? OxygenConcentrationBO.fromJson(json['oxygenConcentration'] as Map<String, dynamic>) ? OxygenConcentrationBO.fromJson(
json['oxygenConcentration'] as Map<String, dynamic>)
: const OxygenConcentrationBO( : const OxygenConcentrationBO(
currentValue: '24', currentValue: '24',
setValue: '90', setValue: '60',
unit: '%', unit: '%',
isOn: true, isOn: true,
), ),
co2Concentration: json['co2Concentration'] != null co2Concentration: json['co2Concentration'] != null
? CO2ConcentrationBO.fromJson(json['co2Concentration'] as Map<String, dynamic>) ? CO2ConcentrationBO.fromJson(
json['co2Concentration'] as Map<String, dynamic>)
: const CO2ConcentrationBO( : const CO2ConcentrationBO(
currentValue: '2400', currentValue: '2400',
alarmThreshold: '4000', alarmThreshold: '4000',
unit: 'PPM', unit: 'PPM',
), ),
careLevel: json['careLevel'] != null careLevel: json['careLevel'] != null
? CareLevelControlBO.fromJson(json['careLevel'] as Map<String, dynamic>) ? CareLevelControlBO.fromJson(
json['careLevel'] as Map<String, dynamic>)
: const CareLevelControlBO( : const CareLevelControlBO(
currentLevel: CareLevel.special, currentLevel: CareLevel.special,
), ),
...@@ -163,22 +168,26 @@ class DeviceControlBO extends Equatable { ...@@ -163,22 +168,26 @@ class DeviceControlBO extends Equatable {
description: 'CO₂超设定值时自动启动外循环净化,当降至2000ppm后,本功能自动关闭', description: 'CO₂超设定值时自动启动外循环净化,当降至2000ppm后,本功能自动关闭',
), ),
windSpeed: json['windSpeed'] != null windSpeed: json['windSpeed'] != null
? WindSpeedControlBO.fromJson(json['windSpeed'] as Map<String, dynamic>) ? WindSpeedControlBO.fromJson(
json['windSpeed'] as Map<String, dynamic>)
: const WindSpeedControlBO( : const WindSpeedControlBO(
currentMode: WindSpeedMode.sleep, currentMode: WindSpeedMode.sleep,
), ),
nebulizationTime: json['nebulizationTime'] != null nebulizationTime: json['nebulizationTime'] != null
? NebulizationTimeBO.fromJson(json['nebulizationTime'] as Map<String, dynamic>) ? NebulizationTimeBO.fromJson(
json['nebulizationTime'] as Map<String, dynamic>)
: const NebulizationTimeBO( : const NebulizationTimeBO(
setMinutes: '00', setMinutes: '30',
), ),
disinfectionTime: json['disinfectionTime'] != null disinfectionTime: json['disinfectionTime'] != null
? DisinfectionTimeBO.fromJson(json['disinfectionTime'] as Map<String, dynamic>) ? DisinfectionTimeBO.fromJson(
json['disinfectionTime'] as Map<String, dynamic>)
: const DisinfectionTimeBO( : const DisinfectionTimeBO(
setMinutes: '14', setMinutes: '30',
), ),
openOxygen: json['openOxygen'] != null openOxygen: json['openOxygen'] != null
? OpenOxygenControlBO.fromJson(json['openOxygen'] as Map<String, dynamic>) ? OpenOxygenControlBO.fromJson(
json['openOxygen'] as Map<String, dynamic>)
: const OpenOxygenControlBO( : const OpenOxygenControlBO(
isOn: false, isOn: false,
description: '开启后风扇打开,制冷、加热和循环等设备暂停。\n*保持设备周围空气相对禁止,严禁烟火', description: '开启后风扇打开,制冷、加热和循环等设备暂停。\n*保持设备周围空气相对禁止,严禁烟火',
...@@ -191,12 +200,14 @@ class DeviceControlBO extends Equatable { ...@@ -191,12 +200,14 @@ class DeviceControlBO extends Equatable {
seconds: '00', seconds: '00',
), ),
circulationMode: json['circulationMode'] != null circulationMode: json['circulationMode'] != null
? CirculationModeBO.fromJson(json['circulationMode'] as Map<String, dynamic>) ? CirculationModeBO.fromJson(
json['circulationMode'] as Map<String, dynamic>)
: const CirculationModeBO( : const CirculationModeBO(
currentMode: CirculationMode.external, currentMode: CirculationMode.external,
), ),
lightControl: json['lightControl'] != null lightControl: json['lightControl'] != null
? LightControlBO.fromJson(json['lightControl'] as Map<String, dynamic>) ? LightControlBO.fromJson(
json['lightControl'] as Map<String, dynamic>)
: const LightControlBO( : const LightControlBO(
checkLightOn: false, checkLightOn: false,
illuminationOn: false, illuminationOn: false,
...@@ -365,7 +376,7 @@ class OxygenConcentrationBO extends Equatable { ...@@ -365,7 +376,7 @@ class OxygenConcentrationBO extends Equatable {
factory OxygenConcentrationBO.fromJson(Map<String, dynamic> json) { factory OxygenConcentrationBO.fromJson(Map<String, dynamic> json) {
return OxygenConcentrationBO( return OxygenConcentrationBO(
currentValue: json['currentValue'] as String? ?? '24', currentValue: json['currentValue'] as String? ?? '24',
setValue: json['setValue'] as String? ?? '90', setValue: json['setValue'] as String? ?? '60',
unit: json['unit'] as String? ?? '%', unit: json['unit'] as String? ?? '%',
isOn: json['isOn'] as bool? ?? true, isOn: json['isOn'] as bool? ?? true,
); );
...@@ -495,7 +506,7 @@ class FreshAirControlBO extends Equatable { ...@@ -495,7 +506,7 @@ class FreshAirControlBO extends Equatable {
} }
/// 风速模式枚举 /// 风速模式枚举
enum WindSpeedMode { sleep, comfort, strong } enum WindSpeedMode { off, sleep, comfort, strong }
/// 用途:风速调节控制数据 /// 用途:风速调节控制数据
/// 涉及页面:设备控制页面 /// 涉及页面:设备控制页面
...@@ -548,7 +559,7 @@ class NebulizationTimeBO extends Equatable { ...@@ -548,7 +559,7 @@ class NebulizationTimeBO extends Equatable {
factory NebulizationTimeBO.fromJson(Map<String, dynamic> json) { factory NebulizationTimeBO.fromJson(Map<String, dynamic> json) {
return NebulizationTimeBO( return NebulizationTimeBO(
setMinutes: json['setMinutes'] as String? ?? '00', setMinutes: json['setMinutes'] as String? ?? '30',
); );
} }
...@@ -576,7 +587,7 @@ class DisinfectionTimeBO extends Equatable { ...@@ -576,7 +587,7 @@ class DisinfectionTimeBO extends Equatable {
factory DisinfectionTimeBO.fromJson(Map<String, dynamic> json) { factory DisinfectionTimeBO.fromJson(Map<String, dynamic> json) {
return DisinfectionTimeBO( return DisinfectionTimeBO(
setMinutes: json['setMinutes'] as String? ?? '14', setMinutes: json['setMinutes'] as String? ?? '30',
); );
} }
...@@ -741,7 +752,8 @@ class LightControlBO extends Equatable { ...@@ -741,7 +752,8 @@ class LightControlBO extends Equatable {
} }
@override @override
List<Object?> get props => [checkLightOn, illuminationOn, blueLightOn, redLightOn]; List<Object?> get props =>
[checkLightOn, illuminationOn, blueLightOn, redLightOn];
} }
/// 用途:设备控制用户设置数据(仅包含用户可配置的字段,不包含MCU获取的值) /// 用途:设备控制用户设置数据(仅包含用户可配置的字段,不包含MCU获取的值)
...@@ -851,16 +863,21 @@ class DeviceControlUserSettings extends Equatable { ...@@ -851,16 +863,21 @@ class DeviceControlUserSettings extends Equatable {
sn: sn ?? this.sn, sn: sn ?? this.sn,
cabinTempSetValue: cabinTempSetValue ?? this.cabinTempSetValue, cabinTempSetValue: cabinTempSetValue ?? this.cabinTempSetValue,
cabinTempIsOn: cabinTempIsOn ?? this.cabinTempIsOn, cabinTempIsOn: cabinTempIsOn ?? this.cabinTempIsOn,
cabinHumiditySetValue: cabinHumiditySetValue ?? this.cabinHumiditySetValue, cabinHumiditySetValue:
cabinHumiditySetValue ?? this.cabinHumiditySetValue,
cabinHumidityIsOn: cabinHumidityIsOn ?? this.cabinHumidityIsOn, cabinHumidityIsOn: cabinHumidityIsOn ?? this.cabinHumidityIsOn,
oxygenConcentrationSetValue: oxygenConcentrationSetValue ?? this.oxygenConcentrationSetValue, oxygenConcentrationSetValue:
oxygenConcentrationIsOn: oxygenConcentrationIsOn ?? this.oxygenConcentrationIsOn, oxygenConcentrationSetValue ?? this.oxygenConcentrationSetValue,
oxygenConcentrationIsOn:
oxygenConcentrationIsOn ?? this.oxygenConcentrationIsOn,
co2AlarmThreshold: co2AlarmThreshold ?? this.co2AlarmThreshold, co2AlarmThreshold: co2AlarmThreshold ?? this.co2AlarmThreshold,
careLevelValue: careLevelValue ?? this.careLevelValue, careLevelValue: careLevelValue ?? this.careLevelValue,
freshAirModeValue: freshAirModeValue ?? this.freshAirModeValue, freshAirModeValue: freshAirModeValue ?? this.freshAirModeValue,
windSpeedModeValue: windSpeedModeValue ?? this.windSpeedModeValue, windSpeedModeValue: windSpeedModeValue ?? this.windSpeedModeValue,
nebulizationTimeMinutes: nebulizationTimeMinutes ?? this.nebulizationTimeMinutes, nebulizationTimeMinutes:
disinfectionTimeMinutes: disinfectionTimeMinutes ?? this.disinfectionTimeMinutes, nebulizationTimeMinutes ?? this.nebulizationTimeMinutes,
disinfectionTimeMinutes:
disinfectionTimeMinutes ?? this.disinfectionTimeMinutes,
openOxygenIsOn: openOxygenIsOn ?? this.openOxygenIsOn, openOxygenIsOn: openOxygenIsOn ?? this.openOxygenIsOn,
circulationModeValue: circulationModeValue ?? this.circulationModeValue, circulationModeValue: circulationModeValue ?? this.circulationModeValue,
checkLightOn: checkLightOn ?? this.checkLightOn, checkLightOn: checkLightOn ?? this.checkLightOn,
...@@ -884,7 +901,8 @@ class DeviceControlUserSettings extends Equatable { ...@@ -884,7 +901,8 @@ class DeviceControlUserSettings extends Equatable {
isOn: cabinHumidityIsOn ?? bo.cabinHumidity.isOn, isOn: cabinHumidityIsOn ?? bo.cabinHumidity.isOn,
), ),
oxygenConcentration: bo.oxygenConcentration.copyWith( oxygenConcentration: bo.oxygenConcentration.copyWith(
setValue: oxygenConcentrationSetValue ?? bo.oxygenConcentration.setValue, setValue:
oxygenConcentrationSetValue ?? bo.oxygenConcentration.setValue,
isOn: oxygenConcentrationIsOn ?? bo.oxygenConcentration.isOn, isOn: oxygenConcentrationIsOn ?? bo.oxygenConcentration.isOn,
), ),
co2Concentration: bo.co2Concentration.copyWith( co2Concentration: bo.co2Concentration.copyWith(
...@@ -927,7 +945,8 @@ class DeviceControlUserSettings extends Equatable { ...@@ -927,7 +945,8 @@ class DeviceControlUserSettings extends Equatable {
cabinTempIsOn: json['cabinTempIsOn'] as bool?, cabinTempIsOn: json['cabinTempIsOn'] as bool?,
cabinHumiditySetValue: json['cabinHumiditySetValue'] as String?, cabinHumiditySetValue: json['cabinHumiditySetValue'] as String?,
cabinHumidityIsOn: json['cabinHumidityIsOn'] as bool?, cabinHumidityIsOn: json['cabinHumidityIsOn'] as bool?,
oxygenConcentrationSetValue: json['oxygenConcentrationSetValue'] as String?, oxygenConcentrationSetValue:
json['oxygenConcentrationSetValue'] as String?,
oxygenConcentrationIsOn: json['oxygenConcentrationIsOn'] as bool?, oxygenConcentrationIsOn: json['oxygenConcentrationIsOn'] as bool?,
co2AlarmThreshold: json['co2AlarmThreshold'] as String?, co2AlarmThreshold: json['co2AlarmThreshold'] as String?,
careLevelValue: json['careLevelValue'] != null careLevelValue: json['careLevelValue'] != null
...@@ -969,18 +988,26 @@ class DeviceControlUserSettings extends Equatable { ...@@ -969,18 +988,26 @@ class DeviceControlUserSettings extends Equatable {
if (sn != null) 'sn': sn, if (sn != null) 'sn': sn,
if (cabinTempSetValue != null) 'cabinTempSetValue': cabinTempSetValue, if (cabinTempSetValue != null) 'cabinTempSetValue': cabinTempSetValue,
if (cabinTempIsOn != null) 'cabinTempIsOn': cabinTempIsOn, if (cabinTempIsOn != null) 'cabinTempIsOn': cabinTempIsOn,
if (cabinHumiditySetValue != null) 'cabinHumiditySetValue': cabinHumiditySetValue, if (cabinHumiditySetValue != null)
'cabinHumiditySetValue': cabinHumiditySetValue,
if (cabinHumidityIsOn != null) 'cabinHumidityIsOn': cabinHumidityIsOn, if (cabinHumidityIsOn != null) 'cabinHumidityIsOn': cabinHumidityIsOn,
if (oxygenConcentrationSetValue != null) 'oxygenConcentrationSetValue': oxygenConcentrationSetValue, if (oxygenConcentrationSetValue != null)
if (oxygenConcentrationIsOn != null) 'oxygenConcentrationIsOn': oxygenConcentrationIsOn, 'oxygenConcentrationSetValue': oxygenConcentrationSetValue,
if (oxygenConcentrationIsOn != null)
'oxygenConcentrationIsOn': oxygenConcentrationIsOn,
if (co2AlarmThreshold != null) 'co2AlarmThreshold': co2AlarmThreshold, if (co2AlarmThreshold != null) 'co2AlarmThreshold': co2AlarmThreshold,
if (careLevelValue != null) 'careLevelValue': careLevelValue!.name, if (careLevelValue != null) 'careLevelValue': careLevelValue!.name,
if (freshAirModeValue != null) 'freshAirModeValue': freshAirModeValue!.name, if (freshAirModeValue != null)
if (windSpeedModeValue != null) 'windSpeedModeValue': windSpeedModeValue!.name, 'freshAirModeValue': freshAirModeValue!.name,
if (nebulizationTimeMinutes != null) 'nebulizationTimeMinutes': nebulizationTimeMinutes, if (windSpeedModeValue != null)
if (disinfectionTimeMinutes != null) 'disinfectionTimeMinutes': disinfectionTimeMinutes, 'windSpeedModeValue': windSpeedModeValue!.name,
if (nebulizationTimeMinutes != null)
'nebulizationTimeMinutes': nebulizationTimeMinutes,
if (disinfectionTimeMinutes != null)
'disinfectionTimeMinutes': disinfectionTimeMinutes,
if (openOxygenIsOn != null) 'openOxygenIsOn': openOxygenIsOn, if (openOxygenIsOn != null) 'openOxygenIsOn': openOxygenIsOn,
if (circulationModeValue != null) 'circulationModeValue': circulationModeValue!.name, if (circulationModeValue != null)
'circulationModeValue': circulationModeValue!.name,
if (checkLightOn != null) 'checkLightOn': checkLightOn, if (checkLightOn != null) 'checkLightOn': checkLightOn,
if (illuminationOn != null) 'illuminationOn': illuminationOn, if (illuminationOn != null) 'illuminationOn': illuminationOn,
if (blueLightOn != null) 'blueLightOn': blueLightOn, if (blueLightOn != null) 'blueLightOn': blueLightOn,
......
...@@ -747,7 +747,10 @@ class BleBluetoothManager<T> { ...@@ -747,7 +747,10 @@ class BleBluetoothManager<T> {
} }
static bool _startsWithAny(String value, List<String> prefixes) { static bool _startsWithAny(String value, List<String> prefixes) {
return prefixes.any(value.startsWith); final normalizedValue = value.trim().toUpperCase();
return prefixes.any(
(prefix) => normalizedValue.startsWith(prefix.trim().toUpperCase()),
);
} }
static String _normalizeRemoteIdForSort(String remoteId) { static String _normalizeRemoteIdForSort(String remoteId) {
......
...@@ -10,7 +10,6 @@ import 'package:laki_icu_app/models/bo/monitoring_bo.dart'; ...@@ -10,7 +10,6 @@ import 'package:laki_icu_app/models/bo/monitoring_bo.dart';
import 'cubit/device_control_index_cubit.dart'; import 'cubit/device_control_index_cubit.dart';
import 'cubit/device_control_index_state.dart'; import 'cubit/device_control_index_state.dart';
import 'widgets/device_control_care_panel.dart'; import 'widgets/device_control_care_panel.dart';
import 'widgets/device_control_confirm_dialog.dart';
import 'widgets/device_control_info_panel.dart'; import 'widgets/device_control_info_panel.dart';
import 'widgets/device_control_metric_card.dart'; import 'widgets/device_control_metric_card.dart';
import 'widgets/device_control_mode_panel.dart'; import 'widgets/device_control_mode_panel.dart';
...@@ -163,14 +162,9 @@ class _DeviceControlLayout extends StatelessWidget { ...@@ -163,14 +162,9 @@ class _DeviceControlLayout extends StatelessWidget {
icon: Icons.air, icon: Icons.air,
body: '开启后风扇打开、制冷、加热和\n循环等设备暂停。', body: '开启后风扇打开、制冷、加热和\n循环等设备暂停。',
warning: '*保持设备周围空气相对禁止,严禁烟火', warning: '*保持设备周围空气相对禁止,严禁烟火',
onTap: () { onTap: () => context.read<DeviceControlBloc>().add(
confirmDeviceControlChange( DeviceControlOpenOxygenSwitchChanged(!isOn),
context, ),
() => context.read<DeviceControlBloc>().add(
DeviceControlOpenOxygenSwitchChanged(!isOn),
),
);
},
); );
}, },
), ),
......
...@@ -7,7 +7,6 @@ import 'package:laki_icu_app/blocs/device_control/device_control_state.dart'; ...@@ -7,7 +7,6 @@ import 'package:laki_icu_app/blocs/device_control/device_control_state.dart';
import 'package:laki_icu_app/models/bo/device_control_bo.dart'; import 'package:laki_icu_app/models/bo/device_control_bo.dart';
import 'device_control_common.dart'; import 'device_control_common.dart';
import 'device_control_confirm_dialog.dart';
/// 护理等级面板 /// 护理等级面板
class DeviceControlCarePanel extends StatelessWidget { class DeviceControlCarePanel extends StatelessWidget {
...@@ -37,14 +36,9 @@ class DeviceControlCarePanel extends StatelessWidget { ...@@ -37,14 +36,9 @@ class DeviceControlCarePanel extends StatelessWidget {
Expanded( Expanded(
child: GestureDetector( child: GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: () { onTap: () => context.read<DeviceControlBloc>().add(
confirmDeviceControlChange( DeviceControlCareLevelChanged(item.level),
context, ),
() => context.read<DeviceControlBloc>().add(
DeviceControlCareLevelChanged(item.level),
),
);
},
child: Text( child: Text(
item.label, item.label,
textAlign: TextAlign.center, textAlign: TextAlign.center,
...@@ -107,16 +101,11 @@ class _CareLevelBar extends StatelessWidget { ...@@ -107,16 +101,11 @@ class _CareLevelBar extends StatelessWidget {
Expanded( Expanded(
child: GestureDetector( child: GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: () { onTap: () => context.read<DeviceControlBloc>().add(
confirmDeviceControlChange( DeviceControlCareLevelChanged(
context, _careLevelItems[index].level,
() => context.read<DeviceControlBloc>().add( ),
DeviceControlCareLevelChanged( ),
_careLevelItems[index].level,
),
),
);
},
child: Container( child: Container(
height: 20.h, height: 20.h,
decoration: BoxDecoration( decoration: BoxDecoration(
......
...@@ -94,31 +94,31 @@ class DeviceControlPill extends StatelessWidget { ...@@ -94,31 +94,31 @@ class DeviceControlPill extends StatelessWidget {
super.key, super.key,
required this.text, required this.text,
this.active = false, this.active = false,
this.onTap,
}); });
final String text; final String text;
final bool active; final bool active;
final VoidCallback? onTap;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return GestureDetector(
height: 40.h, behavior: HitTestBehavior.opaque,
constraints: BoxConstraints(minWidth: 90.w), onTap: onTap,
padding: EdgeInsets.symmetric(horizontal: 18.w), child: Container(
alignment: Alignment.center, height: 40.h,
decoration: BoxDecoration( constraints: BoxConstraints(minWidth: 90.w),
color: Colors.white.withValues(alpha: active ? 0.14 : 0.06), padding: EdgeInsets.symmetric(horizontal: 18.w),
border: Border.all( alignment: Alignment.center,
color: active ? const Color(0xFF52FFBB) : const Color(0xFF75C1DD), decoration: BoxDecoration(
width: 1.w, color: Colors.white.withValues(alpha: active ? 0.14 : 0.06),
border: Border.all(
color: active ? const Color(0xFF52FFBB) : const Color(0xFF75C1DD),
width: 1.w,
),
borderRadius: BorderRadius.circular(20.r),
), ),
borderRadius: BorderRadius.circular(20.r),
),
child: GestureDetector(
onTap: () {
var key = super.key;
debugPrint("test $key");
},
child: Text( child: Text(
text, text,
style: TextStyle( style: TextStyle(
......
...@@ -13,8 +13,9 @@ class DeviceControlConfirmConfig { ...@@ -13,8 +13,9 @@ class DeviceControlConfirmConfig {
Future<void> confirmDeviceControlChange( Future<void> confirmDeviceControlChange(
BuildContext context, BuildContext context,
VoidCallback onConfirmed, VoidCallback onConfirmed, {
) async { String message = '确认设置当前修改参数',
}) async {
if (!DeviceControlConfirmConfig.enabled) { if (!DeviceControlConfirmConfig.enabled) {
onConfirmed(); onConfirmed();
return; return;
...@@ -23,7 +24,7 @@ Future<void> confirmDeviceControlChange( ...@@ -23,7 +24,7 @@ Future<void> confirmDeviceControlChange(
final confirmed = await showDialog<bool>( final confirmed = await showDialog<bool>(
context: context, context: context,
barrierColor: Colors.black.withValues(alpha: 0.44), barrierColor: Colors.black.withValues(alpha: 0.44),
builder: (_) => const _DeviceControlConfirmDialog(), builder: (_) => _DeviceControlConfirmDialog(message: message),
); );
if (!context.mounted || confirmed != true) return; if (!context.mounted || confirmed != true) return;
...@@ -31,7 +32,9 @@ Future<void> confirmDeviceControlChange( ...@@ -31,7 +32,9 @@ Future<void> confirmDeviceControlChange(
} }
class _DeviceControlConfirmDialog extends StatelessWidget { class _DeviceControlConfirmDialog extends StatelessWidget {
const _DeviceControlConfirmDialog(); const _DeviceControlConfirmDialog({required this.message});
final String message;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -83,8 +86,9 @@ class _DeviceControlConfirmDialog extends StatelessWidget { ...@@ -83,8 +86,9 @@ class _DeviceControlConfirmDialog extends StatelessWidget {
), ),
const Spacer(), const Spacer(),
Text( Text(
'确认设置当前修改参数', message,
maxLines: 1, maxLines: 3,
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
color: Colors.white, color: Colors.white,
......
...@@ -40,7 +40,12 @@ class DeviceControlMetricCard extends StatelessWidget { ...@@ -40,7 +40,12 @@ class DeviceControlMetricCard extends StatelessWidget {
previous.data.oxygenConcentration.currentValue != previous.data.oxygenConcentration.currentValue !=
current.data.oxygenConcentration.currentValue || current.data.oxygenConcentration.currentValue ||
previous.data.co2Concentration.currentValue != previous.data.co2Concentration.currentValue !=
current.data.co2Concentration.currentValue, current.data.co2Concentration.currentValue ||
previous.data.cabinTemp.isOn != current.data.cabinTemp.isOn ||
previous.data.cabinHumidity.isOn != current.data.cabinHumidity.isOn ||
previous.data.oxygenConcentration.isOn !=
current.data.oxygenConcentration.isOn ||
previous.data.openOxygen.isOn != current.data.openOxygen.isOn,
builder: (context, state) { builder: (context, state) {
final currentValue = isTemperature final currentValue = isTemperature
? state.data.cabinTemp.currentValue ? state.data.cabinTemp.currentValue
...@@ -72,6 +77,19 @@ class DeviceControlMetricCard extends StatelessWidget { ...@@ -72,6 +77,19 @@ class DeviceControlMetricCard extends StatelessWidget {
isOxygen: isOxygen, isOxygen: isOxygen,
isCo2: isCo2, isCo2: isCo2,
); );
final isSwitchOn = isTemperature
? state.data.cabinTemp.isOn
: isHumidity
? state.data.cabinHumidity.isOn
: isOxygen
? state.data.oxygenConcentration.isOn
: false;
final switchEventBuilder = _switchEventBuilder(
isTemperature: isTemperature,
isHumidity: isHumidity,
isOxygen: isOxygen,
);
final displaySetValue = !isCo2 && !isSwitchOn ? '--' : setValue;
return DeviceControlPanelFrame( return DeviceControlPanelFrame(
active: isOxygen, active: isOxygen,
...@@ -86,12 +104,18 @@ class DeviceControlMetricCard extends StatelessWidget { ...@@ -86,12 +104,18 @@ class DeviceControlMetricCard extends StatelessWidget {
child: DeviceControlPanelTitle(_title(metric.label)), child: DeviceControlPanelTitle(_title(metric.label)),
), ),
DeviceControlPill( DeviceControlPill(
text: isOxygen text: isCo2 ? 'PPM' : (isSwitchOn ? 'ON' : 'Off'),
? 'ON' active: !isCo2 && isSwitchOn,
: isCo2 onTap: switchEventBuilder == null
? 'PPM' ? null
: 'Off', : () {
active: isOxygen, confirmDeviceControlChange(
context,
() => context.read<DeviceControlBloc>().add(
switchEventBuilder(!isSwitchOn),
),
);
},
), ),
], ],
), ),
...@@ -166,7 +190,6 @@ class DeviceControlMetricCard extends StatelessWidget { ...@@ -166,7 +190,6 @@ class DeviceControlMetricCard extends StatelessWidget {
? null ? null
: () => _showSetValueKeyboard( : () => _showSetValueKeyboard(
context, context,
initialValue: setValue,
decimalEnabled: isTemperature, decimalEnabled: isTemperature,
eventBuilder: setValueEventBuilder, eventBuilder: setValueEventBuilder,
), ),
...@@ -174,7 +197,7 @@ class DeviceControlMetricCard extends StatelessWidget { ...@@ -174,7 +197,7 @@ class DeviceControlMetricCard extends StatelessWidget {
padding: padding:
EdgeInsets.symmetric(horizontal: 18.w, vertical: 8.h), EdgeInsets.symmetric(horizontal: 18.w, vertical: 8.h),
child: Text( child: Text(
setValue, displaySetValue,
style: TextStyle( style: TextStyle(
color: isCo2 color: isCo2
? const Color(0xFFFFC400) ? const Color(0xFFFFC400)
...@@ -262,15 +285,31 @@ class DeviceControlMetricCard extends StatelessWidget { ...@@ -262,15 +285,31 @@ class DeviceControlMetricCard extends StatelessWidget {
return null; return null;
} }
static DeviceControlEvent Function(bool isOn)? _switchEventBuilder({
required bool isTemperature,
required bool isHumidity,
required bool isOxygen,
}) {
if (isTemperature) {
return (isOn) => DeviceControlCabinTempSwitchChanged(isOn);
}
if (isHumidity) {
return (isOn) => DeviceControlCabinHumiditySwitchChanged(isOn);
}
if (isOxygen) {
return (isOn) => DeviceControlOxygenConcentrationSwitchChanged(isOn);
}
return null;
}
static Future<void> _showSetValueKeyboard( static Future<void> _showSetValueKeyboard(
BuildContext context, { BuildContext context, {
required String initialValue,
required bool decimalEnabled, required bool decimalEnabled,
required DeviceControlEvent Function(String value) eventBuilder, required DeviceControlEvent Function(String value) eventBuilder,
}) async { }) async {
final result = await NumericKeyboard.show( final result = await NumericKeyboard.show(
context, context,
initialValue: initialValue == '--' ? '' : initialValue, initialValue: '',
decimalEnabled: decimalEnabled, decimalEnabled: decimalEnabled,
); );
if (!context.mounted || result == null) return; if (!context.mounted || result == null) return;
......
...@@ -7,7 +7,6 @@ import 'package:laki_icu_app/blocs/device_control/device_control_state.dart'; ...@@ -7,7 +7,6 @@ import 'package:laki_icu_app/blocs/device_control/device_control_state.dart';
import 'package:laki_icu_app/models/bo/device_control_bo.dart'; import 'package:laki_icu_app/models/bo/device_control_bo.dart';
import 'device_control_common.dart'; import 'device_control_common.dart';
import 'device_control_confirm_dialog.dart';
/// 模式切换面板(外循环/检查灯/照明灯/内循环/蓝光/红光) /// 模式切换面板(外循环/检查灯/照明灯/内循环/蓝光/红光)
class DeviceControlModePanel extends StatelessWidget { class DeviceControlModePanel extends StatelessWidget {
...@@ -95,14 +94,9 @@ class DeviceControlModePanel extends StatelessWidget { ...@@ -95,14 +94,9 @@ class DeviceControlModePanel extends StatelessWidget {
label: item.label, label: item.label,
icon: item.icon, icon: item.icon,
active: item.active, active: item.active,
onTap: () { onTap: () => context.read<DeviceControlBloc>().add(
confirmDeviceControlChange( item.event,
context, ),
() => context.read<DeviceControlBloc>().add(
item.event,
),
);
},
), ),
), ),
], ],
......
...@@ -7,7 +7,6 @@ import 'package:laki_icu_app/blocs/device_control/device_control_state.dart'; ...@@ -7,7 +7,6 @@ import 'package:laki_icu_app/blocs/device_control/device_control_state.dart';
import 'package:laki_icu_app/utils/numeric_keyboard.dart'; import 'package:laki_icu_app/utils/numeric_keyboard.dart';
import 'device_control_common.dart'; import 'device_control_common.dart';
import 'device_control_confirm_dialog.dart';
/// 设置雾化/消毒时间面板 /// 设置雾化/消毒时间面板
class DeviceControlTimePanel extends StatelessWidget { class DeviceControlTimePanel extends StatelessWidget {
...@@ -82,10 +81,7 @@ class DeviceControlTimePanel extends StatelessWidget { ...@@ -82,10 +81,7 @@ class DeviceControlTimePanel extends StatelessWidget {
final value = result.trim(); final value = result.trim();
if (value.isEmpty) return; if (value.isEmpty) return;
await confirmDeviceControlChange( context.read<DeviceControlBloc>().add(eventBuilder(value));
context,
() => context.read<DeviceControlBloc>().add(eventBuilder(value)),
);
} }
} }
......
...@@ -7,7 +7,6 @@ import 'package:laki_icu_app/blocs/device_control/device_control_state.dart'; ...@@ -7,7 +7,6 @@ import 'package:laki_icu_app/blocs/device_control/device_control_state.dart';
import 'package:laki_icu_app/models/bo/device_control_bo.dart'; import 'package:laki_icu_app/models/bo/device_control_bo.dart';
import 'device_control_common.dart'; import 'device_control_common.dart';
import 'device_control_confirm_dialog.dart';
/// 风速调节面板 /// 风速调节面板
class DeviceControlWindPanel extends StatelessWidget { class DeviceControlWindPanel extends StatelessWidget {
...@@ -34,16 +33,11 @@ class DeviceControlWindPanel extends StatelessWidget { ...@@ -34,16 +33,11 @@ class DeviceControlWindPanel extends StatelessWidget {
label: '睡眠模式', label: '睡眠模式',
icon: Icons.nightlight_round, icon: Icons.nightlight_round,
active: currentMode == WindSpeedMode.sleep, active: currentMode == WindSpeedMode.sleep,
onTap: () { onTap: () => context.read<DeviceControlBloc>().add(
confirmDeviceControlChange( const DeviceControlWindSpeedModeChanged(
context, WindSpeedMode.sleep,
() => context.read<DeviceControlBloc>().add( ),
const DeviceControlWindSpeedModeChanged( ),
WindSpeedMode.sleep,
),
),
);
},
), ),
), ),
SizedBox(height: 18.h), SizedBox(height: 18.h),
...@@ -52,16 +46,11 @@ class DeviceControlWindPanel extends StatelessWidget { ...@@ -52,16 +46,11 @@ class DeviceControlWindPanel extends StatelessWidget {
label: '舒适模式', label: '舒适模式',
icon: Icons.favorite_border, icon: Icons.favorite_border,
active: currentMode == WindSpeedMode.comfort, active: currentMode == WindSpeedMode.comfort,
onTap: () { onTap: () => context.read<DeviceControlBloc>().add(
confirmDeviceControlChange( const DeviceControlWindSpeedModeChanged(
context, WindSpeedMode.comfort,
() => context.read<DeviceControlBloc>().add( ),
const DeviceControlWindSpeedModeChanged( ),
WindSpeedMode.comfort,
),
),
);
},
), ),
), ),
SizedBox(height: 18.h), SizedBox(height: 18.h),
...@@ -70,16 +59,11 @@ class DeviceControlWindPanel extends StatelessWidget { ...@@ -70,16 +59,11 @@ class DeviceControlWindPanel extends StatelessWidget {
label: '强劲模式', label: '强劲模式',
icon: Icons.air, icon: Icons.air,
active: currentMode == WindSpeedMode.strong, active: currentMode == WindSpeedMode.strong,
onTap: () { onTap: () => context.read<DeviceControlBloc>().add(
confirmDeviceControlChange( const DeviceControlWindSpeedModeChanged(
context, WindSpeedMode.strong,
() => context.read<DeviceControlBloc>().add( ),
const DeviceControlWindSpeedModeChanged( ),
WindSpeedMode.strong,
),
),
);
},
), ),
), ),
], ],
......
...@@ -612,7 +612,7 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -612,7 +612,7 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
try { try {
await _bluetoothManager.scanForDevices( await _bluetoothManager.scanForDevices(
namePrefixes: const [], namePrefixes: const ['CNA'],
timeout: const Duration(seconds: 10), timeout: const Duration(seconds: 10),
); );
} catch (e) { } catch (e) {
...@@ -916,7 +916,8 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -916,7 +916,8 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
); );
// 按告警标题去重:相同标题 → 原地覆盖;不同标题 → 插入头部 // 按告警标题去重:相同标题 → 原地覆盖;不同标题 → 插入头部
final existingIndex = state.cameraAlerts.indexWhere((a) => a.title == title); final existingIndex =
state.cameraAlerts.indexWhere((a) => a.title == title);
if (existingIndex >= 0) { if (existingIndex >= 0) {
// 已存在相同标题 → 原地替换 // 已存在相同标题 → 原地替换
final updatedAlerts = List<AlertInfoBO>.from(state.cameraAlerts); final updatedAlerts = List<AlertInfoBO>.from(state.cameraAlerts);
...@@ -1361,8 +1362,12 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> { ...@@ -1361,8 +1362,12 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
if (client == null || if (client == null ||
!client.isConnected || !client.isConnected ||
deviceSn == null || deviceSn == null ||
deviceSn.isEmpty) return; deviceSn.isEmpty) {
if (alert.alarmId == null) return; return;
}
if (alert.alarmId == null) {
return;
}
try { try {
client.publishCameraAlarmResult( client.publishCameraAlarmResult(
......
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