view.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:intl/intl.dart';
  4. import 'package:vitalapp/architecture/utils/prompt_box.dart';
  5. import 'package:vitalapp/components/alert_dialog.dart';
  6. import 'package:vitalapp/components/appbar.dart';
  7. import 'package:vitalapp/components/dialog_table.dart';
  8. import 'package:vitalapp/components/no_data_view.dart';
  9. import 'package:vitalapp/consts/styles.dart';
  10. import 'package:vitalapp/global.dart';
  11. import 'package:vitalapp/managers/interfaces/models/diagnosis_aggregation_record_model.dart';
  12. import 'package:vitalapp/pages/medical/records/controller.dart';
  13. import 'package:vitalapp/pages/patient/list/widgets/status.dart';
  14. import 'package:vitalapp/pages/widgets/record_common_item.dart';
  15. class MedicalRecordsPage extends GetView<MedicalRecordsController> {
  16. const MedicalRecordsPage({super.key});
  17. @override
  18. Widget build(BuildContext context) {
  19. return GetBuilder(
  20. init: MedicalRecordsController(),
  21. id: "MedicalRecords",
  22. builder: (_) {
  23. return Scaffold(
  24. backgroundColor: const Color.fromRGBO(238, 238, 238, 1),
  25. appBar: VAppBar(
  26. titleWidget: const Text('健康检测记录'),
  27. ),
  28. body: Stack(
  29. children: [
  30. Row(
  31. mainAxisAlignment: MainAxisAlignment.start,
  32. crossAxisAlignment: CrossAxisAlignment.start,
  33. children: [
  34. _buildDiagram(),
  35. _buildListView(),
  36. ],
  37. )
  38. ],
  39. ),
  40. );
  41. },
  42. );
  43. }
  44. Widget _buildDiagram() {
  45. return Expanded(
  46. flex: 1,
  47. child: Padding(
  48. padding: const EdgeInsets.all(16.0).copyWith(right: 0),
  49. child: Container(
  50. // color: Colors.white,
  51. padding: const EdgeInsets.all(16),
  52. decoration: BoxDecoration(
  53. color: Colors.white,
  54. border: Border.all(
  55. color: Colors.white,
  56. ),
  57. borderRadius: GlobalStyles.borderRadius,
  58. ),
  59. child: Image.asset(
  60. 'assets/images/exam/normalMeasurementChart.png',
  61. height: double.infinity,
  62. fit: BoxFit.fitWidth,
  63. ),
  64. ),
  65. ),
  66. );
  67. }
  68. Widget _buildListView() {
  69. final scrollController = ScrollController();
  70. scrollController.addListener(
  71. () {
  72. // 如果滑动到底部
  73. try {
  74. if (scrollController.position.atEdge) {
  75. if (scrollController.position.pixels != 0) {
  76. if (controller.state.hasNextPage) {
  77. controller.loadNextPageList();
  78. }
  79. }
  80. }
  81. } catch (e) {
  82. // logger.e("listViewScrollController exception:", e);
  83. }
  84. },
  85. );
  86. return Expanded(
  87. flex: 2,
  88. child: Padding(
  89. padding: const EdgeInsets.all(16.0),
  90. child: RefreshIndicator(
  91. child: Obx(() {
  92. final children = <Widget>[];
  93. for (var element in controller.state.dataList) {
  94. children.add(
  95. _MedicalRecordCard(
  96. dto: element,
  97. ),
  98. );
  99. }
  100. return controller.state.dataList.isEmpty
  101. ? VNoDataView()
  102. : Scrollbar(
  103. trackVisibility: true,
  104. controller: scrollController,
  105. child: GridView(
  106. shrinkWrap: true,
  107. controller: scrollController,
  108. gridDelegate:
  109. const SliverGridDelegateWithFixedCrossAxisCount(
  110. crossAxisCount: 1,
  111. mainAxisSpacing: 16,
  112. crossAxisSpacing: 20,
  113. childAspectRatio: 1080 / 180,
  114. ),
  115. children: children,
  116. ),
  117. );
  118. }),
  119. onRefresh: () async {}),
  120. ),
  121. );
  122. }
  123. }
  124. class _MedicalRecordCard extends GetView<MedicalRecordsController> {
  125. final DiagnosisAggregationRecordModel dto;
  126. const _MedicalRecordCard({required this.dto});
  127. @override
  128. Widget build(BuildContext context) {
  129. bool canDelete = kIsOnline || dto.isExistLocalData == true;
  130. final body = Stack(
  131. children: [
  132. Row(
  133. children: [
  134. Expanded(
  135. flex: 10,
  136. child: Container(
  137. padding: const EdgeInsets.symmetric(
  138. horizontal: 30,
  139. vertical: 12,
  140. ),
  141. child: Column(
  142. crossAxisAlignment: CrossAxisAlignment.start,
  143. children: [
  144. const SizedBox(
  145. height: 8,
  146. ),
  147. Wrap(
  148. alignment: WrapAlignment.start,
  149. spacing: 20,
  150. runSpacing: 8,
  151. children: [
  152. RecordCommonItem(
  153. itemName: '姓名',
  154. itemValue: dto.patientName ?? '',
  155. fontSize: 18,
  156. ),
  157. ],
  158. ),
  159. const SizedBox(
  160. height: 20,
  161. ),
  162. Wrap(
  163. alignment: WrapAlignment.start,
  164. spacing: 20,
  165. runSpacing: 8,
  166. children: [
  167. SizedBox(
  168. width: 250,
  169. child: RecordCommonItem(
  170. itemName: '检查医生',
  171. itemValue: dto.doctorName ?? '',
  172. fontSize: 18,
  173. ),
  174. ),
  175. RecordCommonItem(
  176. itemName: '诊断时间',
  177. itemValue: DateFormat("yyyy-MM-dd HH:mm:ss")
  178. .format(dto.diagnosisTime!.toLocal()),
  179. fontSize: 18,
  180. ),
  181. ],
  182. )
  183. ],
  184. ),
  185. ),
  186. ),
  187. Expanded(
  188. flex: 1,
  189. child: Icon(
  190. Icons.keyboard_arrow_right,
  191. size: 64,
  192. color: Colors.grey.shade400,
  193. ),
  194. ),
  195. ],
  196. ),
  197. Positioned(
  198. top: 16,
  199. right: 0,
  200. child: _diagnosisSignStatusTag(
  201. dto: dto,
  202. ),
  203. ),
  204. if (canDelete)
  205. Positioned(
  206. bottom: 0,
  207. right: 0,
  208. child: _DiagnosisRemoveMarkButton(dto: dto),
  209. ),
  210. if (dto.isExistLocalData == true)
  211. Positioned(
  212. top: 0,
  213. bottom: 0,
  214. right: 96,
  215. child: _DiagnosisEidtButton(dto: dto),
  216. ),
  217. ],
  218. );
  219. return Material(
  220. borderRadius: GlobalStyles.borderRadius,
  221. child: Ink(
  222. decoration: BoxDecoration(
  223. color: Colors.white,
  224. borderRadius: GlobalStyles.borderRadius,
  225. ),
  226. child: InkWell(
  227. borderRadius: GlobalStyles.borderRadius,
  228. onTap: () async {
  229. var result = await controller.getTableData(dto);
  230. await VDialogTable(
  231. isExistLocalData: dto.isExistLocalData,
  232. title: '数据展示',
  233. columnNames: const ['序号', '检测项目', '检测结果', '单位'],
  234. tableData: result,
  235. diagnosisTime: DateFormat("yyyy-MM-dd HH:mm:ss")
  236. .format(dto.diagnosisTime!.toLocal()),
  237. ).show();
  238. },
  239. child: body,
  240. ),
  241. ),
  242. );
  243. }
  244. }
  245. // ignore: camel_case_types
  246. class _diagnosisSignStatusTag extends StatelessWidget {
  247. final DiagnosisAggregationRecordModel dto;
  248. const _diagnosisSignStatusTag({required this.dto});
  249. @override
  250. Widget build(BuildContext context) {
  251. return Container(
  252. alignment: Alignment.centerRight,
  253. width: 120,
  254. child: StatusLabel(
  255. title: dto.isExistLocalData! ? "未上传" : "已上传",
  256. color: dto.isExistLocalData! ? Colors.red : Colors.green,
  257. ),
  258. );
  259. }
  260. }
  261. class _DiagnosisRemoveMarkButton extends StatelessWidget {
  262. final DiagnosisAggregationRecordModel dto;
  263. const _DiagnosisRemoveMarkButton({required this.dto});
  264. @override
  265. Widget build(BuildContext context) {
  266. return GestureDetector(
  267. onTap: () {
  268. Get.dialog(
  269. VAlertDialog(
  270. title: "提示",
  271. width: 260,
  272. content: Container(
  273. height: 32,
  274. padding: const EdgeInsets.symmetric(horizontal: 24),
  275. alignment: Alignment.center,
  276. child: Text(
  277. "确定删除此记录?",
  278. style: TextStyle(fontSize: 20),
  279. ),
  280. ),
  281. onConfirm: () async {
  282. Get.find<MedicalRecordsController>().removeRecord(dto.appDataId!);
  283. Get.back();
  284. },
  285. ),
  286. barrierDismissible: false,
  287. barrierColor: Colors.black.withOpacity(.4),
  288. );
  289. },
  290. child: Container(
  291. padding: EdgeInsets.only(top: 10, left: 10, right: 2, bottom: 2),
  292. decoration: BoxDecoration(
  293. color: Colors.red,
  294. borderRadius: BorderRadius.only(
  295. topLeft: Radius.circular(32),
  296. bottomRight: Radius.circular(8),
  297. ),
  298. ),
  299. child: Icon(
  300. Icons.delete_forever,
  301. size: 26,
  302. color: Colors.white,
  303. ),
  304. ),
  305. );
  306. }
  307. }
  308. class _DiagnosisEidtButton extends StatelessWidget {
  309. final DiagnosisAggregationRecordModel dto;
  310. const _DiagnosisEidtButton({required this.dto});
  311. @override
  312. Widget build(BuildContext context) {
  313. return Container(
  314. alignment: Alignment.center,
  315. child: IconButton(
  316. onPressed: () {
  317. Get.find<MedicalRecordsController>().editRecord(dto);
  318. },
  319. iconSize: 48,
  320. color: Colors.grey.shade400,
  321. icon: Icon(Icons.edit_note),
  322. ),
  323. );
  324. }
  325. }