controller.dart 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. import 'package:fis_jsonrpc/rpc.dart';
  2. import 'package:get/get.dart';
  3. import 'package:vitalapp/architecture/defines.dart';
  4. import 'package:vitalapp/architecture/utils/prompt_box.dart';
  5. import 'package:vitalapp/managers/interfaces/device.dart';
  6. import 'package:vitalapp/managers/interfaces/models/device.dart';
  7. import 'package:vitalapp/managers/interfaces/patient.dart';
  8. import 'package:vitalapp/pages/controllers/crowd_labels.dart';
  9. import 'package:vitalapp/pages/controllers/home_nav_mixin.dart';
  10. import 'package:vitalapp/pages/facial_recognition/view.dart';
  11. import 'package:vitalapp/pages/patient/bluetooth_card_reader/view.dart';
  12. import 'package:vitalapp/pages/patient/card_reader/index.dart';
  13. import 'package:vitalapp/pages/patient/create/state.dart';
  14. import 'package:vitalapp/pages/patient/list/controller.dart';
  15. import 'package:vitalapp/routes/nav_ids.dart';
  16. import 'package:vnote_device_plugin/consts/types.dart';
  17. import '../../facial_recognition/index.dart';
  18. class CreatePatientController extends FControllerBase with HomeNavMixin {
  19. final _patientManager = Get.find<IPatientManager>();
  20. final crowdLabelsController = Get.find<CrowdLabelsController>();
  21. final _patientListController = Get.find<PatientListController>();
  22. final _deviceManager = Get.find<IDeviceManager>();
  23. final state = CreatePatientState();
  24. @override
  25. Future<void> onLoad() {
  26. final params = Get.parameters;
  27. if (params.containsKey("from")) {
  28. if (params["from"] == "list") {
  29. state.isCreateOnly = true;
  30. }
  31. }
  32. return super.onLoad();
  33. }
  34. /// 保存档案,调整签约
  35. void gotoSignContract() async {
  36. setBusy("正在保存...");
  37. String? code;
  38. try {
  39. code = await _submitForm();
  40. if (code == null) {
  41. busy = false;
  42. PromptBox.toast("保存失败");
  43. return;
  44. }
  45. // final code = "13B95A2B2790464BBFD9B30A71F15C95";
  46. busy = false;
  47. Future.delayed(
  48. const Duration(milliseconds: 800),
  49. () {
  50. state.reset(); // 重置状态
  51. },
  52. );
  53. } finally {
  54. if (code != null) {
  55. Get.toNamed(
  56. "/contract/package_list",
  57. parameters: {"patientCode": code},
  58. );
  59. }
  60. }
  61. // Get.find<HomeController>().switchNavByName("/patient/list");
  62. // Future.delayed(
  63. // const Duration(milliseconds: 800),
  64. // () {
  65. // // TODO:
  66. // Get.find<PatientListController>().gotoDetail(code);
  67. // busy = false;
  68. // },
  69. // );
  70. }
  71. /// 存为档案,调整到档案详情
  72. void gotoPatientDetail() async {
  73. setBusy("正在保存...");
  74. final code = await _submitForm();
  75. if (code == null) {
  76. busy = false;
  77. PromptBox.toast("保存失败");
  78. return;
  79. } else {
  80. Future.delayed(
  81. const Duration(milliseconds: 800),
  82. () {
  83. state.reset(); // 重置状态
  84. busy = false;
  85. PromptBox.toast("保存成功");
  86. _patientListController.reloadList();
  87. },
  88. );
  89. }
  90. ///不跳转到详情页
  91. // Get.find<HomeController>().switchNavByName("/patient/list");
  92. // Get.put(PatientListController());
  93. Future.delayed(
  94. const Duration(milliseconds: 800),
  95. () {
  96. Get.find<PatientListController>().gotoDetail(code);
  97. busy = false;
  98. },
  99. );
  100. }
  101. /// 保存并返回
  102. void saveAndBack() async {
  103. setBusy("正在保存...");
  104. final code = await _submitForm();
  105. busy = false;
  106. if (code == null) {
  107. busy = false;
  108. return;
  109. }
  110. Get.back(result: code, id: NavIds.HOME);
  111. }
  112. Future<DeviceModel?> getDevice(String type) async {
  113. List<DeviceModel> devices = await _deviceManager.getDeviceList();
  114. return devices.firstWhereOrNull((element) => element.type == type);
  115. }
  116. /// 点击读卡事件
  117. void onReadCardClicked() async {
  118. final DeviceModel? device = await getDevice(DeviceTypes.IC_READER);
  119. final CardReaderResult? result;
  120. if (device != null) {
  121. // return;
  122. result = await Get.dialog<CardReaderResult>(
  123. const BluetoothCardReaderDialog(),
  124. );
  125. } else {
  126. result = await Get.dialog<CardReaderResult>(
  127. const CardReaderDialog(),
  128. );
  129. }
  130. if (result != null && result.success) {
  131. PromptBox.toast("读取成功");
  132. state.cardNo = result.cardNo; // 回填身份证号
  133. state.name = result.name; // 回填姓名
  134. state.gender = result.gender; // 回填性别
  135. state.nation = result.nation; // 回填民族
  136. state.birthday = result.birthday; // 回填出生日期
  137. state.censusRegister = result.address; // 回填户籍地址
  138. if (state.isSyncAddresses) {
  139. state.address = result.address; // 回填现住地址
  140. }
  141. } else {
  142. print("读卡取消");
  143. }
  144. }
  145. /// 点击身份识别建档
  146. void onFaceRecognitionClicked() async {
  147. final FaceRecognitionResult? result = await Get.to<FaceRecognitionResult>(
  148. () => const FacialRecognitionPage(),
  149. );
  150. if (result != null && result.success) {
  151. PromptBox.toast("录入成功");
  152. state.cardNo = result.cardNo; // 回填身份证号
  153. state.name = result.name; // 回填姓名
  154. state.gender = result.gender; // 回填性别
  155. state.nation = result.nation; // 回填民族
  156. state.birthday = result.birthday; // 回填出生日期
  157. state.censusRegister = result.address; // 回填户籍地址
  158. if (state.isSyncAddresses) {
  159. state.address = result.address; // 回填现住地址
  160. }
  161. } else {
  162. print("识别取消");
  163. }
  164. }
  165. /// 处理 “同户籍地址” 勾选变更事件
  166. void onSyncAddressCheckChanged(bool isChecked) {
  167. state.isSyncAddresses = isChecked;
  168. if (isChecked) {
  169. // 同步户籍地址到现住地址
  170. state.address = state.censusRegister;
  171. } else {
  172. state.address = "";
  173. }
  174. }
  175. /// 处理户籍地址变更
  176. void onCensusRegisterChanged(String value) {
  177. state.censusRegister = value;
  178. if (state.isSyncAddresses) {
  179. state.address = value;
  180. }
  181. }
  182. Future<String?> _submitForm() async {
  183. final validateMsg = await _validateForm();
  184. if (validateMsg != null) {
  185. toast(validateMsg);
  186. return null;
  187. }
  188. final crowdLabelCodes = crowdLabelsController.state.selectedCodes;
  189. final request = CreatePatientRequest(
  190. patientName: state.name,
  191. phone: state.phoneNo,
  192. patientGender: state.gender,
  193. nationality: state.nation,
  194. birthday: state.birthday?.toUtc(),
  195. cardType: state.cardType,
  196. cardNo: state.cardNo,
  197. patientAddress: state.address,
  198. permanentResidenceAddress: state.censusRegister,
  199. crowdLabels: crowdLabelCodes,
  200. );
  201. final result = await _patientManager.create(request);
  202. return result;
  203. }
  204. bool validateIDCard(String idCard) {
  205. // 校验身份证号码长度
  206. if (idCard.length != 18) {
  207. return false;
  208. }
  209. // 校验前17位是否为数字
  210. String idCard17 = idCard.substring(0, 17);
  211. if (!isNumeric(idCard17)) {
  212. return false;
  213. }
  214. // 校验最后一位校验码
  215. String checkCode = getCheckCode(idCard17);
  216. if (idCard[17].toUpperCase() != checkCode) {
  217. return false;
  218. }
  219. return true;
  220. }
  221. bool isNumeric(String str) {
  222. if (str.isEmpty) {
  223. return false;
  224. }
  225. return double.tryParse(str) != null;
  226. }
  227. bool isAlphaNumeric(String str) {
  228. final RegExp alphaNumericRegExp = RegExp(r'^[a-zA-Z0-9]+$');
  229. return alphaNumericRegExp.hasMatch(str);
  230. }
  231. bool isAlphaNumericChineseWithSpace(String str) {
  232. final RegExp alphaNumericChineseWithSpaceRegExp =
  233. RegExp(r'^[a-zA-Z0-9\u4e00-\u9fa5\s]+$');
  234. return alphaNumericChineseWithSpaceRegExp.hasMatch(str);
  235. }
  236. String getCheckCode(String idCard17) {
  237. List<int> coefficients = [
  238. 7,
  239. 9,
  240. 10,
  241. 5,
  242. 8,
  243. 4,
  244. 2,
  245. 1,
  246. 6,
  247. 3,
  248. 7,
  249. 9,
  250. 10,
  251. 5,
  252. 8,
  253. 4,
  254. 2
  255. ];
  256. List<String> checkCodes = [
  257. '1',
  258. '0',
  259. 'X',
  260. '9',
  261. '8',
  262. '7',
  263. '6',
  264. '5',
  265. '4',
  266. '3',
  267. '2'
  268. ];
  269. int sum = 0;
  270. for (int i = 0; i < idCard17.length; i++) {
  271. int digit = int.parse(idCard17[i]);
  272. sum += digit * coefficients[i];
  273. }
  274. int remainder = sum % 11;
  275. return checkCodes[remainder];
  276. }
  277. Future<String?> _validateForm() async {
  278. if (state.name.isEmpty) {
  279. return "请填写姓名";
  280. }
  281. // else {
  282. // if (!isAlphaNumericChineseWithSpace(state.name) ||
  283. // state.name.length >= 20) {
  284. // return "姓名只能由中文、字母或数字组成,并且小于20个字符";
  285. // }
  286. // }
  287. if (state.cardNo.isEmpty) {
  288. return "请填写证件号";
  289. }
  290. if (state.phoneNo.isNotEmpty) {
  291. if (state.phoneNo.length != 11 || !isNumeric(state.phoneNo)) {
  292. return "请填写正确的手机号";
  293. }
  294. }
  295. if (state.cardType == CardTypeEnum.Identity) {
  296. bool isNotIDCard = validateIDCard(state.cardNo);
  297. if (!isNotIDCard) {
  298. return "请填写正确的证件号";
  299. }
  300. }
  301. if (state.cardType == CardTypeEnum.SocialInsurance) {
  302. if (state.cardNo.length != 18 || !isNumeric(state.cardNo)) {
  303. return "请填写正确的社保号";
  304. }
  305. }
  306. if (state.cardType == CardTypeEnum.Passport) {
  307. if (state.cardNo.length != 9 || !isAlphaNumeric(state.cardNo)) {
  308. return "请填写正确的护照号";
  309. }
  310. }
  311. /// TODO 需求变更暂时删除
  312. // final selectedNormalCodes = crowdLabelsController.state.selectedNormalCodes;
  313. // if (selectedNormalCodes.length > 1) {
  314. // return "人群分类:一般人群、儿童、孕妇、老年人,只可选择其一!";
  315. // }
  316. // final crowdLabelCodes = crowdLabelsController.state.selectedCodes;
  317. // if (crowdLabelCodes.isEmpty) {
  318. // return "请选择人群分类";
  319. // }
  320. // if (state.gender == GenderEnum.Male &&
  321. // crowdLabelCodes.contains('RQFL_YF')) {
  322. // return "当前居民性别为“男”,人群分类不可选择孕妇!";
  323. // }
  324. return null;
  325. }
  326. }