123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- import 'dart:convert';
- import 'package:fis_common/index.dart';
- import 'package:fis_common/logger/logger.dart';
- import 'package:fis_jsonrpc/rpc.dart';
- import 'package:fis_jsonrpc/rpc.dart' as r;
- import 'package:fis_jsonrpc/rpc.dart';
- import 'package:fis_lib_report/report/report_template_document.dart';
- import 'package:fis_lib_report/report_info/report_info.dart';
- import 'package:fis_ui/index.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter/services.dart';
- import 'package:flutter_sms/flutter_sms.dart';
- import 'package:fluwx/fluwx.dart';
- import 'package:get/get.dart';
- import 'package:intl/intl.dart';
- import 'package:url_launcher/url_launcher.dart';
- import 'package:vitalapp/architecture/utils/prompt_box.dart';
- import 'package:vitalapp/pages/measure_home/controller.dart';
- import 'package:vitalapp/pages/measure_home/view.dart';
- import 'package:vitalapp/pages/report_edit/controller.dart';
- import 'package:vitalapp/pages/report_edit/view.dart';
- import 'package:vitalapp/pages/report_edit/widgets/report_share_dialog.dart';
- import 'package:vitalapp/pages/report_preview/controller.dart';
- import 'package:vitalapp/pages/report_preview/view.dart';
- import 'package:vitalapp/pages/widgets/row_separator.dart';
- import 'package:vitalapp/rpc.dart';
- import 'interfaces/base_manager.dart';
- import 'interfaces/models/report_element_info.dart';
- import 'interfaces/models/report_tag_key.dart';
- import 'interfaces/report.dart';
- import 'package:fis_common/event/event_type.dart';
- import 'package:fis_i18n/i18n.dart';
- class ReportManager extends BaseManager implements IReportManager {
- final onEditReport = FEventHandler<String>();
- ///提交报告事件
- final onSubmitReport = FEventHandler<bool>();
- ///手机端提交报告
- final onMobileSubmitReport = FEventHandler<bool>();
- ///直接打印文档
- @override
- Future<void> directlyPrintPDF(String reportCode, String fileName) async {
- try {
- await _initPreviewReport(reportCode);
- try {} catch (e) {
- logger.e("print report error:", e);
- }
- } catch (e) {
- logger.e('InspectionReportController _initPreviewReport ex:', e);
- }
- }
- /// 直接打印图片
- @override
- Future<void> directlyPrintPDFJpges(
- List<String>? images, String fileName) async {
- try {} catch (e) {
- logger.e("print report error:", e);
- }
- }
- ///打印文件(通过下载地址)
- @override
- Future<void> directlyPrintPDFFile(String fileUrl, String fileName) async {
- try {} catch (e) {
- logger.e("print report error:", e);
- }
- }
- @override
- List<FReportElementInfo> convertReportData(String jsonData) {
- List<FReportElementInfo> result = [];
- final infos = jsonDecode(jsonData) as List<dynamic>;
- for (var element in infos) {
- result.add(
- FReportElementInfo(
- key: element['Key'],
- tagId: element['TagId'],
- name: element['Name'],
- value: element['Value'],
- ),
- );
- }
- return result;
- }
- ///语音识别
- Future<String> commitASRInfoAsync(String token, String extension) async {
- try {
- var audioConvertResult = await rpc.aSR.commitASRInfoAsync(
- CommitASRInfoRequest(
- token: token,
- url: token,
- fileType: extension,
- ),
- );
- return audioConvertResult.content ?? '';
- } catch (e) {
- logger.e('ReportEditController commitASRInfoAsync ex:', e);
- }
- return '';
- }
- ///直接下载图像PDF
- @override
- Future<void> directlyDownloadPDFJpges(
- List<String>? images, String fileName) async {
- try {} catch (e) {
- logger.e("export report error:", e);
- }
- }
- ///直接下载 PDF 文件,通过 URL
- @override
- Future<void> directlyDownloadPDFFile(String fileUrl, String fileName) async {
- try {} catch (e) {
- logger.e("export report error:", e);
- }
- }
- ///直接下载文档报告
- @override
- Future<void> directlyDownloadPDF(String reportCode, String fileName) async {
- try {
- await _initPreviewReport(reportCode);
- try {} catch (e) {
- logger.e("export report error:", e);
- }
- } catch (e) {
- logger.e('InspectionReportController _initPreviewReport ex:', e);
- }
- }
- ///获取默认模板
- @override
- Future<String> getReportTemplate() async {
- return '';
- }
- /// 打开报告分享窗口
- ///
- /// [reportUrlToShare] 待分享的报告code
- @override
- Future<bool> openReportShareDialog(String? reportToShare) async {
- if (reportToShare == null || reportToShare.isEmpty) {
- return false;
- }
- var reportUrlToShare =
- await rpc.report.findReportShareUrlAsync(FindReportShareUrlRequest(
- languageCode: 'zh-CN',
- reportCode: reportToShare,
- token: token,
- ));
- if (reportUrlToShare.isEmpty) {
- PromptBox.toast("报告分享地址为空");
- return false;
- }
- Get.dialog(
- ReportShareDialog(
- reportUrlToShare,
- reportToShare,
- ),
- );
- return true;
- }
- ///提交报告标签
- Future<bool> submitReportTags(
- String reportCode, List<String> selectedTags) async {
- try {
- final result =
- await rpc.report.modifyReportLabelsAsync(ModifyReportLabelsRequest(
- token: token,
- reportCode: reportCode,
- reportLabels: selectedTags,
- ));
- return result;
- } catch (e) {
- logger.e('AddReportTagController submitReportTags ex:', e);
- }
- return false;
- }
- ///初始化标签所需数据
- ///
- /// [reportType] 默认值远程诊断
- Future<Map<ReportTagKey, List<String>>> getReportTagDatas(
- String recordCode, [
- ReportTypeEnum? reportType,
- ]) async {
- Map<ReportTagKey, List<String>> allReportTags = {};
- try {
- final labels = await rpc.report.findReportLabelsAsync(
- FindReportLabelsRequest(
- token: token,
- recordCode: recordCode,
- reportType: reportType ?? ReportTypeEnum.RemoteDiagnosis,
- ),
- );
- labels.forEach((label) {
- final tagKey =
- ReportTagKey(label.reportLabelCode ?? '', label.labelName ?? '');
- if (!allReportTags.containsKey(tagKey)) {
- allReportTags[tagKey] = label.labelItems ?? [];
- } else {
- logger.e(
- 'AddReportTagController _initDatas contains duplicate labels :' +
- tagKey.code);
- }
- });
- } catch (e) {
- logger.e('ReportManager getReportTagDatas ex:', e);
- }
- return allReportTags;
- }
- @override
- Future<List<r.ReportDTO>> findReportsAsync(String recordCode) async {
- try {
- var reportInfo = await rpc.ultrasoundReport.vitalFindReportsAsync(
- FindReportsRequest(
- token: token,
- recordCode: recordCode,
- ),
- );
- return reportInfo;
- } catch (e) {
- logger.e('ReportManager findReportsAsync ex:$e');
- return [];
- }
- }
- ///获取报告提交内容信息Json
- String getMobileReportDatasJson({
- String? patientName,
- String? patientSex,
- String? age,
- List<String>? imageInfos,
- String? des,
- String? summary,
- String? creatorName,
- String? fullName,
- String? customDoctor,
- String? customOrganzation,
- String? deviceOrganzationName,
- }) {
- return "";
- }
- /// 格式化时间
- ///
- /// [time] 后端返回的时间
- @override
- String getTime(String time) {
- String stringTime = '';
- if (time.isNotEmpty) {
- stringTime = DateFormat("yyyy-MM-dd HH:mm:ss").format(
- DateTime.fromMillisecondsSinceEpoch(
- DateTime.tryParse(time)?.millisecondsSinceEpoch as int,
- ),
- );
- }
- return stringTime;
- }
- ///打开报告编辑页面
- @override
- Future<void> openReportEdit(
- String patientCode, {
- String consultationCode = '',
- String recordCode = '',
- String reportCode = '',
- int patientTab = 0,
- String referralRecordCode = '',
- }) async {
- _openReportEditPage(token, patientCode, referralRecordCode, reportCode,
- consultationCode, recordCode);
- }
- /// 根据扫查记录获取转诊扫查图像详情
- @override
- Future<RemedicalListResult> queryReferralRemedicalListByRecordInfoAsync(
- String recordCode, String referralRecordCode) async {
- try {
- final getRecordsPage =
- await rpc.remedical.queryReferralRemedicalListByRecordInfoAsync(
- QueryReferralExamReportRequest(
- token: token,
- recordCode: recordCode,
- referralRecordCode: referralRecordCode,
- ),
- );
- return getRecordsPage;
- } catch (e) {
- return RemedicalListResult();
- }
- }
- ///打开报告编辑页
- void _openReportEditPage(
- String token,
- String patientCode,
- String referralRecordCode,
- String reportCode,
- String consultationCode,
- String recordCode) {
- var arguments = {
- 'token': token,
- 'patientCode': patientCode,
- 'referralRecordCode': referralRecordCode,
- 'reportCode': reportCode,
- 'consultationCode': consultationCode,
- 'recordCode': recordCode,
- };
- Get.to(
- () => ReporteditPage(),
- binding: BindingsBuilder(() {
- Get.put(ReportEditController());
- }),
- arguments: arguments,
- );
- ///SP60全屏显示撰写报告
- // router.to(
- // RouteNames.Remedical.ReportEdit,
- // id: NavIds.HOME,
- // parameters: arguments,
- // );
- }
- ///进入测量页面
- void enterVidMeasurePage({
- String imageUrl = '',
- int imageindex = 0,
- String remedicalCode = '',
- String patientCode = '',
- String recordCode = '',
- String? remedicalAISelectedInfoCode = '',
- bool needRouterBack = false,
- bool reportPageEnter = false,
- }) {
- _openMeasurePage(
- patientCode,
- remedicalCode,
- recordCode,
- 0,
- remedicalAISelectedInfoCode,
- needRouterBack: needRouterBack,
- reportPageEnter: reportPageEnter,
- );
- }
- @override
- Future<RemedicalListResult> getRemedicalListByRecordInfoAsync(
- String recordCode) async {
- try {
- final result =
- await rpc.remoteUltrasound.vitalGetRemedicalListByRecordInfoAsync(
- QueryRecordRequest(
- token: token,
- recordCode: recordCode,
- ),
- );
- return result;
- } catch (e) {
- return RemedicalListResult();
- }
- }
- ///注册微信分享api
- @override
- void initFluwx() async {
- try {
- if (kIsMobile) {
- await registerWxApi(
- appId: "wx2167274095118ddb",
- doOnAndroid: true,
- doOnIOS: true,
- universalLink: "https://flyinsono.com/",
- );
- }
- } catch (e) {
- logger.e('ReportManager initFluwx', e);
- }
- }
- /// 获取测量图像
- @override
- Future<List<RemedicalMeasuredInfoDTO>> findRemedicalMeasuredInfoAsync(
- String recordCode, {
- BusinessTypeEnum businessTypeEnum = BusinessTypeEnum.RemoteDiagnosis,
- }) async {
- List<RemedicalMeasuredInfoDTO> remedicalMeasured = [];
- try {
- final result =
- await rpc.remoteUltrasound.vitalFindRemedicalMeasuredInfoAsync(
- FindRemedicalMeasuredInfoRequest(
- token: token,
- recordCode: recordCode,
- businessType: businessTypeEnum,
- ),
- );
- remedicalMeasured = result;
- } catch (e) {
- remedicalMeasured = [];
- printError(
- info: "findRemedicalMeasuredInfoAsync exception:" + e.toString());
- logger.e("findRemedicalMeasuredInfoAsync exception:", e);
- }
- return remedicalMeasured;
- }
- ///跟据reportCode获取报告详情
- @override
- Future<r.ReportDTO> findReportByCodeAsync(String reportCode) async {
- final reportInfo = await rpc.ultrasoundReport.vitalFindReportByCodeAsync(
- FindReportByCodeRequest(
- token: token,
- reportCode: reportCode,
- ),
- );
- return reportInfo;
- }
- ///手机端底部弹窗选择分享方式
- @override
- Future<bool> showBottomSheet(r.ReportDTO reportInfo) async {
- bool result = false;
- var reportCode = reportInfo.reportCode ?? '';
- final url = await findReportShareUrlAsync(reportCode);
- String smsContent = "【杏聆荟】${reportInfo.patientName}的检查报告已生成,可点击${url}查看报告。";
- smsContent = smsContent.replaceAll('#', '%23');
- await showModalBottomSheet(
- context: Get.context!,
- backgroundColor: Colors.white, //背景颜色
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.only(
- topLeft: Radius.circular(8), topRight: Radius.circular(8))),
- isScrollControlled: false,
- isDismissible: true,
- builder: (BuildContext context) {
- return Column(
- mainAxisSize: MainAxisSize.min, // 设置最小的弹出
- children: [
- ListTile(
- leading: Icon(Icons.wechat),
- title: Text('朋友圈'),
- onTap: () async {
- _shareWX(url, reportInfo.patientName);
- Get.back();
- },
- ),
- const RowSeparator(),
- ListTile(
- leading: const Icon(Icons.message),
- title: const Text("短信分享"),
- onTap: () async {
- _sendSMS(smsContent, []);
- Get.back();
- },
- ),
- const RowSeparator(),
- ListTile(
- leading: const Icon(Icons.copy),
- title: const Text('复制链接'),
- onTap: () {
- if (FPlatform.isWindows || FPlatform.isMacOS) {
- rpc.platform.copyToClipboard(url);
- } else {
- Clipboard.setData(ClipboardData(text: url));
- }
- PromptBox.toast('复制成功');
- Get.back();
- },
- ),
- ],
- );
- });
- return result;
- }
- ///微信分享
- Future<void> _shareWX(String url, String? patientName) async {
- var result = await isWeChatInstalled;
- if (!result) {
- PromptBox.toast('无法打开微信 请检查是否安装了微信');
- return;
- }
- //分享后打开的图文连接
- String linkUrl = url;
- //分享的小图片
- String imageUrl =
- "https://flyinsono-bj-1300984704.cos.ap-beijing.myqcloud.com/FlyinsonoIcon.png";
- /// 分享到好友
- WeChatShareBaseModel model = WeChatShareWebPageModel(
- //链接
- linkUrl,
- //标题
- title: '超声报告',
- //描述
- description: patientName ?? " ",
- //小图
- thumbnail: WeChatImage.network(imageUrl),
- //微信消息
- scene: WeChatScene.SESSION,
- );
- final rst = await shareToWeChat(model);
- logger.i("ReportManager - share by wechat|$rst|$linkUrl");
- }
- void _sendSMS(String message, List<String> recipents) async {
- if (FPlatform.isAndroid) {
- // await launchUrl(Uri.parse('sms:?body=$message'));
- await launch('sms:?body=$message'); // 修正乱码问题
- } else {
- String _result = await sendSMS(message: message, recipients: recipents)
- .catchError((onError) {
- print(onError);
- });
- print(_result);
- }
- }
- @override
- Future<List<r.ReportDTO>> getReportInfoAsync(String recordCode) async {
- try {
- var result = await findReportsAsync(recordCode);
- return result;
- } catch (e) {
- logger.e('RealTimeConsultationReportController getFollowUpVisitInfo ex:' +
- e.toString());
- return [];
- }
- }
- ///获取分享报告链接
- @override
- Future<String> findReportShareUrlAsync(String reportCode) async {
- var reportUrlToShare = await rpc.report.findReportShareUrlAsync(
- FindReportShareUrlRequest(reportCode: reportCode, token: token));
- return reportUrlToShare;
- }
- ///打开报告预览页面
- @override
- Future<void> openReportPreviewPage(
- String recordCode,
- String referralRecordCode, {
- String reportCode = '',
- }) async {
- try {
- final reports = await findReportsAsync(recordCode);
- if (reports.isEmpty) {
- PromptBox.toast("暂无报告");
- return;
- }
- _openReportPreview(token, reportCode, recordCode);
- } catch (e) {
- printError(
- info: "getRemedicalListByRecordInfoAsync exception:" + e.toString());
- logger.e("getRemedicalListByRecordInfoAsync exception:", e);
- }
- }
- void _openReportPreview(String token, String reportCode, String recordCode) {
- var arguments = {
- 'token': token,
- 'reportCode': reportCode,
- 'recordCode': recordCode,
- };
- Get.to(
- () => ReportPreviewPage(),
- binding: BindingsBuilder(() {
- Get.put(ReportPreviewController());
- }),
- arguments: arguments,
- );
- }
- Future<void> _initPreviewReport(String reportCode) async {
- try {
- if (reportCode.isNotEmpty) {
- final reportInfo =
- await rpc.ultrasoundReport.vitalFindReportByCodeAsync(
- FindReportByCodeRequest(
- token: token,
- reportCode: reportCode,
- ),
- );
- final jsonStr = reportInfo.reportDatasJson;
- final measureJsonStr = reportInfo.reportMeasureDatasJson;
- if (jsonStr != null && jsonStr.isNotEmpty) {
- final jsonItems = jsonDecode(jsonStr) as List<dynamic>;
- if (measureJsonStr.isNotNullOrEmpty) {
- final measureJsonItems =
- jsonDecode(measureJsonStr!) as List<dynamic>;
- jsonItems.addAll(measureJsonItems);
- }
- var reportTemplate = reportInfo.reportTemplateJson;
- var reportTempalteDoc =
- ReportTemplateDocument.fromJson(jsonDecode(reportTemplate!));
- FReportInfo.instance.init(
- reportTempalteDoc,
- DateTime.now(),
- "",
- revoke: i18nBook.common.revoke.t,
- selectEntry: i18nBook.remedical.selectWord.t,
- selectImageHint: i18nBook.remedical.clickAndSelectImage.t,
- );
- FReportInfo.instance.fromJson(jsonItems);
- }
- }
- } catch (e) {
- print(e);
- }
- }
- void _openMeasurePage(
- String patientCode,
- String remedicalCode,
- String recordCode,
- int type,
- String? remedicalAISelectedInfoCode, {
- bool needRouterBack = false,
- bool reportPageEnter = false,
- }) async {
- var parasmeters = {
- "page": "measure",
- "patientCode": patientCode,
- "remedicalCode": remedicalCode,
- "recordCode": recordCode,
- "source": type.toString(),
- "token": token,
- "remedicalAISelectedInfoCode": remedicalAISelectedInfoCode ?? '',
- };
- /// parasmeters 添加参数 needBack
- parasmeters["needRouterBack"] = needRouterBack.toString();
- Get.to(
- () => MeasureHomePage(),
- binding: BindingsBuilder(() {
- Get.put(MeasureHomeController());
- }),
- arguments: parasmeters,
- );
- // await router.to(
- // RouteNames.Remedical.Measure,
- // id: (kIsMobile || (reportPageEnter && needRouterBack))
- // ? null
- // : NavIds.HOME,
- // parameters: parasmeters,
- // );
- }
- }
- // enum VidImageSource {
- // Remedical,
- // Consultation,
- // Laboratory,
- // AiResultModifier,
- // }
|