controller.dart 11 KB

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