last_record.dart 8.6 KB

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