|
@@ -0,0 +1,324 @@
|
|
|
+import 'dart:convert';
|
|
|
+import 'package:ecg_list_view/ecg_list/widgets/conclusion_dialog.dart';
|
|
|
+import 'package:fis_common/index.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/components/appbar.dart';
|
|
|
+import 'package:vitalapp/components/no_data_view.dart';
|
|
|
+import 'package:vitalapp/pages/medical/widgets/twelve_ecg_view/view.dart';
|
|
|
+import 'package:vnote_device_plugin/models/exams/twelve_heart.dart';
|
|
|
+
|
|
|
+class EcgResultView extends StatefulWidget {
|
|
|
+ final ElectrocardiogramRecord recordInfo;
|
|
|
+ EcgResultView(this.recordInfo);
|
|
|
+ @override
|
|
|
+ State<StatefulWidget> createState() {
|
|
|
+ return EcgResultViewState();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class EcgResultViewState extends State<EcgResultView> {
|
|
|
+ TwelveHeartResultEntity? resultConclusion;
|
|
|
+ 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();
|
|
|
+
|
|
|
+ /// 初始时的心电初始数据
|
|
|
+ List<int> _initEcgDatas = [];
|
|
|
+
|
|
|
+ @override
|
|
|
+ void initState() {
|
|
|
+ String examData = widget.recordInfo.examData ?? '';
|
|
|
+ if (examData.isNotEmpty) {
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ super.initState();
|
|
|
+ }
|
|
|
+
|
|
|
+ @override
|
|
|
+ Widget build(BuildContext context) {
|
|
|
+ final double ecgViewWidth = 950;
|
|
|
+ final double ecgViewHeight = 550;
|
|
|
+ return Scaffold(
|
|
|
+ resizeToAvoidBottomInset: false, // 防止内容自动调整以避免被键盘遮挡
|
|
|
+ appBar: VAppBar(
|
|
|
+ titleText: "体检心电",
|
|
|
+ actions: [
|
|
|
+ Container(
|
|
|
+ margin: EdgeInsets.only(right: 10),
|
|
|
+ child: Text(
|
|
|
+ widget.recordInfo.patientName ?? '',
|
|
|
+ style: TextStyle(color: Colors.white, fontSize: 24),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ body: widget.recordInfo.examData.isNullOrEmpty
|
|
|
+ ? VNoDataView()
|
|
|
+ : Container(
|
|
|
+ color: Colors.white,
|
|
|
+ child: Row(
|
|
|
+ children: [
|
|
|
+ SizedBox(width: 5),
|
|
|
+ if (_initEcgDatas.isNotEmpty) ...[
|
|
|
+ Expanded(
|
|
|
+ flex: 8,
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ Expanded(
|
|
|
+ child: _buildHeader(),
|
|
|
+ ),
|
|
|
+ TwelveEcgView(
|
|
|
+ width: ecgViewWidth,
|
|
|
+ height: ecgViewHeight,
|
|
|
+ initData: _initEcgDatas,
|
|
|
+ currentIndex: 0,
|
|
|
+ isConclusion: true,
|
|
|
+ ),
|
|
|
+ Container(
|
|
|
+ margin: EdgeInsets.only(left: 5),
|
|
|
+ height: 25,
|
|
|
+ child: Text("点击图像可放大查看"),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ] else ...[
|
|
|
+ SizedBox(
|
|
|
+ width: ecgViewWidth,
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ Expanded(
|
|
|
+ flex: 3,
|
|
|
+ child: _buildAnalysisResults(),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildHeader() {
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ final gapHeight = 15.0;
|
|
|
+ return Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
+ children: [
|
|
|
+ Container(
|
|
|
+ width: 650,
|
|
|
+ child: Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
+ children: [
|
|
|
+ SizedBox(height: gapHeight),
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ SizedBox(width: 15),
|
|
|
+ _buildKeyValue("走速:", "25 mm/s"),
|
|
|
+ SizedBox(width: 15),
|
|
|
+ _buildKeyValue("增益:", "5 mm/mV"),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ SizedBox(height: gapHeight),
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ SizedBox(width: 15),
|
|
|
+ _buildKeyValue("基线滤波:", "1.6-2.0 Hz"),
|
|
|
+ SizedBox(width: 15),
|
|
|
+ _buildKeyValue("肌电滤波:", "53 Hz"),
|
|
|
+ SizedBox(width: 15),
|
|
|
+ _buildKeyValue("AC", ""),
|
|
|
+ SizedBox(width: 15),
|
|
|
+ _buildKeyValue("工频滤波:", "50 Hz"),
|
|
|
+ SizedBox(width: 15),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ SizedBox(height: gapHeight),
|
|
|
+ Row(
|
|
|
+ children: [
|
|
|
+ SizedBox(width: 15),
|
|
|
+ _buildKeyValue(
|
|
|
+ "RV5/SV1:", "${resultConclusion?.Rv5_Sv1_1} Hz"),
|
|
|
+ SizedBox(width: 20),
|
|
|
+ _buildKeyValue(
|
|
|
+ "RV5+SV1:", "${resultConclusion?.Rv5_Sv1_2} Hz"),
|
|
|
+ SizedBox(width: 15),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ //Expanded(child: SizedBox.shrink()),
|
|
|
+ Column(
|
|
|
+ crossAxisAlignment: CrossAxisAlignment.end,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ "诊断提示:",
|
|
|
+ style: TextStyle(fontSize: 20),
|
|
|
+ ),
|
|
|
+ Expanded(child: SizedBox()),
|
|
|
+ ElevatedButton(
|
|
|
+ onPressed: () {},
|
|
|
+ child: Text("词条选择"),
|
|
|
+ ),
|
|
|
+ SizedBox(height: 10)
|
|
|
+ ],
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ Widget _buildKeyValue(String key, String value) {
|
|
|
+ return Row(
|
|
|
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
+ children: [
|
|
|
+ Text(
|
|
|
+ key,
|
|
|
+ style: TextStyle(fontSize: 20),
|
|
|
+ ),
|
|
|
+ Text(
|
|
|
+ value,
|
|
|
+ style: const TextStyle(fontSize: 20),
|
|
|
+ ),
|
|
|
+ ],
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ 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(
|
|
|
+ children: [
|
|
|
+ SizedBox(
|
|
|
+ height: 5,
|
|
|
+ ),
|
|
|
+ Expanded(child: _buildPromptWords()),
|
|
|
+ _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)), // 可选:设置边框圆角
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ ),
|
|
|
+ );
|
|
|
+ }
|
|
|
+}
|