123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616 |
- import 'dart:convert';
- import 'package:ecg_list_view/ecg_list/widgets/conclusion_dialog.dart';
- import 'package:fis_common/index.dart';
- import 'package:flutter/foundation.dart';
- import 'package:get/get.dart';
- import 'package:http/http.dart' as http;
- import 'package:fis_jsonrpc/rpc.dart';
- import 'package:flutter/cupertino.dart';
- import 'package:flutter/material.dart';
- import 'package:vitalapp/architecture/storage/storage.dart';
- import 'package:vitalapp/architecture/utils/prompt_box.dart';
- import 'package:vitalapp/architecture/utils/upload.dart';
- import 'package:vitalapp/components/appbar.dart';
- import 'package:vitalapp/components/dropdown_button.dart';
- import 'package:vitalapp/components/no_data_view.dart';
- import 'package:vitalapp/components/select.dart';
- import 'package:vitalapp/managers/interfaces/exam.dart';
- import 'package:vitalapp/managers/interfaces/report.dart';
- import 'package:vitalapp/managers/interfaces/report_template.dart';
- import 'package:vitalapp/pages/medical/controller.dart';
- import 'package:vitalapp/pages/medical/models/worker.dart';
- import 'package:vitalapp/pages/medical/widgets/device_status_position.dart';
- import 'package:vitalapp/pages/medical/widgets/twelve_ecg.dart';
- import 'package:vitalapp/pages/medical/widgets/twelve_ecg_view/controller.dart';
- import 'package:vitalapp/pages/medical/widgets/twelve_ecg_view/view.dart';
- import 'package:vitalapp/pages/medical/widgets/twelve_ecg_view/widgets/ecg_device_status.dart';
- import 'package:vitalapp/pages/medical/widgets/twelve_ecg_view/widgets/full_screen_ecg_data_dialog.dart';
- import 'package:vitalapp/rpc.dart';
- import 'package:vnote_device_plugin/models/exams/twelve_heart.dart';
- import 'ecg_term_selection.dart';
- class EcgResultView extends StatefulWidget {
- final ElectrocardiogramRecord recordInfo;
- final String reportCode;
- EcgResultView(
- this.recordInfo, {
- this.reportCode = "",
- });
- @override
- State<StatefulWidget> createState() {
- return EcgResultViewState();
- }
- }
- class EcgResultViewState extends State<EcgResultView> {
- TwelveHeartResultEntity? resultConclusion;
- final MedicalController medicalController = Get.find<MedicalController>();
- final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
- final _promptWordsController = TextEditingController();
- final _hrController = TextEditingController();
- final _qRSAxisController = TextEditingController();
- final _pRController = TextEditingController();
- final _qTDurController = TextEditingController();
- final _qTCDurController = TextEditingController();
- final _pAxisController = TextEditingController();
- final _qRSController = TextEditingController();
- final _tAxisController = TextEditingController();
- final _pDurController = TextEditingController();
- final _tDurController = TextEditingController();
- double _paperSpeed = 25.0;
- int _gain = 5;
- List<ReportTemplateDTO> _templates = [];
- ReportTemplateDTO _currentSelectedTemplate = ReportTemplateDTO();
-
- List<int> _initEcgDatas = [];
- @override
- void initState() {
- String examData = widget.recordInfo.examData ?? '';
- if (examData.isNotEmpty) {
- Get.find<IReportTemplateManager>()
- .getReportTemplatePage(
- businessType: ReportTemplateBusinessTypeEnum.HEIECG)
- .then((result) {
- setState(() {
- _templates = result.pageData ?? [];
- if (_templates.isNotEmpty) {
- _currentSelectedTemplate = _templates.first;
- }
- });
- });
- Map<String, dynamic> examDatas = jsonDecode(examData);
- if (examDatas.containsKey("ECG_POINT12")) {
- String exgPoint12Url = examDatas["ECG_POINT12"].toString();
- if (exgPoint12Url.startsWith('https://') ||
- exgPoint12Url.startsWith("http://")) {
- http.get(Uri.parse(exgPoint12Url)).then((value) {
- var initEcgData = jsonDecode(value.body).cast<int>();
-
- setState(() {
- _initEcgDatas = initEcgData;
- });
- });
- }
- }
- if (examDatas.containsKey("Analyse12")) {
- String analyse12 = examDatas["Analyse12"].toString();
- if (analyse12.isNotEmpty) {
- resultConclusion =
- TwelveHeartResultEntity.fromJson(jsonDecode(analyse12));
- if (resultConclusion != null) {
- _promptWordsController.text = resultConclusion!.advice;
- _qRSAxisController.text = resultConclusion!.QRSAxis;
- _pRController.text = resultConclusion!.PR;
- _qTDurController.text = resultConclusion!.QTDur;
- _qTCDurController.text = resultConclusion!.QTCDur;
- _pAxisController.text = resultConclusion!.PAxis;
- _qRSController.text = resultConclusion!.QRSDur;
- _tAxisController.text = resultConclusion!.TAxis;
- _pDurController.text = resultConclusion!.PDur;
- _tDurController.text = resultConclusion!.TDur;
- }
- }
- }
- }
- var startDate =
- medicalController.diagnosisDataValue['TwelveHeart']?['StartDate'] ?? "";
- var endDate =
- medicalController.diagnosisDataValue['TwelveHeart']?['EndDate'] ?? '';
- if (startDate.toString() != "" && endDate.toString() != "")
- Get.find<TwelveEcgViewController>().state.rangeValues = RangeValues(
- double.parse(startDate.toString()), double.parse(endDate.toString()));
- super.initState();
- }
- @override
- Widget build(BuildContext context) {
- final double ecgViewWidth = 950;
- return Scaffold(
- key: scaffoldKey,
- resizeToAvoidBottomInset: false,
- appBar: VAppBar(
- titleText: "体检心电",
- actions: [
- Container(
- margin: EdgeInsets.only(right: 10),
- child: Row(
- children: [
- Text(
- widget.recordInfo.patientName ?? '',
- style: TextStyle(color: Colors.white, fontSize: 24),
- ),
- SizedBox(width: 38),
- ElevatedButton(
- onPressed: () async {
- String examData = widget.recordInfo.examData ?? '';
- if (examData.isNotEmpty) {
- await Get.find<TwelveEcgViewController>()
- .updateEcgImage();
- String base64Image = medicalController
- .diagnosisDataValue['TwelveHeart']?['ECG12'];
- Map<String, dynamic> examDatas = jsonDecode(examData);
- if (examDatas.containsKey("ECG12")) {
- if (kIsWeb) {
- var file =
- UploadUtils.convertBase64ToFile(base64Image);
- String? url = await rpc.storage.webUpload(file!);
- examDatas['ECG12'] = url ?? '';
- } else {
- final imageFile =
- UploadUtils.convertBase64ToXFile(base64Image);
- String? imageUrl = await rpc.storage
- .upload(imageFile!, fileType: "jpg");
- examDatas['ECG12'] = imageUrl ?? '';
- }
- }
- if (examDatas.containsKey("Analyse12")) {
- resultConclusion!.advice =
- _promptWordsController.text;
- resultConclusion!.QRSAxis = _qRSAxisController.text;
- resultConclusion!.PR = _pRController.text;
- resultConclusion!.QTDur = _qTDurController.text;
- resultConclusion!.QTCDur = _qTCDurController.text;
- resultConclusion!.PAxis = _pAxisController.text;
- resultConclusion!.QRSDur = _qRSController.text;
- resultConclusion!.TAxis = _tAxisController.text;
- resultConclusion!.PDur = _pDurController.text;
- resultConclusion!.TDur = _tDurController.text;
- resultConclusion!.paperSpeed =
- _paperSpeed.toString();
- resultConclusion!.gain = _gain.toString();
- var newData = resultConclusion?.toJson();
- examDatas["Analyse12"] = jsonEncode(newData);
- examDatas["HEART12"] = _hrController.text;
- var exam = jsonEncode(examDatas);
- if (widget.reportCode.isEmpty) {
- final String result =
- await Get.find<IReportManager>().addReport(
- recordCode: widget.recordInfo.code ?? '',
- reportDatasJson: exam,
- name: widget.recordInfo.patientName ?? '',
- reportTemplateCode:
- _currentSelectedTemplate.reportTemplateCode,
- );
- if (result.isNotEmpty) {
- PromptBox.toast('提交成功');
- Get.back();
- }
- } else {
- final bool result =
- await Get.find<IReportManager>().modifyReport(
- recordCode: widget.recordInfo.code ?? '',
- reportInfoJson: exam,
- name: widget.recordInfo.patientName ?? '',
- reportTemplateCode: _currentSelectedTemplate
- .reportTemplateCode ??
- '',
- reportCode: widget.reportCode,
- );
- if (result) {
- PromptBox.toast('提交成功');
- Get.back();
- }
- }
- }
- }
- },
- child: Text(
- "提交",
- style: TextStyle(
- fontSize: 20,
- ),
- ))
- ],
- )),
- ],
- ),
- drawer: Drawer(
- width: 550,
- child: ECGTermSelection(
- onTab: (v) {
- _promptWordsController.text += "\r\n" + v;
- },
- ),
- ),
- body: widget.recordInfo.examData.isNullOrEmpty
- ? VNoDataView()
- : Container(
- color: Colors.white,
- child: Row(
- children: [
- SizedBox(width: 5),
- if (_initEcgDatas.isNotEmpty) ...[
- Expanded(
- flex: 10,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Expanded(
- child: _buildHeader(context),
- ),
- Stack(
- children: [
- GetBuilder(
- init: TwelveEcgViewController(
- initPoints: _initEcgDatas),
- id: "twelve_ecg_view",
- builder: (_) {
- return FullScreenEcgDataDialog(
- height: kIsWeb ? 520 : 610,
- showHeader: false,
- widthScale: 1,
- hintFontSize: 14,
- );
- }),
- Positioned(
- top: 70,
- left: 20,
- child: Row(
- children: [
- SizedBox(width: 25),
- _buildKeyValue(
- "",
- "1.6Hz",
- fontSize: 14,
- ),
- SizedBox(width: 15),
- _buildKeyValue(
- "",
- "53 Hz",
- fontSize: 14,
- ),
- SizedBox(width: 15),
- _buildKeyValue(
- "",
- "AC",
- fontSize: 14,
- ),
- SizedBox(width: 15),
- _buildKeyValue(
- "",
- "50 Hz",
- fontSize: 14,
- ),
- SizedBox(width: 15),
- ],
- ),
- )
- ],
- )
- ],
- ),
- ),
- ] else ...[
- SizedBox(
- width: ecgViewWidth,
- ),
- ],
- Expanded(
- flex: 3,
- child: _buildAnalysisResults(),
- ),
- ],
- ),
- ),
- );
- }
- Widget _buildHeader(BuildContext buildContext) {
- String heartRate12 = "";
- String examData = widget.recordInfo.examData ?? '';
- if (examData.isNotEmpty) {
- Map<String, dynamic> examDatas = jsonDecode(examData);
- if (examDatas.containsKey("HEART12")) {
- heartRate12 = examDatas["HEART12"].toString();
- _hrController.text = heartRate12;
- }
- }
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Container(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- children: [
- SizedBox(width: 10),
- Row(
- children: [
- Text(
- "走速:",
- style: TextStyle(fontSize: 20),
- ),
- GenericDropdownButton<double>(
- items: [12.5, 25, 50],
- itemToString: (v) {
- return v.toString();
- },
- initialValue: _paperSpeed,
- onChanged: (value) {
- _paperSpeed = value;
- Get.find<TwelveEcgViewController>()
- .changeHorizontalRatio(_paperSpeed / 25);
- },
- ),
- Text(
- "mm/s",
- style: TextStyle(fontSize: 20),
- ),
- ],
- ),
-
- SizedBox(width: 10),
- Row(
- children: [
- Text(
- "增益:",
- style: TextStyle(fontSize: 20),
- ),
- GenericDropdownButton<int>(
- items: [5, 10, 20],
- itemToString: (v) {
- return v.toString();
- },
- initialValue: _gain,
- onChanged: (value) {
- _gain = value;
- int radio = _gain ~/ 5;
- List<int> tempDatas = [];
- for (int p in _initEcgDatas) {
- tempDatas.add(p * radio);
- }
- Get.find<TwelveEcgViewController>()
- .changeVerticalRatio(tempDatas);
- },
- ),
- Text(
- "mm/mV",
- style: TextStyle(fontSize: 20),
- ),
- ],
- ),
-
- SizedBox(width: 10),
- _buildKeyValue(
- "RV5/SV1:", "${resultConclusion?.Rv5_Sv1_1} Hz"),
- SizedBox(width: 10),
- _buildKeyValue(
- "RV5+SV1:", "${resultConclusion?.Rv5_Sv1_2} Hz"),
- SizedBox(width: 10),
- ],
- ),
- Row(
- children: [
- SizedBox(width: 10),
- _buildKeyValue("姓名:", widget.recordInfo.patientName ?? ''),
- SizedBox(width: 10),
- _buildKeyValue("性别:",
- patientGenderConvertAge(widget.recordInfo.patientGender)),
- SizedBox(width: 10),
- _buildKeyValue(
- "年龄:", birthDayConvertAge(widget.recordInfo.birthday)),
- SizedBox(width: 10),
- if (_templates.isNotEmpty) ...[
- Text(
- "模板:",
- style: TextStyle(fontSize: 20),
- ),
- GenericDropdownButton<ReportTemplateDTO>(
- items: _templates,
- initialValue: _currentSelectedTemplate,
- itemToString: (t) {
- return t.reportTemplateName ?? '';
- },
- onChanged: (v) {
- _currentSelectedTemplate = v;
- },
- ),
- ],
- SizedBox(
- width: 40,
- ),
- SizedBox(
- child: Text(
- "若需要更改图像截取范围,请滑动下方的滑动条",
- style: TextStyle(
- fontSize: 15,
- ),
- ),
- ),
- ],
- ),
-
- ],
- ),
- ),
- Column(
- crossAxisAlignment: CrossAxisAlignment.end,
- children: [
- Text(
- "诊断提示:",
- style: TextStyle(fontSize: 16),
- ),
- ],
- ),
- ],
- );
- }
- String patientGenderConvertAge(GenderEnum patientGender) {
- switch (patientGender) {
- case GenderEnum.Male:
- return "男";
- case GenderEnum.Female:
- return "女";
- default:
- return "";
- }
- }
- String birthDayConvertAge(DateTime? birthday) {
- if (birthday == null) {
- return "";
- }
-
- DateTime now = DateTime.now();
-
- int age = calculateAge(birthday, now);
- return age.toString();
- }
- int calculateAge(DateTime birthDate, DateTime now) {
-
- int age = now.year - birthDate.year;
-
- if (now.month < birthDate.month ||
- (now.month == birthDate.month && now.day < birthDate.day)) {
- age--;
- }
- return age;
- }
- Widget _buildKeyValue(
- String key,
- String value, {
- double fontSize = 20,
- }) {
- return Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Text(
- key,
- style: TextStyle(fontSize: fontSize),
- ),
- Text(
- value,
- style: TextStyle(fontSize: fontSize),
- ),
- ],
- );
- }
- Widget _buildKeyInput(
- String key, TextEditingController controller, String? unit) {
- final textStyle = const TextStyle(fontSize: 20);
- return Container(
- margin: EdgeInsets.symmetric(vertical: 2),
- child: Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- SizedBox(
- width: 110,
- child: Text(
- key,
- style: textStyle,
- ),
- ),
- Expanded(
- child: TextField(
- decoration: InputDecoration(
- contentPadding: EdgeInsets.only(
- top: 2.0, bottom: 2.0, left: 10, right: 10),
- border: OutlineInputBorder(
- borderSide:
- BorderSide(color: Colors.black, width: 1.0),
- borderRadius:
- BorderRadius.all(Radius.circular(8.0)),
- ),
- ),
- controller: controller,
- style: textStyle,
- ),
- ),
- if (unit.isNotNullOrEmpty) ...[
- SizedBox(
- width: 50,
- child: Text(
- unit!,
- style: textStyle,
- ),
- ),
- ],
- ],
- ),
- );
- }
- Widget _buildAnalysisResults() {
- if (resultConclusion == null) {
- return SizedBox();
- }
- return Container(
- margin: EdgeInsets.symmetric(horizontal: 10),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- SizedBox(
- height: 5,
- ),
- Expanded(child: _buildPromptWords()),
- ElevatedButton(
- onPressed: () {
- scaffoldKey.currentState?.openDrawer();
- },
- child: Text("词条选择"),
- ),
- _buildKeyInput("心率:", _hrController, " bpm"),
- _buildKeyInput("P时限:", _pDurController, " ms"),
- _buildKeyInput("QRS时限:", _qRSController, " ms"),
- _buildKeyInput("T时限:", _tDurController, " ms"),
- _buildKeyInput("PR间期:", _pRController, " ms"),
- _buildKeyInput("QT间期:", _qTDurController, " ms"),
- _buildKeyInput("QTc间期:", _qTCDurController, " ms"),
- _buildKeyInput("P轴:", _pAxisController, " °"),
- _buildKeyInput("QRS轴:", _qRSController, " °"),
- _buildKeyInput("T轴:", _tAxisController, " °"),
- ],
- ),
- );
- }
- Widget _buildPromptWords() {
- return SizedBox(
- child: TextField(
- controller: _promptWordsController,
- maxLines: 5,
- decoration: InputDecoration(
- hintText: '请输入提示词',
- border: OutlineInputBorder(
- borderSide:
- BorderSide(color: Colors.black, width: 1.0),
- borderRadius: BorderRadius.all(Radius.circular(8.0)),
- ),
- ),
- ),
- );
- }
- }
|