Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
laki_icu_app
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张宏
laki_icu_app
Commits
0f9cb2e3
Commit
0f9cb2e3
authored
Jun 29, 2026
by
akari
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: 中控页功能联调修复
parent
4dff6ccd
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1312 additions
and
303 deletions
+1312
-303
device_calibration_config.dart
.../device_calibration_config/device_calibration_config.dart
+3
-0
device_calibration_config_bloc.dart
...ce_calibration_config/device_calibration_config_bloc.dart
+89
-0
device_calibration_config_event.dart
...e_calibration_config/device_calibration_config_event.dart
+40
-0
device_calibration_config_state.dart
...e_calibration_config/device_calibration_config_state.dart
+30
-0
device_control_bloc.dart
lib/blocs/device_control/device_control_bloc.dart
+216
-7
main.dart
lib/main.dart
+24
-7
device_calibration_config_bo.dart
lib/models/bo/device_calibration_config_bo.dart
+378
-0
device_control_bo.dart
lib/models/bo/device_control_bo.dart
+24
-0
numeric_keyboard.dart
lib/utils/numeric_keyboard.dart
+112
-37
device_control_care_panel.dart
...ing/device_control/widgets/device_control_care_panel.dart
+82
-46
device_control_common.dart
...itoring/device_control/widgets/device_control_common.dart
+21
-12
device_control_metric_card.dart
...ng/device_control/widgets/device_control_metric_card.dart
+69
-52
device_control_oxygen_timer_panel.dart
...ce_control/widgets/device_control_oxygen_timer_panel.dart
+53
-27
device_control_time_panel.dart
...ing/device_control/widgets/device_control_time_panel.dart
+2
-0
monitoring_index_cubit.dart
lib/views/monitoring/index/cubit/monitoring_index_cubit.dart
+12
-0
monitoring_index_view.dart
lib/views/monitoring/index/monitoring_index_view.dart
+45
-16
bluetooth_bind_dialog.dart
...views/monitoring/index/widgets/bluetooth_bind_dialog.dart
+17
-7
monitoring_metric_card.dart
...iews/monitoring/index/widgets/monitoring_metric_card.dart
+10
-4
factory_settings_index_cubit.dart
.../factory_settings/cubit/factory_settings_index_cubit.dart
+49
-18
factory_device_calibration_panel.dart
...ry_settings/widgets/factory_device_calibration_panel.dart
+32
-69
factory_settings_panel.dart
...ings/factory_settings/widgets/factory_settings_panel.dart
+4
-1
No files found.
lib/blocs/device_calibration_config/device_calibration_config.dart
0 → 100644
View file @
0f9cb2e3
export
'device_calibration_config_bloc.dart'
;
export
'device_calibration_config_event.dart'
;
export
'device_calibration_config_state.dart'
;
lib/blocs/device_calibration_config/device_calibration_config_bloc.dart
0 → 100644
View file @
0f9cb2e3
import
'package:hydrated_bloc/hydrated_bloc.dart'
;
import
'package:laki_icu_app/models/bo/device_calibration_config_bo.dart'
;
import
'device_calibration_config_event.dart'
;
import
'device_calibration_config_state.dart'
;
class
DeviceCalibrationConfigBloc
extends
HydratedBloc
<
DeviceCalibrationConfigEvent
,
DeviceCalibrationConfigState
>
{
DeviceCalibrationConfigBloc
()
:
super
(
const
DeviceCalibrationConfigState
())
{
on
<
DeviceCalibrationConfigLoaded
>(
_onLoaded
);
on
<
DeviceCalibrationConfigItemUpdated
>(
_onItemUpdated
);
on
<
DeviceCalibrationConfigUpdated
>(
_onConfigUpdated
);
on
<
DeviceCalibrationConfigResetToDefault
>(
_onResetToDefault
);
}
Future
<
void
>
_onLoaded
(
DeviceCalibrationConfigLoaded
event
,
Emitter
<
DeviceCalibrationConfigState
>
emit
,
)
async
{
emit
(
state
.
copyWith
(
isLoading:
true
,
clearError:
true
));
try
{
emit
(
state
.
copyWith
(
isLoading:
false
,
clearError:
true
));
}
catch
(
e
)
{
emit
(
state
.
copyWith
(
isLoading:
false
,
error:
e
.
toString
()));
}
}
void
_onItemUpdated
(
DeviceCalibrationConfigItemUpdated
event
,
Emitter
<
DeviceCalibrationConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
updateItem
(
event
.
key
,
event
.
value
),
clearError:
true
,
));
}
void
_onConfigUpdated
(
DeviceCalibrationConfigUpdated
event
,
Emitter
<
DeviceCalibrationConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
event
.
config
,
clearError:
true
,
));
}
void
_onResetToDefault
(
DeviceCalibrationConfigResetToDefault
event
,
Emitter
<
DeviceCalibrationConfigState
>
emit
,
)
{
emit
(
const
DeviceCalibrationConfigState
(
config:
DeviceCalibrationConfigBO
.
defaultConfig
,
));
}
void
updateItem
(
DeviceCalibrationItemKey
key
,
int
value
)
{
add
(
DeviceCalibrationConfigItemUpdated
(
key:
key
,
value:
value
));
}
void
updateConfig
(
DeviceCalibrationConfigBO
config
)
{
add
(
DeviceCalibrationConfigUpdated
(
config
));
}
void
resetToDefault
()
{
add
(
const
DeviceCalibrationConfigResetToDefault
());
}
@override
DeviceCalibrationConfigState
?
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
try
{
return
DeviceCalibrationConfigState
(
config:
DeviceCalibrationConfigBO
.
fromJson
(
json
),
);
}
catch
(
e
)
{
return
null
;
}
}
@override
Map
<
String
,
dynamic
>?
toJson
(
DeviceCalibrationConfigState
state
)
{
return
state
.
config
.
toJson
();
}
}
/// 全局设备校准配置 Bloc 引用。
///
/// 由 main.dart 在创建时写入,页面外需要直接读取校准参数时可通过此引用获取。
DeviceCalibrationConfigBloc
?
globalDeviceCalibrationConfigBloc
;
lib/blocs/device_calibration_config/device_calibration_config_event.dart
0 → 100644
View file @
0f9cb2e3
import
'package:equatable/equatable.dart'
;
import
'package:laki_icu_app/models/bo/device_calibration_config_bo.dart'
;
abstract
class
DeviceCalibrationConfigEvent
extends
Equatable
{
const
DeviceCalibrationConfigEvent
();
@override
List
<
Object
?>
get
props
=>
[];
}
class
DeviceCalibrationConfigLoaded
extends
DeviceCalibrationConfigEvent
{
const
DeviceCalibrationConfigLoaded
();
}
class
DeviceCalibrationConfigItemUpdated
extends
DeviceCalibrationConfigEvent
{
const
DeviceCalibrationConfigItemUpdated
({
required
this
.
key
,
required
this
.
value
,
});
final
DeviceCalibrationItemKey
key
;
final
int
value
;
@override
List
<
Object
?>
get
props
=>
[
key
,
value
];
}
class
DeviceCalibrationConfigUpdated
extends
DeviceCalibrationConfigEvent
{
const
DeviceCalibrationConfigUpdated
(
this
.
config
);
final
DeviceCalibrationConfigBO
config
;
@override
List
<
Object
?>
get
props
=>
[
config
];
}
class
DeviceCalibrationConfigResetToDefault
extends
DeviceCalibrationConfigEvent
{
const
DeviceCalibrationConfigResetToDefault
();
}
lib/blocs/device_calibration_config/device_calibration_config_state.dart
0 → 100644
View file @
0f9cb2e3
import
'package:equatable/equatable.dart'
;
import
'package:laki_icu_app/models/bo/device_calibration_config_bo.dart'
;
class
DeviceCalibrationConfigState
extends
Equatable
{
const
DeviceCalibrationConfigState
({
this
.
config
=
DeviceCalibrationConfigBO
.
defaultConfig
,
this
.
isLoading
=
false
,
this
.
error
,
});
final
DeviceCalibrationConfigBO
config
;
final
bool
isLoading
;
final
String
?
error
;
DeviceCalibrationConfigState
copyWith
({
DeviceCalibrationConfigBO
?
config
,
bool
?
isLoading
,
String
?
error
,
bool
clearError
=
false
,
})
{
return
DeviceCalibrationConfigState
(
config:
config
??
this
.
config
,
isLoading:
isLoading
??
this
.
isLoading
,
error:
clearError
?
null
:
error
??
this
.
error
,
);
}
@override
List
<
Object
?>
get
props
=>
[
config
,
isLoading
,
error
];
}
lib/blocs/device_control/device_control_bloc.dart
View file @
0f9cb2e3
...
@@ -129,6 +129,7 @@ class DeviceControlBloc
...
@@ -129,6 +129,7 @@ class DeviceControlBloc
DateTime
?
_pendingCareLevelSince
;
DateTime
?
_pendingCareLevelSince
;
late
final
StreamSubscription
<
McuReportChangedEvent
>
_mcuReportSub
;
late
final
StreamSubscription
<
McuReportChangedEvent
>
_mcuReportSub
;
late
final
StreamSubscription
<
BluetoothDataPacket
>
_bluetoothDataSub
;
late
final
StreamSubscription
<
BluetoothDataPacket
>
_bluetoothDataSub
;
Timer
?
_oxygenTimer
;
/// 上次设备告警分发时间(30s 防抖)
/// 上次设备告警分发时间(30s 防抖)
DateTime
?
_lastAlarmDispatchTime
;
DateTime
?
_lastAlarmDispatchTime
;
...
@@ -269,6 +270,7 @@ class DeviceControlBloc
...
@@ -269,6 +270,7 @@ class DeviceControlBloc
),
),
);
);
emit
(
state
.
copyWith
(
data:
newData
,
clearError:
true
));
emit
(
state
.
copyWith
(
data:
newData
,
clearError:
true
));
_syncLocalOxygenTimer
(
report
.
oxygenConcentration
);
// 异步分发:触发设备异常告警(MQTT 上行 + UI 通知)
// 异步分发:触发设备异常告警(MQTT 上行 + UI 通知)
_dispatchDeviceAlarm
(
newData
);
_dispatchDeviceAlarm
(
newData
);
...
@@ -903,6 +905,11 @@ class DeviceControlBloc
...
@@ -903,6 +905,11 @@ class DeviceControlBloc
DeviceControlOxygenTimerUpdated
event
,
DeviceControlOxygenTimerUpdated
event
,
Emitter
<
DeviceControlState
>
emit
,
Emitter
<
DeviceControlState
>
emit
,
)
{
)
{
final
totalSeconds
=
_oxygenTimerSecondsFromParts
(
event
.
hours
,
event
.
minutes
,
event
.
seconds
,
);
final
newData
=
state
.
data
.
copyWith
(
final
newData
=
state
.
data
.
copyWith
(
oxygenTimer:
state
.
data
.
oxygenTimer
.
copyWith
(
oxygenTimer:
state
.
data
.
oxygenTimer
.
copyWith
(
hours:
event
.
hours
,
hours:
event
.
hours
,
...
@@ -910,7 +917,14 @@ class DeviceControlBloc
...
@@ -910,7 +917,14 @@ class DeviceControlBloc
seconds:
event
.
seconds
,
seconds:
event
.
seconds
,
),
),
);
);
emit
(
state
.
copyWith
(
data:
newData
,
clearError:
true
));
final
newUserSettings
=
state
.
userSettings
.
copyWith
(
oxygenTimerSeconds:
totalSeconds
,
);
emit
(
state
.
copyWith
(
data:
newData
,
userSettings:
newUserSettings
,
clearError:
true
,
));
}
}
/// [用户操作] 清零供氧计时
/// [用户操作] 清零供氧计时
...
@@ -925,7 +939,14 @@ class DeviceControlBloc
...
@@ -925,7 +939,14 @@ class DeviceControlBloc
seconds:
'00'
,
seconds:
'00'
,
),
),
);
);
emit
(
state
.
copyWith
(
data:
newData
,
clearError:
true
));
final
newUserSettings
=
state
.
userSettings
.
copyWith
(
oxygenTimerSeconds:
0
,
);
emit
(
state
.
copyWith
(
data:
newData
,
userSettings:
newUserSettings
,
clearError:
true
,
));
await
_writeControlValueToBluetooth
(
await
_writeControlValueToBluetooth
(
identifier:
0x29
,
identifier:
0x29
,
setValue:
'0'
,
setValue:
'0'
,
...
@@ -1045,13 +1066,128 @@ class DeviceControlBloc
...
@@ -1045,13 +1066,128 @@ class DeviceControlBloc
emit
(
state
.
copyWith
(
data:
newData
,
clearError:
true
));
emit
(
state
.
copyWith
(
data:
newData
,
clearError:
true
));
}
}
/// [用户操作]
重置设备设置为默认值 —— 清除持久化
/// [用户操作]
关闭所有可关闭控制并按 300ms 间隔下发
void
_onResetSettings
(
Future
<
void
>
_onResetSettings
(
DeviceControlResetSettings
event
,
DeviceControlResetSettings
event
,
Emitter
<
DeviceControlState
>
emit
,
Emitter
<
DeviceControlState
>
emit
,
)
{
)
async
{
emit
(
const
DeviceControlState
());
final
newData
=
state
.
data
.
copyWith
(
// TODO: 发送重置指令到MCU
cabinTemp:
state
.
data
.
cabinTemp
.
copyWith
(
isOn:
false
),
cabinHumidity:
state
.
data
.
cabinHumidity
.
copyWith
(
isOn:
false
),
oxygenConcentration:
state
.
data
.
oxygenConcentration
.
copyWith
(
isOn:
false
,
setValue:
_clampIntString
(
state
.
data
.
oxygenConcentration
.
setValue
,
0
,
60
,
),
),
openOxygen:
state
.
data
.
openOxygen
.
copyWith
(
isOn:
false
),
windSpeed:
state
.
data
.
windSpeed
.
copyWith
(
currentMode:
WindSpeedMode
.
off
),
nebulizationTime:
state
.
data
.
nebulizationTime
.
copyWith
(
setMinutes:
'0'
),
disinfectionTime:
state
.
data
.
disinfectionTime
.
copyWith
(
setMinutes:
'0'
),
careLevel:
state
.
data
.
careLevel
.
copyWith
(
currentLevel:
CareLevel
.
off
),
lightControl:
state
.
data
.
lightControl
.
copyWith
(
checkLightOn:
false
,
illuminationOn:
false
,
blueLightOn:
false
,
redLightOn:
false
,
),
);
final
newUserSettings
=
state
.
userSettings
.
copyWith
(
cabinTempIsOn:
false
,
cabinHumidityIsOn:
false
,
oxygenConcentrationIsOn:
false
,
oxygenConcentrationSetValue:
newData
.
oxygenConcentration
.
setValue
,
openOxygenIsOn:
false
,
windSpeedModeValue:
WindSpeedMode
.
off
,
nebulizationTimeMinutes:
'0'
,
disinfectionTimeMinutes:
'0'
,
careLevelValue:
CareLevel
.
off
,
checkLightOn:
false
,
illuminationOn:
false
,
blueLightOn:
false
,
redLightOn:
false
,
);
emit
(
state
.
copyWith
(
data:
newData
,
userSettings:
newUserSettings
,
clearError:
true
,
));
await
_writeResetCommandWithDelay
(
identifier:
0x02
,
setValue:
'10'
,
errorPrefix:
'舱内温度关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
0x04
,
setValue:
'100'
,
errorPrefix:
'舱内湿度关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
0x05
,
setValue:
'20'
,
errorPrefix:
'氧气浓度关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
0x26
,
setValue:
'0'
,
errorPrefix:
'开放供氧关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
0xB3
,
setValue:
'
${_windSpeedProtocolValue(WindSpeedMode.off)}
'
,
errorPrefix:
'风速关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
0x0C
,
setValue:
'0'
,
errorPrefix:
'雾化关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
0x0D
,
setValue:
'0'
,
errorPrefix:
'消毒关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
0xA8
,
setValue:
'
${_careLevelProtocolValue(CareLevel.off)}
'
,
errorPrefix:
'护理等级关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
_lightIdentifier
(
_LightTarget
.
check
),
setValue:
'0'
,
errorPrefix:
'检查灯关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
_lightIdentifier
(
_LightTarget
.
illumination
),
setValue:
'0'
,
errorPrefix:
'照明灯关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
_lightIdentifier
(
_LightTarget
.
blue
),
setValue:
'0'
,
errorPrefix:
'蓝光关闭'
,
emit:
emit
,
);
await
_writeResetCommandWithDelay
(
identifier:
_lightIdentifier
(
_LightTarget
.
red
),
setValue:
'0'
,
errorPrefix:
'红光关闭'
,
emit:
emit
,
delayAfter:
false
,
);
}
}
int
get
_oxygenSetValueMax
=>
state
.
data
.
openOxygen
.
isOn
?
80
:
60
;
int
get
_oxygenSetValueMax
=>
state
.
data
.
openOxygen
.
isOn
?
80
:
60
;
...
@@ -1099,6 +1235,60 @@ class DeviceControlBloc
...
@@ -1099,6 +1235,60 @@ class DeviceControlBloc
return
'
${parsed.clamp(min, max)}
'
;
return
'
${parsed.clamp(min, max)}
'
;
}
}
void
_syncLocalOxygenTimer
(
int
oxygenConcentration
)
{
if
(
oxygenConcentration
>=
30
)
{
_oxygenTimer
??=
Timer
.
periodic
(
const
Duration
(
seconds:
1
),
(
_
)
{
if
(
isClosed
)
return
;
final
totalSeconds
=
_currentOxygenTimerSeconds
()
+
1
;
final
timer
=
_oxygenTimerFromSeconds
(
totalSeconds
);
add
(
DeviceControlOxygenTimerUpdated
(
timer
.
hours
,
timer
.
minutes
,
timer
.
seconds
,
));
});
return
;
}
_stopLocalOxygenTimer
();
}
int
_currentOxygenTimerSeconds
()
{
return
state
.
userSettings
.
oxygenTimerSeconds
??
_oxygenTimerSecondsFromParts
(
state
.
data
.
oxygenTimer
.
hours
,
state
.
data
.
oxygenTimer
.
minutes
,
state
.
data
.
oxygenTimer
.
seconds
,
);
}
int
_oxygenTimerSecondsFromParts
(
String
hours
,
String
minutes
,
String
seconds
,
)
{
final
parsedHours
=
int
.
tryParse
(
hours
)
??
0
;
final
parsedMinutes
=
int
.
tryParse
(
minutes
)
??
0
;
final
parsedSeconds
=
int
.
tryParse
(
seconds
)
??
0
;
return
parsedHours
*
3600
+
parsedMinutes
*
60
+
parsedSeconds
;
}
OxygenTimerBO
_oxygenTimerFromSeconds
(
int
totalSeconds
)
{
final
safeSeconds
=
totalSeconds
<
0
?
0
:
totalSeconds
;
final
hours
=
safeSeconds
~/
3600
;
final
minutes
=
(
safeSeconds
%
3600
)
~/
60
;
final
seconds
=
safeSeconds
%
60
;
return
OxygenTimerBO
(
hours:
hours
.
toString
().
padLeft
(
2
,
'0'
),
minutes:
minutes
.
toString
().
padLeft
(
2
,
'0'
),
seconds:
seconds
.
toString
().
padLeft
(
2
,
'0'
),
);
}
void
_stopLocalOxygenTimer
()
{
_oxygenTimer
?.
cancel
();
_oxygenTimer
=
null
;
}
Future
<
void
>
_setExclusiveLight
({
Future
<
void
>
_setExclusiveLight
({
required
_LightTarget
target
,
required
_LightTarget
target
,
required
bool
isOn
,
required
bool
isOn
,
...
@@ -1306,6 +1496,24 @@ class DeviceControlBloc
...
@@ -1306,6 +1496,24 @@ class DeviceControlBloc
);
);
}
}
Future
<
void
>
_writeResetCommandWithDelay
({
required
int
identifier
,
required
String
setValue
,
required
String
errorPrefix
,
required
Emitter
<
DeviceControlState
>
emit
,
bool
delayAfter
=
true
,
})
async
{
await
_writeControlValueToBluetooth
(
identifier:
identifier
,
setValue:
setValue
,
errorPrefix:
errorPrefix
,
emit:
emit
,
);
if
(
delayAfter
&&
!
isClosed
)
{
await
Future
<
void
>.
delayed
(
const
Duration
(
milliseconds:
300
));
}
}
int
_windSpeedProtocolValue
(
WindSpeedMode
mode
)
{
int
_windSpeedProtocolValue
(
WindSpeedMode
mode
)
{
switch
(
mode
)
{
switch
(
mode
)
{
case
WindSpeedMode
.
off
:
case
WindSpeedMode
.
off
:
...
@@ -1421,6 +1629,7 @@ class DeviceControlBloc
...
@@ -1421,6 +1629,7 @@ class DeviceControlBloc
@override
@override
Future
<
void
>
close
()
async
{
Future
<
void
>
close
()
async
{
_stopLocalOxygenTimer
();
await
_mcuReportSub
.
cancel
();
await
_mcuReportSub
.
cancel
();
await
_bluetoothDataSub
.
cancel
();
await
_bluetoothDataSub
.
cancel
();
return
super
.
close
();
return
super
.
close
();
...
...
lib/main.dart
View file @
0f9cb2e3
...
@@ -29,10 +29,18 @@ import 'package:flutter_ume_kit_dio_plus/flutter_ume_kit_dio_plus.dart';
...
@@ -29,10 +29,18 @@ import 'package:flutter_ume_kit_dio_plus/flutter_ume_kit_dio_plus.dart';
import
'package:flutter_ume_kit_ui_plus/flutter_ume_kit_ui_plus.dart'
;
import
'package:flutter_ume_kit_ui_plus/flutter_ume_kit_ui_plus.dart'
;
import
'package:laki_icu_app/blocs/device_control/device_control_bloc.dart'
;
import
'package:laki_icu_app/blocs/device_control/device_control_bloc.dart'
;
import
'package:laki_icu_app/blocs/device_calibration_config/device_calibration_config.dart'
;
import
'package:laki_icu_app/blocs/device_threshold_config/device_threshold_config.dart'
;
import
'package:laki_icu_app/blocs/device_threshold_config/device_threshold_config.dart'
;
import
'package:marionette_flutter/marionette_flutter.dart'
;
import
'package:marionette_flutter/marionette_flutter.dart'
;
Future
<
void
>
main
(
List
<
String
>
args
)
async
{
Future
<
void
>
main
(
List
<
String
>
args
)
async
{
if
(
kDebugMode
)
{
// MarionetteBinding 继承自 WidgetsFlutterBinding,必须最先且唯一初始化
MarionetteBinding
.
ensureInitialized
();
}
else
{
WidgetsFlutterBinding
.
ensureInitialized
();
}
// 初始化 HydratedBloc 存储(用于持久化设备控制用户设置等)
// 初始化 HydratedBloc 存储(用于持久化设备控制用户设置等)
final
storageDirectory
=
await
getApplicationDocumentsDirectory
();
final
storageDirectory
=
await
getApplicationDocumentsDirectory
();
HydratedBloc
.
storage
=
await
HydratedStorage
.
build
(
HydratedBloc
.
storage
=
await
HydratedStorage
.
build
(
...
@@ -41,9 +49,6 @@ Future<void> main(List<String> args) async {
...
@@ -41,9 +49,6 @@ Future<void> main(List<String> args) async {
// UME 调试工具(仅 Debug 模式启用)
// UME 调试工具(仅 Debug 模式启用)
if
(
kDebugMode
)
{
if
(
kDebugMode
)
{
// MarionetteBinding 继承自 WidgetsFlutterBinding,必须最先且唯一初始化
MarionetteBinding
.
ensureInitialized
();
PluginManager
.
instance
PluginManager
.
instance
..
register
(
WidgetInfoInspector
())
..
register
(
WidgetInfoInspector
())
..
register
(
WidgetDetailInspector
())
..
register
(
WidgetDetailInspector
())
...
@@ -54,8 +59,6 @@ Future<void> main(List<String> args) async {
...
@@ -54,8 +59,6 @@ Future<void> main(List<String> args) async {
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
manual
,
overlays:
[]);
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
manual
,
overlays:
[]);
runApp
(
UMEWidget
(
enable:
true
,
child:
const
MyApp
()));
runApp
(
UMEWidget
(
enable:
true
,
child:
const
MyApp
()));
}
else
{
}
else
{
WidgetsFlutterBinding
.
ensureInitialized
();
// 全局全屏:隐藏系统状态栏和底部导航栏
// 全局全屏:隐藏系统状态栏和底部导航栏
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
manual
,
overlays:
[]);
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
manual
,
overlays:
[]);
runApp
(
const
MyApp
());
runApp
(
const
MyApp
());
...
@@ -78,6 +81,7 @@ class _MyAppState extends State<MyApp> {
...
@@ -78,6 +81,7 @@ class _MyAppState extends State<MyApp> {
late
final
AuthBloc
_authBloc
;
late
final
AuthBloc
_authBloc
;
BluetoothReadBloc
?
_bluetoothReadBloc
;
BluetoothReadBloc
?
_bluetoothReadBloc
;
DeviceControlBloc
?
_deviceControlBloc
;
DeviceControlBloc
?
_deviceControlBloc
;
DeviceCalibrationConfigBloc
?
_deviceCalibrationConfigBloc
;
DeviceThresholdConfigBloc
?
_deviceThresholdConfigBloc
;
DeviceThresholdConfigBloc
?
_deviceThresholdConfigBloc
;
StreamSubscription
?
_tokenExpiredSubscription
;
StreamSubscription
?
_tokenExpiredSubscription
;
bool
_isInitializing
=
true
;
bool
_isInitializing
=
true
;
...
@@ -101,6 +105,15 @@ class _MyAppState extends State<MyApp> {
...
@@ -101,6 +105,15 @@ class _MyAppState extends State<MyApp> {
return
_deviceThresholdConfigBloc
!;
return
_deviceThresholdConfigBloc
!;
}
}
DeviceCalibrationConfigBloc
get
_deviceCalibrationConfigBlocInstance
{
if
(
_deviceCalibrationConfigBloc
!=
null
)
{
return
_deviceCalibrationConfigBloc
!;
}
_deviceCalibrationConfigBloc
=
DeviceCalibrationConfigBloc
();
globalDeviceCalibrationConfigBloc
=
_deviceCalibrationConfigBloc
;
return
_deviceCalibrationConfigBloc
!;
}
@override
@override
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
...
@@ -169,6 +182,7 @@ class _MyAppState extends State<MyApp> {
...
@@ -169,6 +182,7 @@ class _MyAppState extends State<MyApp> {
_authBloc
.
close
();
_authBloc
.
close
();
_bluetoothReadBloc
?.
close
();
_bluetoothReadBloc
?.
close
();
_deviceControlBloc
?.
close
();
_deviceControlBloc
?.
close
();
_deviceCalibrationConfigBloc
?.
close
();
_deviceThresholdConfigBloc
?.
close
();
_deviceThresholdConfigBloc
?.
close
();
super
.
dispose
();
super
.
dispose
();
}
}
...
@@ -187,6 +201,9 @@ class _MyAppState extends State<MyApp> {
...
@@ -187,6 +201,9 @@ class _MyAppState extends State<MyApp> {
BlocProvider
<
DeviceControlBloc
>.
value
(
BlocProvider
<
DeviceControlBloc
>.
value
(
value:
_deviceControlBlocInstance
,
value:
_deviceControlBlocInstance
,
),
),
BlocProvider
<
DeviceCalibrationConfigBloc
>.
value
(
value:
_deviceCalibrationConfigBlocInstance
,
),
BlocProvider
<
DeviceThresholdConfigBloc
>.
value
(
BlocProvider
<
DeviceThresholdConfigBloc
>.
value
(
value:
_deviceThresholdConfigBlocInstance
,
value:
_deviceThresholdConfigBlocInstance
,
),
),
...
@@ -200,8 +217,8 @@ class _MyAppState extends State<MyApp> {
...
@@ -200,8 +217,8 @@ class _MyAppState extends State<MyApp> {
debugShowCheckedModeBanner:
false
,
debugShowCheckedModeBanner:
false
,
builder:
(
context
,
child
)
{
builder:
(
context
,
child
)
{
// 每次页面重建时重新隐藏状态栏,防止路由切换后状态栏重新出现
// 每次页面重建时重新隐藏状态栏,防止路由切换后状态栏重新出现
SystemChrome
.
setEnabledSystemUIMode
(
SystemChrome
.
setEnabledSystemUIMode
(
SystemUiMode
.
manual
,
SystemUiMode
.
manual
,
overlays:
[]);
overlays:
[]);
return
child
??
const
SizedBox
.
shrink
();
return
child
??
const
SizedBox
.
shrink
();
},
},
),
),
...
...
lib/models/bo/device_calibration_config_bo.dart
0 → 100644
View file @
0f9cb2e3
import
'package:equatable/equatable.dart'
;
/// 用途:设备校准参数配置
/// 涉及页面:工厂设置-设备校准页面
class
DeviceCalibrationConfigBO
extends
Equatable
{
/// 温度系数%S1(上)
final
int
tempCoefficientS1Upper
;
/// 温度系数%S1(下)
final
int
tempCoefficientS1Lower
;
/// 环境温度冬夏临界值T0
final
int
ambientTempSeasonThresholdT0
;
/// 摄像头循环重启(分钟)
final
int
cameraLoopRestartMinutes
;
/// 摄像头定时重启(小时)
final
int
cameraScheduledRestartHours
;
/// CO2最低设置值C1
final
int
co2MinSettingC1
;
/// CO2差值C2
final
int
co2DifferenceC2
;
/// CO2基准值C3
final
int
co2BaseValueC3
;
/// CO2系数C4
final
int
co2CoefficientC4
;
/// 密闭舱氧气修正点X0
final
int
closedCabinOxygenCorrectionPointX0
;
/// 密闭舱氧气修正幅度X1
final
int
closedCabinOxygenCorrectionRangeX1
;
/// 密闭舱氧气修正步进值X4
final
int
closedCabinOxygenCorrectionStepX4
;
/// 开放式供氧氧气修正点S0
final
int
openOxygenCorrectionPointS0
;
/// 开放式供氧氧气修正幅度S1
final
int
openOxygenCorrectionRangeS1
;
/// 开放式供氧氧气修正步进值S4
final
int
openOxygenCorrectionStepS4
;
const
DeviceCalibrationConfigBO
({
required
this
.
tempCoefficientS1Upper
,
required
this
.
tempCoefficientS1Lower
,
required
this
.
ambientTempSeasonThresholdT0
,
required
this
.
cameraLoopRestartMinutes
,
required
this
.
cameraScheduledRestartHours
,
required
this
.
co2MinSettingC1
,
required
this
.
co2DifferenceC2
,
required
this
.
co2BaseValueC3
,
required
this
.
co2CoefficientC4
,
required
this
.
closedCabinOxygenCorrectionPointX0
,
required
this
.
closedCabinOxygenCorrectionRangeX1
,
required
this
.
closedCabinOxygenCorrectionStepX4
,
required
this
.
openOxygenCorrectionPointS0
,
required
this
.
openOxygenCorrectionRangeS1
,
required
this
.
openOxygenCorrectionStepS4
,
});
static
const
DeviceCalibrationConfigBO
defaultConfig
=
DeviceCalibrationConfigBO
(
tempCoefficientS1Upper:
17
,
tempCoefficientS1Lower:
34
,
ambientTempSeasonThresholdT0:
17
,
cameraLoopRestartMinutes:
34
,
cameraScheduledRestartHours:
17
,
co2MinSettingC1:
4000
,
co2DifferenceC2:
2000
,
co2BaseValueC3:
1500
,
co2CoefficientC4:
34
,
closedCabinOxygenCorrectionPointX0:
17
,
closedCabinOxygenCorrectionRangeX1:
34
,
closedCabinOxygenCorrectionStepX4:
17
,
openOxygenCorrectionPointS0:
34
,
openOxygenCorrectionRangeS1:
17
,
openOxygenCorrectionStepS4:
17
,
);
List
<
DeviceCalibrationSectionBO
>
get
sections
=>
[
DeviceCalibrationSectionBO
(
title:
'主温度调节系数'
,
items:
[
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
tempCoefficientS1Upper
,
label:
'温度系数%S1(上):'
,
value:
tempCoefficientS1Upper
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
tempCoefficientS1Lower
,
label:
'温度系数%S1(下):'
,
value:
tempCoefficientS1Lower
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
ambientTempSeasonThresholdT0
,
label:
'环境温度冬夏临界值T0:'
,
value:
ambientTempSeasonThresholdT0
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
cameraLoopRestartMinutes
,
label:
'摄像头循环重启(分钟):'
,
value:
cameraLoopRestartMinutes
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
cameraScheduledRestartHours
,
label:
'摄像头定时重启(小时):'
,
value:
cameraScheduledRestartHours
,
),
],
),
DeviceCalibrationSectionBO
(
title:
'CO₂报警及净化修正值'
,
items:
[
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
co2MinSettingC1
,
label:
'CO₂最低设置值C1:'
,
value:
co2MinSettingC1
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
co2DifferenceC2
,
label:
'CO₂差值C2:'
,
value:
co2DifferenceC2
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
co2BaseValueC3
,
label:
'CO₂基准值C3:'
,
value:
co2BaseValueC3
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
co2CoefficientC4
,
label:
'CO₂系数C4:'
,
value:
co2CoefficientC4
,
),
],
),
DeviceCalibrationSectionBO
(
title:
'密闭舱氧气修正值'
,
items:
[
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
closedCabinOxygenCorrectionPointX0
,
label:
'密闭舱氧气修正点X0:'
,
value:
closedCabinOxygenCorrectionPointX0
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
closedCabinOxygenCorrectionRangeX1
,
label:
'密闭舱氧气修正幅度X1:'
,
value:
closedCabinOxygenCorrectionRangeX1
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
closedCabinOxygenCorrectionStepX4
,
label:
'密闭舱氧气修正步进值X4:'
,
value:
closedCabinOxygenCorrectionStepX4
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
openOxygenCorrectionPointS0
,
label:
'开放式供氧氧气修正点S0:'
,
value:
openOxygenCorrectionPointS0
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
openOxygenCorrectionRangeS1
,
label:
'开放式供氧氧气修正幅度S1:'
,
value:
openOxygenCorrectionRangeS1
,
),
DeviceCalibrationItemBO
(
key:
DeviceCalibrationItemKey
.
openOxygenCorrectionStepS4
,
label:
'开放式供氧氧气修正步进值S4:'
,
value:
openOxygenCorrectionStepS4
,
),
],
),
];
DeviceCalibrationConfigBO
copyWith
({
int
?
tempCoefficientS1Upper
,
int
?
tempCoefficientS1Lower
,
int
?
ambientTempSeasonThresholdT0
,
int
?
cameraLoopRestartMinutes
,
int
?
cameraScheduledRestartHours
,
int
?
co2MinSettingC1
,
int
?
co2DifferenceC2
,
int
?
co2BaseValueC3
,
int
?
co2CoefficientC4
,
int
?
closedCabinOxygenCorrectionPointX0
,
int
?
closedCabinOxygenCorrectionRangeX1
,
int
?
closedCabinOxygenCorrectionStepX4
,
int
?
openOxygenCorrectionPointS0
,
int
?
openOxygenCorrectionRangeS1
,
int
?
openOxygenCorrectionStepS4
,
})
{
return
DeviceCalibrationConfigBO
(
tempCoefficientS1Upper:
tempCoefficientS1Upper
??
this
.
tempCoefficientS1Upper
,
tempCoefficientS1Lower:
tempCoefficientS1Lower
??
this
.
tempCoefficientS1Lower
,
ambientTempSeasonThresholdT0:
ambientTempSeasonThresholdT0
??
this
.
ambientTempSeasonThresholdT0
,
cameraLoopRestartMinutes:
cameraLoopRestartMinutes
??
this
.
cameraLoopRestartMinutes
,
cameraScheduledRestartHours:
cameraScheduledRestartHours
??
this
.
cameraScheduledRestartHours
,
co2MinSettingC1:
co2MinSettingC1
??
this
.
co2MinSettingC1
,
co2DifferenceC2:
co2DifferenceC2
??
this
.
co2DifferenceC2
,
co2BaseValueC3:
co2BaseValueC3
??
this
.
co2BaseValueC3
,
co2CoefficientC4:
co2CoefficientC4
??
this
.
co2CoefficientC4
,
closedCabinOxygenCorrectionPointX0:
closedCabinOxygenCorrectionPointX0
??
this
.
closedCabinOxygenCorrectionPointX0
,
closedCabinOxygenCorrectionRangeX1:
closedCabinOxygenCorrectionRangeX1
??
this
.
closedCabinOxygenCorrectionRangeX1
,
closedCabinOxygenCorrectionStepX4:
closedCabinOxygenCorrectionStepX4
??
this
.
closedCabinOxygenCorrectionStepX4
,
openOxygenCorrectionPointS0:
openOxygenCorrectionPointS0
??
this
.
openOxygenCorrectionPointS0
,
openOxygenCorrectionRangeS1:
openOxygenCorrectionRangeS1
??
this
.
openOxygenCorrectionRangeS1
,
openOxygenCorrectionStepS4:
openOxygenCorrectionStepS4
??
this
.
openOxygenCorrectionStepS4
,
);
}
DeviceCalibrationConfigBO
updateItem
(
DeviceCalibrationItemKey
key
,
int
value
,
)
{
switch
(
key
)
{
case
DeviceCalibrationItemKey
.
tempCoefficientS1Upper
:
return
copyWith
(
tempCoefficientS1Upper:
value
);
case
DeviceCalibrationItemKey
.
tempCoefficientS1Lower
:
return
copyWith
(
tempCoefficientS1Lower:
value
);
case
DeviceCalibrationItemKey
.
ambientTempSeasonThresholdT0
:
return
copyWith
(
ambientTempSeasonThresholdT0:
value
);
case
DeviceCalibrationItemKey
.
cameraLoopRestartMinutes
:
return
copyWith
(
cameraLoopRestartMinutes:
value
);
case
DeviceCalibrationItemKey
.
cameraScheduledRestartHours
:
return
copyWith
(
cameraScheduledRestartHours:
value
);
case
DeviceCalibrationItemKey
.
co2MinSettingC1
:
return
copyWith
(
co2MinSettingC1:
value
);
case
DeviceCalibrationItemKey
.
co2DifferenceC2
:
return
copyWith
(
co2DifferenceC2:
value
);
case
DeviceCalibrationItemKey
.
co2BaseValueC3
:
return
copyWith
(
co2BaseValueC3:
value
);
case
DeviceCalibrationItemKey
.
co2CoefficientC4
:
return
copyWith
(
co2CoefficientC4:
value
);
case
DeviceCalibrationItemKey
.
closedCabinOxygenCorrectionPointX0
:
return
copyWith
(
closedCabinOxygenCorrectionPointX0:
value
);
case
DeviceCalibrationItemKey
.
closedCabinOxygenCorrectionRangeX1
:
return
copyWith
(
closedCabinOxygenCorrectionRangeX1:
value
);
case
DeviceCalibrationItemKey
.
closedCabinOxygenCorrectionStepX4
:
return
copyWith
(
closedCabinOxygenCorrectionStepX4:
value
);
case
DeviceCalibrationItemKey
.
openOxygenCorrectionPointS0
:
return
copyWith
(
openOxygenCorrectionPointS0:
value
);
case
DeviceCalibrationItemKey
.
openOxygenCorrectionRangeS1
:
return
copyWith
(
openOxygenCorrectionRangeS1:
value
);
case
DeviceCalibrationItemKey
.
openOxygenCorrectionStepS4
:
return
copyWith
(
openOxygenCorrectionStepS4:
value
);
}
}
factory
DeviceCalibrationConfigBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
DeviceCalibrationConfigBO
(
tempCoefficientS1Upper:
json
[
'tempCoefficientS1Upper'
]
as
int
?
??
17
,
tempCoefficientS1Lower:
json
[
'tempCoefficientS1Lower'
]
as
int
?
??
34
,
ambientTempSeasonThresholdT0:
json
[
'ambientTempSeasonThresholdT0'
]
as
int
?
??
17
,
cameraLoopRestartMinutes:
json
[
'cameraLoopRestartMinutes'
]
as
int
?
??
34
,
cameraScheduledRestartHours:
json
[
'cameraScheduledRestartHours'
]
as
int
?
??
17
,
co2MinSettingC1:
json
[
'co2MinSettingC1'
]
as
int
?
??
4000
,
co2DifferenceC2:
json
[
'co2DifferenceC2'
]
as
int
?
??
2000
,
co2BaseValueC3:
json
[
'co2BaseValueC3'
]
as
int
?
??
1500
,
co2CoefficientC4:
json
[
'co2CoefficientC4'
]
as
int
?
??
34
,
closedCabinOxygenCorrectionPointX0:
json
[
'closedCabinOxygenCorrectionPointX0'
]
as
int
?
??
17
,
closedCabinOxygenCorrectionRangeX1:
json
[
'closedCabinOxygenCorrectionRangeX1'
]
as
int
?
??
34
,
closedCabinOxygenCorrectionStepX4:
json
[
'closedCabinOxygenCorrectionStepX4'
]
as
int
?
??
17
,
openOxygenCorrectionPointS0:
json
[
'openOxygenCorrectionPointS0'
]
as
int
?
??
34
,
openOxygenCorrectionRangeS1:
json
[
'openOxygenCorrectionRangeS1'
]
as
int
?
??
17
,
openOxygenCorrectionStepS4:
json
[
'openOxygenCorrectionStepS4'
]
as
int
?
??
17
,
);
}
Map
<
String
,
dynamic
>
toJson
()
{
return
{
'tempCoefficientS1Upper'
:
tempCoefficientS1Upper
,
'tempCoefficientS1Lower'
:
tempCoefficientS1Lower
,
'ambientTempSeasonThresholdT0'
:
ambientTempSeasonThresholdT0
,
'cameraLoopRestartMinutes'
:
cameraLoopRestartMinutes
,
'cameraScheduledRestartHours'
:
cameraScheduledRestartHours
,
'co2MinSettingC1'
:
co2MinSettingC1
,
'co2DifferenceC2'
:
co2DifferenceC2
,
'co2BaseValueC3'
:
co2BaseValueC3
,
'co2CoefficientC4'
:
co2CoefficientC4
,
'closedCabinOxygenCorrectionPointX0'
:
closedCabinOxygenCorrectionPointX0
,
'closedCabinOxygenCorrectionRangeX1'
:
closedCabinOxygenCorrectionRangeX1
,
'closedCabinOxygenCorrectionStepX4'
:
closedCabinOxygenCorrectionStepX4
,
'openOxygenCorrectionPointS0'
:
openOxygenCorrectionPointS0
,
'openOxygenCorrectionRangeS1'
:
openOxygenCorrectionRangeS1
,
'openOxygenCorrectionStepS4'
:
openOxygenCorrectionStepS4
,
};
}
@override
List
<
Object
?>
get
props
=>
[
tempCoefficientS1Upper
,
tempCoefficientS1Lower
,
ambientTempSeasonThresholdT0
,
cameraLoopRestartMinutes
,
cameraScheduledRestartHours
,
co2MinSettingC1
,
co2DifferenceC2
,
co2BaseValueC3
,
co2CoefficientC4
,
closedCabinOxygenCorrectionPointX0
,
closedCabinOxygenCorrectionRangeX1
,
closedCabinOxygenCorrectionStepX4
,
openOxygenCorrectionPointS0
,
openOxygenCorrectionRangeS1
,
openOxygenCorrectionStepS4
,
];
}
class
DeviceCalibrationSectionBO
extends
Equatable
{
const
DeviceCalibrationSectionBO
({
required
this
.
title
,
required
this
.
items
,
});
final
String
title
;
final
List
<
DeviceCalibrationItemBO
>
items
;
@override
List
<
Object
?>
get
props
=>
[
title
,
items
];
}
class
DeviceCalibrationItemBO
extends
Equatable
{
const
DeviceCalibrationItemBO
({
required
this
.
key
,
required
this
.
label
,
required
this
.
value
,
});
final
DeviceCalibrationItemKey
key
;
final
String
label
;
final
int
value
;
@override
List
<
Object
?>
get
props
=>
[
key
,
label
,
value
];
}
enum
DeviceCalibrationItemKey
{
tempCoefficientS1Upper
,
tempCoefficientS1Lower
,
ambientTempSeasonThresholdT0
,
cameraLoopRestartMinutes
,
cameraScheduledRestartHours
,
co2MinSettingC1
,
co2DifferenceC2
,
co2BaseValueC3
,
co2CoefficientC4
,
closedCabinOxygenCorrectionPointX0
,
closedCabinOxygenCorrectionRangeX1
,
closedCabinOxygenCorrectionStepX4
,
openOxygenCorrectionPointS0
,
openOxygenCorrectionRangeS1
,
openOxygenCorrectionStepS4
,
}
lib/models/bo/device_control_bo.dart
View file @
0f9cb2e3
...
@@ -801,6 +801,9 @@ class DeviceControlUserSettings extends Equatable {
...
@@ -801,6 +801,9 @@ class DeviceControlUserSettings extends Equatable {
/// 开放供氧开关
/// 开放供氧开关
final
bool
?
openOxygenIsOn
;
final
bool
?
openOxygenIsOn
;
/// 本地供氧计时秒数
final
int
?
oxygenTimerSeconds
;
/// 循环模式
/// 循环模式
final
CirculationMode
?
circulationModeValue
;
final
CirculationMode
?
circulationModeValue
;
...
@@ -831,6 +834,7 @@ class DeviceControlUserSettings extends Equatable {
...
@@ -831,6 +834,7 @@ class DeviceControlUserSettings extends Equatable {
this
.
nebulizationTimeMinutes
,
this
.
nebulizationTimeMinutes
,
this
.
disinfectionTimeMinutes
,
this
.
disinfectionTimeMinutes
,
this
.
openOxygenIsOn
,
this
.
openOxygenIsOn
,
this
.
oxygenTimerSeconds
,
this
.
circulationModeValue
,
this
.
circulationModeValue
,
this
.
checkLightOn
,
this
.
checkLightOn
,
this
.
illuminationOn
,
this
.
illuminationOn
,
...
@@ -853,6 +857,7 @@ class DeviceControlUserSettings extends Equatable {
...
@@ -853,6 +857,7 @@ class DeviceControlUserSettings extends Equatable {
String
?
nebulizationTimeMinutes
,
String
?
nebulizationTimeMinutes
,
String
?
disinfectionTimeMinutes
,
String
?
disinfectionTimeMinutes
,
bool
?
openOxygenIsOn
,
bool
?
openOxygenIsOn
,
int
?
oxygenTimerSeconds
,
CirculationMode
?
circulationModeValue
,
CirculationMode
?
circulationModeValue
,
bool
?
checkLightOn
,
bool
?
checkLightOn
,
bool
?
illuminationOn
,
bool
?
illuminationOn
,
...
@@ -879,6 +884,7 @@ class DeviceControlUserSettings extends Equatable {
...
@@ -879,6 +884,7 @@ class DeviceControlUserSettings extends Equatable {
disinfectionTimeMinutes:
disinfectionTimeMinutes:
disinfectionTimeMinutes
??
this
.
disinfectionTimeMinutes
,
disinfectionTimeMinutes
??
this
.
disinfectionTimeMinutes
,
openOxygenIsOn:
openOxygenIsOn
??
this
.
openOxygenIsOn
,
openOxygenIsOn:
openOxygenIsOn
??
this
.
openOxygenIsOn
,
oxygenTimerSeconds:
oxygenTimerSeconds
??
this
.
oxygenTimerSeconds
,
circulationModeValue:
circulationModeValue
??
this
.
circulationModeValue
,
circulationModeValue:
circulationModeValue
??
this
.
circulationModeValue
,
checkLightOn:
checkLightOn
??
this
.
checkLightOn
,
checkLightOn:
checkLightOn
??
this
.
checkLightOn
,
illuminationOn:
illuminationOn
??
this
.
illuminationOn
,
illuminationOn:
illuminationOn
??
this
.
illuminationOn
,
...
@@ -926,6 +932,9 @@ class DeviceControlUserSettings extends Equatable {
...
@@ -926,6 +932,9 @@ class DeviceControlUserSettings extends Equatable {
openOxygen:
openOxygenIsOn
!=
null
openOxygen:
openOxygenIsOn
!=
null
?
bo
.
openOxygen
.
copyWith
(
isOn:
openOxygenIsOn
)
?
bo
.
openOxygen
.
copyWith
(
isOn:
openOxygenIsOn
)
:
null
,
:
null
,
oxygenTimer:
oxygenTimerSeconds
!=
null
?
_oxygenTimerFromSeconds
(
oxygenTimerSeconds
!)
:
null
,
circulationMode:
circulationModeValue
!=
null
circulationMode:
circulationModeValue
!=
null
?
bo
.
circulationMode
.
copyWith
(
currentMode:
circulationModeValue
)
?
bo
.
circulationMode
.
copyWith
(
currentMode:
circulationModeValue
)
:
null
,
:
null
,
...
@@ -970,6 +979,7 @@ class DeviceControlUserSettings extends Equatable {
...
@@ -970,6 +979,7 @@ class DeviceControlUserSettings extends Equatable {
nebulizationTimeMinutes:
json
[
'nebulizationTimeMinutes'
]
as
String
?,
nebulizationTimeMinutes:
json
[
'nebulizationTimeMinutes'
]
as
String
?,
disinfectionTimeMinutes:
json
[
'disinfectionTimeMinutes'
]
as
String
?,
disinfectionTimeMinutes:
json
[
'disinfectionTimeMinutes'
]
as
String
?,
openOxygenIsOn:
json
[
'openOxygenIsOn'
]
as
bool
?,
openOxygenIsOn:
json
[
'openOxygenIsOn'
]
as
bool
?,
oxygenTimerSeconds:
json
[
'oxygenTimerSeconds'
]
as
int
?,
circulationModeValue:
json
[
'circulationModeValue'
]
!=
null
circulationModeValue:
json
[
'circulationModeValue'
]
!=
null
?
CirculationMode
.
values
.
firstWhere
(
?
CirculationMode
.
values
.
firstWhere
(
(
e
)
=>
e
.
name
==
json
[
'circulationModeValue'
]
as
String
,
(
e
)
=>
e
.
name
==
json
[
'circulationModeValue'
]
as
String
,
...
@@ -1006,6 +1016,7 @@ class DeviceControlUserSettings extends Equatable {
...
@@ -1006,6 +1016,7 @@ class DeviceControlUserSettings extends Equatable {
if
(
disinfectionTimeMinutes
!=
null
)
if
(
disinfectionTimeMinutes
!=
null
)
'disinfectionTimeMinutes'
:
disinfectionTimeMinutes
,
'disinfectionTimeMinutes'
:
disinfectionTimeMinutes
,
if
(
openOxygenIsOn
!=
null
)
'openOxygenIsOn'
:
openOxygenIsOn
,
if
(
openOxygenIsOn
!=
null
)
'openOxygenIsOn'
:
openOxygenIsOn
,
if
(
oxygenTimerSeconds
!=
null
)
'oxygenTimerSeconds'
:
oxygenTimerSeconds
,
if
(
circulationModeValue
!=
null
)
if
(
circulationModeValue
!=
null
)
'circulationModeValue'
:
circulationModeValue
!.
name
,
'circulationModeValue'
:
circulationModeValue
!.
name
,
if
(
checkLightOn
!=
null
)
'checkLightOn'
:
checkLightOn
,
if
(
checkLightOn
!=
null
)
'checkLightOn'
:
checkLightOn
,
...
@@ -1031,6 +1042,7 @@ class DeviceControlUserSettings extends Equatable {
...
@@ -1031,6 +1042,7 @@ class DeviceControlUserSettings extends Equatable {
nebulizationTimeMinutes
,
nebulizationTimeMinutes
,
disinfectionTimeMinutes
,
disinfectionTimeMinutes
,
openOxygenIsOn
,
openOxygenIsOn
,
oxygenTimerSeconds
,
circulationModeValue
,
circulationModeValue
,
checkLightOn
,
checkLightOn
,
illuminationOn
,
illuminationOn
,
...
@@ -1038,3 +1050,15 @@ class DeviceControlUserSettings extends Equatable {
...
@@ -1038,3 +1050,15 @@ class DeviceControlUserSettings extends Equatable {
redLightOn
,
redLightOn
,
];
];
}
}
OxygenTimerBO
_oxygenTimerFromSeconds
(
int
totalSeconds
)
{
final
safeSeconds
=
totalSeconds
<
0
?
0
:
totalSeconds
;
final
hours
=
safeSeconds
~/
3600
;
final
minutes
=
(
safeSeconds
%
3600
)
~/
60
;
final
seconds
=
safeSeconds
%
60
;
return
OxygenTimerBO
(
hours:
hours
.
toString
().
padLeft
(
2
,
'0'
),
minutes:
minutes
.
toString
().
padLeft
(
2
,
'0'
),
seconds:
seconds
.
toString
().
padLeft
(
2
,
'0'
),
);
}
lib/utils/numeric_keyboard.dart
View file @
0f9cb2e3
...
@@ -18,6 +18,8 @@ class NumericKeyboard extends StatefulWidget {
...
@@ -18,6 +18,8 @@ class NumericKeyboard extends StatefulWidget {
super
.
key
,
super
.
key
,
required
this
.
initialValue
,
required
this
.
initialValue
,
this
.
decimalEnabled
=
false
,
this
.
decimalEnabled
=
false
,
this
.
showCloseKey
=
false
,
this
.
closeKeyValue
,
this
.
onChanged
,
this
.
onChanged
,
this
.
onConfirm
,
this
.
onConfirm
,
});
});
...
@@ -28,6 +30,12 @@ class NumericKeyboard extends StatefulWidget {
...
@@ -28,6 +30,12 @@ class NumericKeyboard extends StatefulWidget {
/// 是否允许输入小数点(温度模式为 true)
/// 是否允许输入小数点(温度模式为 true)
final
bool
decimalEnabled
;
final
bool
decimalEnabled
;
/// 是否在键盘右下角显示关闭按钮
final
bool
showCloseKey
;
/// 点击关闭按钮时返回的值;为空则只关闭弹窗
final
String
?
closeKeyValue
;
/// 输入变化回调(可选)
/// 输入变化回调(可选)
final
ValueChanged
<
String
>?
onChanged
;
final
ValueChanged
<
String
>?
onChanged
;
...
@@ -45,6 +53,8 @@ class NumericKeyboard extends StatefulWidget {
...
@@ -45,6 +53,8 @@ class NumericKeyboard extends StatefulWidget {
BuildContext
context
,
{
BuildContext
context
,
{
String
initialValue
=
''
,
String
initialValue
=
''
,
bool
decimalEnabled
=
false
,
bool
decimalEnabled
=
false
,
bool
showCloseKey
=
false
,
String
?
closeKeyValue
,
})
{
})
{
return
showModalBottomSheet
<
String
>(
return
showModalBottomSheet
<
String
>(
context:
context
,
context:
context
,
...
@@ -54,6 +64,8 @@ class NumericKeyboard extends StatefulWidget {
...
@@ -54,6 +64,8 @@ class NumericKeyboard extends StatefulWidget {
builder:
(
_
)
=>
NumericKeyboard
(
builder:
(
_
)
=>
NumericKeyboard
(
initialValue:
initialValue
,
initialValue:
initialValue
,
decimalEnabled:
decimalEnabled
,
decimalEnabled:
decimalEnabled
,
showCloseKey:
showCloseKey
,
closeKeyValue:
closeKeyValue
,
),
),
);
);
}
}
...
@@ -92,6 +104,9 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
...
@@ -92,6 +104,9 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
Navigator
.
of
(
context
).
pop
(
_text
);
Navigator
.
of
(
context
).
pop
(
_text
);
}
}
return
;
// 不触发 onChanged 和后续 setState 中的 pop
return
;
// 不触发 onChanged 和后续 setState 中的 pop
case
'关闭'
:
Navigator
.
of
(
context
).
pop
(
widget
.
closeKeyValue
);
return
;
case
'.'
:
case
'.'
:
if
(!
widget
.
decimalEnabled
||
_hasDecimal
)
return
;
if
(!
widget
.
decimalEnabled
||
_hasDecimal
)
return
;
if
(
_text
.
isEmpty
)
{
if
(
_text
.
isEmpty
)
{
...
@@ -249,7 +264,7 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
...
@@ -249,7 +264,7 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
Widget
_buildKeypad
()
{
Widget
_buildKeypad
()
{
// 按键定义:行列表,每行包含(标签, 宽度比例, 颜色类型)
// 按键定义:行列表,每行包含(标签, 宽度比例, 颜色类型)
final
key
s
=
<
List
<
_KeyDef
>>[
final
topRow
s
=
<
List
<
_KeyDef
>>[
[
[
const
_KeyDef
(
'1'
,
1
),
const
_KeyDef
(
'1'
,
1
),
const
_KeyDef
(
'2'
,
1
),
const
_KeyDef
(
'2'
,
1
),
...
@@ -262,46 +277,94 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
...
@@ -262,46 +277,94 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
const
_KeyDef
(
'6'
,
1
),
const
_KeyDef
(
'6'
,
1
),
const
_KeyDef
(
'C'
,
1
,
isAction:
true
),
const
_KeyDef
(
'C'
,
1
,
isAction:
true
),
],
],
[
const
_KeyDef
(
'7'
,
1
),
const
_KeyDef
(
'8'
,
1
),
const
_KeyDef
(
'9'
,
1
),
const
_KeyDef
(
''
,
1
),
],
[
if
(
widget
.
decimalEnabled
)
const
_KeyDef
(
'.'
,
1
),
_KeyDef
(
'0'
,
widget
.
decimalEnabled
?
2
:
3
),
const
_KeyDef
(
''
,
1
),
],
];
];
return
Padding
(
return
Padding
(
padding:
const
EdgeInsets
.
only
(
top:
2
),
padding:
const
EdgeInsets
.
only
(
top:
2
),
child:
Column
(
child:
Column
(
children:
keys
.
map
((
row
)
{
children:
[
return
Row
(
...
topRows
.
map
((
row
)
{
children:
row
.
map
((
keyDef
)
{
return
Row
(
if
(
keyDef
.
label
.
isEmpty
)
{
children:
row
.
map
((
keyDef
)
{
return
const
Spacer
(
flex:
1
);
if
(
keyDef
.
label
.
isEmpty
)
{
}
return
const
Spacer
(
flex:
1
);
return
Expanded
(
}
flex:
keyDef
.
flex
,
return
Expanded
(
flex:
keyDef
.
flex
,
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
5
),
child:
_buildKeyButton
(
keyDef
),
),
);
}).
toList
(),
);
}),
Row
(
children:
[
Expanded
(
flex:
3
,
child:
Column
(
children:
[
Row
(
children:
[
const
_KeyDef
(
'7'
,
1
),
const
_KeyDef
(
'8'
,
1
),
const
_KeyDef
(
'9'
,
1
),
].
map
((
keyDef
)
{
return
Expanded
(
flex:
keyDef
.
flex
,
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
5
),
child:
_buildKeyButton
(
keyDef
),
),
);
}).
toList
(),
),
Row
(
children:
[
if
(
widget
.
decimalEnabled
)
const
_KeyDef
(
'.'
,
1
),
_KeyDef
(
'0'
,
widget
.
decimalEnabled
?
2
:
3
),
].
map
((
keyDef
)
{
return
Expanded
(
flex:
keyDef
.
flex
,
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
5
),
child:
_buildKeyButton
(
keyDef
),
),
);
}).
toList
(),
),
],
),
),
Expanded
(
child:
Padding
(
child:
Padding
(
padding:
const
EdgeInsets
.
all
(
5
),
padding:
const
EdgeInsets
.
all
(
5
),
child:
_buildKeyButton
(
keyDef
),
child:
widget
.
showCloseKey
?
_buildKeyButton
(
const
_KeyDef
(
'关闭'
,
1
,
isAction:
true
,
isDanger:
true
,
),
height:
130
,
)
:
const
SizedBox
.
shrink
(),
),
),
)
;
)
,
}).
toList
()
,
]
,
)
;
)
,
}).
toList
()
,
]
,
),
),
);
);
}
}
Widget
_buildKeyButton
(
_KeyDef
keyDef
)
{
Widget
_buildKeyButton
(
_KeyDef
keyDef
,
{
double
height
=
60
}
)
{
final
isAction
=
keyDef
.
isAction
;
final
isAction
=
keyDef
.
isAction
;
final
isDanger
=
keyDef
.
isDanger
;
return
SizedBox
(
return
SizedBox
(
height:
60
,
height:
height
,
child:
Material
(
child:
Material
(
color:
Colors
.
transparent
,
color:
Colors
.
transparent
,
borderRadius:
BorderRadius
.
circular
(
8
),
borderRadius:
BorderRadius
.
circular
(
8
),
...
@@ -310,14 +373,18 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
...
@@ -310,14 +373,18 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
onTap:
()
=>
_onKeyTap
(
keyDef
.
label
),
onTap:
()
=>
_onKeyTap
(
keyDef
.
label
),
child:
Ink
(
child:
Ink
(
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
isAction
color:
isDanger
?
const
Color
(
0xFF10385D
)
?
const
Color
(
0xFF7A1D1D
)
:
const
Color
(
0xFF092849
),
:
isAction
?
const
Color
(
0xFF10385D
)
:
const
Color
(
0xFF092849
),
borderRadius:
BorderRadius
.
circular
(
8
),
borderRadius:
BorderRadius
.
circular
(
8
),
border:
Border
.
all
(
border:
Border
.
all
(
color:
isAction
color:
isDanger
?
const
Color
(
0xFF5D9EC5
)
?
const
Color
(
0xFFFF6B6B
)
:
const
Color
(
0xFF3F9ED2
),
:
isAction
?
const
Color
(
0xFF5D9EC5
)
:
const
Color
(
0xFF3F9ED2
),
width:
1
,
width:
1
,
),
),
boxShadow:
const
[
boxShadow:
const
[
...
@@ -334,9 +401,11 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
...
@@ -334,9 +401,11 @@ class _NumericKeyboardState extends State<NumericKeyboard> {
style:
TextStyle
(
style:
TextStyle
(
fontSize:
isAction
?
20
:
25
,
fontSize:
isAction
?
20
:
25
,
fontWeight:
isAction
?
FontWeight
.
w600
:
FontWeight
.
w700
,
fontWeight:
isAction
?
FontWeight
.
w600
:
FontWeight
.
w700
,
color:
isAction
color:
isDanger
?
const
Color
(
0xFFB8E7FF
)
?
const
Color
(
0xFFFFE7E7
)
:
const
Color
(
0xFFEAF9FF
),
:
isAction
?
const
Color
(
0xFFB8E7FF
)
:
const
Color
(
0xFFEAF9FF
),
),
),
),
),
),
),
...
@@ -352,5 +421,11 @@ class _KeyDef {
...
@@ -352,5 +421,11 @@ class _KeyDef {
final
String
label
;
final
String
label
;
final
int
flex
;
final
int
flex
;
final
bool
isAction
;
final
bool
isAction
;
const
_KeyDef
(
this
.
label
,
this
.
flex
,
{
this
.
isAction
=
false
});
final
bool
isDanger
;
const
_KeyDef
(
this
.
label
,
this
.
flex
,
{
this
.
isAction
=
false
,
this
.
isDanger
=
false
,
});
}
}
lib/views/monitoring/device_control/widgets/device_control_care_panel.dart
View file @
0f9cb2e3
...
@@ -61,15 +61,22 @@ class DeviceControlCarePanel extends StatelessWidget {
...
@@ -61,15 +61,22 @@ class DeviceControlCarePanel extends StatelessWidget {
}
}
}
}
class
_CareLevelBar
extends
State
less
Widget
{
class
_CareLevelBar
extends
State
ful
Widget
{
const
_CareLevelBar
({
required
this
.
currentLevel
});
const
_CareLevelBar
({
required
this
.
currentLevel
});
final
CareLevel
currentLevel
;
final
CareLevel
currentLevel
;
@override
@override
State
<
_CareLevelBar
>
createState
()
=>
_CareLevelBarState
();
}
class
_CareLevelBarState
extends
State
<
_CareLevelBar
>
{
int
?
_lastDragIndex
;
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
activeIndex
=
_careLevelItems
.
indexWhere
(
final
activeIndex
=
_careLevelItems
.
indexWhere
(
(
item
)
=>
item
.
level
==
currentLevel
,
(
item
)
=>
item
.
level
==
widget
.
currentLevel
,
);
);
return
LayoutBuilder
(
return
LayoutBuilder
(
...
@@ -83,29 +90,38 @@ class _CareLevelBar extends StatelessWidget {
...
@@ -83,29 +90,38 @@ class _CareLevelBar extends StatelessWidget {
segmentWidth
-
segmentWidth
-
knobSize
/
2
;
knobSize
/
2
;
return
SizedBox
(
return
GestureDetector
(
height:
knobSize
,
behavior:
HitTestBehavior
.
opaque
,
child:
Stack
(
onTapDown:
(
details
)
=>
_setLevelFromDx
(
clipBehavior:
Clip
.
none
,
context
,
alignment:
Alignment
.
centerLeft
,
details
.
localPosition
.
dx
,
children:
[
constraints
.
maxWidth
,
Positioned
(
activeIndex
,
left:
0
,
),
right:
0
,
onHorizontalDragUpdate:
(
details
)
=>
_setLevelFromDx
(
top:
(
knobSize
-
20
.
h
)
/
2
,
context
,
child:
Row
(
details
.
localPosition
.
dx
,
children:
[
constraints
.
maxWidth
,
for
(
var
index
=
0
;
activeIndex
,
index
<
_careLevelItems
.
length
;
),
index
++)
...[
onHorizontalDragEnd:
(
_
)
=>
_lastDragIndex
=
null
,
Expanded
(
onHorizontalDragCancel:
()
=>
_lastDragIndex
=
null
,
child:
GestureDetector
(
child:
SizedBox
(
behavior:
HitTestBehavior
.
opaque
,
height:
knobSize
,
onTap:
()
=>
context
.
read
<
DeviceControlBloc
>().
add
(
child:
Stack
(
DeviceControlCareLevelChanged
(
clipBehavior:
Clip
.
none
,
_careLevelItems
[
index
].
level
,
alignment:
Alignment
.
centerLeft
,
),
children:
[
),
Positioned
(
left:
0
,
right:
0
,
top:
(
knobSize
-
20
.
h
)
/
2
,
child:
Row
(
children:
[
for
(
var
index
=
0
;
index
<
_careLevelItems
.
length
;
index
++)
...[
Expanded
(
child:
Container
(
child:
Container
(
height:
20
.
h
,
height:
20
.
h
,
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
...
@@ -126,37 +142,57 @@ class _CareLevelBar extends StatelessWidget {
...
@@ -126,37 +142,57 @@ class _CareLevelBar extends StatelessWidget {
),
),
),
),
),
),
),
if
(
index
<
_careLevelItems
.
length
-
1
)
if
(
index
<
_careLevelItems
.
length
-
1
)
SizedBox
(
width:
segmentGap
),
SizedBox
(
width:
segmentGap
)
,
]
,
],
],
]
,
)
,
),
),
),
Positioned
(
Positioned
(
left:
knobLeft
.
clamp
(
0
,
constraints
.
maxWidth
-
knobSize
),
left:
knobLeft
.
clamp
(
0
,
constraints
.
maxWidth
-
knobSize
),
child:
Container
(
child:
Container
(
width:
knobSize
,
width
:
knobSize
,
height
:
knobSize
,
height:
knobSize
,
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
const
Color
(
0xFFF7F7F7
),
color:
const
Color
(
0xFFF7F7F7
)
,
shape:
BoxShape
.
circle
,
shape:
BoxShape
.
circle
,
boxShadow:
[
boxShadow:
[
BoxShadow
(
BoxShadow
(
color:
Colors
.
white
.
withValues
(
alpha:
0.72
),
color:
Colors
.
white
.
withValues
(
alpha:
0.72
)
,
blurRadius:
10
.
r
,
blurRadius:
10
.
r
,
)
,
)
,
]
,
]
,
)
,
),
),
),
),
)
,
]
,
]
,
)
,
),
),
);
);
},
},
);
);
}
}
void
_setLevelFromDx
(
BuildContext
context
,
double
dx
,
double
width
,
int
activeIndex
,
)
{
if
(
width
<=
0
)
return
;
final
index
=
(
dx
/
width
*
_careLevelItems
.
length
)
.
floor
()
.
clamp
(
0
,
_careLevelItems
.
length
-
1
)
.
toInt
();
if
(
index
==
activeIndex
||
index
==
_lastDragIndex
)
return
;
_lastDragIndex
=
index
;
context
.
read
<
DeviceControlBloc
>().
add
(
DeviceControlCareLevelChanged
(
_careLevelItems
[
index
].
level
),
);
}
BorderRadius
_segmentRadius
(
int
index
)
{
BorderRadius
_segmentRadius
(
int
index
)
{
final
radius
=
Radius
.
circular
(
12
.
r
);
final
radius
=
Radius
.
circular
(
12
.
r
);
if
(
index
==
0
)
{
if
(
index
==
0
)
{
...
...
lib/views/monitoring/device_control/widgets/device_control_common.dart
View file @
0f9cb2e3
...
@@ -155,23 +155,32 @@ class DeviceControlAdjustText extends StatelessWidget {
...
@@ -155,23 +155,32 @@ class DeviceControlAdjustText extends StatelessWidget {
/// 大号操作按钮
/// 大号操作按钮
class
DeviceControlBigActionButton
extends
StatelessWidget
{
class
DeviceControlBigActionButton
extends
StatelessWidget
{
const
DeviceControlBigActionButton
({
super
.
key
,
required
this
.
text
});
const
DeviceControlBigActionButton
({
super
.
key
,
required
this
.
text
,
this
.
onTap
,
});
final
String
text
;
final
String
text
;
final
VoidCallback
?
onTap
;
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
Container
(
return
GestureDetector
(
width:
double
.
infinity
,
behavior:
HitTestBehavior
.
opaque
,
height:
64
.
h
,
onTap:
onTap
,
decoration:
deviceControlButtonDecoration
(
backgroundAsset:
assetButton
),
child:
Container
(
alignment:
Alignment
.
center
,
width:
double
.
infinity
,
child:
Text
(
height:
64
.
h
,
'《《
$text
》》'
,
decoration:
deviceControlButtonDecoration
(
backgroundAsset:
assetButton
),
style:
TextStyle
(
alignment:
Alignment
.
center
,
color:
const
Color
(
0xFFC9F8FF
),
child:
Text
(
fontSize:
28
.
sp
,
'《《
$text
》》'
,
fontWeight:
FontWeight
.
w700
,
style:
TextStyle
(
color:
const
Color
(
0xFFC9F8FF
),
fontSize:
28
.
sp
,
fontWeight:
FontWeight
.
w700
,
),
),
),
),
),
);
);
...
...
lib/views/monitoring/device_control/widgets/device_control_metric_card.dart
View file @
0f9cb2e3
...
@@ -89,69 +89,86 @@ class DeviceControlMetricCard extends StatelessWidget {
...
@@ -89,69 +89,86 @@ class DeviceControlMetricCard extends StatelessWidget {
isHumidity:
isHumidity
,
isHumidity:
isHumidity
,
isOxygen:
isOxygen
,
isOxygen:
isOxygen
,
);
);
final
displaySetValue
=
!
isCo2
&&
!
isSwitchOn
?
'--'
:
setValue
;
final
displaySetValue
=
setValue
;
final
VoidCallback
?
switchTap
=
switchEventBuilder
==
null
?
null
:
()
{
confirmDeviceControlChange
(
context
,
()
=>
context
.
read
<
DeviceControlBloc
>().
add
(
switchEventBuilder
(!
isSwitchOn
),
),
);
};
final
isCardActive
=
!
isCo2
&&
isSwitchOn
;
return
DeviceControlPanelFrame
(
return
DeviceControlPanelFrame
(
active:
is
Oxygen
,
active:
is
CardActive
,
backgroundAsset:
is
Oxygen
?
assetMetricGreen
:
assetMetricBlue
,
backgroundAsset:
is
CardActive
?
assetMetricGreen
:
assetMetricBlue
,
padding:
EdgeInsets
.
fromLTRB
(
32
.
w
,
26
.
h
,
32
.
w
,
28
.
h
),
padding:
EdgeInsets
.
fromLTRB
(
32
.
w
,
26
.
h
,
32
.
w
,
28
.
h
),
child:
Column
(
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
children:
[
Row
(
GestureDetector
(
children:
[
behavior:
HitTestBehavior
.
opaque
,
Expanded
(
onTap:
switchTap
,
child:
DeviceControlPanelTitle
(
_title
(
metric
.
label
)),
child:
Row
(
),
children:
[
DeviceControlPill
(
Expanded
(
text:
isCo2
?
'PPM'
:
(
isSwitchOn
?
'ON'
:
'Off'
),
child:
DeviceControlPanelTitle
(
_title
(
metric
.
label
)),
active:
!
isCo2
&&
isSwitchOn
,
onTap:
switchEventBuilder
==
null
?
null
:
()
{
confirmDeviceControlChange
(
context
,
()
=>
context
.
read
<
DeviceControlBloc
>().
add
(
switchEventBuilder
(!
isSwitchOn
),
),
);
},
),
],
),
const
Spacer
(),
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
end
,
children:
[
Text
(
currentValue
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
isCo2
?
60
.
sp
:
82
.
sp
,
height:
0.9
,
fontWeight:
FontWeight
.
bold
,
),
),
),
DeviceControlPill
(
SizedBox
(
width:
12
.
w
),
text:
isCo2
?
'PPM'
:
(
isSwitchOn
?
'ON'
:
'Off'
),
Padding
(
active:
!
isCo2
&&
isSwitchOn
,
padding:
EdgeInsets
.
only
(
bottom:
8
.
h
),
onTap:
switchTap
,
child:
Text
(
),
isCo2
?
''
:
metric
.
unit
,
],
),
),
Expanded
(
child:
GestureDetector
(
behavior:
HitTestBehavior
.
opaque
,
onTap:
switchTap
,
child:
const
SizedBox
.
expand
(),
),
),
GestureDetector
(
behavior:
HitTestBehavior
.
opaque
,
onTap:
switchTap
,
child:
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
end
,
children:
[
Text
(
currentValue
,
style:
TextStyle
(
style:
TextStyle
(
color:
Colors
.
white
,
color:
Colors
.
white
,
fontSize:
28
.
sp
,
fontSize:
isCo2
?
60
.
sp
:
82
.
sp
,
fontWeight:
FontWeight
.
w600
,
height:
0.9
,
fontWeight:
FontWeight
.
bold
,
),
),
),
),
),
SizedBox
(
width:
12
.
w
),
const
Spacer
(),
Padding
(
Image
.
asset
(
padding:
EdgeInsets
.
only
(
bottom:
8
.
h
),
deviceControlIconAsset
(
metric
.
label
),
child:
Text
(
width:
72
.
w
,
isCo2
?
''
:
metric
.
unit
,
height:
72
.
w
,
style:
TextStyle
(
fit:
BoxFit
.
contain
,
color:
Colors
.
white
,
),
fontSize:
28
.
sp
,
],
fontWeight:
FontWeight
.
w600
,
),
),
),
const
Spacer
(),
Image
.
asset
(
deviceControlIconAsset
(
metric
.
label
),
width:
72
.
w
,
height:
72
.
w
,
fit:
BoxFit
.
contain
,
),
],
),
),
),
Divider
(
Divider
(
color:
Colors
.
white
.
withValues
(
alpha:
0.18
),
height:
28
.
h
),
color:
Colors
.
white
.
withValues
(
alpha:
0.18
),
height:
28
.
h
),
...
...
lib/views/monitoring/device_control/widgets/device_control_oxygen_timer_panel.dart
View file @
0f9cb2e3
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:laki_icu_app/blocs/device_control/device_control_bloc.dart'
;
import
'package:laki_icu_app/blocs/device_control/device_control_event.dart'
;
import
'package:laki_icu_app/blocs/device_control/device_control_state.dart'
;
import
'device_control_common.dart'
;
import
'device_control_common.dart'
;
...
@@ -9,42 +13,64 @@ class DeviceControlOxygenTimerPanel extends StatelessWidget {
...
@@ -9,42 +13,64 @@ class DeviceControlOxygenTimerPanel extends StatelessWidget {
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
return
DeviceControlPanelFrame
(
return
BlocBuilder
<
DeviceControlBloc
,
DeviceControlState
>(
backgroundAsset:
assetPanelWide
,
buildWhen:
(
previous
,
current
)
=>
padding:
EdgeInsets
.
fromLTRB
(
30
.
w
,
26
.
h
,
30
.
w
,
28
.
h
),
previous
.
data
.
oxygenTimer
!=
current
.
data
.
oxygenTimer
,
child:
Column
(
builder:
(
context
,
state
)
{
crossAxisAlignment:
CrossAxisAlignment
.
start
,
final
oxygenTimer
=
state
.
data
.
oxygenTimer
;
children:
[
final
timeText
=
const
DeviceControlPanelTitle
(
'供氧计时'
),
'
${oxygenTimer.hours}
:
${oxygenTimer.minutes}
:
${oxygenTimer.seconds}
'
;
const
Spacer
(),
Row
(
return
DeviceControlPanelFrame
(
backgroundAsset:
assetPanelWide
,
padding:
EdgeInsets
.
fromLTRB
(
30
.
w
,
26
.
h
,
30
.
w
,
28
.
h
),
child:
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
children:
[
const
DeviceControlPanelTitle
(
'供氧计时'
),
const
Spacer
(),
Row
(
children:
[
Text
(
timeText
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
42
.
sp
,
letterSpacing:
2
,
fontWeight:
FontWeight
.
w500
,
),
),
const
Spacer
(),
GestureDetector
(
behavior:
HitTestBehavior
.
opaque
,
onTap:
()
=>
context
.
read
<
DeviceControlBloc
>()
.
add
(
const
DeviceControlOxygenTimerCleared
()),
child:
const
DeviceControlPill
(
text:
'清零'
),
),
],
),
Divider
(
color:
Colors
.
white
.
withValues
(
alpha:
0.16
),
height:
38
.
h
),
Text
(
Text
(
'
00:00:00
'
,
'
ICU舱设置重置
'
,
style:
TextStyle
(
style:
TextStyle
(
color:
Colors
.
white
,
color:
Colors
.
white
,
fontSize:
42
.
sp
,
fontSize:
28
.
sp
,
letterSpacing:
2
,
fontWeight:
FontWeight
.
w600
,
fontWeight:
FontWeight
.
w500
,
),
),
),
),
const
Spacer
(),
const
Spacer
(),
const
DeviceControlPill
(
text:
'清零'
),
DeviceControlBigActionButton
(
text:
'初始化设置'
,
onTap:
()
=>
context
.
read
<
DeviceControlBloc
>()
.
add
(
const
DeviceControlResetSettings
()),
),
],
],
),
),
Divider
(
color:
Colors
.
white
.
withValues
(
alpha:
0.16
),
height:
38
.
h
),
);
Text
(
},
'ICU舱设置重置'
,
style:
TextStyle
(
color:
Colors
.
white
,
fontSize:
28
.
sp
,
fontWeight:
FontWeight
.
w600
,
),
),
const
Spacer
(),
const
DeviceControlBigActionButton
(
text:
'初始化设置'
),
],
),
);
);
}
}
}
}
lib/views/monitoring/device_control/widgets/device_control_time_panel.dart
View file @
0f9cb2e3
...
@@ -76,6 +76,8 @@ class DeviceControlTimePanel extends StatelessWidget {
...
@@ -76,6 +76,8 @@ class DeviceControlTimePanel extends StatelessWidget {
context
,
context
,
initialValue:
initialValue
==
'--'
?
''
:
initialValue
,
initialValue:
initialValue
==
'--'
?
''
:
initialValue
,
decimalEnabled:
false
,
decimalEnabled:
false
,
showCloseKey:
true
,
closeKeyValue:
'0'
,
);
);
if
(!
context
.
mounted
||
result
==
null
)
return
;
if
(!
context
.
mounted
||
result
==
null
)
return
;
...
...
lib/views/monitoring/index/cubit/monitoring_index_cubit.dart
View file @
0f9cb2e3
...
@@ -651,6 +651,18 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
...
@@ -651,6 +651,18 @@ class MonitoringIndexCubit extends HydratedCubit<MonitoringIndexState> {
try
{
try
{
await
stopBluetoothScan
();
await
stopBluetoothScan
();
final
boundDeviceId
=
state
.
boundBluetoothDeviceId
;
if
(
boundDeviceId
!=
null
&&
boundDeviceId
.
isNotEmpty
&&
boundDeviceId
!=
device
.
remoteId
)
{
await
unbindBluetoothDevice
();
if
(
isClosed
)
return
;
emit
(
state
.
copyWith
(
isBluetoothBinding:
true
,
bindingBluetoothDeviceId:
device
.
remoteId
,
bluetoothMessage:
'正在绑定蓝牙设备:
${device.name}
'
,
));
}
await
_bluetoothManager
.
connectToDevice
(
device
);
await
_bluetoothManager
.
connectToDevice
(
device
);
if
(!
_bluetoothManager
.
isConnected
)
{
if
(!
_bluetoothManager
.
isConnected
)
{
throw
StateError
(
'蓝牙连接未就绪'
);
throw
StateError
(
'蓝牙连接未就绪'
);
...
...
lib/views/monitoring/index/monitoring_index_view.dart
View file @
0f9cb2e3
...
@@ -4,6 +4,8 @@ import 'package:auto_route/auto_route.dart';
...
@@ -4,6 +4,8 @@ import 'package:auto_route/auto_route.dart';
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:laki_icu_app/blocs/device_control/device_control_bloc.dart'
;
import
'package:laki_icu_app/blocs/device_control/device_control_state.dart'
;
import
'package:laki_icu_app/enums/video_stream_mode_enum.dart'
;
import
'package:laki_icu_app/enums/video_stream_mode_enum.dart'
;
import
'package:laki_icu_app/models/bo/monitoring_bo.dart'
;
import
'package:laki_icu_app/models/bo/monitoring_bo.dart'
;
import
'package:laki_icu_app/utils/event_bus.dart'
;
import
'package:laki_icu_app/utils/event_bus.dart'
;
...
@@ -214,25 +216,52 @@ class _MonitoringIndexContentState extends State<MonitoringIndexContent> {
...
@@ -214,25 +216,52 @@ class _MonitoringIndexContentState extends State<MonitoringIndexContent> {
Widget
_buildMetrics
(
List
<
MonitoringMetricBO
>
metrics
)
{
Widget
_buildMetrics
(
List
<
MonitoringMetricBO
>
metrics
)
{
final
displayMetrics
=
_environmentMetrics
(
metrics
);
final
displayMetrics
=
_environmentMetrics
(
metrics
);
final
children
=
<
Widget
>[];
return
BlocBuilder
<
DeviceControlBloc
,
DeviceControlState
>(
for
(
int
i
=
0
;
i
<
displayMetrics
.
length
;
i
++)
{
buildWhen:
(
previous
,
current
)
=>
children
.
add
(
previous
.
data
.
cabinTemp
.
isOn
!=
current
.
data
.
cabinTemp
.
isOn
||
Expanded
(
previous
.
data
.
cabinHumidity
.
isOn
!=
current
.
data
.
cabinHumidity
.
isOn
||
child:
MonitoringMetricCard
(
previous
.
data
.
oxygenConcentration
.
isOn
!=
metric:
displayMetrics
[
i
],
current
.
data
.
oxygenConcentration
.
isOn
,
onTap:
()
=>
_openDeviceControl
(
displayMetrics
[
i
]),
builder:
(
context
,
controlState
)
{
),
final
children
=
<
Widget
>[];
),
for
(
int
i
=
0
;
i
<
displayMetrics
.
length
;
i
++)
{
);
final
metric
=
displayMetrics
[
i
];
if
(
i
<
displayMetrics
.
length
-
1
)
{
children
.
add
(
children
.
add
(
SizedBox
(
width:
20
.
w
));
Expanded
(
}
child:
MonitoringMetricCard
(
}
metric:
metric
,
return
Row
(
switchValue:
_metricSwitchValue
(
metric
,
controlState
),
children:
children
,
onTap:
()
=>
_openDeviceControl
(
metric
),
),
),
);
if
(
i
<
displayMetrics
.
length
-
1
)
{
children
.
add
(
SizedBox
(
width:
20
.
w
));
}
}
return
Row
(
children:
children
,
);
},
);
);
}
}
bool
_metricSwitchValue
(
MonitoringMetricBO
metric
,
DeviceControlState
controlState
,
)
{
if
(
metric
.
label
.
contains
(
'温度'
))
{
return
controlState
.
data
.
cabinTemp
.
isOn
;
}
if
(
metric
.
label
.
contains
(
'湿度'
))
{
return
controlState
.
data
.
cabinHumidity
.
isOn
;
}
if
(
metric
.
label
.
contains
(
'氧气'
))
{
return
controlState
.
data
.
oxygenConcentration
.
isOn
;
}
return
false
;
}
void
_openDeviceControl
(
MonitoringMetricBO
metric
)
{
void
_openDeviceControl
(
MonitoringMetricBO
metric
)
{
context
.
tabsRouter
.
setActiveIndex
(
7
);
context
.
tabsRouter
.
setActiveIndex
(
7
);
}
}
...
...
lib/views/monitoring/index/widgets/bluetooth_bind_dialog.dart
View file @
0f9cb2e3
...
@@ -139,11 +139,12 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
...
@@ -139,11 +139,12 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
}
}
Widget
_buildPanelStatus
(
BuildContext
context
,
MonitoringIndexState
state
)
{
Widget
_buildPanelStatus
(
BuildContext
context
,
MonitoringIndexState
state
)
{
final
devices
=
_cnaDevices
(
state
);
final
message
=
state
.
isBluetoothScanning
final
message
=
state
.
isBluetoothScanning
?
'自动发现附近可配对的监护舱设备,搜索中...'
?
'自动发现附近可配对的监护舱设备,搜索中...'
:
state
.
bluetoothD
evices
.
isEmpty
:
d
evices
.
isEmpty
?
'未发现设备,可重新搜索附近蓝牙设备'
?
'未发现设备,可重新搜索附近蓝牙设备'
:
'蓝牙扫描结束,共发现
${
state.bluetoothD
evices.length}
个设备'
;
:
'蓝牙扫描结束,共发现
${
d
evices.length}
个设备'
;
return
Row
(
return
Row
(
children:
[
children:
[
...
@@ -187,7 +188,9 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
...
@@ -187,7 +188,9 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
}
}
Widget
_buildDeviceList
(
BuildContext
context
,
MonitoringIndexState
state
)
{
Widget
_buildDeviceList
(
BuildContext
context
,
MonitoringIndexState
state
)
{
if
(
state
.
bluetoothDevices
.
isEmpty
)
{
final
devices
=
_sortDevicesForDisplay
(
state
);
if
(
devices
.
isEmpty
)
{
return
Center
(
return
Center
(
child:
Text
(
child:
Text
(
state
.
isBluetoothScanning
?
'正在扫描附近设备...'
:
'暂无设备'
,
state
.
isBluetoothScanning
?
'正在扫描附近设备...'
:
'暂无设备'
,
...
@@ -199,8 +202,6 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
...
@@ -199,8 +202,6 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
);
);
}
}
final
devices
=
_sortDevicesForDisplay
(
state
);
return
ListView
.
separated
(
return
ListView
.
separated
(
padding:
EdgeInsets
.
zero
,
padding:
EdgeInsets
.
zero
,
itemCount:
devices
.
length
,
itemCount:
devices
.
length
,
...
@@ -227,12 +228,13 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
...
@@ -227,12 +228,13 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
}
}
List
<
BluetoothScanDevice
>
_sortDevicesForDisplay
(
MonitoringIndexState
state
)
{
List
<
BluetoothScanDevice
>
_sortDevicesForDisplay
(
MonitoringIndexState
state
)
{
final
devices
=
_cnaDevices
(
state
);
final
boundDeviceId
=
state
.
boundBluetoothDeviceId
;
final
boundDeviceId
=
state
.
boundBluetoothDeviceId
;
if
(
boundDeviceId
==
null
||
boundDeviceId
.
isEmpty
)
{
if
(
boundDeviceId
==
null
||
boundDeviceId
.
isEmpty
)
{
return
state
.
bluetoothD
evices
;
return
d
evices
;
}
}
return
List
<
BluetoothScanDevice
>.
from
(
state
.
bluetoothDevices
)
return
devices
..
sort
((
left
,
right
)
{
..
sort
((
left
,
right
)
{
final
leftIsBound
=
left
.
remoteId
==
boundDeviceId
;
final
leftIsBound
=
left
.
remoteId
==
boundDeviceId
;
final
rightIsBound
=
right
.
remoteId
==
boundDeviceId
;
final
rightIsBound
=
right
.
remoteId
==
boundDeviceId
;
...
@@ -243,6 +245,14 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
...
@@ -243,6 +245,14 @@ class _BluetoothBindDialogState extends State<BluetoothBindDialog> {
});
});
}
}
bool
_isCnaDevice
(
BluetoothScanDevice
device
)
{
return
device
.
name
.
trim
().
toUpperCase
().
startsWith
(
'CNA'
);
}
List
<
BluetoothScanDevice
>
_cnaDevices
(
MonitoringIndexState
state
)
{
return
state
.
bluetoothDevices
.
where
(
_isCnaDevice
).
toList
();
}
Future
<
void
>
_confirmUnbindBluetoothDevice
(
Future
<
void
>
_confirmUnbindBluetoothDevice
(
BuildContext
context
,
BuildContext
context
,
BluetoothScanDevice
device
,
BluetoothScanDevice
device
,
...
...
lib/views/monitoring/index/widgets/monitoring_metric_card.dart
View file @
0f9cb2e3
...
@@ -76,16 +76,22 @@ class MonitoringMetricCard extends StatelessWidget {
...
@@ -76,16 +76,22 @@ class MonitoringMetricCard extends StatelessWidget {
height:
41
.
h
,
height:
41
.
h
,
alignment:
AlignmentDirectional
.
center
,
alignment:
AlignmentDirectional
.
center
,
decoration:
BoxDecoration
(
decoration:
BoxDecoration
(
color:
Color
(
0xFF0A1B34
),
color:
switchValue
?
const
Color
(
0xFF063F1A
)
:
const
Color
(
0xFF0A1B34
),
border:
BoxBorder
.
all
(
border:
BoxBorder
.
all
(
width:
1
.
w
,
width:
1
.
w
,
color:
Color
(
0xFF5A8BB0
),
color:
switchValue
?
const
Color
(
0xFF3EFF5F
)
:
const
Color
(
0xFF5A8BB0
),
),
),
borderRadius:
BorderRadius
.
circular
(
20
)),
borderRadius:
BorderRadius
.
circular
(
20
)),
child:
Text
(
child:
Text
(
"ON
"
,
switchValue
?
"ON"
:
"Off
"
,
style:
TextStyle
(
style:
TextStyle
(
color:
Color
(
0xFF3C6082
),
color:
switchValue
?
const
Color
(
0xFF52FFBB
)
:
const
Color
(
0xFF3C6082
),
fontSize:
24
.
sp
,
fontSize:
24
.
sp
,
fontWeight:
FontWeight
.
bold
),
fontWeight:
FontWeight
.
bold
),
),
),
...
...
lib/views/settings/factory_settings/cubit/factory_settings_index_cubit.dart
View file @
0f9cb2e3
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:laki_icu_app/blocs/device_threshold_config/device_threshold_config.dart'
;
import
'package:laki_icu_app/blocs/device_threshold_config/device_threshold_config.dart'
;
import
'package:laki_icu_app/models/bo/device_threshold_config_bo.dart'
;
import
'package:laki_icu_app/utils/toast_utils.dart'
;
import
'package:laki_icu_app/utils/toast_utils.dart'
;
import
'factory_settings_index_state.dart'
;
import
'factory_settings_index_state.dart'
;
...
@@ -14,6 +15,10 @@ class FactorySettingsIndexCubit extends Cubit<FactorySettingsIndexState> {
...
@@ -14,6 +15,10 @@ class FactorySettingsIndexCubit extends Cubit<FactorySettingsIndexState> {
final
DeviceThresholdConfigBloc
_thresholdConfigBloc
;
final
DeviceThresholdConfigBloc
_thresholdConfigBloc
;
void
_saveEditingConfig
(
DeviceThresholdConfigBO
config
)
{
_thresholdConfigBloc
.
updateConfig
(
config
);
}
void
showCalibrationPage
()
{
void
showCalibrationPage
()
{
emit
(
state
.
copyWith
(
isCalibrationPage:
true
));
emit
(
state
.
copyWith
(
isCalibrationPage:
true
));
}
}
...
@@ -23,66 +28,92 @@ class FactorySettingsIndexCubit extends Cubit<FactorySettingsIndexState> {
...
@@ -23,66 +28,92 @@ class FactorySettingsIndexCubit extends Cubit<FactorySettingsIndexState> {
}
}
void
editTempMax
(
int
value
)
{
void
editTempMax
(
int
value
)
{
final
editingConfig
=
state
.
editingConfig
.
copyWith
(
tempMax:
value
);
emit
(
state
.
copyWith
(
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
tempMax:
value
)
,
editingConfig:
editingConfig
,
isDirty:
tru
e
,
isDirty:
fals
e
,
));
));
_saveEditingConfig
(
editingConfig
);
}
}
void
editTempMin
(
int
value
)
{
void
editTempMin
(
int
value
)
{
final
editingConfig
=
state
.
editingConfig
.
copyWith
(
tempMin:
value
);
emit
(
state
.
copyWith
(
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
tempMin:
value
)
,
editingConfig:
editingConfig
,
isDirty:
tru
e
,
isDirty:
fals
e
,
));
));
_saveEditingConfig
(
editingConfig
);
}
}
void
editOxygenMax
(
int
value
)
{
void
editOxygenMax
(
int
value
)
{
final
editingConfig
=
state
.
editingConfig
.
copyWith
(
oxygenMax:
value
);
emit
(
state
.
copyWith
(
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
oxygenMax:
value
)
,
editingConfig:
editingConfig
,
isDirty:
tru
e
,
isDirty:
fals
e
,
));
));
_saveEditingConfig
(
editingConfig
);
}
}
void
editOxygenMin
(
int
value
)
{
void
editOxygenMin
(
int
value
)
{
final
editingConfig
=
state
.
editingConfig
.
copyWith
(
oxygenMin:
value
);
emit
(
state
.
copyWith
(
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
oxygenMin:
value
)
,
editingConfig:
editingConfig
,
isDirty:
tru
e
,
isDirty:
fals
e
,
));
));
_saveEditingConfig
(
editingConfig
);
}
}
void
editHumidityMax
(
int
value
)
{
void
editHumidityMax
(
int
value
)
{
final
editingConfig
=
state
.
editingConfig
.
copyWith
(
humidityMax:
value
);
emit
(
state
.
copyWith
(
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
humidityMax:
value
)
,
editingConfig:
editingConfig
,
isDirty:
tru
e
,
isDirty:
fals
e
,
));
));
_saveEditingConfig
(
editingConfig
);
}
}
void
editHumidityMin
(
int
value
)
{
void
editHumidityMin
(
int
value
)
{
final
editingConfig
=
state
.
editingConfig
.
copyWith
(
humidityMin:
value
);
emit
(
state
.
copyWith
(
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
humidityMin:
value
)
,
editingConfig:
editingConfig
,
isDirty:
tru
e
,
isDirty:
fals
e
,
));
));
_saveEditingConfig
(
editingConfig
);
}
}
void
editUvTimeMax
(
int
value
)
{
void
editUvTimeMax
(
int
value
)
{
final
editingConfig
=
state
.
editingConfig
.
copyWith
(
uvTimeMax:
value
);
emit
(
state
.
copyWith
(
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
uvTimeMax:
value
)
,
editingConfig:
editingConfig
,
isDirty:
tru
e
,
isDirty:
fals
e
,
));
));
_saveEditingConfig
(
editingConfig
);
}
}
void
editIrTimeMax
(
int
value
)
{
void
editIrTimeMax
(
int
value
)
{
final
editingConfig
=
state
.
editingConfig
.
copyWith
(
irTimeMax:
value
);
emit
(
state
.
copyWith
(
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
irTimeMax:
value
)
,
editingConfig:
editingConfig
,
isDirty:
tru
e
,
isDirty:
fals
e
,
));
));
_saveEditingConfig
(
editingConfig
);
}
}
void
editAtomizeTimeMax
(
int
value
)
{
void
editAtomizeTimeMax
(
int
value
)
{
final
editingConfig
=
state
.
editingConfig
.
copyWith
(
atomizeTimeMax:
value
);
emit
(
state
.
copyWith
(
editingConfig:
editingConfig
,
isDirty:
false
,
));
_saveEditingConfig
(
editingConfig
);
}
void
resetToDefault
()
{
emit
(
state
.
copyWith
(
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
atomizeTimeMax:
value
)
,
editingConfig:
DeviceThresholdConfigBO
.
defaultConfig
,
isDirty:
tru
e
,
isDirty:
fals
e
,
));
));
_saveEditingConfig
(
DeviceThresholdConfigBO
.
defaultConfig
);
}
}
void
applyChanges
()
{
void
applyChanges
()
{
...
...
lib/views/settings/factory_settings/widgets/factory_device_calibration_panel.dart
View file @
0f9cb2e3
import
'package:flutter/material.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:laki_icu_app/blocs/device_calibration_config/device_calibration_config.dart'
;
import
'package:laki_icu_app/models/bo/device_calibration_config_bo.dart'
;
import
'package:laki_icu_app/utils/numeric_keyboard.dart'
;
import
'package:laki_icu_app/utils/numeric_keyboard.dart'
;
import
'package:laki_icu_app/utils/toast_utils.dart'
;
import
'../../widgets/settings_panel_frame.dart'
;
import
'../../widgets/settings_panel_frame.dart'
;
import
'../cubit/factory_settings_index_cubit.dart'
;
import
'../cubit/factory_settings_index_cubit.dart'
;
...
@@ -20,42 +23,57 @@ class FactoryDeviceCalibrationPanel extends StatefulWidget {
...
@@ -20,42 +23,57 @@ class FactoryDeviceCalibrationPanel extends StatefulWidget {
class
_FactoryDeviceCalibrationPanelState
class
_FactoryDeviceCalibrationPanelState
extends
State
<
FactoryDeviceCalibrationPanel
>
{
extends
State
<
FactoryDeviceCalibrationPanel
>
{
late
List
<
_CalibrationSection
>
_sections
;
late
DeviceCalibrationConfigBO
_config
;
@override
@override
void
initState
()
{
void
initState
()
{
super
.
initState
();
super
.
initState
();
_
sections
=
_defaultSections
()
;
_
config
=
context
.
read
<
DeviceCalibrationConfigBloc
>().
state
.
config
;
}
}
Future
<
void
>
_editItem
(
_CalibrationItem
item
)
async
{
Future
<
void
>
_editItem
(
DeviceCalibrationItemBO
item
)
async
{
final
result
=
await
NumericKeyboard
.
show
(
final
result
=
await
NumericKeyboard
.
show
(
context
,
context
,
initialValue:
item
.
value
,
initialValue:
'
${item.value}
'
,
decimalEnabled:
false
,
decimalEnabled:
false
,
);
);
if
(!
mounted
||
result
==
null
)
return
;
if
(!
mounted
||
result
==
null
)
return
;
final
value
=
result
.
trim
();
final
value
=
result
.
trim
();
if
(
value
.
isEmpty
)
return
;
if
(
value
.
isEmpty
)
return
;
final
parsedValue
=
int
.
tryParse
(
value
);
if
(
parsedValue
==
null
)
return
;
setState
(()
{
setState
(()
{
item
.
value
=
value
;
_config
=
_config
.
updateItem
(
item
.
key
,
parsedValue
)
;
});
});
_saveConfig
();
}
}
void
_resetDefaults
()
{
void
_resetDefaults
()
{
setState
(()
{
setState
(()
{
_
sections
=
_defaultSections
()
;
_
config
=
DeviceCalibrationConfigBO
.
defaultConfig
;
});
});
_saveConfig
();
}
void
_saveConfig
()
{
context
.
read
<
DeviceCalibrationConfigBloc
>().
updateConfig
(
_config
);
}
}
void
_applyChanges
()
{
void
_applyChanges
()
{
// UI placeholder only. Real calibration persistence will be wired later.
try
{
_saveConfig
();
showToast
(
'操作成功'
);
}
catch
(
e
)
{
showToast
(
'操作失败'
);
}
}
}
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
final
sections
=
_config
.
sections
;
return
Row
(
return
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
stretch
,
crossAxisAlignment:
CrossAxisAlignment
.
stretch
,
children:
[
children:
[
...
@@ -66,12 +84,12 @@ class _FactoryDeviceCalibrationPanelState
...
@@ -66,12 +84,12 @@ class _FactoryDeviceCalibrationPanelState
crossAxisAlignment:
CrossAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
children:
[
_CalibrationSectionView
(
_CalibrationSectionView
(
section:
_
sections
[
0
],
section:
sections
[
0
],
onItemTap:
_enableCalibrationEditing
?
_editItem
:
null
,
onItemTap:
_enableCalibrationEditing
?
_editItem
:
null
,
),
),
SizedBox
(
height:
28
.
h
),
SizedBox
(
height:
28
.
h
),
_CalibrationSectionView
(
_CalibrationSectionView
(
section:
_
sections
[
1
],
section:
sections
[
1
],
onItemTap:
_enableCalibrationEditing
?
_editItem
:
null
,
onItemTap:
_enableCalibrationEditing
?
_editItem
:
null
,
),
),
],
],
...
@@ -88,7 +106,7 @@ class _FactoryDeviceCalibrationPanelState
...
@@ -88,7 +106,7 @@ class _FactoryDeviceCalibrationPanelState
crossAxisAlignment:
CrossAxisAlignment
.
start
,
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
children:
[
_CalibrationSectionView
(
_CalibrationSectionView
(
section:
_
sections
[
2
],
section:
sections
[
2
],
onItemTap:
_enableCalibrationEditing
?
_editItem
:
null
,
onItemTap:
_enableCalibrationEditing
?
_editItem
:
null
,
),
),
const
Spacer
(),
const
Spacer
(),
...
@@ -142,8 +160,8 @@ class _CalibrationSectionView extends StatelessWidget {
...
@@ -142,8 +160,8 @@ class _CalibrationSectionView extends StatelessWidget {
required
this
.
onItemTap
,
required
this
.
onItemTap
,
});
});
final
_CalibrationSection
section
;
final
DeviceCalibrationSectionBO
section
;
final
ValueChanged
<
_CalibrationItem
>?
onItemTap
;
final
ValueChanged
<
DeviceCalibrationItemBO
>?
onItemTap
;
@override
@override
Widget
build
(
BuildContext
context
)
{
Widget
build
(
BuildContext
context
)
{
...
@@ -179,7 +197,7 @@ class _CalibrationRow extends StatelessWidget {
...
@@ -179,7 +197,7 @@ class _CalibrationRow extends StatelessWidget {
required
this
.
onTap
,
required
this
.
onTap
,
});
});
final
_CalibrationItem
item
;
final
DeviceCalibrationItemBO
item
;
final
VoidCallback
?
onTap
;
final
VoidCallback
?
onTap
;
@override
@override
...
@@ -202,7 +220,7 @@ class _CalibrationRow extends StatelessWidget {
...
@@ -202,7 +220,7 @@ class _CalibrationRow extends StatelessWidget {
GestureDetector
(
GestureDetector
(
behavior:
HitTestBehavior
.
opaque
,
behavior:
HitTestBehavior
.
opaque
,
onTap:
onTap
,
onTap:
onTap
,
child:
_CalibrationValueBox
(
value:
item
.
value
),
child:
_CalibrationValueBox
(
value:
'
${item.value}
'
),
),
),
],
],
);
);
...
@@ -277,58 +295,3 @@ class _CalibrationButton extends StatelessWidget {
...
@@ -277,58 +295,3 @@ class _CalibrationButton extends StatelessWidget {
);
);
}
}
}
}
class
_CalibrationSection
{
const
_CalibrationSection
({
required
this
.
title
,
required
this
.
items
,
});
final
String
title
;
final
List
<
_CalibrationItem
>
items
;
}
class
_CalibrationItem
{
_CalibrationItem
({
required
this
.
label
,
required
this
.
value
,
});
final
String
label
;
String
value
;
}
List
<
_CalibrationSection
>
_defaultSections
()
{
return
[
_CalibrationSection
(
title:
'主温度调节系数'
,
items:
[
_CalibrationItem
(
label:
'温度系数%S1(上):'
,
value:
'17'
),
_CalibrationItem
(
label:
'温度系数%S1(下):'
,
value:
'34'
),
_CalibrationItem
(
label:
'环境温度冬夏临界值T0:'
,
value:
'17'
),
_CalibrationItem
(
label:
'摄像头循环重启(分钟):'
,
value:
'34'
),
_CalibrationItem
(
label:
'摄像头定时重启(小时):'
,
value:
'17'
),
],
),
_CalibrationSection
(
title:
'CO₂报警及净化修正值'
,
items:
[
_CalibrationItem
(
label:
'CO₂最低设置值C1:'
,
value:
'4000'
),
_CalibrationItem
(
label:
'CO₂差值C2:'
,
value:
'2000'
),
_CalibrationItem
(
label:
'CO₂基准值C3:'
,
value:
'1500'
),
_CalibrationItem
(
label:
'CO₂系数C4:'
,
value:
'34'
),
],
),
_CalibrationSection
(
title:
'密闭舱氧气修正值'
,
items:
[
_CalibrationItem
(
label:
'密闭舱氧气修正点X0:'
,
value:
'17'
),
_CalibrationItem
(
label:
'密闭舱氧气修正幅度X1:'
,
value:
'34'
),
_CalibrationItem
(
label:
'密闭舱氧气修正步进值X4:'
,
value:
'17'
),
_CalibrationItem
(
label:
'开放式供氧氧气修正点S0:'
,
value:
'34'
),
_CalibrationItem
(
label:
'开放式供氧氧气修正幅度S1:'
,
value:
'17'
),
_CalibrationItem
(
label:
'开放式供氧氧气修正步进值S4:'
,
value:
'17'
),
],
),
];
}
lib/views/settings/factory_settings/widgets/factory_settings_panel.dart
View file @
0f9cb2e3
...
@@ -143,7 +143,10 @@ class _FactoryActionColumn extends StatelessWidget {
...
@@ -143,7 +143,10 @@ class _FactoryActionColumn extends StatelessWidget {
if
(
_showFactoryCalibrationEntry
&&
_showFactoryInitEntry
)
if
(
_showFactoryCalibrationEntry
&&
_showFactoryInitEntry
)
SizedBox
(
height:
28
.
h
),
SizedBox
(
height:
28
.
h
),
if
(
_showFactoryInitEntry
)
if
(
_showFactoryInitEntry
)
const
_WideFactoryButton
(
text:
'初始化设置'
),
_WideFactoryButton
(
text:
'初始化设置'
,
onPressed:
()
=>
cubit
.
resetToDefault
(),
),
],
],
),
),
),
),
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment