Commit d1e20f66 authored by akari's avatar akari

feat: 添加设备校准页面

parent 907782b8
...@@ -14,6 +14,14 @@ class FactorySettingsIndexCubit extends Cubit<FactorySettingsIndexState> { ...@@ -14,6 +14,14 @@ class FactorySettingsIndexCubit extends Cubit<FactorySettingsIndexState> {
final DeviceThresholdConfigBloc _thresholdConfigBloc; final DeviceThresholdConfigBloc _thresholdConfigBloc;
void showCalibrationPage() {
emit(state.copyWith(isCalibrationPage: true));
}
void hideCalibrationPage() {
emit(state.copyWith(isCalibrationPage: false));
}
void editTempMax(int value) { void editTempMax(int value) {
emit(state.copyWith( emit(state.copyWith(
editingConfig: state.editingConfig.copyWith(tempMax: value), editingConfig: state.editingConfig.copyWith(tempMax: value),
......
...@@ -32,32 +32,40 @@ class FactorySettingsIndexState extends Equatable { ...@@ -32,32 +32,40 @@ class FactorySettingsIndexState extends Equatable {
this.warningText = '非专业人员请勿更改设备各项参数!', this.warningText = '非专业人员请勿更改设备各项参数!',
this.editingConfig = DeviceThresholdConfigBO.defaultConfig, this.editingConfig = DeviceThresholdConfigBO.defaultConfig,
this.isDirty = false, this.isDirty = false,
this.isCalibrationPage = false,
}); });
final String warningText; final String warningText;
final DeviceThresholdConfigBO editingConfig; final DeviceThresholdConfigBO editingConfig;
final bool isDirty; final bool isDirty;
final bool isCalibrationPage;
List<FactorySettingGroup> get leftGroups => [ List<FactorySettingGroup> get leftGroups => [
FactorySettingGroup( FactorySettingGroup(
title: '温度范围设定(℃)', title: '温度范围设定(℃)',
items: [ items: [
FactorySettingItem(label: '温度设定上限:', value: '${editingConfig.tempMax}'), FactorySettingItem(
FactorySettingItem(label: '温度设定下限:', value: '${editingConfig.tempMin}'), label: '温度设定上限:', value: '${editingConfig.tempMax}'),
FactorySettingItem(
label: '温度设定下限:', value: '${editingConfig.tempMin}'),
], ],
), ),
FactorySettingGroup( FactorySettingGroup(
title: '氧浓度范围设定(%)', title: '氧浓度范围设定(%)',
items: [ items: [
FactorySettingItem(label: '氧浓度设定上限:', value: '${editingConfig.oxygenMax}'), FactorySettingItem(
FactorySettingItem(label: '氧浓度设定下限:', value: '${editingConfig.oxygenMin}'), label: '氧浓度设定上限:', value: '${editingConfig.oxygenMax}'),
FactorySettingItem(
label: '氧浓度设定下限:', value: '${editingConfig.oxygenMin}'),
], ],
), ),
FactorySettingGroup( FactorySettingGroup(
title: '湿度范围设定(%)', title: '湿度范围设定(%)',
items: [ items: [
FactorySettingItem(label: '湿度设定上限:', value: '${editingConfig.humidityMax}'), FactorySettingItem(
FactorySettingItem(label: '湿度设定下限:', value: '${editingConfig.humidityMin}'), label: '湿度设定上限:', value: '${editingConfig.humidityMax}'),
FactorySettingItem(
label: '湿度设定下限:', value: '${editingConfig.humidityMin}'),
], ],
), ),
]; ];
...@@ -65,9 +73,12 @@ class FactorySettingsIndexState extends Equatable { ...@@ -65,9 +73,12 @@ class FactorySettingsIndexState extends Equatable {
FactorySettingGroup get timeLimitGroup => FactorySettingGroup( FactorySettingGroup get timeLimitGroup => FactorySettingGroup(
title: '时间上限设定(分钟)', title: '时间上限设定(分钟)',
items: [ items: [
FactorySettingItem(label: 'UV时间设定上限:', value: '${editingConfig.uvTimeMax}'), FactorySettingItem(
FactorySettingItem(label: '红外时间设定上限:', value: '${editingConfig.irTimeMax}'), label: 'UV时间设定上限:', value: '${editingConfig.uvTimeMax}'),
FactorySettingItem(label: '雾化时间设定上限:', value: '${editingConfig.atomizeTimeMax}'), FactorySettingItem(
label: '红外时间设定上限:', value: '${editingConfig.irTimeMax}'),
FactorySettingItem(
label: '雾化时间设定上限:', value: '${editingConfig.atomizeTimeMax}'),
], ],
); );
...@@ -75,11 +86,13 @@ class FactorySettingsIndexState extends Equatable { ...@@ -75,11 +86,13 @@ class FactorySettingsIndexState extends Equatable {
String? warningText, String? warningText,
DeviceThresholdConfigBO? editingConfig, DeviceThresholdConfigBO? editingConfig,
bool? isDirty, bool? isDirty,
bool? isCalibrationPage,
}) { }) {
return FactorySettingsIndexState( return FactorySettingsIndexState(
warningText: warningText ?? this.warningText, warningText: warningText ?? this.warningText,
editingConfig: editingConfig ?? this.editingConfig, editingConfig: editingConfig ?? this.editingConfig,
isDirty: isDirty ?? this.isDirty, isDirty: isDirty ?? this.isDirty,
isCalibrationPage: isCalibrationPage ?? this.isCalibrationPage,
); );
} }
...@@ -88,5 +101,6 @@ class FactorySettingsIndexState extends Equatable { ...@@ -88,5 +101,6 @@ class FactorySettingsIndexState extends Equatable {
warningText, warningText,
editingConfig, editingConfig,
isDirty, isDirty,
isCalibrationPage,
]; ];
} }
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.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 '../cubit/factory_settings_index_cubit.dart';
class FactoryDeviceCalibrationPanel extends StatefulWidget {
const FactoryDeviceCalibrationPanel({super.key});
@override
State<FactoryDeviceCalibrationPanel> createState() =>
_FactoryDeviceCalibrationPanelState();
}
class _FactoryDeviceCalibrationPanelState
extends State<FactoryDeviceCalibrationPanel> {
late List<_CalibrationSection> _sections;
@override
void initState() {
super.initState();
_sections = _defaultSections();
}
Future<void> _editItem(_CalibrationItem item) async {
final result = await NumericKeyboard.show(
context,
initialValue: item.value,
decimalEnabled: false,
);
if (!mounted || result == null) return;
final value = result.trim();
if (value.isEmpty) return;
setState(() {
item.value = value;
});
}
void _resetDefaults() {
setState(() {
_sections = _defaultSections();
});
}
void _applyChanges() {
showToast('操作成功');
}
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_CalibrationSectionView(
section: _sections[0],
onItemTap: _editItem,
),
SizedBox(height: 28.h),
_CalibrationSectionView(
section: _sections[1],
onItemTap: _editItem,
),
],
),
),
),
Container(
width: 1.w,
margin: EdgeInsets.symmetric(horizontal: 42.w),
color: const Color(0xFF3A9BD2).withValues(alpha: 0.42),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_CalibrationSectionView(
section: _sections[2],
onItemTap: _editItem,
),
const Spacer(),
Center(
child: _CalibrationButton(
text: '初始化设置',
width: 360.w,
height: 72.h,
onPressed: _resetDefaults,
),
),
SizedBox(height: 46.h),
Row(
children: [
Expanded(
child: _CalibrationButton(
text: '返回',
height: 92.h,
onPressed: () {
context
.read<FactorySettingsIndexCubit>()
.hideCalibrationPage();
},
),
),
SizedBox(width: 34.w),
Expanded(
child: _CalibrationButton(
text: '应用更改',
height: 92.h,
onPressed: _applyChanges,
),
),
],
),
],
),
),
],
);
}
}
class _CalibrationSectionView extends StatelessWidget {
const _CalibrationSectionView({
required this.section,
required this.onItemTap,
});
final _CalibrationSection section;
final ValueChanged<_CalibrationItem> onItemTap;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
section.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.white,
fontSize: 26.sp,
fontWeight: FontWeight.w800,
),
),
SizedBox(height: 24.h),
for (final item in section.items) ...[
_CalibrationRow(item: item, onTap: () => onItemTap(item)),
SizedBox(height: 18.h),
],
],
);
}
}
class _CalibrationRow extends StatelessWidget {
const _CalibrationRow({
required this.item,
required this.onTap,
});
final _CalibrationItem item;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return Row(
children: [
Expanded(
child: Text(
item.label,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.white,
fontSize: 21.sp,
fontWeight: FontWeight.w600,
),
),
),
SizedBox(width: 16.w),
GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onTap,
child: _CalibrationValueBox(value: item.value),
),
],
);
}
}
class _CalibrationValueBox extends StatelessWidget {
const _CalibrationValueBox({required this.value});
final String value;
@override
Widget build(BuildContext context) {
return Container(
width: 104.w,
height: 48.h,
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color(0xFF14253A).withValues(alpha: 0.86),
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: const Color(0xFF68CFFF), width: 1.w),
),
child: Text(
value,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.white,
fontSize: 25.sp,
fontWeight: FontWeight.w800,
),
),
);
}
}
class _CalibrationButton extends StatelessWidget {
const _CalibrationButton({
required this.text,
required this.onPressed,
this.width,
required this.height,
});
final String text;
final VoidCallback onPressed;
final double? width;
final double height;
@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: onPressed,
child: Container(
width: width,
height: height,
padding: EdgeInsets.symmetric(horizontal: 28.w),
decoration: settingsButtonDecoration(active: true),
alignment: Alignment.center,
child: Text(
text,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Colors.white,
fontSize: 25.sp,
fontWeight: FontWeight.w800,
),
),
),
);
}
}
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'),
],
),
];
}
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/utils/numeric_keyboard.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';
import '../cubit/factory_settings_index_state.dart'; import '../cubit/factory_settings_index_state.dart';
import 'factory_device_calibration_panel.dart';
class FactorySettingsPanel extends StatelessWidget { class FactorySettingsPanel extends StatelessWidget {
const FactorySettingsPanel({super.key}); const FactorySettingsPanel({super.key});
...@@ -22,7 +24,9 @@ class FactorySettingsPanel extends StatelessWidget { ...@@ -22,7 +24,9 @@ class FactorySettingsPanel extends StatelessWidget {
_WarningBanner(text: state.warningText), _WarningBanner(text: state.warningText),
SizedBox(height: 44.h), SizedBox(height: 44.h),
Expanded( Expanded(
child: Row( child: state.isCalibrationPage
? const FactoryDeviceCalibrationPanel()
: Row(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
Expanded( Expanded(
...@@ -33,7 +37,8 @@ class FactorySettingsPanel extends StatelessWidget { ...@@ -33,7 +37,8 @@ class FactorySettingsPanel extends StatelessWidget {
Container( Container(
width: 1.w, width: 1.w,
margin: EdgeInsets.symmetric(horizontal: 42.w), margin: EdgeInsets.symmetric(horizontal: 42.w),
color: const Color(0xFF3A9BD2).withValues(alpha: 0.42), color:
const Color(0xFF3A9BD2).withValues(alpha: 0.42),
), ),
Expanded( Expanded(
child: _FactoryActionColumn( child: _FactoryActionColumn(
...@@ -127,9 +132,15 @@ class _FactoryActionColumn extends StatelessWidget { ...@@ -127,9 +132,15 @@ class _FactoryActionColumn extends StatelessWidget {
Center( Center(
child: Column( child: Column(
children: [ children: [
const _WideFactoryButton(text: '设备校准'), _WideFactoryButton(
text: '设备校准',
onPressed: () => cubit.showCalibrationPage(),
),
SizedBox(height: 28.h), SizedBox(height: 28.h),
const _WideFactoryButton(text: '初始化设置'), _WideFactoryButton(
text: '初始化设置',
onPressed: () => const {},
),
], ],
), ),
), ),
...@@ -191,40 +202,48 @@ class _FactorySettingRow extends StatelessWidget { ...@@ -191,40 +202,48 @@ class _FactorySettingRow extends StatelessWidget {
final FactorySettingItem item; final FactorySettingItem item;
void _onTap(BuildContext context) { Future<void> _onTap(BuildContext context) async {
final cubit = context.read<FactorySettingsIndexCubit>(); final cubit = context.read<FactorySettingsIndexCubit>();
final currentValue = int.tryParse(item.value) ?? 0; final result = await NumericKeyboard.show(
context,
initialValue: item.value == '--' ? '' : item.value,
decimalEnabled: false,
);
if (!context.mounted || result == null) return;
final value = int.tryParse(result.trim());
if (value == null) return;
showDialog<int>( switch (item.label) {
context: context, case '温度设定上限:':
builder: (context) => _EditDialog(
label: item.label,
initialValue: currentValue,
),
).then((value) {
if (value != null) {
if (item.label == '温度设定上限:') {
cubit.editTempMax(value); cubit.editTempMax(value);
} else if (item.label == '温度设定下限:') { break;
case '温度设定下限:':
cubit.editTempMin(value); cubit.editTempMin(value);
} else if (item.label == '氧浓度设定上限:') { break;
case '氧浓度设定上限:':
cubit.editOxygenMax(value); cubit.editOxygenMax(value);
} else if (item.label == '氧浓度设定下限:') { break;
case '氧浓度设定下限:':
cubit.editOxygenMin(value); cubit.editOxygenMin(value);
} else if (item.label == '湿度设定上限:') { break;
case '湿度设定上限:':
cubit.editHumidityMax(value); cubit.editHumidityMax(value);
} else if (item.label == '湿度设定下限:') { break;
case '湿度设定下限:':
cubit.editHumidityMin(value); cubit.editHumidityMin(value);
} else if (item.label == 'UV时间设定上限:') { break;
case 'UV时间设定上限:':
cubit.editUvTimeMax(value); cubit.editUvTimeMax(value);
} else if (item.label == '红外时间设定上限:') { break;
case '红外时间设定上限:':
cubit.editIrTimeMax(value); cubit.editIrTimeMax(value);
} else if (item.label == '雾化时间设定上限:') { break;
case '雾化时间设定上限:':
cubit.editAtomizeTimeMax(value); cubit.editAtomizeTimeMax(value);
break;
} }
} }
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -281,16 +300,20 @@ class _ValueBox extends StatelessWidget { ...@@ -281,16 +300,20 @@ class _ValueBox extends StatelessWidget {
} }
class _WideFactoryButton extends StatelessWidget { class _WideFactoryButton extends StatelessWidget {
const _WideFactoryButton({required this.text}); const _WideFactoryButton({required this.text, this.onPressed});
final String text; final String text;
final VoidCallback? onPressed;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(
width: 360.w, width: 360.w,
height: 110.h, height: 110.h,
child: _FactoryButton(text: text), child: _FactoryButton(
text: text,
onPressed: onPressed,
),
); );
} }
} }
...@@ -336,64 +359,3 @@ class _FactoryButton extends StatelessWidget { ...@@ -336,64 +359,3 @@ class _FactoryButton extends StatelessWidget {
); );
} }
} }
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('确定'),
),
],
);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment