import 'dart:convert'; import 'package:fis_common/event/event_type.dart'; import 'package:fis_common/index.dart'; import 'package:fis_common/logger/logger.dart'; import 'package:fis_jsonrpc/rpc.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:get/get.dart'; import 'package:vitalapp/architecture/utils/advance_debounce.dart'; import 'package:vitalapp/architecture/utils/datetime.dart'; import 'package:vitalapp/architecture/utils/prompt_box.dart'; import 'package:vitalapp/components/alert_dialog.dart'; import 'package:vitalapp/components/appbar.dart'; import 'package:vitalapp/components/button.dart'; import 'package:vitalapp/components/scroll_list.dart'; import 'package:vitalapp/components/table/table_column.dart'; import 'package:vitalapp/managers/interfaces/diagnosis.dart'; import 'package:vitalapp/managers/interfaces/models/diagnosis_aggregation_record_model.dart'; import 'package:vitalapp/managers/interfaces/patient.dart'; import 'package:vitalapp/managers/interfaces/prescription.dart'; import 'package:vitalapp/managers/interfaces/registration.dart'; import 'package:vitalapp/pages/check/examination/controller.dart'; import 'package:vitalapp/pages/check/examination/view.dart'; import 'package:vitalapp/pages/check/prescription/examination_prescription.dart'; import 'package:vitalapp/pages/check/prescription/prescription_form_keys.dart'; import 'package:vitalapp/pages/medical/controller.dart'; import 'package:vitalapp/pages/medical/views/exam_medical.dart'; import 'package:vitalapp/pages/medical_checkup_station/registration/controller.dart'; import 'package:vitalapp/pages/medical_checkup_station/registration/state/list.dart'; import 'package:vitalapp/pages/medical_checkup_station/registration/widgets/form/index.dart'; import 'package:vitalapp/pages/medical_checkup_station/registration/widgets/report/report_preview.dart'; import 'package:vitalapp/pages/medical_checkup_station/usb_print/module/printer_info.dart'; import 'package:vitalapp/pages/medical_checkup_station/usb_print/page/temp/print_preview.dart'; import 'package:vitalapp/pages/widgets/overflow_tooltip_wrapper.dart'; import 'package:vitalapp/store/store.dart'; class RegistrationListController { late RegistrationController registrationController; RegistrationListController(RegistrationController controller) { registrationController = controller; } final state = ListState(); final _registrationManager = Get.find(); final _prescriptionManager = Get.find(); ResidentModel currentResident = ResidentModel(idNumber: ""); List _allExam = [ "HEIBasic", "HEIUrinalysis", "HEIUltrasonic", "HEIBiochemical", "HEIBloodRoutine", "HEIECG", "HEITCMC" ]; Map examData = {}; List noMedicalCheckUpList() { List noCheckUpList = _allExam .where((element) => !(currentResident.finishedExamKeys ?? []).contains(element)) .toList(); return noCheckUpList; } List medicalCheckUpList() { List checkUpList = _allExam .where((element) => (currentResident.finishedExamKeys ?? []).contains(element)) .toList(); return checkUpList; } /// 是否有健康检测的页面权限 bool _hasHealthMonitor() { bool hasAuth = false; Store.user.menuPermissionList?.forEach((element) { if (element.code == "JKJC") { hasAuth = true; } }); return hasAuth; } Future getRegisterInfoPage({ int? pageSize = 10, int? pageIndex = 1, String? keyword = "", }) async { registrationController.tableLoading = true; registrationController.currPageIndex = pageIndex!; var result = await registrationController.registrationManager .getRegisterInfoPageAsync( pageSize: pageSize, pageIndex: pageIndex, keyword: keyword, startTime: state.startTime, endTime: state.endTime, ); List _residentList = []; if (result?.pageData != null) { for (RegisterInfoDTO i in result!.pageData!) { String statusStr = ''; ExamStateEnum status = i.state; switch (status) { case ExamStateEnum.Unchecked: statusStr = "未体检"; break; case ExamStateEnum.Invalid: statusStr = "已作废"; break; case ExamStateEnum.Inspected: statusStr = "体检中"; break; case ExamStateEnum.Reported: statusStr = "已报告"; break; } _residentList.add( ResidentModel( name: i.name ?? '', idNumber: i.iDCardNo ?? '', code: i.code ?? '', homeAddress: i.adress, age: getAgeOfIdNumber(i.iDCardNo ?? ''), physicalExamNumber: i.physicalExamNumber, phone: i.phone, finishedExamKeys: i.finishedExamKeys, physicalExamStatus: statusStr, birthDay: i.birthday?.toLocal(), sex: i.sex, batchNumber: i.batchNumber, resultsAndSuggestions: i.resultsAndSuggestions, createdDoctorName: i.createdDoctorName, physicalExamTime: i.updateTime, ), ); } registrationController.appointmentModelListLength = result.totalCount; } else { registrationController.appointmentModelListLength = 0; } registrationController.residentList = _residentList; registrationController.tableLoading = false; registrationController.update(["registration_table"]); registrationController.update(["registration_table_pagination"]); } String getAgeOfIdNumber(String idNumber) { if (idNumber.isEmpty) return ''; final idCardRegex = RegExp(r'^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})(\d|X)$'); final match = idCardRegex.firstMatch(idNumber); if (match != null) { final year = int.parse(match.group(2)!); final month = int.parse(match.group(3)!); final day = int.parse(match.group(4)!); final birthDate = DateTime(year, month, day); String age = DataTimeUtils.calculateAge(birthDate); return age; } return ''; // 返回一个默认值 } /// 登记列表表头 List> buildTableColumns( BuildContext context, bool? isVital, ) { /// 是否是一体机 bool isIntegralDesk = isVital ?? false; var textStyle = TextStyle( fontSize: 18, overflow: TextOverflow.ellipsis, fontFamily: "NotoSansSC", ); return >[ TableColumn( headerText: "体检号", flex: 5, render: (rowData, index) => Container( padding: const EdgeInsets.symmetric(vertical: kIsWeb ? 10 : 16), child: OverflowTooltipWrapper( child: Text( rowData.physicalExamNumber ?? '', style: textStyle, ), ), ), ), TableColumn( flex: 3, headerText: "姓名", render: (rowData, index) => Center( child: Text( rowData.name ?? '', style: textStyle, ), ), ), if (isIntegralDesk) TableColumn( headerText: "年龄", flex: 3, render: (rowData, index) => Center( child: Text( rowData.age != null ? rowData.age.toString() : "", style: textStyle, ), ), ), TableColumn( headerText: "身份证号", flex: 6, render: (rowData, index) => Center( child: Text( rowData.idNumber, style: textStyle, ), ), ), TableColumn( headerText: "手机号", flex: 4, render: (rowData, index) => Center( child: Text( rowData.phone == "" ? "-" : rowData.phone ?? '-', style: textStyle, ), ), ), TableColumn( headerRender: () { return Center( child: Padding( padding: EdgeInsets.only(right: 15), child: Text( "体检时间", style: TextStyle( fontSize: 20, ), ), ), ); }, flex: 3, render: (rowData, index) => Center( child: Text( rowData.physicalExamTime == null ? "" : DataTimeUtils.formatDateString(rowData.physicalExamTime!), style: textStyle, ), ), ), // if (isIntegralDesk) TableColumn( headerText: "责任医生", maxWidth: 120, flex: 4, render: (rowData, index) => Center( child: Text( rowData.createdDoctorName ?? "", style: textStyle, ), ), ), // if (!isIntegralDesk) // TableColumn( // headerRender: () { // return Center( // child: Padding( // padding: EdgeInsets.only(right: 15), // child: Text( // "体检状态", // style: TextStyle( // fontSize: 20, // ), // ), // ), // ); // }, // flex: 3, // render: (rowData, index) => Center( // child: Text( // rowData.physicalExamStatus ?? "", // style: textStyle, // ), // ), // ), TableColumn( headerText: "操作", flex: 7, render: (rowData, index) => FittedBox( child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ if (!FPlatform.isPureWeb && !isIntegralDesk) ...[ _buildPrint(context, rowData), ], _buildEditRegistration(rowData), _buildHealthCheck(rowData, isIntegralDesk), _buildEditingExcepting(rowData), _buildShowReport(rowData), ], ), ), ), ]; } /// 打印按钮 Widget _buildPrint(BuildContext context, ResidentModel rowData) { return TextButton( onPressed: () async { advanceDebounce(() async { Store.app.setBusy("加载中..."); try { await registrationController.getExamLabelsByExamNoAsync(rowData); } catch (e) { print(e); } Store.app.busy = false; Get.dialog( Center( child: Container( width: MediaQuery.of(context).size.width * 0.7, height: MediaQuery.of(context).size.height, child: Center( child: PrintPreview( imageList: registrationController.barCodeList, printInfo: registrationController.printInfo ?? PrinterInfo(), ), ), ), ), ); }, "print label", 3000); }, child: const Text( "打印标签", style: TextStyle(fontSize: 18), ), ); } /// 编辑按钮 Widget _buildEditRegistration(ResidentModel rowData) { return TextButton( onPressed: () async { final RegistrationInfoModel? patient = RegistrationInfoModel( patientName: rowData.name, phone: rowData.phone, patientAddress: rowData.homeAddress, cardNo: rowData.idNumber, code: rowData.code, birthday: rowData.birthDay, patientGender: RegistrationInfoModel.getGenderEnum(rowData.sex), ); final RegistrationInfoModel? result = await Get.dialog( RegistrationFormDialog( patient: patient, isEdit: true, ), barrierDismissible: false, ); registrationController.formController.editResident(result); print(result); }, child: const Text( "编辑", style: TextStyle(fontSize: 18), ), ); } Future?> getPrescriptionList( String patientCode, String physicalExamNumber, ) async { // 获取处方列表 List? prescriptionList = await _prescriptionManager.getPrescriptionPage( patientCode: patientCode, physicalExamNumber: physicalExamNumber, ); return prescriptionList; } /// 健康指导 Widget _buildEditingExcepting(ResidentModel rowData) { const designWidth = 1280.0; // 设计尺寸宽度:1280 final width = Get.width; final scale = width / designWidth; // 计算缩放比例 return TextButton( onPressed: () async { state.resultsAndSuggestions = rowData.resultsAndSuggestions; state.prescriptionList = await getPrescriptionList( rowData.idNumber, rowData.physicalExamNumber ?? '', ) ?? []; Get.dialog( VAlertDialog( width: width / scale * 0.85, onConfirm: () async { final result = await _registrationManager.updateResultsAndSuggestionsAsync( rowData.code ?? "", state.resultsAndSuggestions ?? ''); if (result) { rowData.resultsAndSuggestions = state.resultsAndSuggestions; // 内存更新 Get.back(); // Close the dialog } else { PromptBox.toast("保存失败"); } }, confirmLabel: "提交", content: Container( padding: EdgeInsets.all(8.0), child: Stack( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 20, ), Expanded( child: Container( padding: EdgeInsets.symmetric(horizontal: 32), child: TextField( expands: false, maxLines: 10, controller: TextEditingController( text: rowData.resultsAndSuggestions, ), decoration: InputDecoration( hintText: '请输入健康指导信息...', border: OutlineInputBorder( borderRadius: BorderRadius.all( Radius.circular(8.0), ), // 可以调整边框圆角度数 ), contentPadding: EdgeInsets.all(16), // 调整文本内边距 ), onChanged: (value) { state.resultsAndSuggestions = value; }, ), ), ), SizedBox( height: 20, ), Container( padding: EdgeInsets.only(left: 30), width: 280, height: 54, alignment: Alignment.centerRight, child: VButton( onTap: () async { await Get.dialog( ExaminationPrescription( physicalExamNumber: rowData.physicalExamNumber, patientCode: rowData.idNumber, prescription: "", prescriptionTitle: "", ), ); state.prescriptionList = await getPrescriptionList( rowData.idNumber, rowData.physicalExamNumber ?? '', ) ?? []; }, label: '开具健康教育处方', ), ), SizedBox( height: 10, ), _buildPrescriptionList( rowData.physicalExamNumber ?? '', rowData.idNumber, ), SizedBox( height: 20, ), ], ), ], ), ), ), barrierDismissible: false, // Prevent dialog from closing on outside tap ); }, child: const Text( "健康指导", style: TextStyle(fontSize: 18), ), ); } Widget _buildPrescriptionList( String physicalExamNumber, String patientCode, ) { ScrollController _scrollController = ScrollController(); return Obx(() { if (state.prescriptionList.isNotEmpty) return Container( alignment: Alignment.centerLeft, padding: EdgeInsets.only(left: 30), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(width: 30), Container( margin: EdgeInsets.only(bottom: 8, top: 8), child: Text( '处方列表', style: TextStyle( fontSize: 26, fontWeight: FontWeight.bold, ), ), ), SizedBox(width: 16), Container( height: 95, child: AlwaysScrollListView( scrollController: _scrollController, child: Container( padding: EdgeInsets.only(bottom: 8), child: ListView( controller: _scrollController, shrinkWrap: true, scrollDirection: Axis.horizontal, children: [ ...state.prescriptionList.map( (e) => InkWell( radius: 8, onTap: () async { await Get.dialog( ExaminationPrescription( physicalExamNumber: physicalExamNumber, patientCode: patientCode, prescription: e.prescriptionTemplateKey ?? '', prescriptionTitle: '${PrescriptionFormKeys.AllFormKeys[e.prescriptionTemplateKey ?? '']}', isEdit: true, ), ); }, child: Container( decoration: BoxDecoration( border: Border.all( color: Colors.black26, ), borderRadius: BorderRadius.all( Radius.circular(8), ), ), margin: EdgeInsets.all(8), padding: const EdgeInsets.all(8).copyWith(left: 30), child: Container( width: 380, child: Row( children: [ Expanded( child: Text( '${PrescriptionFormKeys.AllFormKeys[e.prescriptionTemplateKey ?? '']}', style: TextStyle( fontSize: 24, fontWeight: FontWeight.bold, ), overflow: TextOverflow.ellipsis, ), ), Container( width: 60, padding: EdgeInsets.only( right: 8, ), child: IconButton( onPressed: () { Get.dialog( VAlertDialog( title: "提示", onConfirm: () async { bool? result = await _prescriptionManager .removePrescription( prescriptionCode: e.code ?? '', ); if (result ?? false) { state.prescriptionList = await getPrescriptionList( patientCode, physicalExamNumber, ) ?? []; Get.back(); } else { PromptBox.toast("删除失败"); } }, content: Container( alignment: Alignment.center, height: 60, child: Text( "确认是否删除 ${PrescriptionFormKeys.AllFormKeys[e.prescriptionTemplateKey ?? '']}", style: TextStyle( fontSize: 24, ), ), ), ), ); }, icon: Icon( Icons.close, size: 40, ), ), ) ], ), ), ), ), ), ], ), ), ), ), ], ), ); return Container(); }); } /// 查看报告 Widget _buildShowReport(ResidentModel rowData) { return TextButton( onPressed: () { Debouncer.run( () async { PromptBox.dismiss(); Store.app.busy = true; List? reportList = await registrationController .registrationManager .getVitalReportInfoAsync( physicalExamNumber: rowData.physicalExamNumber ?? '', ); Store.app.busy = false; ReportDTO2? report = reportList ?.firstWhereOrNull((element) => element.key == "Part"); if (report != null) { logger.i("show report:${report.code}"); Get.dialog( ReportPreview( pdfUrl: report.previewInfo?.fileToken ?? "", ), ); } else { PromptBox.showToast( '暂无报告', maskType: EasyLoadingMaskType.none, // 设置为none以允许用户操作其他控件 ); } }, duration: Duration(milliseconds: 300), ); }, child: const Text( "查看报告", style: TextStyle(fontSize: 18), ), ); } void _examDialog(ResidentModel rowData, bool isIntegralDesk) async { final FEventHandler onSubmitEvent = FEventHandler(); /// 需要检测页面回调数据 Get.put(MedicalController()); Get.dialog( Scaffold( body: Stack( children: [ ExaminationPage( idCard: rowData.idNumber, onSubmitEvent: onSubmitEvent, physicalExamNumber: rowData.physicalExamNumber ?? '', ), Positioned( left: 16, bottom: 16, child: _buildMedicalButton(rowData.idNumber), ) ], ), appBar: VAppBar( titleText: "体检", actions: [ TextButton.icon( onPressed: () async { onSubmitEvent.emit(this, true); }, label: Text( '保存', style: TextStyle(fontSize: 20, color: Colors.white), ), icon: Icon(Icons.save, size: 32, color: Colors.white), ), const SizedBox(width: 8), ], iconBack: () { onSubmitEvent.emit(this, false); Get.delete(); }, ), ), ); } Widget _buildMedicalButton(String patientCode) { if (_hasHealthMonitor()) { return Container( width: 214, margin: EdgeInsets.only(right: 10), child: VButton( onTap: () async { var diagnosis = await Get.find() .getDiagnosisAggregationPageAsync(patientCode, 1, 10); if (diagnosis?.pageData?.isNotEmpty ?? false) { try { Map diagnosisDataValue = {}; for (DiagnosisAggregationRecordModel data in diagnosis!.pageData!) { if (data.diagnosisAggregationData?.isNotEmpty ?? false) { for (DiagnosisAggregationData diaData in data.diagnosisAggregationData!) { diagnosisDataValue[diaData.key ?? ''] = jsonDecode(diaData.diagnosisData ?? ''); } break; } } var medicalController = Get.find(); medicalController.diagnosisDataValue = diagnosisDataValue; } catch (e) {} } Get.dialog( Scaffold( body: ExamMedicalPage( isHealthCheck: true, ), appBar: VAppBar( titleText: "检测", ), ), ); }, child: Text( '检测', style: TextStyle(fontSize: 26), ), ), ); } return SizedBox(); } /// 体检 Widget _buildHealthCheck(ResidentModel rowData, bool isIntegralDesk) { return TextButton( onPressed: () { advanceDebounce( () async { await Get.find() .switchCurrentPatientByCode(rowData.idNumber); if (Get.isRegistered()) { Get.delete(); } Get.put( ExaminationController( patientCode: rowData.idNumber, batchNumber: rowData.batchNumber ?? '', ), ); _examDialog(rowData, isIntegralDesk); }, "HealthCheck", ); }, child: const Text( "填表", style: TextStyle(fontSize: 18), ), ); } }