controller.dart 11 KB

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