123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629 |
- 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<IReportTemplateManager>();
- final labelInputController = TextEditingController();
- final state = ReportEditState();
- final reportManager = Get.find<IReportManager>();
- ///图像选择时通知报告
- final FEventHandler<String> onSelect = new FEventHandler<String>();
- QueryRecordResult? _recordInfo;
- ///选中图像选择框时事件通知
- FEventHandler<List<String>> onSelectedInputChange =
- FEventHandler<List<String>>();
- /// 本地报告编辑器持久化缓存服务
- LocalReportEditorService localReportEditorService =
- Get.find<LocalReportEditorService>();
- 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<ReportDTO> findReportByCodeAsync() async {
- return reportOperateController.findReportByCodeAsync();
- }
- //提交报告
- Future<void> 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<void> openReportPreviewer() async {
- return reportOperateController.openReportPreviewer();
- }
- ///不打开报告预览页面,直接调起打印
- Future<void> printReportDirectly() async {
- return reportOperateController.printReportDirectly();
- }
- ///查找AI图像
- Future<void> findAiImagesAsync() async {
- return remedicalsController.findAiImagesAsync();
- }
- ///不打开报告预览页面,直接导出
- Future<void> exportReportDirectly() async {
- return reportOperateController.exportReportDirectly();
- }
- /// 刷新图像列表
- Future<void> refreshImages() async {
- getRemedicalList();
- }
- ///返回上级页面
- void back() {
- reportCacheController.back();
- }
- /// 初始化词条数据
- Future<void> getDefaultThesaurus(String defaultThesaurus) async {
- return thesaurusController.getDefaultThesaurus(defaultThesaurus);
- }
- ///初始化报告模板
- Future<void> 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<ReportTemplateDTO?> _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<dynamic>;
- // 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<QueryRecordResult?> queryRecordInfoAsync(String recordCode) async {
- return await remedicalsController.queryRecordInfoAsync(recordCode);
- }
- ///获取病人信息
- Future<ClientPatientInfoDTO?> getPatientInfo(String patientCode) async {
- return reportOperateController.getPatientInfo(patientCode);
- }
- //根据缓存实例化报告信息
- void initReportInfoFromJson(ReportInfoItem reportCache) {
- reportCacheController.initReportInfoFromJson(reportCache);
- }
- ///初始化入参
- Future<void> 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<LocalReportEditorService>();
- await localReportEditorService.init();
- }
- ///获取图像列表
- Future<void> 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<void> 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<String> _getCreateName() async {
- return Store.user.displayName;
- }
- Future<void> _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<void> _initTemplates() async {
- var templatePage = await reportTemplateManager.getReportTemplatePage();
- state.templates = templatePage.pageData
- ?.map(
- (e) => FSelectOptionModel(
- title: e.reportTemplateName ?? '',
- value: e.reportTemplateCode,
- ),
- )
- .toList() ??
- [];
- }
- Future<void> 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<void> 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();
- }
- }
|