controller.dart 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. import 'package:fis_common/index.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/defines.dart';
  7. import 'package:vitalapp/architecture/network_connectivity.dart';
  8. import 'package:vitalapp/architecture/utils/prompt_box.dart';
  9. import 'package:vitalapp/components/alert_dialog.dart';
  10. import 'package:vitalapp/global.dart';
  11. import 'package:vitalapp/managers/interfaces/device.dart';
  12. import 'package:vitalapp/managers/interfaces/label.dart';
  13. import 'package:vitalapp/managers/interfaces/models/device.dart';
  14. import 'package:vitalapp/managers/interfaces/models/patient_model_dto.dart';
  15. import 'package:vitalapp/managers/interfaces/patient.dart';
  16. import 'package:vitalapp/managers/interfaces/permission.dart';
  17. import 'package:vitalapp/pages/controllers/blue_location_mixin.dart';
  18. import 'package:vitalapp/pages/controllers/crowd_labels.dart';
  19. import 'package:vitalapp/pages/facial_recognition/index.dart';
  20. import 'package:vitalapp/pages/home/controller.dart';
  21. import 'package:fis_common/logger/logger.dart';
  22. import 'package:vitalapp/pages/id_card_scan/index.dart';
  23. import 'package:vitalapp/pages/patient/bluetooth_card_reader/index.dart';
  24. import 'package:vitalapp/pages/patient/card_reader/index.dart';
  25. import 'package:vitalapp/pages/patient/create/widgets/face_result_dialog.dart';
  26. import 'package:vitalapp/store/store.dart';
  27. import 'package:vnote_device_plugin/consts/types.dart';
  28. import 'state.dart';
  29. class PatientListController extends FControllerBase
  30. with BluetoothAndLocationMixin {
  31. final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
  32. final state = PatientListState();
  33. final _homeController = Get.find<HomeController>();
  34. final _patientManager = Get.find<IPatientManager>();
  35. final _deviceManager = Get.find<IDeviceManager>();
  36. final crowdLabelsController = CrowdLabelsController();
  37. // enum ContractStateEnum {
  38. // Unsigned,
  39. // Cancelled,
  40. // Expired,
  41. // Signed,
  42. // Voided,
  43. // Refused,
  44. // }
  45. final Map<String, String> ContractStateMap = {
  46. "All": "未选择",
  47. "Unsigned": "未签约",
  48. "Cancelled": "已取消",
  49. "Expired": "已过期",
  50. "Signed": "已签约",
  51. "Voided": "已失效",
  52. "Refused": "已拒绝",
  53. };
  54. void patientListGotoDetail(PatientDTO dto) async {
  55. await _patientManager.switchCurrentPatient(dto);
  56. _homeController.switchNavByName("/patient/detail");
  57. logger.i('list切换居民 当前居民是:${dto.patientName} 居民code:${dto.code}');
  58. }
  59. Future<DeviceModel?> getDevice(String type) async {
  60. List<DeviceModel> devices = await _deviceManager.getDeviceList();
  61. return devices.firstWhereOrNull((element) => element.type == type);
  62. }
  63. // TODO 人脸录入 点击人脸识别
  64. void onFaceIdLoginClicked() async {
  65. var verifyResult = await _verifyCameraPermissions();
  66. if (!verifyResult) {
  67. return;
  68. }
  69. final FaceRecognitionResult? result = await Get.to<FaceRecognitionResult>(
  70. () => const FacialRecognitionPage(
  71. mode: FacialRecognitionMode.faceRecognition,
  72. ),
  73. );
  74. if (result != null && result.success) {
  75. final patient = result.patientInfo;
  76. final hasConfirmed = await FaceResultDialog.show(patient, true);
  77. if (hasConfirmed &&
  78. patient.createdOrgCode == Store.user.organizationCode) {
  79. await _checkinPatient(patient);
  80. }
  81. } else {
  82. print("识别取消");
  83. }
  84. }
  85. /// 切换当前登记居民
  86. Future<void> _checkinPatient(PatientBaseDTO patient) async {
  87. final patientDTO = PatientDTO(
  88. code: patient.cardNo,
  89. cardNo: patient.cardNo,
  90. patientName: patient.patientName,
  91. nationality: patient.nationality,
  92. patientGender: patient.patientGender,
  93. birthday: patient.birthday,
  94. patientAddress: patient.patientAddress,
  95. );
  96. await onIdcardInfoIsCreateRecord(patientDTO.code!);
  97. Get.find<HomeController>().switchNavByName("/patient/detail");
  98. }
  99. /// (读卡器读卡)若已建档则跳档案详情页面,若未建档则跳创建档案页面
  100. void onReadCardClickedToDetail() async {
  101. final DeviceModel? device = await getDevice(DeviceTypes.IC_READER);
  102. CardReaderResult? result;
  103. if (device != null) {
  104. final envPassed = await checkDeviceConnectEnv();
  105. if (envPassed) {
  106. result = await Get.dialog<CardReaderResult>(
  107. const BluetoothCardReaderDialog(),
  108. barrierDismissible: false,
  109. );
  110. }
  111. } else {
  112. result = await Get.dialog<CardReaderResult>(
  113. const CardReaderDialog(),
  114. barrierDismissible: false,
  115. );
  116. }
  117. if (result != null && result.success) {
  118. PromptBox.toast("读取成功");
  119. PatientBaseDTO patientInfo = PatientBaseDTO();
  120. patientInfo.cardNo = result.cardNo; // 回填身份证号
  121. patientInfo.patientName = result.name; // 回填姓名
  122. patientInfo.patientGender = result.gender; // 回填性别
  123. patientInfo.nationality = result.nation; // 回填民族
  124. patientInfo.birthday = result.birthday; // 回填出生日期
  125. patientInfo.patientAddress = result.address; // 回填户籍地址
  126. onIdcardInfoIsCreateRecord(patientInfo.cardNo!, patientInfo);
  127. } else {
  128. print("读卡取消");
  129. }
  130. }
  131. /// 手动录入 跳转新建档案页面
  132. void onManualInputPatient() {
  133. Get.find<HomeController>().switchNavByName(
  134. "/patient/create",
  135. );
  136. }
  137. /// 扫码和刷卡公用的方法,获取到的身份证信息
  138. Future<void> onIdcardInfoIsCreateRecord(
  139. String cardNo, [
  140. PatientBaseDTO? patientInfo,
  141. ]) async {
  142. PatientDTO? patientInfoDto = await _patientManager.getDetail(cardNo);
  143. if (patientInfoDto != null) {
  144. await _patientManager.switchCurrentPatient(patientInfoDto);
  145. logger.i(
  146. 'create居民 当前居民是:${patientInfoDto.patientName} 居民code:${patientInfoDto.code}');
  147. }
  148. switchOrCreatePatient(patientInfoDto, patientInfo);
  149. }
  150. /// (拍摄扫描身份证)若已建档则跳档案详情页面,若未建档则跳创建档案页面
  151. void onIdCardScanClickedToDetail() async {
  152. var verifyResult = await _verifyCameraPermissions();
  153. if (!verifyResult) {
  154. return;
  155. }
  156. final IdCardScanResult? result = await Get.to<IdCardScanResult>(
  157. () => const IdCardScanPage(),
  158. );
  159. if (result != null && result.success) {
  160. PromptBox.toast("身份证信息识别成功");
  161. PatientBaseDTO patientInfo = result.patientBaseDTO;
  162. onIdcardInfoIsCreateRecord(patientInfo.cardNo!, patientInfo);
  163. } else {
  164. print("识别取消");
  165. }
  166. }
  167. /// 切换居民还是新建居民
  168. Future<void> switchOrCreatePatient(
  169. PatientDTO? patientInfoDto, [
  170. PatientBaseDTO? patientInfo,
  171. ]) async {
  172. if (patientInfo != null) {
  173. if (patientInfo.createdDoctorName.isNullOrEmpty) {
  174. patientInfo.createdDoctorName = patientInfoDto?.createdDoctorName;
  175. }
  176. if (patientInfo.createdOrgName.isNullOrEmpty) {
  177. patientInfo.createdOrgName = patientInfoDto?.createdOrgName;
  178. }
  179. if (patientInfoDto != null) {
  180. final hasConfirmed = await FaceResultDialog.show(patientInfo, true);
  181. if (!hasConfirmed) {
  182. return;
  183. }
  184. Get.find<HomeController>().switchNavByName("/patient/detail");
  185. } else {
  186. final hasConfirmed = await FaceResultDialog.show(patientInfo, false);
  187. if (!hasConfirmed) {
  188. return;
  189. }
  190. Get.find<HomeController>().switchNavByName(
  191. "/patient/create",
  192. patientInfo.toJson(),
  193. );
  194. }
  195. }
  196. }
  197. void changeFilterFounder(int value) {
  198. state.selectBoxFilterFounder = value;
  199. }
  200. Future<bool> _verifyCameraPermissions() async {
  201. IPermissionManager permissionManager = Get.find<IPermissionManager>();
  202. var isCameraPermissions =
  203. await permissionManager.requestCameraPermissions();
  204. if (!isCameraPermissions) {
  205. await Get.dialog(
  206. VAlertDialog(
  207. title: "提示",
  208. width: 420,
  209. content: Container(
  210. height: 32,
  211. padding: const EdgeInsets.symmetric(horizontal: 24),
  212. alignment: Alignment.center,
  213. child: const Text(
  214. "未授予相机权限,前去设置",
  215. style: TextStyle(fontSize: 20),
  216. ),
  217. ),
  218. showCancel: false,
  219. onConfirm: () async {
  220. Get.back();
  221. await permissionManager.openAppSettingsAsync();
  222. },
  223. ),
  224. barrierDismissible: false,
  225. barrierColor: Colors.black.withOpacity(.4),
  226. );
  227. }
  228. return isCameraPermissions;
  229. }
  230. @override
  231. void onReady() {
  232. netChecker.onlineChangedEvent.addListener(_onlineChanged);
  233. if (Store.user.roleName == "机构负责人") {
  234. state.selectBoxFilterFounder = 1;
  235. }
  236. reloadList();
  237. super.onReady();
  238. }
  239. void _onlineChanged(_, e) {
  240. state.isOnline = e;
  241. }
  242. /// 重新加载列表
  243. Future<void> reloadList({bool isFilter = false}) async {
  244. busy = true;
  245. state.pageIndex = 0;
  246. state.dataList = [];
  247. state.offlineCodes = [];
  248. if (kIsOnline) {
  249. if (!kIsWeb) {
  250. var offlineList = await _patientManager.getPagedOfflineList(
  251. state.searchString,
  252. state.startTime.value,
  253. state.endTime.value?.add(const Duration(days: 1)),
  254. );
  255. if (offlineList != null) {
  256. state.appendDataList(offlineList);
  257. state.offlineCodes = offlineList.map((e) => e.code!).toList();
  258. }
  259. }
  260. }
  261. await loadNextPageList(isFilter: isFilter);
  262. if (kIsOnline) {
  263. _loadStatistic();
  264. }
  265. }
  266. /// 加载下一页列表
  267. Future<void> loadNextPageList({bool isFilter = false}) async {
  268. busy = true;
  269. List<LabelDTO> allLabels = [];
  270. if (kIsOnline) {
  271. allLabels = await Get.find<ILabelManager>().getAllLabels();
  272. }
  273. var labelKeys = allLabels.map((e) => e.code ?? '').toList();
  274. final request = PatientPageRequest(
  275. pageIndex: state.pageIndex + 1,
  276. pageSize: state.pageSize,
  277. keyword: state.searchString,
  278. startTime: state.startTime.value,
  279. endTime: state.endTime.value?.add(const Duration(days: 1)),
  280. crowdLabels: crowdLabelsController.state.isAllSelect
  281. ? ["RQFL_ET", "RQFL_LNR", ...labelKeys]
  282. : crowdLabelsController.state.selectedFilterCodes.length == 0
  283. ? null
  284. : crowdLabelsController.state.selectedFilterCodes,
  285. createdBySelf: state.selectBoxFilterFounder == 0,
  286. contractState: state.contractStateSelectedItem,
  287. );
  288. final pagedList = await _patientManager.getPagedList(request);
  289. if (pagedList != null) {
  290. state.totalCount = pagedList.dataCount;
  291. if (pagedList.pageData != null) {
  292. state.pageIndex = state.pageIndex + 1;
  293. final arr = <PatientModelDTO>[];
  294. for (var element in pagedList.pageData!) {
  295. if (!state.offlineCodes.contains(element.code)) {
  296. var existData =
  297. state.dataList.firstWhereOrNull((e) => e.code == element.code);
  298. if (existData == null) {
  299. arr.add(element);
  300. }
  301. }
  302. }
  303. state.appendDataList(arr);
  304. }
  305. }
  306. busy = false;
  307. }
  308. Future<void> removePatient(String code) async {
  309. setBusy("正在删除...");
  310. final result = await _patientManager.removePatient(code);
  311. cancelBusy();
  312. if (result) {
  313. PromptBox.toast("删除成功");
  314. await Future.delayed(const Duration(milliseconds: 500));
  315. await reloadList();
  316. } else {
  317. PromptBox.toast("删除失败");
  318. }
  319. }
  320. Future<void> _loadStatistic() async {
  321. final result = await _patientManager.getStatistic(
  322. state.selectBoxFilterFounder == 0,
  323. );
  324. state.statisticTodayCount = result.todayCount;
  325. state.statisticTotalCount = result.count;
  326. }
  327. @override
  328. void onClose() {
  329. netChecker.onlineChangedEvent.removeListener(_onlineChanged);
  330. }
  331. }