Melon 9 months ago
parent
commit
6494e7079b

+ 6 - 1
lib/process/primitives/rvsp.dart

@@ -24,7 +24,7 @@ class Rvsp extends TopMeasureItem<RvspFeature> {
     final rapOutputMeta =
         ItemOutputMeta(MeasureTerms.RAP, "RAP", VidUsUnit.mmHg);
 
-    _rap = FloatValue(rapOutputMeta, 0, rapOutputMeta.unit);
+    _rap = FloatValue(rapOutputMeta, 0.0, rapOutputMeta.unit);
     // final rapMeta = ItemMeta(
     //   MeasureTerms.RAP,
     //   measureType: MeasureTerms.Placeholder,
@@ -46,6 +46,11 @@ class Rvsp extends TopMeasureItem<RvspFeature> {
   @override
   RvspFeature buildFeature() => RvspFeature(this);
 
+  void updateRap(double val) {
+    _rap.value = val;
+    calculator?.calculate();
+  }
+
   static Rvsp createRvsp(
     ItemMeta meta, [
     IMeasureItem? parent,

+ 99 - 0
lib/view/measure/custom_item_buttons/combo.dart

@@ -0,0 +1,99 @@
+import 'package:fis_measure/interfaces/process/items/item_metas.dart';
+import 'package:fis_measure/interfaces/process/items/types.dart';
+import 'package:fis_ui/index.dart';
+import 'package:fis_ui/interface/interactive_container.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import '../measure_tool.dart';
+import 'normal_child.dart';
+import 'rvsp.dart';
+
+class CustomComboItemGroup extends FStatelessWidget {
+  static List<String> get specialItemTypes =>
+      specialItemChildTypes.keys.toList();
+
+  static final Map<String, List<String>> specialItemChildTypes = {
+    MeasureTypes.RVSP: ["Rap"],
+  };
+
+  final FInteractiveContainer businessParent;
+  final ItemMeta itemMeta;
+  final int activeIndex;
+  final ValueChanged<int> onChildClick;
+
+  const CustomComboItemGroup({
+    super.key,
+    required this.businessParent,
+    required this.onChildClick,
+    required this.itemMeta,
+    required this.activeIndex,
+  });
+
+  @override
+  FWidget build(BuildContext context) {
+    List<FWidget> children = [];
+    for (var i = 0; i < itemMeta.childItems.length; i++) {
+      final childItem = itemMeta.childItems[i];
+      children.add(
+        NormalChildButton(
+          businessParent: businessParent,
+          activeIndex: activeIndex,
+          index: i,
+          itemMeta: childItem,
+          onClick: () {
+            onChildClick.call(i);
+          },
+        ),
+      );
+    }
+    final specialWidgets = _buildSpecialWidgets();
+    if (specialWidgets != null && specialWidgets.isNotEmpty) {
+      children.addAll(specialWidgets);
+    }
+
+    return FContainer(
+      decoration: const BoxDecoration(
+        color: LeftSiderSelectMeasureState.childContainerBackground,
+        borderRadius: BorderRadius.only(
+            bottomLeft: Radius.circular(5), bottomRight: Radius.circular(5)),
+      ),
+      padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 5),
+      child: FColumn(
+        children: children,
+      ),
+    );
+  }
+
+  List<FWidget>? _buildSpecialWidgets() {
+    final type = itemMeta.measureType;
+    final childNames = specialItemChildTypes[type];
+    if (childNames != null) {
+      return childNames
+          .map((e) => _SpecialChildItemWidget(typeName: e))
+          .toList();
+    }
+    return null;
+  }
+}
+
+class _SpecialChildItemWidget extends FStatelessWidget {
+  late final Map<String, FWidgetBuilder> _specialWidgetMap = {
+    "Rap": buildRap,
+  };
+
+  final String typeName;
+
+  _SpecialChildItemWidget({required this.typeName});
+
+  @override
+  FWidget build(BuildContext context) {
+    final builder = _specialWidgetMap[typeName]!;
+    final widget = builder(context);
+    return widget;
+  }
+
+  FWidget buildRap(BuildContext context) {
+    return RVSPItemButton();
+  }
+}

+ 54 - 0
lib/view/measure/custom_item_buttons/normal_child.dart

@@ -0,0 +1,54 @@
+import 'package:fis_measure/interfaces/process/items/item_metas.dart';
+import 'package:fis_ui/index.dart';
+import 'package:fis_ui/interface/interactive_container.dart';
+import 'package:flutter/material.dart';
+
+import '../measure_tool.dart';
+
+class NormalChildButton extends FStatelessWidget {
+  final int activeIndex;
+  final int index;
+  final ItemMeta itemMeta;
+
+  final VoidCallback onClick;
+
+  final FInteractiveContainer businessParent;
+
+  const NormalChildButton({
+    super.key,
+    required this.activeIndex,
+    required this.index,
+    required this.itemMeta,
+    required this.onClick,
+    required this.businessParent,
+  });
+
+  @override
+  FWidget build(BuildContext context) {
+    final isActived = index == activeIndex;
+    return FContainer(
+      width: double.infinity,
+      margin: const EdgeInsetsDirectional.all(5),
+      child: FElevatedButton(
+        businessParent: businessParent,
+        name: "selectChildItemIdnex:$index",
+        onPressed: () {
+          onClick.call();
+        },
+        child: FText(
+          itemMeta.description,
+        ),
+        style: ElevatedButton.styleFrom(
+          backgroundColor: isActived
+              ? null
+              : LeftSiderSelectMeasureState.buttonBackgroundColor,
+          side: BorderSide(
+            color: isActived
+                ? Colors.transparent
+                : LeftSiderSelectMeasureState.buttonBorderColor,
+          ),
+        ),
+      ),
+    );
+  }
+}

+ 272 - 0
lib/view/measure/custom_item_buttons/rvsp.dart

@@ -0,0 +1,272 @@
+import 'package:fis_i18n/i18n.dart';
+import 'package:fis_measure/define.dart';
+import 'package:fis_measure/interfaces/process/items/item_metas.dart';
+import 'package:fis_measure/interfaces/process/workspace/application.dart';
+import 'package:fis_measure/process/primitives/rvsp.dart';
+import 'package:fis_measure/utils/prompt_box.dart';
+import 'package:fis_ui/index.dart';
+import 'package:fis_ui/interface/interactive_container.dart';
+import 'package:flutter/material.dart';
+import 'package:get/get.dart';
+
+import 'normal_child.dart';
+
+class RVSPItemButton extends FStatefulWidget {
+  const RVSPItemButton({super.key});
+
+  @override
+  FState<FStatefulWidget> createState() => _RVSPItemButtonState();
+}
+
+class _RVSPItemButtonState extends FState<RVSPItemButton> {
+  static const _options = <double>[double.nan, 5, 10, 15];
+  late final RxInt _activeIndex;
+  double _customRapValue = 0;
+
+  @override
+  void initState() {
+    _initState();
+    super.initState();
+  }
+
+  @override
+  FWidget build(BuildContext context) {
+    return NormalChildButton(
+      businessParent: const FPlaceHolderInteractiveContainer(),
+      activeIndex: -1,
+      index: 0,
+      itemMeta: ItemMeta(
+        "RAP",
+        measureType: '',
+        description: 'RAP',
+        outputs: [],
+      ),
+      onClick: () {
+        Get.dialog(_buildDialog());
+      },
+    );
+  }
+
+  void _initState() {
+    final activeMeasureItem = Get.find<IApplication>().activeMeasureItem;
+    if (activeMeasureItem == null) {
+      _activeIndex = RxInt(0);
+      return;
+    }
+    final rap = (activeMeasureItem as Rvsp).rap.value;
+    if (rap == null) {
+      _activeIndex = RxInt(0);
+      return;
+    }
+    final index = _options.indexWhere((e) => e == rap);
+    if (index > 0) {
+      _activeIndex = RxInt(index);
+    } else {
+      _customRapValue = rap;
+      _activeIndex = RxInt(0);
+    }
+  }
+
+  FWidget _buildDialog() {
+    return FObx(() {
+      final children = <Widget>[];
+      for (var i = 0; i < _options.length; i++) {
+        if (i == 0) {
+          children.add(_buildInputButton());
+        } else {
+          children.add(const CustomChildOptionDivider());
+          children.add(_buildValueButton(i));
+        }
+      }
+      return FSimpleDialog(
+        title: const FText("RAP", style: TextStyle(color: Colors.white)),
+        okString: i18nBook.common.confirm.t,
+        cancelString: i18nBook.common.cancel.t,
+        isDefault: true,
+        children: children,
+        onOk: () {
+          _onValueConfrim();
+          Get.back();
+        },
+        onCancel: () {
+          Get.back();
+        },
+        onClose: () {
+          Get.back();
+        },
+      );
+    });
+  }
+
+  void _onValueConfrim() {
+    final activeMeasureItem = Get.find<IApplication>().activeMeasureItem;
+    if (activeMeasureItem == null) {
+      return;
+    }
+
+    double rap;
+    if (_activeIndex.value == 0) {
+      rap = _customRapValue;
+    } else {
+      rap = _options[_activeIndex.value];
+    }
+
+    (activeMeasureItem as Rvsp).updateRap(rap);
+  }
+
+  Widget _buildValueButton(int index) {
+    final isActive = _activeIndex.value == index;
+    final value = _options[index];
+    return CustomChildTextOptionWidget(
+      isActive: isActive,
+      text: "$value mmHg",
+      onClick: () {
+        _activeIndex.value = index;
+      },
+    );
+  }
+
+  Widget _buildInputButton() {
+    const index = 0;
+    final isActive = _activeIndex.value == index;
+    return CustomChildInputOptionWidget(
+      isActive: isActive,
+      value: _customRapValue.toString(),
+      onClick: () {
+        _activeIndex.value = index;
+      },
+      onInputChanged: (String value) {
+        final doubleValue = double.tryParse(value);
+        if (doubleValue == null) {
+          PromptBox.toast("请输入正确的RAP数值");
+        } else {
+          _customRapValue = doubleValue;
+        }
+      },
+    );
+  }
+}
+
+class CustomChildInputOptionWidget extends StatelessWidget {
+  final bool isActive;
+  final String value;
+  final Widget? suffixWidget;
+  final VoidCallback onClick;
+  final ValueChanged<String> onInputChanged;
+
+  const CustomChildInputOptionWidget({
+    super.key,
+    required this.isActive,
+    required this.value,
+    required this.onClick,
+    required this.onInputChanged,
+    this.suffixWidget,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return CustomChildOptionWidget(
+      isActive: isActive,
+      onClick: onClick,
+      child: _buildInput(context),
+    );
+  }
+
+  Widget _buildInput(BuildContext context) {
+    final children = <Widget>[];
+    children.add(
+      FBorderInput(
+        controller: TextEditingController(text: value),
+        onChanged: (value) {
+          onInputChanged.call(value);
+        },
+      ),
+    );
+    if (suffixWidget != null) {
+      children.add(suffixWidget!);
+    }
+    return Row(
+      children: children,
+      mainAxisAlignment: MainAxisAlignment.center,
+    );
+  }
+}
+
+class CustomChildOptionDivider extends StatelessWidget {
+  const CustomChildOptionDivider({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Divider(color: Colors.grey.shade100, height: 1);
+  }
+}
+
+class CustomChildTextOptionWidget extends StatelessWidget {
+  final bool isActive;
+  final String text;
+  final VoidCallback onClick;
+
+  const CustomChildTextOptionWidget({
+    super.key,
+    required this.isActive,
+    required this.text,
+    required this.onClick,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return CustomChildOptionWidget(
+      child: Text(text),
+      isActive: isActive,
+      onClick: onClick,
+    );
+  }
+}
+
+class CustomChildOptionWidget extends StatelessWidget {
+  final bool isActive;
+  final Widget child;
+  final VoidCallback onClick;
+
+  const CustomChildOptionWidget({
+    super.key,
+    required this.isActive,
+    required this.child,
+    required this.onClick,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return Material(
+      child: Container(
+        margin: const EdgeInsets.only(bottom: 4),
+        child: GestureDetector(
+          onTap: () {
+            onClick.call();
+          },
+          child: Container(
+            padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 18),
+            alignment: Alignment.center,
+            color: isActive
+                ? Theme.of(context).secondaryHeaderColor
+                : Colors.white,
+            child: child,
+          ),
+        ),
+      ),
+    );
+  }
+}
+
+class FPlaceHolderInteractiveContainer extends FStatelessWidget
+    implements FInteractiveContainer {
+  const FPlaceHolderInteractiveContainer({super.key});
+
+  @override
+  FWidget build(BuildContext context) {
+    return const FSizedBox();
+  }
+
+  @override
+  String get pageName => "";
+}

+ 12 - 0
lib/view/measure/measure_tool.dart

@@ -22,6 +22,8 @@ import 'package:flutter/material.dart';
 import 'package:get/get.dart';
 import 'package:vid/us/vid_us_image.dart';
 
+import 'custom_item_buttons/combo.dart';
+
 /// 测量项页面
 class LeftSiderSelectMeasure extends FStatefulWidget
     implements FInteractiveContainer {
@@ -515,6 +517,16 @@ class LeftSiderSelectMeasureState extends FState<LeftSiderSelectMeasure> {
     if (isSpecial) {
       //是否为特殊组合测量项
       return const SpecialItemHR();
+    } else if (CustomComboItemGroup.specialItemTypes
+        .contains(itemMeta.measureType)) {
+      return CustomComboItemGroup(
+        activeIndex: activeChildItemIndex,
+        businessParent: widget,
+        itemMeta: itemMeta,
+        onChildClick: (int childItemIndex) {
+          selectChildItem(childItemIndex);
+        },
+      );
     } else {
       return FContainer(
         decoration: const BoxDecoration(