list.dart 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  1. import 'package:fis_common/event/event_type.dart';
  2. import 'package:fis_jsonrpc/rpc.dart';
  3. import 'package:flutter/foundation.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:get/get.dart';
  6. import 'package:vitalapp/architecture/utils/datetime.dart';
  7. import 'package:vitalapp/architecture/utils/prompt_box.dart';
  8. import 'package:vitalapp/components/appbar.dart';
  9. import 'package:vitalapp/components/button.dart';
  10. import 'package:vitalapp/components/table/table_column.dart';
  11. import 'package:vitalapp/managers/interfaces/registration.dart';
  12. import 'package:vitalapp/pages/check/examination/controller.dart';
  13. import 'package:vitalapp/pages/check/examination/view.dart';
  14. import 'package:vitalapp/pages/medical/controller.dart';
  15. import 'package:vitalapp/pages/medical/view.dart';
  16. import 'package:vitalapp/pages/medical_checkup_station/registration/controller.dart';
  17. import 'package:vitalapp/pages/medical_checkup_station/registration/state/list.dart';
  18. import 'package:vitalapp/pages/medical_checkup_station/registration/widgets/form/index.dart';
  19. import 'package:vitalapp/pages/medical_checkup_station/registration/widgets/report/report_preview.dart';
  20. import 'package:vitalapp/pages/medical_checkup_station/usb_print/module/printer_info.dart';
  21. import 'package:vitalapp/pages/medical_checkup_station/usb_print/page/temp/print_preview.dart';
  22. import 'package:vitalapp/store/store.dart';
  23. class RegistrationListController {
  24. late RegistrationController registrationController;
  25. RegistrationListController(RegistrationController controller) {
  26. registrationController = controller;
  27. }
  28. final state = ListState();
  29. final _registrationManager = Get.find<IRegistrationManager>();
  30. ResidentModel currentResident = ResidentModel(idNumber: "");
  31. List<String> _allExam = [
  32. "HEIBasic",
  33. "HEIUrinalysis",
  34. "HEIUltrasonic",
  35. "HEIBiochemical",
  36. "HEIBloodRoutine",
  37. "HEIECG",
  38. "HEITCMC"
  39. ];
  40. Map<String, dynamic> examData = {};
  41. List<String> examList() {
  42. List<String> missingData = _allExam
  43. .where((element) =>
  44. !(currentResident.finishedExamKeys ?? []).contains(element))
  45. .toList();
  46. return missingData;
  47. }
  48. /// 是否有健康检测的页面权限
  49. bool _hasHealthMonitor() {
  50. bool hasAuth = false;
  51. Store.user.menuPermissionList?.forEach((element) {
  52. if (element.code == "JKJC") {
  53. hasAuth = true;
  54. }
  55. });
  56. return hasAuth;
  57. }
  58. Future<void> getRegisterInfoPage({
  59. int? pageSize = 10,
  60. int? pageIndex = 1,
  61. String? keyword = "",
  62. DateTime? startTime,
  63. DateTime? endTime,
  64. }) async {
  65. registrationController.tableLoading = true;
  66. registrationController.currPageIndex = pageIndex!;
  67. var result = await registrationController.registrationManager
  68. .getRegisterInfoPageAsync(
  69. pageSize: pageSize,
  70. pageIndex: pageIndex,
  71. keyword: keyword,
  72. startTime: startTime,
  73. endTime: endTime,
  74. );
  75. List<ResidentModel> _residentList = [];
  76. if (result?.pageData != null) {
  77. for (RegisterInfoDTO i in result!.pageData!) {
  78. String statusStr = '';
  79. ExamStateEnum status = i.state;
  80. switch (status) {
  81. case ExamStateEnum.Unchecked:
  82. statusStr = "未体检";
  83. break;
  84. case ExamStateEnum.Invalid:
  85. statusStr = "已作废";
  86. break;
  87. case ExamStateEnum.Inspected:
  88. statusStr = "已体检";
  89. break;
  90. case ExamStateEnum.Reported:
  91. statusStr = "已报告";
  92. break;
  93. }
  94. _residentList.add(
  95. ResidentModel(
  96. name: i.name ?? '',
  97. idNumber: i.iDCardNo ?? '',
  98. code: i.code ?? '',
  99. homeAddress: i.adress,
  100. age: getAgeOfIdNumber(i.iDCardNo ?? ''),
  101. physicalExamNumber: i.physicalExamNumber,
  102. phone: i.phone,
  103. finishedExamKeys: i.finishedExamKeys,
  104. physicalExamStatus: statusStr,
  105. birthDay: i.birthday,
  106. sex: i.sex,
  107. batchNumber: i.batchNumber,
  108. ),
  109. );
  110. }
  111. registrationController.appointmentModelListLength = result.totalCount;
  112. }
  113. registrationController.residentList = _residentList;
  114. registrationController.tableLoading = false;
  115. registrationController.update(["registration_table"]);
  116. registrationController.update(["registration_table_pagination"]);
  117. }
  118. String getAgeOfIdNumber(String idNumber) {
  119. if (idNumber.isEmpty) return '';
  120. final idCardRegex = RegExp(r'^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})(\d|X)$');
  121. final match = idCardRegex.firstMatch(idNumber);
  122. if (match != null) {
  123. final year = int.parse(match.group(2)!);
  124. final month = int.parse(match.group(3)!);
  125. final day = int.parse(match.group(4)!);
  126. final birthDate = DateTime(year, month, day);
  127. String age = DataTimeUtils.calculateAge(birthDate);
  128. return age;
  129. }
  130. return ''; // 返回一个默认值
  131. }
  132. /// 登记列表表头
  133. List<TableColumn<ResidentModel>> buildTableColumns(BuildContext context) {
  134. var textStyle = TextStyle(
  135. fontSize: 18,
  136. overflow: TextOverflow.ellipsis,
  137. );
  138. return <TableColumn<ResidentModel>>[
  139. TableColumn<ResidentModel>(
  140. headerText: "体检号",
  141. maxWidth: 150,
  142. render: (rowData, index) => Container(
  143. padding: const EdgeInsets.symmetric(vertical: 16),
  144. child: Text(
  145. rowData.physicalExamNumber ?? '',
  146. style: textStyle,
  147. ),
  148. ),
  149. ),
  150. TableColumn<ResidentModel>(
  151. headerText: "姓名",
  152. maxWidth: 100,
  153. render: (rowData, index) => Text(
  154. rowData.name ?? '',
  155. style: textStyle,
  156. ),
  157. ),
  158. TableColumn<ResidentModel>(
  159. headerText: "年龄",
  160. maxWidth: 80,
  161. render: (rowData, index) => Text(
  162. rowData.age != null ? rowData.age.toString() : "",
  163. style: textStyle,
  164. ),
  165. ),
  166. TableColumn<ResidentModel>(
  167. headerText: "身份证号",
  168. // maxWidth: 200,
  169. render: (rowData, index) => Center(
  170. child: Text(
  171. rowData.idNumber,
  172. style: textStyle,
  173. ),
  174. ),
  175. ),
  176. TableColumn<ResidentModel>(
  177. headerText: "手机号",
  178. maxWidth: 120,
  179. render: (rowData, index) => Center(
  180. child: Text(
  181. rowData.phone ?? '',
  182. style: textStyle,
  183. ),
  184. ),
  185. ),
  186. TableColumn<ResidentModel>(
  187. headerText: "体检状态",
  188. maxWidth: 120,
  189. render: (rowData, index) => Center(
  190. child: Text(
  191. rowData.physicalExamStatus ?? "",
  192. style: textStyle,
  193. ),
  194. ),
  195. ),
  196. TableColumn<ResidentModel>(
  197. headerText: "操作",
  198. maxWidth: 360,
  199. width: 200,
  200. render: (rowData, index) => FittedBox(
  201. child: Row(
  202. mainAxisAlignment: MainAxisAlignment.center,
  203. children: [
  204. _buildPrint(context, rowData),
  205. _buildEditRegistration(rowData),
  206. if (kIsWeb) _buildEditingExcepting(rowData),
  207. if (kIsWeb) _buildShowReport(rowData),
  208. _buildHealthCheck(rowData),
  209. ],
  210. ),
  211. ),
  212. ),
  213. ];
  214. }
  215. /// 打印按钮
  216. Widget _buildPrint(BuildContext context, ResidentModel rowData) {
  217. return TextButton(
  218. onPressed: () async {
  219. // if (registrationController.printInfo == null) {
  220. // PromptBox.toast("打印出错");
  221. // return;
  222. // }
  223. // if (kIsWeb) {
  224. await registrationController.getExamLabelsByExamNoAsync(rowData);
  225. // } else {
  226. Get.dialog(
  227. Center(
  228. child: Container(
  229. width: MediaQuery.of(context).size.width * 0.7,
  230. height: MediaQuery.of(context).size.height,
  231. child: Center(
  232. child: PrintPreview(
  233. imageList: registrationController.barCodeList,
  234. printInfo: registrationController.printInfo ?? PrinterInfo(),
  235. ),
  236. ),
  237. ),
  238. ),
  239. );
  240. // }
  241. },
  242. child: const Text(
  243. "打印标签",
  244. style: TextStyle(fontSize: 18),
  245. ),
  246. );
  247. }
  248. /// 编辑按钮
  249. Widget _buildEditRegistration(ResidentModel rowData) {
  250. return TextButton(
  251. onPressed: () async {
  252. final PatientDTO? patient = PatientDTO(
  253. patientName: rowData.name,
  254. phone: rowData.phone,
  255. patientAddress: rowData.homeAddress,
  256. cardNo: rowData.idNumber,
  257. code: rowData.code,
  258. birthday: rowData.birthDay,
  259. patientGender: rowData.sex == "男"
  260. ? GenderEnum.Male
  261. : rowData.sex == "女"
  262. ? GenderEnum.Female
  263. : GenderEnum.Unknown,
  264. );
  265. final PatientDTO? result = await Get.dialog<PatientDTO>(
  266. RegistrationFormDialog(
  267. patient: patient,
  268. isEdit: true,
  269. ),
  270. barrierDismissible: false,
  271. );
  272. registrationController.formController.editResident(result);
  273. print(result);
  274. },
  275. child: const Text(
  276. "编辑",
  277. style: TextStyle(fontSize: 18),
  278. ),
  279. );
  280. }
  281. /// 健康指导
  282. Widget _buildEditingExcepting(ResidentModel rowData) {
  283. return TextButton(
  284. onPressed: () {
  285. Get.dialog(
  286. Dialog(
  287. backgroundColor: Colors.white, // 设置对话框背景颜色为白色
  288. child: Container(
  289. padding: EdgeInsets.all(16.0),
  290. child: Stack(
  291. children: [
  292. Column(
  293. children: [
  294. SizedBox(
  295. height: 20,
  296. ),
  297. Expanded(
  298. child: TextField(
  299. expands: true,
  300. maxLines: null,
  301. decoration: InputDecoration(
  302. hintText: '请输入健康指导信息...',
  303. border: InputBorder.none,
  304. ),
  305. onChanged: (value) {
  306. state.resultsAndSuggestions = value;
  307. },
  308. ),
  309. ),
  310. ElevatedButton(
  311. onPressed: () async {
  312. await _registrationManager
  313. .updateResultsAndSuggestionsAsync(
  314. rowData.code ?? "",
  315. state.resultsAndSuggestions ?? '');
  316. Get.back(); // Close the dialog
  317. },
  318. child: Text(
  319. '提交',
  320. style: TextStyle(fontSize: 18),
  321. ),
  322. ),
  323. ],
  324. ),
  325. Positioned(
  326. top: 1.0,
  327. right: 1.0,
  328. child: IconButton(
  329. icon: Icon(Icons.close),
  330. onPressed: () {
  331. Get.back();
  332. },
  333. ),
  334. ),
  335. ],
  336. ),
  337. ),
  338. ),
  339. barrierDismissible:
  340. false, // Prevent dialog from closing on outside tap
  341. );
  342. },
  343. child: const Text(
  344. "健康指导",
  345. style: TextStyle(fontSize: 18),
  346. ));
  347. }
  348. /// 查看报告
  349. Widget _buildShowReport(ResidentModel rowData) {
  350. return TextButton(
  351. onPressed: () async {
  352. List<ReportDTO2>? reportList = await registrationController
  353. .registrationManager
  354. .getVitalReportInfoAsync(
  355. physicalExamNumber: rowData.physicalExamNumber ?? '',
  356. );
  357. ReportDTO2? report =
  358. reportList?.firstWhereOrNull((element) => element.key == "Part");
  359. if (report != null) {
  360. Get.dialog(
  361. ReportPreview(
  362. pdfUrl: report.previewInfo?.fileToken ?? "",
  363. ),
  364. );
  365. } else {
  366. PromptBox.toast("暂无报告");
  367. }
  368. },
  369. child: const Text(
  370. "查看报告",
  371. style: TextStyle(fontSize: 18),
  372. ),
  373. );
  374. }
  375. void _setCurrentSelectPatientInfo(ResidentModel rowData) {
  376. Store.user.currentSelectPatientInfo = PatientDTO(
  377. cardNo: rowData.idNumber,
  378. patientName: rowData.name,
  379. code: rowData.idNumber,
  380. patientAddress: rowData.homeAddress,
  381. );
  382. }
  383. void _examDialog(ResidentModel rowData) {
  384. final FEventHandler<bool> onSubmitEvent = FEventHandler<bool>();
  385. Get.dialog(
  386. Scaffold(
  387. body: Stack(
  388. children: [
  389. ExaminationPage(
  390. idCard: rowData.idNumber,
  391. onSubmitEvent: onSubmitEvent,
  392. ),
  393. Positioned(
  394. left: 16,
  395. bottom: 16,
  396. child: _buildMedicalButton(),
  397. )
  398. ],
  399. ),
  400. appBar: VAppBar(
  401. titleText: "体检",
  402. actions: [
  403. _buildSaveButton(onSubmitEvent),
  404. ],
  405. iconBack: () {
  406. onSubmitEvent.emit(this, true);
  407. },
  408. ),
  409. ),
  410. );
  411. }
  412. Widget _buildSaveButton(FEventHandler<bool> onSubmitEvent) {
  413. return Container(
  414. margin: EdgeInsets.only(right: 10),
  415. child: ElevatedButton(
  416. onPressed: () async {
  417. onSubmitEvent.emit(this, true);
  418. },
  419. child: Text('保存'),
  420. ),
  421. );
  422. }
  423. Widget _buildMedicalButton() {
  424. if (_hasHealthMonitor()) {
  425. return Container(
  426. width: 214,
  427. margin: EdgeInsets.only(right: 10),
  428. child: VButton(
  429. onTap: () {
  430. Get.dialog<MedicalController>(
  431. Scaffold(
  432. body: MedicalPage(
  433. isHealthCheck: true,
  434. ),
  435. appBar: VAppBar(
  436. titleText: "检测",
  437. ),
  438. ),
  439. );
  440. },
  441. child: Text(
  442. '检测',
  443. style: TextStyle(fontSize: 26),
  444. ),
  445. ),
  446. );
  447. }
  448. return SizedBox();
  449. }
  450. /// 体检
  451. Widget _buildHealthCheck(ResidentModel rowData) {
  452. return TextButton(
  453. onPressed: () {
  454. Get.lazyPut(
  455. () => ExaminationController(
  456. patientCode: rowData.idNumber,
  457. batchNumber: rowData.batchNumber ?? '',
  458. ),
  459. );
  460. _setCurrentSelectPatientInfo(rowData);
  461. _examDialog(rowData);
  462. },
  463. child: const Text(
  464. "体检",
  465. style: TextStyle(fontSize: 18),
  466. ),
  467. );
  468. }
  469. }