import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:vitalapp/components/alert_dialog.dart'; import 'package:vitalapp/pages/check/models/form.dart'; import 'package:vitalapp/pages/check/widgets/exam_configurable/exam_card.dart'; import 'package:vitalapp/pages/medical/models/item.dart'; import 'package:vnote_device_plugin/models/exams/nibp.dart'; /// 小弹窗输入 class VDialogBloodPressure extends StatelessWidget { /// 标题 final String? title; /// 描述 final String? description; /// 输入占位符 final String? placeholder; /// 初始值 final List? initialValue; const VDialogBloodPressure({ super.key, this.title, this.description, this.placeholder, this.initialValue, }); Future show() => VAlertDialog.showDialog(this); @override Widget build(BuildContext context) { final controller1 = TextEditingController(text: initialValue?.first); final controller2 = TextEditingController(text: initialValue?.last); return VAlertDialog( title: title, width: 440, contentPadding: const EdgeInsets.symmetric(vertical: 12, horizontal: 24), content: _buildContent(context, controller1, controller2), showCancel: true, onConfirm: () { Get.back(result: json.encode([controller1.text, controller2.text])); }, ); } Widget _buildContent( BuildContext context, TextEditingController controller1, TextEditingController controller2, ) { final children = []; if (description != null) { children.add( Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: Text( description!, style: const TextStyle(color: Colors.black87, fontSize: 18), ), ), ); children.add(const SizedBox(height: 8)); } else { children.add(const SizedBox(height: 12)); } children.add(_buildInputWidget(context, controller1, controller2)); return SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: children, ), ); } Widget _buildInputWidget( BuildContext context, TextEditingController controller1, TextEditingController controller2, ) { const fontSize = 20.0; return Row( children: [ _buildItem(context, controller1, '高压'), const Text( '/', style: TextStyle(fontSize: fontSize), ), _buildItem(context, controller2, '低压'), ], ); } Widget _buildItem( BuildContext context, TextEditingController controller, String hintText, ) { const fontSize = 20.0; const height = 56.0; return Expanded( child: SizedBox( height: height, child: TextField( controller: controller, readOnly: false, autofocus: true, keyboardType: const TextInputType.numberWithOptions( decimal: true), // 允许输入数字和小数点 inputFormatters: [ FilteringTextInputFormatter.allow( RegExp(r'^\d+\.?\d{0,2}'), ), // 只允许输入数字和小数点,俩位小数 ], style: const TextStyle(fontSize: fontSize), decoration: InputDecoration( border: const UnderlineInputBorder( borderRadius: BorderRadius.zero, borderSide: BorderSide(), ), enabledBorder: const UnderlineInputBorder( borderRadius: BorderRadius.zero, borderSide: BorderSide( color: Colors.black54, ), ), focusedBorder: UnderlineInputBorder( borderRadius: BorderRadius.zero, borderSide: BorderSide( color: Theme.of(context).primaryColor.withOpacity(.4), ), ), filled: true, fillColor: Colors.white, contentPadding: const EdgeInsets.symmetric( vertical: (height - fontSize * 1.2) / 2, horizontal: 8, ), hintStyle: const TextStyle(fontSize: fontSize), labelStyle: const TextStyle(fontSize: fontSize), hintText: hintText, isCollapsed: true, ), onSubmitted: (value) { print(value); Get.back(result: value); }, ), ), ); } } /// TODO 优化血压组件,存储需要重新设计 // ignore: must_be_immutable class FollowBloodPressure extends StatefulWidget { FollowBloodPressure({ super.key, required this.currentValue, required this.bloodPressure, required this.currentFormObject, }); Map currentValue; Function(Map) bloodPressure; final FormObject currentFormObject; @override State createState() => _FollowBloodPressureState(); } class _FollowBloodPressureState extends State { PressureStatus pressureStatus = PressureStatus.left; NibpExamValue? value; NibpExamValue? _nibpExamValue; @override void initState() { if (widget.currentValue['Blood'] != null) { String currentValue = widget.currentValue['Blood']; _nibpExamValue = NibpExamValue( systolicPressure: int.parse(jsonDecode(currentValue).first.toString()), diastolicPressure: int.parse(jsonDecode(currentValue).last.toString()), pulse: 0, ); } super.initState(); } void didUpdateWidget(FollowBloodPressure oldWidget) { if (oldWidget.currentValue != widget.currentValue) { if (widget.currentValue['Blood'] != null) { String currentValue = widget.currentValue['Blood']; _nibpExamValue = NibpExamValue( systolicPressure: int.parse(jsonDecode(currentValue).first.toString()), diastolicPressure: int.parse(jsonDecode(currentValue).last.toString()), pulse: 0, ); setState(() {}); } } super.didUpdateWidget(oldWidget); } @override void dispose() { super.dispose(); } @override Widget build(BuildContext context) { return Stack( children: [ ExamCard( content: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ InkWell( child: SideBar( title: '血压', value: _buildResult( _nibpExamValue, ' mmHg', ), unit: 'mmHg', required: widget.currentFormObject.required, ), onTap: () async { String? result = await VDialogBloodPressure( title: '血压', initialValue: [ _nibpExamValue?.systolicPressure.toString() ?? '', _nibpExamValue?.diastolicPressure.toString() ?? '', ], ).show(); if (result != null) { _nibpExamValue = NibpExamValue( diastolicPressure: int.parse(jsonDecode(result).last), systolicPressure: int.parse(jsonDecode(result).first), pulse: 0, ); widget.bloodPressure({ "Blood": result, }); } setState(() {}); }, ), ], ), ), ], ); } Widget _buildResult(NibpExamValue? nibpExamValue, String? unit) { const textStyle = TextStyle(fontSize: 26, color: Colors.black); return Row( children: [ Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ Align( alignment: Alignment.centerLeft, child: RichText( text: TextSpan( text: nibpExamValue?.systolicPressure.toString() ?? '', style: textStyle, children: [ TextSpan( text: unit ?? '', style: textStyle.copyWith(fontSize: 20), ), ]), ), ), Align( alignment: Alignment.centerRight, child: RichText( text: TextSpan( text: nibpExamValue?.diastolicPressure.toString() ?? '', style: textStyle, children: [ TextSpan( text: unit ?? '', style: textStyle.copyWith(fontSize: 20), ), ], ), ), ), ], ), ], ); } } class SideBar extends StatelessWidget { final String title; final Widget value; final String unit; final bool? required; const SideBar({ required this.title, required this.value, required this.unit, this.required, }); @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( // padding: const EdgeInsets.symmetric(horizontal: 30), child: RichText( text: TextSpan( text: "", children: [ if (required ?? false) TextSpan( text: "* ", style: const TextStyle(color: Colors.red, fontSize: 35), ), TextSpan( text: title, style: TextStyle( fontSize: 26, color: Colors.black, fontFamily: "NotoSansSC", fontFamilyFallback: const ["NotoSansSC"], ), ), ], ), ), ), Container( alignment: Alignment.bottomRight, padding: const EdgeInsets.only( right: 30, ), child: Row( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ value, ], ), ), ], ); } }