last_record.dart 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. import 'dart:convert';
  2. import 'package:flutter/material.dart';
  3. import 'package:flutter/services.dart';
  4. import 'package:get/get.dart';
  5. import 'package:vitalapp/components/dialog_ecg_image.dart';
  6. import 'package:vitalapp/pages/medical/widgets/twelve_ecg_view/widgets/conclusion_dialog.dart';
  7. import 'package:vnote_device_plugin/models/exams/twelve_heart.dart';
  8. class LastRecordTable extends StatelessWidget {
  9. final bool? isExistLocalData;
  10. const LastRecordTable({
  11. super.key,
  12. this.title,
  13. required this.columnNames,
  14. required this.tableData,
  15. this.diagnosisTime,
  16. this.isExistLocalData = false,
  17. this.checkKey,
  18. });
  19. final List<List<String>> tableData;
  20. final List<String> columnNames;
  21. final String? title;
  22. final String? diagnosisTime;
  23. final String? checkKey;
  24. @override
  25. Widget build(BuildContext context) {
  26. return Container(child: Expanded(child: _buildTable()));
  27. }
  28. Widget _buildTable() {
  29. final scrollController = ScrollController();
  30. return Column(
  31. children: [
  32. const SizedBox(
  33. height: 10,
  34. ),
  35. Table(
  36. children: [
  37. TableRow(
  38. decoration: const BoxDecoration(
  39. color: Color.fromRGBO(215, 234, 255, 1),
  40. ),
  41. children: columnNames
  42. .map((columnName) => _buildHeaderCell(columnName))
  43. .toList(),
  44. ),
  45. ],
  46. ),
  47. Expanded(
  48. child: Scrollbar(
  49. controller: scrollController,
  50. thumbVisibility: true,
  51. child: SingleChildScrollView(
  52. controller: scrollController,
  53. child: Table(
  54. children: _buildRow(tableData),
  55. ),
  56. ),
  57. ),
  58. ),
  59. const SizedBox(
  60. height: 10,
  61. ),
  62. // Container(
  63. // alignment: Alignment.centerLeft,
  64. // child: Text(
  65. // "检测时间:${diagnosisTime ?? ''}",
  66. // style: const TextStyle(fontSize: 18),
  67. // )),
  68. // const SizedBox(
  69. // height: 10,
  70. // ),
  71. // Container(
  72. // alignment: Alignment.centerLeft,
  73. // child: const Text(
  74. // '注:本结果仅对该检验样本负责!',
  75. // style: TextStyle(fontSize: 18),
  76. // ))
  77. ],
  78. );
  79. }
  80. List<TableRow> _buildRow(List<List<String>> tableData) {
  81. // var controller = Get.find<HealthCheckListController>();
  82. var tableRows = <TableRow>[];
  83. for (var i = 0; i < tableData.length; i++) {
  84. final rowData = tableData[i];
  85. final label = rowData[0];
  86. tableRows.add(
  87. TableRow(
  88. decoration: i % 2 == 0
  89. ? null
  90. : const BoxDecoration(
  91. color: Color.fromRGBO(233, 244, 255, 1),
  92. ),
  93. children: tableData[i].map(
  94. (cellData) {
  95. if (checkKey == "HEITCMC") {
  96. return _buildConstitutionDataCell(cellData);
  97. }
  98. if (label == '心电测量') {
  99. return _buildImageDataCell(cellData);
  100. } else if (label == '十二导心电(30秒)') {
  101. return _buildImageDataCell(cellData);
  102. } else if (label == '十二导分析结果') {
  103. return _buildEcg12DataCell(cellData);
  104. }
  105. return _buildDataCell(cellData);
  106. },
  107. ).toList(),
  108. ),
  109. );
  110. }
  111. return tableRows;
  112. }
  113. TableCell _buildConstitutionDataCell(String title) {
  114. if (title.contains("Value")) {
  115. title = jsonDecode(title)["Value"].toString();
  116. } else if (title.contains("质")) {
  117. title = title.substring(0, 3);
  118. }
  119. Widget contentWidget = _buildSizeOverflow(title);
  120. return TableCell(
  121. child: Container(
  122. padding: const EdgeInsets.symmetric(horizontal: 14),
  123. alignment: Alignment.centerLeft,
  124. height: 37,
  125. child: contentWidget,
  126. ),
  127. );
  128. }
  129. TableCell _buildHeaderCell(String title) {
  130. return TableCell(
  131. child: Container(
  132. padding: const EdgeInsets.symmetric(horizontal: 14),
  133. alignment: Alignment.centerLeft,
  134. height: 37,
  135. child: Text(
  136. title,
  137. style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
  138. ),
  139. ),
  140. );
  141. }
  142. /// 12导心电的结果
  143. TableCell _buildEcg12DataCell(String value) {
  144. if (value.contains("advice")) {
  145. return TableCell(
  146. child: InkWell(
  147. onTap: () async {
  148. TwelveHeartResultEntity resultConclusion =
  149. TwelveHeartResultEntity.fromJson(jsonDecode(value));
  150. await ConclusionDialog.show(twelveHeartResult: resultConclusion);
  151. },
  152. child: Container(
  153. padding: const EdgeInsets.symmetric(horizontal: 14),
  154. alignment: Alignment.centerLeft,
  155. height: 57,
  156. child: const Text(
  157. "点击查看结果",
  158. style: TextStyle(
  159. color: Colors.blue,
  160. ),
  161. ),
  162. ),
  163. ),
  164. );
  165. }
  166. return TableCell(
  167. child: Container(
  168. padding: const EdgeInsets.symmetric(horizontal: 14),
  169. alignment: Alignment.centerLeft,
  170. height: 57,
  171. child: Text(
  172. value,
  173. style: const TextStyle(fontSize: 14),
  174. ),
  175. ),
  176. );
  177. }
  178. String _replaceSemicolon(String input) {
  179. String result = input;
  180. if (result.endsWith(';')) {
  181. result = result.replaceAll(';', '');
  182. } else {
  183. result = result.replaceAll(';', '、');
  184. }
  185. return result;
  186. }
  187. Widget _buildSizeOverflow(String title) {
  188. return LayoutBuilder(
  189. builder: (BuildContext context, BoxConstraints constraints) {
  190. final textPainter = TextPainter(
  191. text: TextSpan(text: title, style: const TextStyle(fontSize: 14)),
  192. maxLines: 1,
  193. textDirection: TextDirection.ltr,
  194. )..layout(maxWidth: constraints.maxWidth);
  195. Widget contentWidget = Text(
  196. title,
  197. style: const TextStyle(
  198. color: Colors.black,
  199. fontSize: 14,
  200. ),
  201. overflow: TextOverflow.ellipsis,
  202. );
  203. if (textPainter.didExceedMaxLines) {
  204. contentWidget = Tooltip(
  205. message: title,
  206. padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
  207. textStyle: const TextStyle(fontSize: 14, color: Colors.white),
  208. triggerMode: TooltipTriggerMode.tap,
  209. child: contentWidget,
  210. );
  211. } else {
  212. // 文本没有超出
  213. print('Text did not overflow');
  214. }
  215. return contentWidget;
  216. },
  217. );
  218. }
  219. TableCell _buildDataCell(String title) {
  220. if (title.contains(";")) {
  221. title = _replaceSemicolon(title);
  222. }
  223. Widget contentWidget = _buildSizeOverflow(title);
  224. return TableCell(
  225. child: Container(
  226. padding: const EdgeInsets.symmetric(horizontal: 14),
  227. alignment: Alignment.centerLeft,
  228. height: 37,
  229. child: contentWidget,
  230. ),
  231. );
  232. }
  233. TableCell _buildImageDataCell(String title) {
  234. if (title.length > 50) {
  235. Uint8List imageBytes = isExistLocalData!
  236. ? base64.decode(title)
  237. : base64.decode(
  238. "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=");
  239. return TableCell(
  240. child: InkWell(
  241. onTap: () {
  242. print(title);
  243. Get.dialog(
  244. EcgImageDialog(
  245. image: isExistLocalData!
  246. ? Image.memory(
  247. imageBytes,
  248. )
  249. : Image.network(
  250. title,
  251. fit: BoxFit.cover,
  252. ),
  253. ),
  254. );
  255. },
  256. child: Container(
  257. padding: const EdgeInsets.symmetric(horizontal: 8),
  258. alignment: Alignment.center,
  259. height: 40,
  260. child: isExistLocalData!
  261. ? Image.memory(
  262. imageBytes,
  263. fit: BoxFit.fitHeight,
  264. height: 28,
  265. )
  266. : Image.network(
  267. title,
  268. fit: BoxFit.fitHeight,
  269. height: 28,
  270. ),
  271. ),
  272. ),
  273. );
  274. }
  275. return TableCell(
  276. child: Container(
  277. padding: const EdgeInsets.symmetric(horizontal: 14),
  278. alignment: Alignment.centerLeft,
  279. height: 37,
  280. child: Text(
  281. title,
  282. style: const TextStyle(fontSize: 14),
  283. ),
  284. ),
  285. );
  286. }
  287. }