view.dart 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. import 'package:flutter/material.dart';
  2. import 'package:get/get.dart';
  3. import 'package:fis_jsonrpc/rpc.dart';
  4. import 'index.dart';
  5. import 'widgets/build_record_view.dart';
  6. import 'widgets/filter_time.dart';
  7. import 'widgets/icon_tab_list.dart';
  8. import 'widgets/last_record.dart';
  9. import 'widgets/no_data_view.dart';
  10. import 'widgets/search_input.dart';
  11. import 'widgets/table/table.dart';
  12. import 'widgets/table/table_column.dart';
  13. import 'package:fis_ui/index.dart';
  14. import 'package:intl/intl.dart';
  15. import 'widgets/table_pagination.dart';
  16. class EcgListPage extends GetView<EcgListController> {
  17. final void Function(String) onEdit;
  18. final void Function(String, String) onExam;
  19. const EcgListPage({
  20. required this.onEdit,
  21. required this.onExam,
  22. Key? key,
  23. }) : super(key: key);
  24. // 主视图
  25. Widget _buildView(BuildContext context) {
  26. return Row(
  27. children: [
  28. Expanded(
  29. child: Column(
  30. children: [
  31. Container(
  32. margin: const EdgeInsets.all(5),
  33. height: 50,
  34. child: _buildHeader(),
  35. ),
  36. Expanded(child: _buildListView())
  37. ],
  38. ),
  39. ),
  40. Container(
  41. width: 300,
  42. decoration: BoxDecoration(
  43. border: Border(
  44. left: BorderSide(
  45. color: Colors.grey[300]!,
  46. width: 1,
  47. ),
  48. ),
  49. ),
  50. child: _buildRightContent(),
  51. )
  52. ],
  53. );
  54. }
  55. @override
  56. Widget build(BuildContext context) {
  57. return GetBuilder<EcgListController>(
  58. init: EcgListController(),
  59. id: "ecg_list",
  60. builder: (_) {
  61. return Scaffold(
  62. body: SafeArea(
  63. child: _buildView(context),
  64. ),
  65. );
  66. },
  67. );
  68. }
  69. Widget _buildHeader() {
  70. return Row(
  71. children: [
  72. Expanded(
  73. child: SizedBox(
  74. height: 50,
  75. child: SearchInput(
  76. placeholder: "请输入关键字",
  77. onSearch: (v) {
  78. controller.getDatas(pageIndex: 1, keyword: v);
  79. },
  80. ),
  81. ),
  82. ),
  83. const SizedBox(
  84. width: 10,
  85. ),
  86. IconButton(
  87. onPressed: () async {
  88. await Get.dialog(
  89. FilterView(
  90. onConfirm: (start, end) {
  91. controller.startTime = start;
  92. controller.endTime = end;
  93. controller.getDatas();
  94. },
  95. startTime: controller.startTime,
  96. endTime: controller.endTime,
  97. ),
  98. );
  99. },
  100. icon: const Icon(
  101. Icons.filter_alt,
  102. size: 24,
  103. color: Colors.blue,
  104. ),
  105. ),
  106. _tabRadio(
  107. title: "全部",
  108. value: RecordProcessStateEnum.All,
  109. ),
  110. _tabRadio(
  111. title: "待处理",
  112. value: RecordProcessStateEnum.Wait,
  113. ),
  114. _tabRadio(
  115. title: "已完成",
  116. value: RecordProcessStateEnum.Done,
  117. ),
  118. ],
  119. );
  120. }
  121. Widget _buildRightContent() {
  122. return Column(
  123. children: [
  124. const SizedBox(height: 5),
  125. IconTabList(
  126. const {
  127. "报告查看": FIcons.report_a4,
  128. },
  129. selectedValue: [
  130. "报告查看",
  131. ][controller.selectedTabIndex],
  132. onPressed: (v) {
  133. controller.selectedTabIndex = v;
  134. controller.loadReports();
  135. },
  136. ),
  137. _buildRecordInfoView(),
  138. ],
  139. );
  140. }
  141. Widget _buildListView() {
  142. return GetBuilder<EcgListController>(
  143. id: "table",
  144. builder: (_) {
  145. return Column(
  146. children: [
  147. Expanded(
  148. child: ETable<ElectrocardiogramRecord>(
  149. autoHeight: false,
  150. noDataHintText: "暂无数据",
  151. columns: _buildTableColumns(),
  152. source: controller.residentList,
  153. loading: controller.tableLoading,
  154. onRowSelected: (value, index, idxs) {},
  155. onRowTap: (index) async {
  156. controller.onRowTap(index);
  157. },
  158. cellPadding: const EdgeInsets.all(5),
  159. onAllRowsSelected: (value, idxs) => {},
  160. headerTextStyle: const TextStyle(
  161. fontSize: 20,
  162. ),
  163. ),
  164. ),
  165. if (controller.currectSelected != -1) ...[
  166. _buildButtons(),
  167. ],
  168. const TablePagination(),
  169. const SizedBox(
  170. height: 16,
  171. )
  172. ],
  173. );
  174. },
  175. );
  176. }
  177. List<TableColumn<ElectrocardiogramRecord>> _buildTableColumns() {
  178. var textStyle = const TextStyle(
  179. fontSize: 16,
  180. overflow: TextOverflow.ellipsis,
  181. );
  182. return <TableColumn<ElectrocardiogramRecord>>[
  183. TableColumn<ElectrocardiogramRecord>(
  184. headerText: "编号",
  185. flex: 5,
  186. render: (rowData, index) => Container(
  187. padding: const EdgeInsets.symmetric(vertical: 12),
  188. child: Center(
  189. child: Text(
  190. rowData.physicalExamNumber ?? '',
  191. style: textStyle,
  192. ),
  193. ),
  194. ),
  195. ),
  196. TableColumn<ElectrocardiogramRecord>(
  197. headerText: "姓名",
  198. flex: 3,
  199. render: (rowData, index) => Center(
  200. child: Text(
  201. rowData.patientName ?? '',
  202. style: textStyle,
  203. ),
  204. ),
  205. ),
  206. TableColumn<ElectrocardiogramRecord>(
  207. headerText: "性别",
  208. flex: 3,
  209. render: (rowData, index) => Center(
  210. child: Text(
  211. patientGenderConvertAge(rowData.patientGender),
  212. style: textStyle,
  213. ),
  214. ),
  215. ),
  216. TableColumn<ElectrocardiogramRecord>(
  217. headerText: "年龄",
  218. flex: 3,
  219. render: (rowData, index) => Center(
  220. child: Text(
  221. birthDayConvertAge(rowData.birthday),
  222. style: textStyle,
  223. ),
  224. ),
  225. ),
  226. TableColumn<ElectrocardiogramRecord>(
  227. headerText: "所属医院",
  228. flex: 4,
  229. render: (rowData, index) => Center(
  230. child: Text(
  231. rowData.organizationCode ?? "",
  232. style: textStyle,
  233. ),
  234. ),
  235. ),
  236. TableColumn<ElectrocardiogramRecord>(
  237. headerText: "状态",
  238. flex: 3,
  239. render: (rowData, index) => Center(
  240. child: Text(
  241. birthStateConvert(rowData.examState),
  242. style: textStyle,
  243. ),
  244. ),
  245. ),
  246. TableColumn<ElectrocardiogramRecord>(
  247. headerText: "检查时间",
  248. flex: 6,
  249. render: (rowData, index) => Center(
  250. child: Center(
  251. child: Text(
  252. DateFormat("yyy-MM-dd HH:mm:ss").format(
  253. rowData.createTime?.toLocal() ?? DateTime.now(),
  254. ),
  255. style: textStyle,
  256. ),
  257. ),
  258. ),
  259. ),
  260. ];
  261. }
  262. String birthDayConvertAge(DateTime? birthday) {
  263. if (birthday == null) {
  264. return "";
  265. }
  266. // 获取当前日期
  267. DateTime now = DateTime.now();
  268. // 计算年龄
  269. int age = calculateAge(birthday, now);
  270. return age.toString();
  271. }
  272. int calculateAge(DateTime birthDate, DateTime now) {
  273. // 计算年份差
  274. int age = now.year - birthDate.year;
  275. // 检查生日是否已经过了当前年份
  276. if (now.month < birthDate.month ||
  277. (now.month == birthDate.month && now.day < birthDate.day)) {
  278. age--;
  279. }
  280. return age;
  281. }
  282. String patientGenderConvertAge(GenderEnum patientGender) {
  283. switch (patientGender) {
  284. case GenderEnum.Male:
  285. return "男";
  286. case GenderEnum.Female:
  287. return "女";
  288. default:
  289. return "";
  290. }
  291. }
  292. Widget _buildRecordInfoView() {
  293. if (controller.reports.isEmpty) {
  294. return const NoDataView();
  295. }
  296. return Expanded(
  297. child: ListView(
  298. children: controller.reports
  299. .map(
  300. (e) => ReportRecord(
  301. currReport: e,
  302. onEditReport: (v) {
  303. onEdit.call(v);
  304. },
  305. ),
  306. )
  307. .toList(),
  308. ),
  309. );
  310. }
  311. Widget _buildButtons() {
  312. return Row(
  313. mainAxisAlignment: MainAxisAlignment.center,
  314. children: [
  315. SizedBox(
  316. width: 120,
  317. child: ElevatedButton(
  318. onPressed: () {
  319. ElectrocardiogramRecord examRecord =
  320. controller.residentList[controller.currectSelected];
  321. onEdit.call(examRecord.code ?? '');
  322. },
  323. child: const Text("编辑"),
  324. ),
  325. ),
  326. const SizedBox(
  327. width: 15,
  328. ),
  329. SizedBox(
  330. width: 120,
  331. child: ElevatedButton(
  332. onPressed: () {
  333. ElectrocardiogramRecord examRecord =
  334. controller.residentList[controller.currectSelected];
  335. var physicalExamNumber = examRecord.physicalExamNumber ?? '';
  336. onExam.call(examRecord.code ?? '', physicalExamNumber);
  337. },
  338. child: const Text("检查"),
  339. ),
  340. ),
  341. ],
  342. );
  343. }
  344. String birthStateConvert(ExamStateEnum examState) {
  345. switch (examState) {
  346. case ExamStateEnum.Reported:
  347. return "已完成";
  348. default:
  349. return "待处理";
  350. }
  351. }
  352. Widget _tabRadio(
  353. {required String title, required RecordProcessStateEnum value}) {
  354. return InkWell(
  355. onTap: () {
  356. controller.changeTypeFilter(value);
  357. },
  358. child: FContainer(
  359. margin: const EdgeInsets.only(right: 15),
  360. child: FRow(
  361. children: [
  362. FRadio(
  363. value: value,
  364. groupValue: controller.typeFilter,
  365. onChanged: (v) {
  366. controller.changeTypeFilter(value);
  367. },
  368. ),
  369. FText(
  370. title,
  371. style: TextStyle(
  372. color: controller.typeFilter == value
  373. ? const Color(0xff2c77e5)
  374. : const Color(0xff4c4948),
  375. ),
  376. ),
  377. ],
  378. ),
  379. ),
  380. );
  381. }
  382. }