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
fb9b8d79
Commit
fb9b8d79
authored
Jun 25, 2026
by
张宏
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
6666666666666
parent
646029b6
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
928 additions
and
64 deletions
+928
-64
device_threshold_config.dart
...locs/device_threshold_config/device_threshold_config.dart
+3
-0
device_threshold_config_bloc.dart
...device_threshold_config/device_threshold_config_bloc.dart
+280
-0
device_threshold_config_event.dart
...evice_threshold_config/device_threshold_config_event.dart
+107
-0
device_threshold_config_state.dart
...evice_threshold_config/device_threshold_config_state.dart
+30
-0
main.dart
lib/main.dart
+9
-0
camera_alarm_bo.dart
lib/models/bo/camera_alarm_bo.dart
+3
-1
device_threshold_config_bo.dart
lib/models/bo/device_threshold_config_bo.dart
+125
-0
monitoring_bo.dart
lib/models/bo/monitoring_bo.dart
+6
-1
date_utils.dart
lib/utils/date_utils.dart
+15
-0
laki_mqtt_client.dart
lib/utils/mqtt/laki_mqtt_client.dart
+27
-0
monitoring_index_cubit.dart
lib/views/monitoring/index/cubit/monitoring_index_cubit.dart
+62
-29
monitoring_pet_info_card.dart
...ws/monitoring/index/widgets/monitoring_pet_info_card.dart
+1
-0
factory_settings_index_cubit.dart
.../factory_settings/cubit/factory_settings_index_cubit.dart
+84
-1
factory_settings_index_state.dart
.../factory_settings/cubit/factory_settings_index_state.dart
+36
-19
factory_settings_index_view.dart
...ettings/factory_settings/factory_settings_index_view.dart
+4
-1
factory_settings_panel.dart
...ings/factory_settings/widgets/factory_settings_panel.dart
+135
-12
pubspec.yaml
pubspec.yaml
+1
-0
No files found.
lib/blocs/device_threshold_config/device_threshold_config.dart
0 → 100644
View file @
fb9b8d79
export
'device_threshold_config_bloc.dart'
;
export
'device_threshold_config_event.dart'
;
export
'device_threshold_config_state.dart'
;
lib/blocs/device_threshold_config/device_threshold_config_bloc.dart
0 → 100644
View file @
fb9b8d79
import
'package:hydrated_bloc/hydrated_bloc.dart'
;
import
'package:laki_icu_app/models/bo/device_threshold_config_bo.dart'
;
import
'device_threshold_config_event.dart'
;
import
'device_threshold_config_state.dart'
;
class
DeviceThresholdConfigBloc
extends
HydratedBloc
<
DeviceThresholdConfigEvent
,
DeviceThresholdConfigState
>
{
DeviceThresholdConfigBloc
()
:
super
(
const
DeviceThresholdConfigState
())
{
on
<
DeviceThresholdConfigLoaded
>(
_onLoaded
);
on
<
DeviceThresholdConfigTempMaxUpdated
>(
_onTempMaxUpdated
);
on
<
DeviceThresholdConfigTempMinUpdated
>(
_onTempMinUpdated
);
on
<
DeviceThresholdConfigOxygenMaxUpdated
>(
_onOxygenMaxUpdated
);
on
<
DeviceThresholdConfigOxygenMinUpdated
>(
_onOxygenMinUpdated
);
on
<
DeviceThresholdConfigHumidityMaxUpdated
>(
_onHumidityMaxUpdated
);
on
<
DeviceThresholdConfigHumidityMinUpdated
>(
_onHumidityMinUpdated
);
on
<
DeviceThresholdConfigUvTimeMaxUpdated
>(
_onUvTimeMaxUpdated
);
on
<
DeviceThresholdConfigIrTimeMaxUpdated
>(
_onIrTimeMaxUpdated
);
on
<
DeviceThresholdConfigAtomizeTimeMaxUpdated
>(
_onAtomizeTimeMaxUpdated
);
on
<
DeviceThresholdConfigUpdated
>(
_onConfigUpdated
);
on
<
DeviceThresholdConfigResetToDefault
>(
_onResetToDefault
);
}
Future
<
void
>
_onLoaded
(
DeviceThresholdConfigLoaded
event
,
Emitter
<
DeviceThresholdConfigState
>
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
_onTempMaxUpdated
(
DeviceThresholdConfigTempMaxUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
copyWith
(
tempMax:
event
.
value
),
clearError:
true
,
));
}
void
_onTempMinUpdated
(
DeviceThresholdConfigTempMinUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
copyWith
(
tempMin:
event
.
value
),
clearError:
true
,
));
}
void
_onOxygenMaxUpdated
(
DeviceThresholdConfigOxygenMaxUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
copyWith
(
oxygenMax:
event
.
value
),
clearError:
true
,
));
}
void
_onOxygenMinUpdated
(
DeviceThresholdConfigOxygenMinUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
copyWith
(
oxygenMin:
event
.
value
),
clearError:
true
,
));
}
void
_onHumidityMaxUpdated
(
DeviceThresholdConfigHumidityMaxUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
copyWith
(
humidityMax:
event
.
value
),
clearError:
true
,
));
}
void
_onHumidityMinUpdated
(
DeviceThresholdConfigHumidityMinUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
copyWith
(
humidityMin:
event
.
value
),
clearError:
true
,
));
}
void
_onUvTimeMaxUpdated
(
DeviceThresholdConfigUvTimeMaxUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
copyWith
(
uvTimeMax:
event
.
value
),
clearError:
true
,
));
}
void
_onIrTimeMaxUpdated
(
DeviceThresholdConfigIrTimeMaxUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
copyWith
(
irTimeMax:
event
.
value
),
clearError:
true
,
));
}
void
_onAtomizeTimeMaxUpdated
(
DeviceThresholdConfigAtomizeTimeMaxUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
state
.
config
.
copyWith
(
atomizeTimeMax:
event
.
value
),
clearError:
true
,
));
}
void
_onConfigUpdated
(
DeviceThresholdConfigUpdated
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
state
.
copyWith
(
config:
event
.
config
,
clearError:
true
,
));
}
void
_onResetToDefault
(
DeviceThresholdConfigResetToDefault
event
,
Emitter
<
DeviceThresholdConfigState
>
emit
,
)
{
emit
(
const
DeviceThresholdConfigState
(
config:
DeviceThresholdConfigBO
.
defaultConfig
,
));
}
bool
isTemperatureOutOfRange
(
int
currentTemp
)
{
return
currentTemp
<
state
.
config
.
tempMin
||
currentTemp
>
state
.
config
.
tempMax
;
}
bool
isTemperatureTooLow
(
int
currentTemp
)
{
return
currentTemp
<
state
.
config
.
tempMin
;
}
bool
isTemperatureTooHigh
(
int
currentTemp
)
{
return
currentTemp
>
state
.
config
.
tempMax
;
}
bool
isOxygenOutOfRange
(
int
currentOxygen
)
{
return
currentOxygen
<
state
.
config
.
oxygenMin
||
currentOxygen
>
state
.
config
.
oxygenMax
;
}
bool
isOxygenTooLow
(
int
currentOxygen
)
{
return
currentOxygen
<
state
.
config
.
oxygenMin
;
}
bool
isOxygenTooHigh
(
int
currentOxygen
)
{
return
currentOxygen
>
state
.
config
.
oxygenMax
;
}
bool
isHumidityOutOfRange
(
int
currentHumidity
)
{
return
currentHumidity
<
state
.
config
.
humidityMin
||
currentHumidity
>
state
.
config
.
humidityMax
;
}
bool
isHumidityTooLow
(
int
currentHumidity
)
{
return
currentHumidity
<
state
.
config
.
humidityMin
;
}
bool
isHumidityTooHigh
(
int
currentHumidity
)
{
return
currentHumidity
>
state
.
config
.
humidityMax
;
}
bool
isUvTimeOverLimit
(
int
currentTime
)
{
return
currentTime
>
state
.
config
.
uvTimeMax
;
}
bool
isIrTimeOverLimit
(
int
currentTime
)
{
return
currentTime
>
state
.
config
.
irTimeMax
;
}
bool
isAtomizeTimeOverLimit
(
int
currentTime
)
{
return
currentTime
>
state
.
config
.
atomizeTimeMax
;
}
String
getTempRangeDescription
()
{
return
'
${state.config.tempMin}
℃ -
${state.config.tempMax}
℃'
;
}
String
getOxygenRangeDescription
()
{
return
'
${state.config.oxygenMin}
% -
${state.config.oxygenMax}
%'
;
}
String
getHumidityRangeDescription
()
{
return
'
${state.config.humidityMin}
% -
${state.config.humidityMax}
%'
;
}
Map
<
String
,
String
>
getAllThresholdDescriptions
()
{
return
{
'temp'
:
getTempRangeDescription
(),
'oxygen'
:
getOxygenRangeDescription
(),
'humidity'
:
getHumidityRangeDescription
(),
'uvTime'
:
'≤
${state.config.uvTimeMax}
分钟'
,
'irTime'
:
'≤
${state.config.irTimeMax}
分钟'
,
'atomizeTime'
:
'≤
${state.config.atomizeTimeMax}
分钟'
,
};
}
List
<
String
>
checkOutOfRangeIndicators
({
int
?
temp
,
int
?
oxygen
,
int
?
humidity
,
})
{
final
List
<
String
>
outOfRange
=
[];
if
(
temp
!=
null
&&
isTemperatureOutOfRange
(
temp
))
{
outOfRange
.
add
(
'温度'
);
}
if
(
oxygen
!=
null
&&
isOxygenOutOfRange
(
oxygen
))
{
outOfRange
.
add
(
'氧浓度'
);
}
if
(
humidity
!=
null
&&
isHumidityOutOfRange
(
humidity
))
{
outOfRange
.
add
(
'湿度'
);
}
return
outOfRange
;
}
void
updateTempMax
(
int
value
)
=>
add
(
DeviceThresholdConfigTempMaxUpdated
(
value
));
void
updateTempMin
(
int
value
)
=>
add
(
DeviceThresholdConfigTempMinUpdated
(
value
));
void
updateOxygenMax
(
int
value
)
=>
add
(
DeviceThresholdConfigOxygenMaxUpdated
(
value
));
void
updateOxygenMin
(
int
value
)
=>
add
(
DeviceThresholdConfigOxygenMinUpdated
(
value
));
void
updateHumidityMax
(
int
value
)
=>
add
(
DeviceThresholdConfigHumidityMaxUpdated
(
value
));
void
updateHumidityMin
(
int
value
)
=>
add
(
DeviceThresholdConfigHumidityMinUpdated
(
value
));
void
updateUvTimeMax
(
int
value
)
=>
add
(
DeviceThresholdConfigUvTimeMaxUpdated
(
value
));
void
updateIrTimeMax
(
int
value
)
=>
add
(
DeviceThresholdConfigIrTimeMaxUpdated
(
value
));
void
updateAtomizeTimeMax
(
int
value
)
=>
add
(
DeviceThresholdConfigAtomizeTimeMaxUpdated
(
value
));
void
updateConfig
(
DeviceThresholdConfigBO
config
)
=>
add
(
DeviceThresholdConfigUpdated
(
config
));
void
resetToDefault
()
=>
add
(
const
DeviceThresholdConfigResetToDefault
());
@override
DeviceThresholdConfigState
?
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
try
{
return
DeviceThresholdConfigState
(
config:
DeviceThresholdConfigBO
(
tempMax:
json
[
'tempMax'
]
as
int
?
??
34
,
tempMin:
json
[
'tempMin'
]
as
int
?
??
17
,
oxygenMax:
json
[
'oxygenMax'
]
as
int
?
??
34
,
oxygenMin:
json
[
'oxygenMin'
]
as
int
?
??
17
,
humidityMax:
json
[
'humidityMax'
]
as
int
?
??
34
,
humidityMin:
json
[
'humidityMin'
]
as
int
?
??
17
,
uvTimeMax:
json
[
'uvTimeMax'
]
as
int
?
??
34
,
irTimeMax:
json
[
'irTimeMax'
]
as
int
?
??
17
,
atomizeTimeMax:
json
[
'atomizeTimeMax'
]
as
int
?
??
17
,
),
);
}
catch
(
e
)
{
return
null
;
}
}
@override
Map
<
String
,
dynamic
>?
toJson
(
DeviceThresholdConfigState
state
)
{
return
{
'tempMax'
:
state
.
config
.
tempMax
,
'tempMin'
:
state
.
config
.
tempMin
,
'oxygenMax'
:
state
.
config
.
oxygenMax
,
'oxygenMin'
:
state
.
config
.
oxygenMin
,
'humidityMax'
:
state
.
config
.
humidityMax
,
'humidityMin'
:
state
.
config
.
humidityMin
,
'uvTimeMax'
:
state
.
config
.
uvTimeMax
,
'irTimeMax'
:
state
.
config
.
irTimeMax
,
'atomizeTimeMax'
:
state
.
config
.
atomizeTimeMax
,
};
}
}
lib/blocs/device_threshold_config/device_threshold_config_event.dart
0 → 100644
View file @
fb9b8d79
import
'package:equatable/equatable.dart'
;
import
'package:laki_icu_app/models/bo/device_threshold_config_bo.dart'
;
abstract
class
DeviceThresholdConfigEvent
extends
Equatable
{
const
DeviceThresholdConfigEvent
();
@override
List
<
Object
?>
get
props
=>
[];
}
class
DeviceThresholdConfigLoaded
extends
DeviceThresholdConfigEvent
{
const
DeviceThresholdConfigLoaded
();
}
class
DeviceThresholdConfigTempMaxUpdated
extends
DeviceThresholdConfigEvent
{
final
int
value
;
const
DeviceThresholdConfigTempMaxUpdated
(
this
.
value
);
@override
List
<
Object
?>
get
props
=>
[
value
];
}
class
DeviceThresholdConfigTempMinUpdated
extends
DeviceThresholdConfigEvent
{
final
int
value
;
const
DeviceThresholdConfigTempMinUpdated
(
this
.
value
);
@override
List
<
Object
?>
get
props
=>
[
value
];
}
class
DeviceThresholdConfigOxygenMaxUpdated
extends
DeviceThresholdConfigEvent
{
final
int
value
;
const
DeviceThresholdConfigOxygenMaxUpdated
(
this
.
value
);
@override
List
<
Object
?>
get
props
=>
[
value
];
}
class
DeviceThresholdConfigOxygenMinUpdated
extends
DeviceThresholdConfigEvent
{
final
int
value
;
const
DeviceThresholdConfigOxygenMinUpdated
(
this
.
value
);
@override
List
<
Object
?>
get
props
=>
[
value
];
}
class
DeviceThresholdConfigHumidityMaxUpdated
extends
DeviceThresholdConfigEvent
{
final
int
value
;
const
DeviceThresholdConfigHumidityMaxUpdated
(
this
.
value
);
@override
List
<
Object
?>
get
props
=>
[
value
];
}
class
DeviceThresholdConfigHumidityMinUpdated
extends
DeviceThresholdConfigEvent
{
final
int
value
;
const
DeviceThresholdConfigHumidityMinUpdated
(
this
.
value
);
@override
List
<
Object
?>
get
props
=>
[
value
];
}
class
DeviceThresholdConfigUvTimeMaxUpdated
extends
DeviceThresholdConfigEvent
{
final
int
value
;
const
DeviceThresholdConfigUvTimeMaxUpdated
(
this
.
value
);
@override
List
<
Object
?>
get
props
=>
[
value
];
}
class
DeviceThresholdConfigIrTimeMaxUpdated
extends
DeviceThresholdConfigEvent
{
final
int
value
;
const
DeviceThresholdConfigIrTimeMaxUpdated
(
this
.
value
);
@override
List
<
Object
?>
get
props
=>
[
value
];
}
class
DeviceThresholdConfigAtomizeTimeMaxUpdated
extends
DeviceThresholdConfigEvent
{
final
int
value
;
const
DeviceThresholdConfigAtomizeTimeMaxUpdated
(
this
.
value
);
@override
List
<
Object
?>
get
props
=>
[
value
];
}
class
DeviceThresholdConfigUpdated
extends
DeviceThresholdConfigEvent
{
final
DeviceThresholdConfigBO
config
;
const
DeviceThresholdConfigUpdated
(
this
.
config
);
@override
List
<
Object
?>
get
props
=>
[
config
];
}
class
DeviceThresholdConfigResetToDefault
extends
DeviceThresholdConfigEvent
{
const
DeviceThresholdConfigResetToDefault
();
}
lib/blocs/device_threshold_config/device_threshold_config_state.dart
0 → 100644
View file @
fb9b8d79
import
'package:equatable/equatable.dart'
;
import
'package:laki_icu_app/models/bo/device_threshold_config_bo.dart'
;
class
DeviceThresholdConfigState
extends
Equatable
{
const
DeviceThresholdConfigState
({
this
.
config
=
DeviceThresholdConfigBO
.
defaultConfig
,
this
.
isLoading
=
false
,
this
.
error
,
});
final
DeviceThresholdConfigBO
config
;
final
bool
isLoading
;
final
String
?
error
;
DeviceThresholdConfigState
copyWith
({
DeviceThresholdConfigBO
?
config
,
bool
?
isLoading
,
String
?
error
,
bool
clearError
=
false
,
})
{
return
DeviceThresholdConfigState
(
config:
config
??
this
.
config
,
isLoading:
isLoading
??
this
.
isLoading
,
error:
clearError
?
null
:
error
??
this
.
error
,
);
}
@override
List
<
Object
?>
get
props
=>
[
config
,
isLoading
,
error
];
}
lib/main.dart
View file @
fb9b8d79
...
...
@@ -29,6 +29,7 @@ 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:laki_icu_app/blocs/device_control/device_control_bloc.dart'
;
import
'package:laki_icu_app/blocs/device_threshold_config/device_threshold_config.dart'
;
import
'package:marionette_flutter/marionette_flutter.dart'
;
Future
<
void
>
main
(
List
<
String
>
args
)
async
{
...
...
@@ -77,6 +78,7 @@ class _MyAppState extends State<MyApp> {
late
final
AuthBloc
_authBloc
;
BluetoothReadBloc
?
_bluetoothReadBloc
;
DeviceControlBloc
?
_deviceControlBloc
;
DeviceThresholdConfigBloc
?
_deviceThresholdConfigBloc
;
StreamSubscription
?
_tokenExpiredSubscription
;
bool
_isInitializing
=
true
;
...
...
@@ -88,6 +90,9 @@ class _MyAppState extends State<MyApp> {
DeviceControlBloc
get
_deviceControlBlocInstance
=>
_deviceControlBloc
??=
DeviceControlBloc
();
DeviceThresholdConfigBloc
get
_deviceThresholdConfigBlocInstance
=>
_deviceThresholdConfigBloc
??=
DeviceThresholdConfigBloc
();
@override
void
initState
()
{
super
.
initState
();
...
...
@@ -173,6 +178,7 @@ class _MyAppState extends State<MyApp> {
_authBloc
.
close
();
_bluetoothReadBloc
?.
close
();
_deviceControlBloc
?.
close
();
_deviceThresholdConfigBloc
?.
close
();
super
.
dispose
();
}
...
...
@@ -190,6 +196,9 @@ class _MyAppState extends State<MyApp> {
BlocProvider
<
DeviceControlBloc
>.
value
(
value:
_deviceControlBlocInstance
,
),
BlocProvider
<
DeviceThresholdConfigBloc
>.
value
(
value:
_deviceThresholdConfigBlocInstance
,
),
// BlocProvider<CounterBloc>(create: (_) => CounterBloc()),
],
child:
MultiBlocListener
(
...
...
lib/models/bo/camera_alarm_bo.dart
View file @
fb9b8d79
...
...
@@ -63,11 +63,13 @@ class CameraAlarmBO {
);
}
/// 与 Android 行为编码映射完全一致:
/// 行为编码 → 标题映射:
/// 1 → 宠物抓挠
/// 2 → 异常液体
/// 3 → 检测到排泄物
/// 其他 → 未知异常
String
get
titleByBehaviorCode
{
if
(
behaviorCode
==
1
)
return
'宠物抓挠'
;
if
(
behaviorCode
==
2
)
return
'异常液体'
;
if
(
behaviorCode
==
3
)
return
'检测到排泄物'
;
return
'未知异常'
;
...
...
lib/models/bo/device_threshold_config_bo.dart
0 → 100644
View file @
fb9b8d79
import
'package:equatable/equatable.dart'
;
/// 用途:设备阈值配置数据
/// 涉及页面:设备阈值配置页面
class
DeviceThresholdConfigBO
extends
Equatable
{
/// 温度上限 ℃
final
int
tempMax
;
/// 温度下限 ℃
final
int
tempMin
;
/// 氧浓度上限 %
final
int
oxygenMax
;
/// 氧浓度下限 %
final
int
oxygenMin
;
/// 湿度上限 %
final
int
humidityMax
;
/// 湿度下限 %
final
int
humidityMin
;
/// 紫外线时间上限 单位:分钟
final
int
uvTimeMax
;
/// 红外线时间上限 单位:分钟
final
int
irTimeMax
;
/// 雾化时间上限 单位:分钟
final
int
atomizeTimeMax
;
const
DeviceThresholdConfigBO
({
required
this
.
tempMax
,
required
this
.
tempMin
,
required
this
.
oxygenMax
,
required
this
.
oxygenMin
,
required
this
.
humidityMax
,
required
this
.
humidityMin
,
required
this
.
uvTimeMax
,
required
this
.
irTimeMax
,
required
this
.
atomizeTimeMax
,
});
/// UI 默认初始值(截图默认上限34,下限17)
static
const
DeviceThresholdConfigBO
defaultConfig
=
DeviceThresholdConfigBO
(
tempMax:
34
,
tempMin:
17
,
oxygenMax:
34
,
oxygenMin:
17
,
humidityMax:
34
,
humidityMin:
17
,
uvTimeMax:
34
,
irTimeMax:
17
,
atomizeTimeMax:
17
,
);
/// 拷贝修改(用于表单更新)
DeviceThresholdConfigBO
copyWith
({
int
?
tempMax
,
int
?
tempMin
,
int
?
oxygenMax
,
int
?
oxygenMin
,
int
?
humidityMax
,
int
?
humidityMin
,
int
?
uvTimeMax
,
int
?
irTimeMax
,
int
?
atomizeTimeMax
,
})
{
return
DeviceThresholdConfigBO
(
tempMax:
tempMax
??
this
.
tempMax
,
tempMin:
tempMin
??
this
.
tempMin
,
oxygenMax:
oxygenMax
??
this
.
oxygenMax
,
oxygenMin:
oxygenMin
??
this
.
oxygenMin
,
humidityMax:
humidityMax
??
this
.
humidityMax
,
humidityMin:
humidityMin
??
this
.
humidityMin
,
uvTimeMax:
uvTimeMax
??
this
.
uvTimeMax
,
irTimeMax:
irTimeMax
??
this
.
irTimeMax
,
atomizeTimeMax:
atomizeTimeMax
??
this
.
atomizeTimeMax
,
);
}
/// 从 JSON 解析模型
factory
DeviceThresholdConfigBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
return
DeviceThresholdConfigBO
(
tempMax:
json
[
'tempMax'
]
as
int
?
??
34
,
tempMin:
json
[
'tempMin'
]
as
int
?
??
17
,
oxygenMax:
json
[
'oxygenMax'
]
as
int
?
??
34
,
oxygenMin:
json
[
'oxygenMin'
]
as
int
?
??
17
,
humidityMax:
json
[
'humidityMax'
]
as
int
?
??
34
,
humidityMin:
json
[
'humidityMin'
]
as
int
?
??
17
,
uvTimeMax:
json
[
'uvTimeMax'
]
as
int
?
??
34
,
irTimeMax:
json
[
'irTimeMax'
]
as
int
?
??
17
,
atomizeTimeMax:
json
[
'atomizeTimeMax'
]
as
int
?
??
17
,
);
}
/// 转 JSON(接口请求/本地存储)
Map
<
String
,
dynamic
>
toJson
()
{
return
{
'tempMax'
:
tempMax
,
'tempMin'
:
tempMin
,
'oxygenMax'
:
oxygenMax
,
'oxygenMin'
:
oxygenMin
,
'humidityMax'
:
humidityMax
,
'humidityMin'
:
humidityMin
,
'uvTimeMax'
:
uvTimeMax
,
'irTimeMax'
:
irTimeMax
,
'atomizeTimeMax'
:
atomizeTimeMax
,
};
}
@override
List
<
Object
?>
get
props
=>
[
tempMax
,
tempMin
,
oxygenMax
,
oxygenMin
,
humidityMax
,
humidityMin
,
uvTimeMax
,
irTimeMax
,
atomizeTimeMax
,
];
}
lib/models/bo/monitoring_bo.dart
View file @
fb9b8d79
...
...
@@ -122,11 +122,15 @@ class AlertInfoBO extends Equatable {
/// 告警处理状态
final
String
status
;
/// MQTT 下发告警记录 ID,上行 camera/{SN}/up 时使用
final
int
?
alarmId
;
const
AlertInfoBO
({
required
this
.
title
,
required
this
.
description
,
required
this
.
time
,
this
.
status
=
'已处理'
,
this
.
alarmId
,
});
factory
AlertInfoBO
.
fromJson
(
Map
<
String
,
dynamic
>
json
)
{
...
...
@@ -135,11 +139,12 @@ class AlertInfoBO extends Equatable {
description:
json
[
'description'
]
as
String
?
??
''
,
time:
json
[
'time'
]
as
String
?
??
''
,
status:
json
[
'status'
]
as
String
?
??
'已处理'
,
alarmId:
json
[
'alarmId'
]
as
int
?,
);
}
@override
List
<
Object
?>
get
props
=>
[
title
,
description
,
time
,
status
];
List
<
Object
?>
get
props
=>
[
title
,
description
,
time
,
status
,
alarmId
];
}
/// 用途:首页监护舱右侧设备菜单数据
...
...
lib/utils/date_utils.dart
0 → 100644
View file @
fb9b8d79
/// ISO 时间字符串 → yyyy-MM-dd HH:mm:ss
///
/// 输入格式: "2026-06-25T17:08:11.234234234"
/// 输出格式: "2026-06-25 17:08:11"
String
formatIsoTime
(
String
?
isoTime
,
{
String
fallback
=
''
})
{
if
(
isoTime
==
null
||
isoTime
.
isEmpty
)
return
fallback
;
try
{
final
cleaned
=
isoTime
.
contains
(
'T'
)
?
isoTime
.
replaceFirst
(
'T'
,
' '
)
:
isoTime
;
final
dotIndex
=
cleaned
.
indexOf
(
'.'
);
return
dotIndex
>=
0
?
cleaned
.
substring
(
0
,
dotIndex
)
:
cleaned
;
}
catch
(
_
)
{
return
isoTime
;
}
}
lib/utils/mqtt/laki_mqtt_client.dart
View file @
fb9b8d79
...
...
@@ -274,6 +274,33 @@ class LakiMqttClient {
);
}
/// 上行 摄像头宠物异常行为处理结果
///
/// 对应 topic: camera/{SN}/up
/// [status] "handled" = 已处理, "false_alarm" = 误报
int
publishCameraAlarmResult
({
required
String
deviceSn
,
required
int
alarmId
,
required
String
status
,
MqttQos
qos
=
MqttQos
.
atLeastOnce
,
})
{
return
publishJson
(
LakiMqttTopics
.
cameraUp
(
deviceSn
),
{
'eventId'
:
'
${DateTime.now().millisecondsSinceEpoch}
_
${_randomHex(8)}
'
,
'deviceVersionNo'
:
''
,
'deviceType'
:
'ICU'
,
'timestamp'
:
DateTime
.
now
().
millisecondsSinceEpoch
,
'type'
:
'alarm'
,
'data'
:
{
'alarmId'
:
'
$alarmId
'
,
'status'
:
status
,
},
},
qos:
qos
,
);
}
/// 上行 出舱数据
/// create by stephen
/// [deviceSn] 设备 SN,[type] 操作类型(unbindPet),
...
...
lib/views/monitoring/index/cubit/monitoring_index_cubit.dart
View file @
fb9b8d79
...
...
@@ -3,6 +3,7 @@ import 'dart:async';
import
'package:flutter/foundation.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:laki_icu_app/enums/video_stream_mode_enum.dart'
;
import
'package:laki_icu_app/utils/date_utils.dart'
;
import
'package:laki_icu_app/models/bo/monitoring_bo.dart'
;
import
'package:laki_icu_app/models/bo/camera_alarm_bo.dart'
;
...
...
@@ -76,7 +77,7 @@ class MonitoringIndexCubit extends Cubit<MonitoringIndexState> {
_listenMcuReportChanged
();
_loadBoundBluetoothDevice
();
// todo 测试使用 待删除
//
//
todo 测试使用 待删除
_fetchCabinDetailAndConnectVideo
(
"CNA07212L"
);
_connectMqttForDeviceSn
(
"CNA07212L"
);
}
...
...
@@ -712,10 +713,18 @@ class MonitoringIndexCubit extends Cubit<MonitoringIndexState> {
});
}
/// 处理
摄像头告警消息(与 Android qisuanfa_0621 逻辑保持一致)
/// 处理
MQTT camera/{SN}/to 摄像头告警消息
///
/// 仅处理 type == "abnormal_behavior" 的消息,
/// 按 behaviorCode 映射标题:2→异常液体、3→检测到排泄物、其他→未知异常
/// 服务端推送格式:
/// ```json
/// {
/// "type": "abnormal_behavior",
/// "behaviorCode": 1,
/// "behaviorDesc": "宠物抓挠",
/// "petName": "旺财",
/// ...
/// }
/// ```
void
_handleCameraAlarmMessage
(
Map
<
String
,
dynamic
>
json
)
{
if
(
json
[
'type'
]
!=
'abnormal_behavior'
)
return
;
...
...
@@ -726,13 +735,18 @@ class MonitoringIndexCubit extends Cubit<MonitoringIndexState> {
_seenAlarmEventIds
.
add
(
alarm
.
eventId
);
final
timeStr
=
_formatTimestamp
(
alarm
.
timestamp
);
final
title
=
alarm
.
titleByBehaviorCode
;
final
behaviorTitle
=
alarm
.
titleByBehaviorCode
;
final
petName
=
alarm
.
petName
;
final
title
=
petName
!=
null
&&
petName
.
isNotEmpty
?
'
$petName
-
$behaviorTitle
'
:
behaviorTitle
;
final
alert
=
AlertInfoBO
(
title:
title
,
description:
t
itle
,
description:
alarm
.
behaviorDesc
??
behaviorT
itle
,
time:
timeStr
,
status:
'待处理'
,
alarmId:
alarm
.
alarmId
,
);
emit
(
state
.
copyWith
(
...
...
@@ -773,7 +787,7 @@ class MonitoringIndexCubit extends Cubit<MonitoringIndexState> {
doctor:
'缺失字段'
,
avatarUrl:
(
data
[
'avatar'
]
as
String
?)
??
''
,
disease:
(
data
[
'disease'
]
as
String
?)
??
''
,
checkInDate:
(
data
[
'createTime'
]
as
String
?)
??
'缺失字段'
,
checkInDate:
formatIsoTime
(
data
[
'createTime'
]
as
String
?,
fallback:
'缺失字段'
)
,
careLevel:
'缺失字段'
,
);
...
...
@@ -1077,37 +1091,56 @@ class MonitoringIndexCubit extends Cubit<MonitoringIndexState> {
}
/// 标记告警为已处理
///
/// 通过 MQTT camera/{SN}/up 上行处理结果,并从列表中移除。
void
markAlertAsProcessed
(
AlertInfoBO
alert
)
{
if
(
isClosed
)
return
;
final
updatedAlerts
=
state
.
alerts
.
map
((
item
)
{
if
(
item
.
title
==
alert
.
title
&&
item
.
time
==
alert
.
time
)
{
return
AlertInfoBO
(
title:
item
.
title
,
description:
item
.
description
,
time:
item
.
time
,
status:
'已处理'
,
);
}
return
item
;
}).
toList
();
emit
(
state
.
copyWith
(
alerts:
updatedAlerts
,
selectedAlert:
null
));
_publishCameraAlarmResult
(
alert
,
'handled'
);
final
removedCameraAlerts
=
state
.
cameraAlerts
.
where
((
item
)
=>
item
!=
alert
).
toList
();
final
removedAlerts
=
state
.
alerts
.
where
((
item
)
=>
item
!=
alert
).
toList
();
emit
(
state
.
copyWith
(
cameraAlerts:
removedCameraAlerts
,
alerts:
removedAlerts
,
selectedAlert:
null
,
));
}
/// 标记告警为误报
///
/// 通过 MQTT camera/{SN}/up 上行处理结果,并从列表中移除。
void
markAlertAsFalse
(
AlertInfoBO
alert
)
{
if
(
isClosed
)
return
;
final
updatedAlerts
=
state
.
alerts
.
map
((
item
)
{
if
(
item
.
title
==
alert
.
title
&&
item
.
time
==
alert
.
time
)
{
return
AlertInfoBO
(
title:
item
.
title
,
description:
item
.
description
,
time:
item
.
time
,
status:
'误报'
,
_publishCameraAlarmResult
(
alert
,
'false_alarm'
);
final
removedCameraAlerts
=
state
.
cameraAlerts
.
where
((
item
)
=>
item
!=
alert
).
toList
();
final
removedAlerts
=
state
.
alerts
.
where
((
item
)
=>
item
!=
alert
).
toList
();
emit
(
state
.
copyWith
(
cameraAlerts:
removedCameraAlerts
,
alerts:
removedAlerts
,
selectedAlert:
null
,
));
}
/// 上行 MQTT camera/{SN}/up 告警处理结果
void
_publishCameraAlarmResult
(
AlertInfoBO
alert
,
String
status
)
{
final
client
=
_mqttClient
;
final
deviceSn
=
_mqttDeviceSn
;
if
(
client
==
null
||
!
client
.
isConnected
||
deviceSn
==
null
||
deviceSn
.
isEmpty
)
return
;
if
(
alert
.
alarmId
==
null
)
return
;
try
{
client
.
publishCameraAlarmResult
(
deviceSn:
deviceSn
,
alarmId:
alert
.
alarmId
!,
status:
status
,
);
debugPrint
(
'[告警处理] MQTT 上行成功 alarmId=
${alert.alarmId}
status=
$status
'
);
}
catch
(
e
)
{
debugPrint
(
'[告警处理] MQTT 上行失败:
$e
'
);
}
return
item
;
}).
toList
();
emit
(
state
.
copyWith
(
alerts:
updatedAlerts
,
selectedAlert:
null
));
}
@override
...
...
lib/views/monitoring/index/widgets/monitoring_pet_info_card.dart
View file @
fb9b8d79
import
'package:flutter/material.dart'
;
import
'package:flutter_screenutil/flutter_screenutil.dart'
;
import
'package:laki_icu_app/models/bo/monitoring_bo.dart'
;
...
...
lib/views/settings/factory_settings/cubit/factory_settings_index_cubit.dart
View file @
fb9b8d79
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:laki_icu_app/blocs/device_threshold_config/device_threshold_config.dart'
;
import
'factory_settings_index_state.dart'
;
class
FactorySettingsIndexCubit
extends
Cubit
<
FactorySettingsIndexState
>
{
FactorySettingsIndexCubit
()
:
super
(
const
FactorySettingsIndexState
());
FactorySettingsIndexCubit
({
required
DeviceThresholdConfigBloc
thresholdConfigBloc
,
})
:
_thresholdConfigBloc
=
thresholdConfigBloc
,
super
(
FactorySettingsIndexState
(
editingConfig:
thresholdConfigBloc
.
state
.
config
,
));
final
DeviceThresholdConfigBloc
_thresholdConfigBloc
;
void
editTempMax
(
int
value
)
{
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
tempMax:
value
),
isDirty:
true
,
));
}
void
editTempMin
(
int
value
)
{
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
tempMin:
value
),
isDirty:
true
,
));
}
void
editOxygenMax
(
int
value
)
{
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
oxygenMax:
value
),
isDirty:
true
,
));
}
void
editOxygenMin
(
int
value
)
{
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
oxygenMin:
value
),
isDirty:
true
,
));
}
void
editHumidityMax
(
int
value
)
{
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
humidityMax:
value
),
isDirty:
true
,
));
}
void
editHumidityMin
(
int
value
)
{
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
humidityMin:
value
),
isDirty:
true
,
));
}
void
editUvTimeMax
(
int
value
)
{
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
uvTimeMax:
value
),
isDirty:
true
,
));
}
void
editIrTimeMax
(
int
value
)
{
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
irTimeMax:
value
),
isDirty:
true
,
));
}
void
editAtomizeTimeMax
(
int
value
)
{
emit
(
state
.
copyWith
(
editingConfig:
state
.
editingConfig
.
copyWith
(
atomizeTimeMax:
value
),
isDirty:
true
,
));
}
void
applyChanges
()
{
_thresholdConfigBloc
.
updateConfig
(
state
.
editingConfig
);
emit
(
state
.
copyWith
(
isDirty:
false
));
}
void
resetEdits
()
{
emit
(
state
.
copyWith
(
editingConfig:
_thresholdConfigBloc
.
state
.
config
,
isDirty:
false
,
));
}
}
lib/views/settings/factory_settings/cubit/factory_settings_index_state.dart
View file @
fb9b8d79
import
'package:equatable/equatable.dart'
;
import
'package:laki_icu_app/models/bo/device_threshold_config_bo.dart'
;
class
FactorySettingItem
extends
Equatable
{
const
FactorySettingItem
({
...
...
@@ -29,47 +30,63 @@ class FactorySettingGroup extends Equatable {
class
FactorySettingsIndexState
extends
Equatable
{
const
FactorySettingsIndexState
({
this
.
warningText
=
'非专业人员请勿更改设备各项参数!'
,
this
.
leftGroups
=
const
[
this
.
editingConfig
=
DeviceThresholdConfigBO
.
defaultConfig
,
this
.
isDirty
=
false
,
});
final
String
warningText
;
final
DeviceThresholdConfigBO
editingConfig
;
final
bool
isDirty
;
List
<
FactorySettingGroup
>
get
leftGroups
=>
[
FactorySettingGroup
(
title:
'温度范围设定(℃)'
,
items:
[
FactorySettingItem
(
label:
'温度设定上限:'
,
value:
'34
'
),
FactorySettingItem
(
label:
'温度设定下限:'
,
value:
'17
'
),
FactorySettingItem
(
label:
'温度设定上限:'
,
value:
'
${editingConfig.tempMax}
'
),
FactorySettingItem
(
label:
'温度设定下限:'
,
value:
'
${editingConfig.tempMin}
'
),
],
),
FactorySettingGroup
(
title:
'氧浓度范围设定(%)'
,
items:
[
FactorySettingItem
(
label:
'氧浓度设定上限:'
,
value:
'34
'
),
FactorySettingItem
(
label:
'氧浓度设定下限:'
,
value:
'17
'
),
FactorySettingItem
(
label:
'氧浓度设定上限:'
,
value:
'
${editingConfig.oxygenMax}
'
),
FactorySettingItem
(
label:
'氧浓度设定下限:'
,
value:
'
${editingConfig.oxygenMin}
'
),
],
),
FactorySettingGroup
(
title:
'湿度范围设定(%)'
,
items:
[
FactorySettingItem
(
label:
'湿度设定上限:'
,
value:
'34
'
),
FactorySettingItem
(
label:
'湿度设定下限:'
,
value:
'17
'
),
FactorySettingItem
(
label:
'湿度设定上限:'
,
value:
'
${editingConfig.humidityMax}
'
),
FactorySettingItem
(
label:
'湿度设定下限:'
,
value:
'
${editingConfig.humidityMin}
'
),
],
),
],
this
.
timeLimitGroup
=
const
FactorySettingGroup
(
];
FactorySettingGroup
get
timeLimitGroup
=>
FactorySettingGroup
(
title:
'时间上限设定(分钟)'
,
items:
[
FactorySettingItem
(
label:
'UV时间设定上限:'
,
value:
'34
'
),
FactorySettingItem
(
label:
'红外时间设定上限:'
,
value:
'17
'
),
FactorySettingItem
(
label:
'雾化时间设定上限:'
,
value:
'17
'
),
FactorySettingItem
(
label:
'UV时间设定上限:'
,
value:
'
${editingConfig.uvTimeMax}
'
),
FactorySettingItem
(
label:
'红外时间设定上限:'
,
value:
'
${editingConfig.irTimeMax}
'
),
FactorySettingItem
(
label:
'雾化时间设定上限:'
,
value:
'
${editingConfig.atomizeTimeMax}
'
),
],
),
});
);
final
String
warningText
;
final
List
<
FactorySettingGroup
>
leftGroups
;
final
FactorySettingGroup
timeLimitGroup
;
FactorySettingsIndexState
copyWith
({
String
?
warningText
,
DeviceThresholdConfigBO
?
editingConfig
,
bool
?
isDirty
,
})
{
return
FactorySettingsIndexState
(
warningText:
warningText
??
this
.
warningText
,
editingConfig:
editingConfig
??
this
.
editingConfig
,
isDirty:
isDirty
??
this
.
isDirty
,
);
}
@override
List
<
Object
?>
get
props
=>
[
warningText
,
leftGroups
,
timeLimitGroup
,
editingConfig
,
isDirty
,
];
}
lib/views/settings/factory_settings/factory_settings_index_view.dart
View file @
fb9b8d79
import
'package:flutter/material.dart'
;
import
'package:flutter_bloc/flutter_bloc.dart'
;
import
'package:laki_icu_app/blocs/device_threshold_config/device_threshold_config.dart'
;
import
'cubit/factory_settings_index_cubit.dart'
;
import
'widgets/factory_settings_panel.dart'
;
...
...
@@ -10,7 +11,9 @@ class FactorySettingsIndexView extends StatelessWidget {
@override
Widget
build
(
BuildContext
context
)
{
return
BlocProvider
(
create:
(
_
)
=>
FactorySettingsIndexCubit
(),
create:
(
_
)
=>
FactorySettingsIndexCubit
(
thresholdConfigBloc:
context
.
read
<
DeviceThresholdConfigBloc
>(),
),
child:
const
FactorySettingsPanel
(),
);
}
...
...
lib/views/settings/factory_settings/widgets/factory_settings_panel.dart
View file @
fb9b8d79
...
...
@@ -38,6 +38,7 @@ class FactorySettingsPanel extends StatelessWidget {
Expanded
(
child:
_FactoryActionColumn
(
group:
state
.
timeLimitGroup
,
isDirty:
state
.
isDirty
,
),
),
],
...
...
@@ -107,12 +108,17 @@ class _FactorySettingsColumn extends StatelessWidget {
}
class
_FactoryActionColumn
extends
StatelessWidget
{
const
_FactoryActionColumn
({
required
this
.
group
});
const
_FactoryActionColumn
({
required
this
.
group
,
required
this
.
isDirty
,
});
final
FactorySettingGroup
group
;
final
bool
isDirty
;
@override
Widget
build
(
BuildContext
context
)
{
final
cubit
=
context
.
read
<
FactorySettingsIndexCubit
>();
return
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
[
...
...
@@ -130,9 +136,19 @@ class _FactoryActionColumn extends StatelessWidget {
SizedBox
(
height:
64
.
h
),
Row
(
children:
[
const
Expanded
(
child:
_FactoryButton
(
text:
'撤销'
)),
Expanded
(
child:
_FactoryButton
(
text:
'撤销'
,
onPressed:
isDirty
?
()
=>
cubit
.
resetEdits
()
:
null
,
),
),
SizedBox
(
width:
34
.
w
),
const
Expanded
(
child:
_FactoryButton
(
text:
'应用更改'
)),
Expanded
(
child:
_FactoryButton
(
text:
'应用更改'
,
onPressed:
isDirty
?
()
=>
cubit
.
applyChanges
()
:
null
,
),
),
],
),
],
...
...
@@ -175,6 +191,41 @@ class _FactorySettingRow extends StatelessWidget {
final
FactorySettingItem
item
;
void
_onTap
(
BuildContext
context
)
{
final
cubit
=
context
.
read
<
FactorySettingsIndexCubit
>();
final
currentValue
=
int
.
tryParse
(
item
.
value
)
??
0
;
showDialog
<
int
>(
context:
context
,
builder:
(
context
)
=>
_EditDialog
(
label:
item
.
label
,
initialValue:
currentValue
,
),
).
then
((
value
)
{
if
(
value
!=
null
)
{
if
(
item
.
label
==
'温度设定上限:'
)
{
cubit
.
editTempMax
(
value
);
}
else
if
(
item
.
label
==
'温度设定下限:'
)
{
cubit
.
editTempMin
(
value
);
}
else
if
(
item
.
label
==
'氧浓度设定上限:'
)
{
cubit
.
editOxygenMax
(
value
);
}
else
if
(
item
.
label
==
'氧浓度设定下限:'
)
{
cubit
.
editOxygenMin
(
value
);
}
else
if
(
item
.
label
==
'湿度设定上限:'
)
{
cubit
.
editHumidityMax
(
value
);
}
else
if
(
item
.
label
==
'湿度设定下限:'
)
{
cubit
.
editHumidityMin
(
value
);
}
else
if
(
item
.
label
==
'UV时间设定上限:'
)
{
cubit
.
editUvTimeMax
(
value
);
}
else
if
(
item
.
label
==
'红外时间设定上限:'
)
{
cubit
.
editIrTimeMax
(
value
);
}
else
if
(
item
.
label
==
'雾化时间设定上限:'
)
{
cubit
.
editAtomizeTimeMax
(
value
);
}
}
});
}
@override
Widget
build
(
BuildContext
context
)
{
return
Row
(
...
...
@@ -192,7 +243,10 @@ class _FactorySettingRow extends StatelessWidget {
),
),
SizedBox
(
width:
16
.
w
),
_ValueBox
(
value:
item
.
value
),
GestureDetector
(
onTap:
()
=>
_onTap
(
context
),
child:
_ValueBox
(
value:
item
.
value
),
),
],
);
}
...
...
@@ -242,22 +296,29 @@ class _WideFactoryButton extends StatelessWidget {
}
class
_FactoryButton
extends
StatelessWidget
{
const
_FactoryButton
({
required
this
.
text
});
const
_FactoryButton
({
required
this
.
text
,
this
.
onPressed
,
});
final
String
text
;
final
VoidCallback
?
onPressed
;
@override
Widget
build
(
BuildContext
context
)
{
return
Container
(
final
isEnabled
=
onPressed
!=
null
;
return
GestureDetector
(
onTap:
onPressed
,
child:
Container
(
height:
70
.
h
,
padding:
EdgeInsets
.
symmetric
(
horizontal:
28
.
w
),
decoration:
settingsButtonDecoration
(
active:
true
),
decoration:
settingsButtonDecoration
(
active:
isEnabled
),
child:
Row
(
children:
[
Text
(
'《
《'
,
'
《'
,
style:
TextStyle
(
color:
const
Color
(
0xFF67C9F5
).
withValues
(
alpha:
0.72
),
color:
const
Color
(
0xFF67C9F5
).
withValues
(
alpha:
isEnabled
?
0.72
:
0.3
),
fontSize:
25
.
sp
,
fontWeight:
FontWeight
.
w700
,
),
...
...
@@ -269,22 +330,84 @@ class _FactoryButton extends StatelessWidget {
overflow:
TextOverflow
.
ellipsis
,
textAlign:
TextAlign
.
center
,
style:
TextStyle
(
color:
Colors
.
white
,
color:
isEnabled
?
Colors
.
white
:
Colors
.
white
.
withValues
(
alpha:
0.5
)
,
fontSize:
25
.
sp
,
fontWeight:
FontWeight
.
w800
,
),
),
),
Text
(
'》
》'
,
'
》'
,
style:
TextStyle
(
color:
const
Color
(
0xFF67C9F5
).
withValues
(
alpha:
0.72
),
color:
const
Color
(
0xFF67C9F5
).
withValues
(
alpha:
isEnabled
?
0.72
:
0.3
),
fontSize:
25
.
sp
,
fontWeight:
FontWeight
.
w700
,
),
),
],
),
),
);
}
}
class
_EditDialog
extends
StatefulWidget
{
const
_EditDialog
({
required
this
.
label
,
required
this
.
initialValue
,
});
final
String
label
;
final
int
initialValue
;
@override
State
<
_EditDialog
>
createState
()
=>
_EditDialogState
();
}
class
_EditDialogState
extends
State
<
_EditDialog
>
{
late
final
TextEditingController
_controller
;
@override
void
initState
()
{
super
.
initState
();
_controller
=
TextEditingController
(
text:
'
${widget.initialValue}
'
);
}
@override
void
dispose
()
{
_controller
.
dispose
();
super
.
dispose
();
}
void
_onSave
()
{
final
value
=
int
.
tryParse
(
_controller
.
text
);
if
(
value
!=
null
)
{
Navigator
.
of
(
context
).
pop
(
value
);
}
}
@override
Widget
build
(
BuildContext
context
)
{
return
AlertDialog
(
title:
Text
(
widget
.
label
),
content:
TextField
(
controller:
_controller
,
keyboardType:
TextInputType
.
number
,
decoration:
const
InputDecoration
(
hintText:
'请输入数值'
,
),
autofocus:
true
,
),
actions:
[
TextButton
(
onPressed:
()
=>
Navigator
.
of
(
context
).
pop
(),
child:
const
Text
(
'取消'
),
),
TextButton
(
onPressed:
_onSave
,
child:
const
Text
(
'确定'
),
),
],
);
}
}
pubspec.yaml
View file @
fb9b8d79
...
...
@@ -61,6 +61,7 @@ dependencies:
mqtt_client
:
^10.5.1
marionette_flutter
:
^0.5.0
hydrated_bloc
:
^9.1.5
intl
:
^0.20.2
dev_dependencies
:
flutter_test
:
sdk
:
flutter
...
...
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