import 'package:auto_route/annotations.dart'; import 'package:bot_toast/bot_toast.dart'; import 'package:eitc_erm_dental_flutter/exts.dart'; import 'package:eitc_erm_dental_flutter/funcs.dart'; import 'package:eitc_erm_dental_flutter/generated/assets.dart'; import 'package:eitc_erm_dental_flutter/pages/patient/vm/patient_view_model.dart'; import 'package:eitc_erm_dental_flutter/widget/custom_divider.dart'; import 'package:eitc_erm_dental_flutter/widget/main_button.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; EdgeInsets get _itemPadding => EdgeInsets.symmetric(horizontal: 12.w, vertical: 15.h); Widget _getTitleText(BuildContext context, String text) { return Text( text, style: Theme.of(context).textTheme.titleMedium, ); } TextStyle? _getTextStyle(BuildContext context) { return Theme.of(context).textTheme.bodySmall; } ///添加咨询人页面 @RoutePage(name: "addPatientRoute") class AddPatientPage extends ConsumerStatefulWidget { const AddPatientPage({super.key}); @override ConsumerState createState() => _AddPatientPageState(); } class _AddPatientPageState extends ConsumerState { String _relation = ""; //性别,0男性,1女性 int _gender = 0; final TextEditingController _nameController = TextEditingController(); final TextEditingController _ageController = TextEditingController(); final TextEditingController _idCardController = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(getS().addPatient), centerTitle: true, forceMaterialTransparency: true, ), body: SafeArea( child: Column( children: [ Expanded( child: Container( padding: EdgeInsets.fromLTRB(16.w, 12.h, 16.w, 12.h), color: Color(0xFFF4F4F4), child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( getS().addPatientHint, style: _getTextStyle(context), ), SizedBox( height: 8.h, ), Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10.r), ), child: Column( children: [ //性别 _RelationSelector(onSelect: _onRelationSelect), CustomDivider( height: 0.0, ), //名字 _getNameInput(), CustomDivider( height: 0.0, ), //性别 _GenderSelector(onChecked: _onGenderChecked), CustomDivider( height: 0.0, ), //年龄 _getAgeInput(), CustomDivider( height: 0.0, ), //身份证 _getIdCardInput(), ], ), ) ], ), ), )), Container( padding: EdgeInsets.fromLTRB(16.w, 14.h, 16.w, 34.h), width: double.infinity, child: MainButton(text: getS().submit, onPressed: _onSave), ) ], )), ); } Widget _getTextInput(TextEditingController controller, String hint, {TextInputType? keyboardType, int? maxLength, List? formatters}) { return TextField( textAlign: TextAlign.end, maxLength: maxLength, keyboardType: keyboardType, controller: controller, inputFormatters: formatters, style: _getTextStyle(context), decoration: InputDecoration( isDense: true, border: InputBorder.none, hintText: hint, counterText: "", hintStyle: Theme.of(context) .textTheme .bodySmall ?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant), ), ); } ///获取名字输入框 Widget _getNameInput() { return Padding( padding: _itemPadding, child: Row( children: [ _getTitleText(context, getS().name), SizedBox( width: 15.w, ), Expanded( child: _getTextInput(_nameController, getS().pleaseInputRealName)), ], ), ); } ///获取年龄输入框 Widget _getAgeInput() { return Padding( padding: _itemPadding, child: Row( children: [ _getTitleText(context, getS().age), SizedBox( width: 15.w, ), Expanded( child: _getTextInput(_ageController, getS().pleaseInputAge, maxLength: 3, keyboardType: TextInputType.number, formatters: [FilteringTextInputFormatter.digitsOnly])), ], ), ); } ///获取身份证输入框 Widget _getIdCardInput() { return Padding( padding: _itemPadding, child: Row( children: [ _getTitleText(context, getS().idCard), SizedBox( width: 15.w, ), Expanded( child: _getTextInput( _idCardController, getS().pleaseInputValidIdCard, maxLength: 18, formatters: [ FilteringTextInputFormatter.allow(RegExp(r'[0-9Xx]')) ])), ], ), ); } ///当选择了关系 void _onRelationSelect(String relation) { _relation = relation; } ///当选择了性别 void _onGenderChecked(int gender) { logd("选择了性别=$gender"); _gender = gender; } bool _checkInput() { if (_relation.isEmpty) { showToast(text: getS().pleaseSelectRelation); return false; } if (_nameController.text.isEmpty) { showToast(text: getS().pleaseInputRealName); return false; } if (_ageController.text.isEmpty) { showToast(text: getS().pleaseInputAge); return false; } if (!validIdCard(_idCardController.text)) { showToast(text: getS().pleaseInputValidIdCard); return false; } String idCard = _idCardController.text; try { int age = getAgeFromIdCard(idCard); int sex = getGenderFromIdCard(idCard); //判断年龄 if (age != int.parse(_ageController.text)) { showToast(text: getS().ageNotMatchIdCard); return false; } if (!((sex == 1 && _gender == 1) || (sex == 0 && _gender == 0))) { showToast(text: getS().genderNotMatchIdCard); return false; } } catch (e) { loge("校验身份证异常", error: e); } return true; } ///保存 void _onSave() async { if (!_checkInput()) { return; } var cancelFunc = BotToast.showLoading( clickClose: false, crossPage: false, backButtonBehavior: BackButtonBehavior.ignore); bool bo = await ref .read(patientListProvider.notifier) .addPatient(_nameController.text, _idCardController.text, _relation); cancelFunc(); if (bo) { showToast(text: getS().saveSuccess); if (mounted) { Navigator.pop(context, true); } } else { showToast(text: getS().saveFailed); } } } ///关系选择器 class _RelationSelector extends ConsumerStatefulWidget { final void Function(String) onSelect; const _RelationSelector({required this.onSelect}); @override ConsumerState createState() => __RelationSelectorState(); } class __RelationSelectorState extends ConsumerState<_RelationSelector> { String _selectedRelation = ""; bool _isLoading = true; List _relationList = []; @override void initState() { super.initState(); ref.listenManual(patientRelationListProvider, (_, value) { if (value is AsyncLoading) { return; } if (value is AsyncData>) { AsyncData> data = value; _relationList = data.value; } setState(() { _isLoading = false; }); }); } @override Widget build(BuildContext context) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: _onTap, child: Padding( padding: _itemPadding, child: Row( children: [ _getTitleText(context, getS().relation), Spacer(), if (_isLoading) SizedBox.fromSize( size: Size.square(15.r), child: CircularProgressIndicator(), ) else Row( children: [ Text( _selectedRelation.isEmpty ? getS().pleaseSelectRelation : _selectedRelation, style: _getTextStyle(context), ), SizedBox( width: 5.w, ), Icon( Icons.arrow_forward_ios, size: 15.r, ) ], ) ], ), ), ); } void _onTap() async { List list = _relationList; String? result = await showModalBottomSheet( context: context, builder: (_) { return Container( padding: EdgeInsets.symmetric(vertical: 15.h), width: double.infinity, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8.r)), child: ListView.builder( shrinkWrap: true, itemBuilder: (ctx, index) { String relation = list[index]; return GestureDetector( onTap: () => Navigator.pop(ctx, relation), child: Padding( padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.h), child: Text( relation, textAlign: TextAlign.center, style: Theme.of(ctx).textTheme.titleMedium, ), ), ); }, itemCount: list.length, ), ); }); logd("选择了$result"); if (result.isNullOrEmpty) { return; } setState(() { _selectedRelation = result!; }); widget.onSelect(result!); } } ///性别选择器 class _GenderSelector extends StatefulWidget { final void Function(int gender) onChecked; const _GenderSelector({required this.onChecked}); @override State<_GenderSelector> createState() => _GenderSelectorState(); } class _GenderSelectorState extends State<_GenderSelector> { int _gender = 0; @override Widget build(BuildContext context) { return Padding( padding: _itemPadding, child: Row( children: [ _getTitleText(context, getS().gender), Spacer(), Row( children: [ _getCheck(0, getS().male), SizedBox( width: 20.w, ), _getCheck(1, getS().female), ], ) ], ), ); } Widget _getCheck(int checkedValue, String text) { return GestureDetector( onTap: () { setState(() { _gender = checkedValue; }); widget.onChecked(checkedValue); }, child: Row( children: [ SizedBox( width: 24.r, height: 24.r, child: Image.asset(_gender == checkedValue ? Assets.imagesIconGenderChecked : Assets.imagesIconGenderUnchecked), ), Text( text, style: _getTextStyle(context), ) ], ), ); } }