import 'dart:async'; import 'dart:convert'; import 'package:fis_common/helpers/encrypt.dart'; import 'package:fis_common/index.dart'; import 'package:fis_common/logger/logger.dart'; import 'package:fis_i18n/i18n.dart'; import 'package:fis_jsonrpc/rpc.dart'; import 'package:fis_lib_report/converts/event_type.dart'; import 'package:fis_lib_report/report_info/element_tag_names.dart'; import 'package:fis_lib_report/report_info/input_image_info.dart'; import 'package:fis_lib_report/report_info/input_image_list_info.dart'; import 'package:fis_lib_report/report_info/input_text_info.dart'; import 'package:fis_lib_report/report_info/report_info.dart'; import 'package:fis_lib_report/report_info/single_selected_info.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:get/get.dart'; import 'package:fis_ui/index.dart'; import 'package:vitalapp/architecture/defines.dart'; import 'package:vitalapp/architecture/memory_cache/report.dart'; import 'package:vitalapp/architecture/services/entity/report_editor_setting.dart'; import 'package:vitalapp/architecture/services/report_editor_configuration.dart'; import 'package:vitalapp/architecture/utils/prompt_box.dart'; import 'package:vitalapp/managers/interfaces/models/report_edit_source.dart'; import 'package:vitalapp/managers/interfaces/report.dart'; import 'package:vitalapp/managers/interfaces/report_template.dart'; import 'package:vitalapp/pages/report_edit/state.dart'; import 'package:vitalapp/rpc.dart'; import 'package:vitalapp/store/store.dart'; import 'package:fis_measure/process/workspace/rpc_bridge.dart'; import 'controllers/add_report_tag.dart'; import 'controllers/remedicals_controller.dart'; import 'controllers/report_cache_controller.dart'; import 'controllers/report_operate_controller.dart'; import 'controllers/thesaurus_controller.dart'; import 'widgets/speech_input.dart'; class ReportEditController extends FControllerBase { static const String aiRporterName = "VAid"; late final AddReportTagController addreportTagController; late final RemedicalsController remedicalsController; late final ThesaurusController thesaurusController; late final ReportCacheController reportCacheController; late final ReportOperateController reportOperateController; final reportTemplateManager = Get.find(); final labelInputController = TextEditingController(); final state = ReportEditState(); final reportManager = Get.find(); ///图像选择时通知报告 final FEventHandler onSelect = new FEventHandler(); QueryRecordResult? _recordInfo; ///选中图像选择框时事件通知 FEventHandler> onSelectedInputChange = FEventHandler>(); /// 本地报告编辑器持久化缓存服务 LocalReportEditorService localReportEditorService = Get.find(); ReportEditorSetting reportEditorSetting = ReportEditorSetting.ins; /// 是否需要加载本地未完成的编辑缓存 bool get isReloadFromLocalCache => reportEditorSetting.reportDraft.isNotEmpty && reportEditorSetting.reportDraftRecordCode == (state.recordCode.isNotEmpty ? state.recordCode : state.consultationCode); ///图像选择框是否选中 bool inputImagesIsSelected = false; ReportEditController() { remedicalsController = RemedicalsController(this); thesaurusController = ThesaurusController(this); reportCacheController = ReportCacheController(this); addreportTagController = AddReportTagController(this); reportOperateController = ReportOperateController(this); } @override void onReady() { super.onReady(); _initData(); } @override void onClose() { super.onClose(); reportCacheController.removeScheduledCacheReport(); reportCacheController.dispose(); FReportInfo.instance.onSpeechInput.removeListener(_openSpeechInput); RPCBridge.ins.source = VidImageSource.Remedical; labelInputController.dispose(); } ///跟据reportCode获取报告详情 Future findReportByCodeAsync() async { return reportOperateController.findReportByCodeAsync(); } //提交报告 Future submitReport() async { await busyHandle( () async { await reportOperateController.submitReport(); }, text: i18nBook.common.submitting.t, ); Future.delayed(Duration(milliseconds: 1000), () { PromptBox.toast(i18nBook.remedical.submitSuccessToCompleteList.t); }); } ///打开报告预览页面 Future openReportPreviewer() async { return reportOperateController.openReportPreviewer(); } ///不打开报告预览页面,直接调起打印 Future printReportDirectly() async { return reportOperateController.printReportDirectly(); } ///查找AI图像 Future findAiImagesAsync() async { return remedicalsController.findAiImagesAsync(); } ///不打开报告预览页面,直接导出 Future exportReportDirectly() async { return reportOperateController.exportReportDirectly(); } /// 刷新图像列表 Future refreshImages() async { getRemedicalList(); } ///返回上级页面 void back() { reportCacheController.back(); } /// 初始化词条数据 Future getDefaultThesaurus(String defaultThesaurus) async { return thesaurusController.getDefaultThesaurus(defaultThesaurus); } ///初始化报告模板 Future initUserDefaultTemplate() async { final defaultTemplateInfo = await _getDefaultTemplateCode(); if (defaultTemplateInfo == null) { PromptBox.toast(i18nBook.errorCodes.errorCode5002.t); logger.e( 'ReportEditController _initTemplate error: defaultTemplateInfo is null'); } else { state.selectedTemplate = defaultTemplateInfo; } } ///获取默认模板 Future _getDefaultTemplateCode() async { try { final result = await rpc.ultrasoundReport.vitalGetDefaultReportTemplateContentAsync( GetDefaultReportTemplateContentRequest( token: Store.user.token, languageCode: i18nBook.locale.toCodeString('-'), ), ); return result; } catch (e) { logger.e('ReportTemplateController getDefaultTemplateCode', e); return null; } } ///初始化报告模板、报告缓存、报告编辑器缓存 void _initData({bool isReload = false}) async { try { busy = true; FReportInfo.instance.isASROn = true; await initParameters(); initReportEditorCache(); thesaurusController.initDefaultThesaurus(); await _initTemplates(); await _initPatientInfo(); String createrName = await _getCreateName(); if (state.reportCode.isNotEmpty) { await reportCacheController.initServerReport(); _initExamDoctorInfo(createrName); } else { if (!isReload) { await initUserDefaultTemplate(); /// 从本地缓存中恢复未编辑完的报告 if (isReloadFromLocalCache) { final reportDraftJsonStr = jsonDecode(reportEditorSetting.reportDraft) as List; // var reportTemplateJsonStr = // state.selectedTemplate.reportTemplateJson; bool checkIsSameTemplate = reportEditorSetting.reportDraftTemplateCode == state.selectedTemplate.reportTemplateCode; // _checkIsSameTemplate(reportTemplateJsonStr, reportDraftJsonStr); // 检查报告模板是否一致 if (checkIsSameTemplate) { Future.delayed(Duration(milliseconds: 500), () { PromptBox.toast(i18nBook.remedical.restoreCache.t); FReportInfo.instance.fromJson(reportDraftJsonStr); }); } else { if (state.templates.isNotEmpty) { // 遍历模板列表,查找是否存在该模板 var template = state.templates.firstWhereOrNull((element) => element.value == reportEditorSetting.reportDraftTemplateCode); if (template != null) { ReportTemplateDTO reportTemplate = await reportTemplateManager.findReportTemplateByCode( code: reportEditorSetting.reportDraftTemplateCode); FConfirmAlert.show( context: Get.context!, title: i18nBook.common.tip.t, subTitle: i18nBook.remedical.restoreCacheAlert.t, confrimLabel: i18nBook.common.confirm.t, cancelLabel: i18nBook.common.cancel.t, businessParent: FVirtualPageWidget('report editor'), onConfirm: () async { await changeTemplate(reportTemplate); Future.delayed(Duration(milliseconds: 500), () { FReportInfo.instance.fromJson(reportDraftJsonStr); Future.delayed(Duration(milliseconds: 500), () { PromptBox.toast(i18nBook.remedical.restoreCache.t); }); }); }, ); } } } } else { reportCacheController.initReportCache(); } } var devicePatientId = state.devicePatientId; _initReportInfo(createrName, state.patientSex, devicePatientId); } _initImageInputChangeListener(); await getRemedicalList(); _autoFillCurrentUserSignature(); _addReportInfoListen(); } catch (e) { logger.e('ReportEditController initData:', e); } reportCacheController.setScheduledCacheReport(); busy = false; } ///查询检查详情 Future queryRecordInfoAsync(String recordCode) async { return await remedicalsController.queryRecordInfoAsync(recordCode); } ///获取病人信息 Future getPatientInfo(String patientCode) async { return reportOperateController.getPatientInfo(patientCode); } //根据缓存实例化报告信息 void initReportInfoFromJson(ReportInfoItem reportCache) { reportCacheController.initReportInfoFromJson(reportCache); } ///初始化入参 Future initParameters() async { var parameters = Get.arguments; print(parameters); if (parameters.containsKey('token')) { thesaurusController.initAllThesaurus(); } if (parameters.containsKey('patientCode')) { state.patientId = parameters['patientCode'] ?? ''; } if (parameters.containsKey('reportEditSource')) { state.reportEditSource = ReportEditSource.values.firstWhere( (element) => element.name == parameters['reportEditSource']); } if (parameters.containsKey('recordCode')) { state.recordCode = parameters['recordCode'] ?? ''; if (state.recordCode.isNotEmpty) { _recordInfo = await queryRecordInfoAsync(state.recordCode); } } if (parameters.containsKey('referralRecordCode')) { state.referralRecordCode = parameters['referralRecordCode'] ?? ''; } if (parameters.containsKey('reportCode')) { state.reportCode = parameters['reportCode'] ?? ''; } } /// 初始化报告编辑器本地缓存 void initReportEditorCache() async { final localReportEditorService = Get.find(); await localReportEditorService.init(); } ///获取图像列表 Future getRemedicalList() async { remedicalsController.getRemedicalList(); if (state.recordCode.isNotEmpty) { remedicalsController.findRemedicalMeasuredInfoAsync(); } } /// 自动填充当前用户的电子签名 void _autoFillCurrentUserSignature() { try { final signature = Store.user.signature; if (signature.isEmpty) return; Future.delayed(Duration(seconds: 1), () { final signatureElement = FReportInfo.instance .getElementInfoByTagName(TagNames.DIGITALSIGNATURE); if (signatureElement != null) { final signatureArea = signatureElement as InputImageInfo; signatureArea.selectedImage = signature; } }); } catch (e) { logger.e('ReportEditController _autoFillCurrentUserSignature ex:', e); } } ///打开添加报告标签弹窗 Future openAddReportTag() async { await addreportTagController.openAddReportTag(); } ///跟据检查Code更新报告缓存 void updateReportCacheByRecordCode(String recordCode) { return reportCacheController.updateReportCacheByRecordCode(recordCode); } //初始化报告信息 void _initReportInfo(String createName, String gender, String patientId) { Future.delayed( Duration(milliseconds: 800), () async { //国家脑卒中项目,掌超上传医院 var customOrganzation = _recordInfo?.customOrganzation ?? ''; //国家脑卒中项目,掌超上传医生 var customDoctor = _recordInfo?.customDoctor ?? ''; final hospitalInput = FReportInfo.instance.getElementInfoByTagName(TagNames.HOSPITALNAME); if (hospitalInput != null) { final hospital = hospitalInput as InputTextInfo; if (customOrganzation.isNotEmpty) { hospital.text = customOrganzation; } else { if (Store.user.organizationName.isNullOrEmpty) { hospital.text = _recordInfo?.deviceOrganzationName ?? ''; } else { hospital.text = Store.user.organizationName; } } } final examDoctorInput = FReportInfo.instance.getElementInfoByTagName(TagNames.INSPHYSICIAN); if (examDoctorInput != null) { final examDoctor = examDoctorInput as InputTextInfo; if (customDoctor.isNotNullOrEmpty) { examDoctor.text = customDoctor; } else { examDoctor.text = createName; } } final patientIdInputElement = FReportInfo.instance .getElementInfoByTagName(TagNames.PATIENT_ID_TAG); if (patientIdInputElement != null) { final patientIdInput = patientIdInputElement as InputTextInfo; patientIdInput.text = patientId; } final genderSelect = FReportInfo.instance .getElementInfoByTagName(TagNames.PATIENT_SEX_TAG); if (genderSelect != null && genderSelect is SingleSelectedInfo) { final items = genderSelect.items ?? []; if (gender == 'AnimalInfoMale' || gender == 'Male') { if (items.contains('男')) { genderSelect.selectedItem = '男'; } else if (items.contains('雄性')) { genderSelect.selectedItem = '雄性'; } else if (items.contains('Male')) { genderSelect.selectedItem = 'Male'; } } else if (gender == 'AnimalInfoFemale' || gender == 'Female') { if (items.contains('女')) { genderSelect.selectedItem = '女'; } else if (items.contains('Female')) { genderSelect.selectedItem = 'Female'; } else if (items.contains('雌性')) { genderSelect.selectedItem = '雌性'; } } } else { print('null genderSelect'); } }, ); } ///测量图像单击事件 void onMersureImageTap(String token, int index) { return remedicalsController.onMersureImageTap(token, index); } //初始化报告信息 void _initExamDoctorInfo(String createName) { if (Store.user.organizationName.isNotEmpty) { Future.delayed( Duration(milliseconds: 1000), () { //国家脑卒中项目,掌超上传医院 var customOrganzation = _recordInfo?.customOrganzation ?? ''; //国家脑卒中项目,掌超上传医生 var customDoctor = _recordInfo?.customDoctor ?? ''; final examDoctorInput = FReportInfo.instance .getElementInfoByTagName(TagNames.INSPHYSICIAN); if (examDoctorInput != null) { final examDoctor = examDoctorInput as InputTextInfo; if (examDoctor.text == aiRporterName || examDoctor.text.isNullOrEmpty) { examDoctor.text = createName; } } final reportPhysicianInput = FReportInfo.instance.getElementInfoByTagName(TagNames.RPHYSICIAN); if (reportPhysicianInput != null) { final doctor = reportPhysicianInput as InputTextInfo; if (customDoctor.isNotNullOrEmpty) { doctor.text = customDoctor; } else if (doctor.text != createName || doctor.text == aiRporterName) { doctor.text = createName; } } final hospitalInput = FReportInfo.instance .getElementInfoByTagName(TagNames.HOSPITALNAME); if (hospitalInput != null) { final hospital = hospitalInput as InputTextInfo; if (hospital.text.isEmpty) { if (customOrganzation.isNotNullOrEmpty) { hospital.text = customOrganzation; } else { if (Store.user.organizationName.isEmpty) { hospital.text = _recordInfo?.deviceOrganzationName ?? ''; } else { hospital.text = Store.user.organizationName; } } } } }, ); } } /// 【报告编辑】选中 vid 图像进入测量页 void enterVidMeasurePage( String imageUrl, int imageindex, String remedicalCode, String? remedicalAISelectedInfoCode, ) async { final patientCode = state.patientId; final recordCode = state.recordCode; reportManager.enterVidMeasurePage( imageUrl: imageUrl, imageindex: imageindex, remedicalCode: remedicalCode, patientCode: patientCode, recordCode: recordCode, remedicalAISelectedInfoCode: remedicalAISelectedInfoCode, needRouterBack: true, reportPageEnter: true, ); } void _initImageInputChangeListener() { Future.delayed(Duration(milliseconds: 1000), () { final imagesInput = FReportInfo.instance.getElementInfoByTagName(TagNames.SELECTIMAGES); if (imagesInput != null) { var imagesInfo = imagesInput as InputImageListInfo; imagesInfo.onRemove.addListener((sender, e) { final selectedImages = state.selectedImages; if (selectedImages.contains(e)) { state.selectedImages.remove(e); onSelectedInputChange.emit(this, state.selectedImages); } }); imagesInfo.onSelectedInputChange.addListener((sender, e) { inputImagesIsSelected = e; if (e) { state.selectedImages = []; state.selectedImages.addAll(imagesInfo.selectedImages); } else { state.selectedImages = []; } onSelectedInputChange.emit(this, state.selectedImages); }); } }); } void _addReportInfoListen() { FReportInfo.instance.onSpeechInput.addListener(_openSpeechInput); } void _openSpeechInput(sender, e) async { await Get.dialog( SpeechInput(e), ); } void onConsultationImageSelected(String coverImageUrl) { remedicalsController.onConsultationImageSelected(coverImageUrl); } Future _getCreateName() async { return Store.user.displayName; } Future _initPatientInfo() async { final patientInfo = await getPatientInfo(state.patientId); var devicePatientIDs = patientInfo?.devicePatientIDs ?? []; var devicePatientId = devicePatientIDs.isNotEmpty ? patientInfo?.devicePatientIDs?.first ?? '' : ''; state.devicePatientId = devicePatientId; if (patientInfo != null) { state.patientName = FEncryptHelper.decryptBase64(patientInfo.encryptFullName ?? ''); var patientData = patientInfo.patientData ?? []; if (patientData.isNotEmpty) { var ageInfo = patientData.firstWhereOrNull((element) => element.key == 'AgeYear'); state.patientAge = ageInfo == null ? '' : ageInfo.value ?? ''; var patientSexInfo = patientData.firstWhereOrNull((element) => element.key == 'Sex' || element.key == 'AnimalInfoSex'); state.patientSex = patientSexInfo == null ? '' : patientSexInfo.value ?? ''; } } } //校验草稿中的所有组件是否都存在,不存在则不加载草稿 bool _checkIsSameTemplate(String? reportTemplateJsonStr, List json) { if (reportTemplateJsonStr != null) { for (var item in json) { var tag = item['Key'] ?? ''; if (!reportTemplateJsonStr.contains(tag)) { return false; } } } return true; } Future _initTemplates() async { var templatePage = await reportTemplateManager.getReportTemplatePage(); state.templates = templatePage.pageData ?.map( (e) => FSelectOptionModel( title: e.reportTemplateName ?? '', value: e.reportTemplateCode, ), ) .toList() ?? []; } Future onSelectedTemplateChange(String? value) async { var reportTemplate = await reportTemplateManager.findReportTemplateByCode(code: value ?? ''); state.selectedTemplate = reportTemplate; FReportInfo.instance.reload( Store.user.displayName, DateTime.now(), reportTemplate.reportTemplateJson ?? '', onSelect, i18nBook.common.revoke.t, i18nBook.remedical.selectWord.t, '', isASROn: true, ); state.selectedImages = []; _initData( isReload: true, ); thesaurusController.initDefaultThesaurus(); } Future changeTemplate(ReportTemplateDTO reportTemplate) async { state.selectedTemplate = reportTemplate; FReportInfo.instance.reload( Store.user.displayName, DateTime.now(), reportTemplate.reportTemplateJson ?? '', onSelect, i18nBook.common.revoke.t, i18nBook.remedical.selectWord.t, '', isASROn: true, ); state.selectedImages = []; _initData( isReload: true, ); await thesaurusController.initDefaultThesaurus(); } }