controller.dart 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. import 'dart:convert';
  2. import 'package:fis_jsonrpc/rpc.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/utils/prompt_box.dart';
  7. import 'package:vitalapp/architecture/values/features.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/patient.dart';
  13. import 'package:vitalapp/managers/interfaces/permission.dart';
  14. import 'package:vitalapp/pages/controllers/crowd_labels.dart';
  15. import 'package:vitalapp/pages/controllers/home_nav_mixin.dart';
  16. import 'package:vitalapp/pages/patient/bluetooth_card_reader/view.dart';
  17. import 'package:vitalapp/pages/patient/card_reader/index.dart';
  18. import 'package:vitalapp/pages/patient/create/state.dart';
  19. import 'package:vitalapp/pages/patient/create/widgets/face_result_dialog.dart';
  20. import 'package:vitalapp/pages/patient/list/controller.dart';
  21. import 'package:vitalapp/routes/routes.dart';
  22. import 'package:vitalapp/store/store.dart';
  23. import 'package:vnote_device_plugin/consts/types.dart';
  24. import 'package:fis_common/logger/logger.dart';
  25. import '../../facial_recognition/index.dart';
  26. import '../../id_card_scan/index.dart';
  27. class CreatePatientController extends FControllerBase with HomeNavMixin {
  28. final _patientManager = Get.find<IPatientManager>();
  29. final crowdLabelsController = Get.find<CrowdLabelsController>();
  30. final _patientListController = Get.find<PatientListController>();
  31. final _deviceManager = Get.find<IDeviceManager>();
  32. final state = CreatePatientState();
  33. @override
  34. Future<void> onLoad() {
  35. final params = Get.parameters;
  36. if (params.containsKey("from")) {
  37. if (params["from"] == "list") {
  38. state.isCreateOnly = true;
  39. }
  40. }
  41. if (Routes.parameters.containsKey('patientInfo')) {
  42. if (Routes.parameters['patientInfo'] != null) {
  43. PatientBaseDTO patientInfo = PatientBaseDTO.fromJson(
  44. jsonDecode(
  45. Routes.parameters['patientInfo']!,
  46. ),
  47. );
  48. patientInfoParse(patientInfo);
  49. }
  50. }
  51. return super.onLoad();
  52. }
  53. /// 保存档案,调整签约
  54. void gotoSignContract() async {
  55. setBusy("正在保存...");
  56. String? code;
  57. try {
  58. final validateMsg = await _validateForm();
  59. if (validateMsg != null) {
  60. toast(validateMsg);
  61. return null;
  62. }
  63. code = await _submitForm();
  64. if (code == null) {
  65. busy = false;
  66. PromptBox.toast("保存失败");
  67. return;
  68. }
  69. // final code = "13B95A2B2790464BBFD9B30A71F15C95";
  70. busy = false;
  71. Future.delayed(
  72. const Duration(milliseconds: 800),
  73. () {
  74. state.reset(); // 重置状态
  75. },
  76. );
  77. } finally {
  78. if (code != null) {
  79. Get.toNamed(
  80. "/contract/package_list",
  81. parameters: {"patientCode": code},
  82. );
  83. }
  84. }
  85. // Get.find<HomeController>().switchNavByName("/patient/list");
  86. // Future.delayed(
  87. // const Duration(milliseconds: 800),
  88. // () {
  89. // // TODO:
  90. // Get.find<PatientListController>().gotoDetail(code);
  91. // busy = false;
  92. // },
  93. // );
  94. }
  95. /// 存为档案,调整到档案详情
  96. void saveAndBack() async {
  97. final validateMsg = await _validateForm();
  98. if (validateMsg != null) {
  99. toast(validateMsg);
  100. return null;
  101. }
  102. final code = await _submitForm();
  103. if (code == null) {
  104. busy = false;
  105. logger.e('CreatePatientController saveAndBack code is null');
  106. // PromptBox.toast("保存失败");
  107. return;
  108. } else {
  109. busy = false;
  110. // await queryIsNeedFaceInput(); //询问是否录入人脸
  111. if (Store.user.hasFeature(FeatureKeys.FaceRecognition) && kIsOnline) {
  112. var photoUrl = await getPatientPhoto(state.cardNo);
  113. if (photoUrl.isEmpty) {
  114. await onFaceEntryClicked(); //不询问直接录入
  115. }
  116. }
  117. Future.delayed(
  118. ///这个800ms不能移除,移除后会导致建档失败
  119. const Duration(milliseconds: 800),
  120. () {
  121. state.reset(); // 重置状态
  122. busy = false;
  123. PromptBox.toast("保存成功");
  124. _patientListController.reloadList();
  125. },
  126. );
  127. }
  128. ///不跳转到详情页
  129. // Get.find<HomeController>().switchNavByName("/patient/list");
  130. // Get.put(PatientListController());
  131. Future.delayed(
  132. ///这个800ms不能移除,移除后会导致建档失败
  133. const Duration(milliseconds: 800),
  134. () async {
  135. onIdcardInfoIsCreateRecord(code);
  136. await Get.find<PatientListController>().gotoDetail(
  137. code,
  138. );
  139. busy = false;
  140. },
  141. );
  142. }
  143. /// 询问是否需要人脸录入
  144. Future<void> queryIsNeedFaceInput() async {
  145. /// 拥有人脸权限并且不是身份证扫码建档
  146. if (Store.user.hasFeature(FeatureKeys.FaceRecognition) && kIsOnline) {
  147. var photoUrl = await getPatientPhoto(state.cardNo);
  148. if (photoUrl.isNotEmpty) {
  149. await Get.dialog(VAlertDialog(
  150. contentPadding: const EdgeInsets.fromLTRB(20, 1, 20, 1),
  151. title: '提示',
  152. content: Container(
  153. margin: const EdgeInsets.only(bottom: 20),
  154. child: Column(
  155. mainAxisSize: MainAxisSize.min,
  156. children: [
  157. Image.network(photoUrl,
  158. width: 300, height: 220, fit: BoxFit.cover,
  159. loadingBuilder: (context, child, progress) {
  160. if (progress == null ||
  161. progress.cumulativeBytesLoaded ==
  162. progress.expectedTotalBytes) {
  163. return Image.network(
  164. photoUrl,
  165. width: 300,
  166. height: 220,
  167. fit: BoxFit.cover,
  168. );
  169. }
  170. return const CircularProgressIndicator(
  171. color: Colors.blueAccent);
  172. }),
  173. const Text("该居民已采集过人脸,是否重新采集?",
  174. style: TextStyle(fontSize: 20),
  175. textAlign: TextAlign.center),
  176. ],
  177. ),
  178. ),
  179. confirmLabel: '重新采集',
  180. cancelLabel: '跳过',
  181. showCancel: true,
  182. onConfirm: () async {
  183. await onFaceEntryClicked();
  184. Get.back();
  185. },
  186. onCanceled: () {
  187. Get.back();
  188. },
  189. ));
  190. } else {
  191. await Get.dialog(VAlertDialog(
  192. contentPadding: const EdgeInsets.fromLTRB(20, 1, 20, 1),
  193. title: '提示',
  194. content: Container(
  195. margin: const EdgeInsets.only(bottom: 20),
  196. child: const Text(
  197. '请采集人像,完成后可以使用人脸识别功能',
  198. style: TextStyle(fontSize: 20),
  199. textAlign: TextAlign.center,
  200. ),
  201. ),
  202. confirmLabel: '采集',
  203. cancelLabel: '暂不采集',
  204. showCancel: true,
  205. onConfirm: () async {
  206. await onFaceEntryClicked();
  207. Get.back();
  208. },
  209. onCanceled: () {
  210. Get.back();
  211. },
  212. ));
  213. }
  214. }
  215. }
  216. Future<DeviceModel?> getDevice(String type) async {
  217. List<DeviceModel> devices = await _deviceManager.getDeviceList();
  218. return devices.firstWhereOrNull((element) => element.type == type);
  219. }
  220. /// 点击读卡事件
  221. void onReadCardClicked() async {
  222. final DeviceModel? device = await getDevice(DeviceTypes.IC_READER);
  223. final CardReaderResult? result;
  224. if (device != null) {
  225. // return;
  226. result = await Get.dialog<CardReaderResult>(
  227. const BluetoothCardReaderDialog(),
  228. barrierDismissible: false,
  229. );
  230. } else {
  231. result = await Get.dialog<CardReaderResult>(
  232. const CardReaderDialog(),
  233. barrierDismissible: false,
  234. );
  235. }
  236. if (result != null && result.success) {
  237. PromptBox.toast("读取成功");
  238. state.cardNo = result.cardNo; // 回填身份证号
  239. state.name = result.name; // 回填姓名
  240. state.gender = result.gender; // 回填性别
  241. state.nation = result.nation; // 回填民族
  242. state.birthday = result.birthday; // 回填出生日期
  243. state.censusRegister = result.address; // 回填户籍地址
  244. if (state.isSyncAddresses) {
  245. state.address = result.address; // 回填现住地址
  246. }
  247. } else {
  248. print("读卡取消");
  249. }
  250. }
  251. /// 点击读卡事件 (若已建档跳详情页面 若未建档跳创建页面)
  252. void onReadCardClickedToDetail() async {
  253. final DeviceModel? device = await getDevice(DeviceTypes.IC_READER);
  254. final CardReaderResult? result;
  255. if (device != null) {
  256. // return;
  257. result = await Get.dialog<CardReaderResult>(
  258. const BluetoothCardReaderDialog(),
  259. barrierDismissible: false,
  260. );
  261. } else {
  262. result = await Get.dialog<CardReaderResult>(
  263. const CardReaderDialog(),
  264. barrierDismissible: false,
  265. );
  266. }
  267. if (result != null && result.success) {
  268. PromptBox.toast("读取成功");
  269. PatientBaseDTO patientInfo = PatientBaseDTO();
  270. patientInfo.cardNo = result.cardNo; // 回填身份证号
  271. patientInfo.patientName = result.name; // 回填姓名
  272. patientInfo.patientGender = result.gender; // 回填性别
  273. patientInfo.nationality = result.nation; // 回填民族
  274. patientInfo.birthday = result.birthday; // 回填出生日期
  275. patientInfo.patientAddress = result.address; // 回填户籍地址
  276. onIdcardInfoIsCreateRecord(patientInfo.cardNo!, patientInfo);
  277. } else {
  278. print("读卡取消");
  279. }
  280. }
  281. /// 点击身份识别建档(拍摄扫描身份证)
  282. void onIdCardScanClicked() async {
  283. var verifyResult = await _verifyCameraPermissions();
  284. if (!verifyResult) {
  285. return;
  286. }
  287. Store.user.isShowUserCard = false;
  288. final IdCardScanResult? result = await Get.to<IdCardScanResult>(
  289. () => const IdCardScanPage(),
  290. );
  291. if (result != null && result.success) {
  292. PromptBox.toast("身份证信息识别成功");
  293. PatientBaseDTO patientInfo = result.patientBaseDTO;
  294. patientInfoParse(patientInfo);
  295. } else {
  296. print("识别取消");
  297. }
  298. Store.user.isShowUserCard = true;
  299. }
  300. /// 点击身份识别(拍摄扫描身份证)
  301. void onIdCardScanClickedToDetail() async {
  302. var verifyResult = await _verifyCameraPermissions();
  303. if (!verifyResult) {
  304. return;
  305. }
  306. final IdCardScanResult? result = await Get.to<IdCardScanResult>(
  307. () => const IdCardScanPage(),
  308. );
  309. if (result != null && result.success) {
  310. PromptBox.toast("身份证信息识别成功");
  311. PatientBaseDTO patientInfo = result.patientBaseDTO;
  312. onIdcardInfoIsCreateRecord(patientInfo.cardNo!, patientInfo);
  313. } else {
  314. print("识别取消");
  315. }
  316. }
  317. void patientInfoParse(PatientBaseDTO patientInfo) {
  318. state.cardNo = patientInfo.cardNo ?? ""; // 回填身份证号
  319. state.name = patientInfo.patientName ?? ""; // 回填姓名
  320. state.gender = patientInfo.patientGender; // 回填性别
  321. state.nation = patientInfo.nationality ?? ""; // 回填民族
  322. state.birthday = patientInfo.birthday; // 回填出生日期
  323. state.censusRegister = patientInfo.patientAddress ?? ""; // 回填户籍地址
  324. if (state.isSyncAddresses) {
  325. state.address = patientInfo.patientAddress ?? ""; // 回填现住地址
  326. }
  327. }
  328. Future<bool> _verifyCameraPermissions() async {
  329. IPermissionManager permissionManager = Get.find<IPermissionManager>();
  330. var isCameraPermissions =
  331. await permissionManager.requestCameraPermissions();
  332. if (!isCameraPermissions) {
  333. await Get.dialog(
  334. VAlertDialog(
  335. title: "提示",
  336. width: 420,
  337. content: Container(
  338. height: 32,
  339. padding: const EdgeInsets.symmetric(horizontal: 24),
  340. alignment: Alignment.center,
  341. child: const Text(
  342. "未授予相机权限,前去设置",
  343. style: TextStyle(fontSize: 20),
  344. ),
  345. ),
  346. showCancel: false,
  347. onConfirm: () async {
  348. Get.back();
  349. await permissionManager.openAppSettingsAsync();
  350. },
  351. ),
  352. barrierDismissible: false,
  353. barrierColor: Colors.black.withOpacity(.4),
  354. );
  355. }
  356. return isCameraPermissions;
  357. }
  358. /// 点击人脸识别
  359. void onFaceIdLoginClicked() async {
  360. var verifyResult = await _verifyCameraPermissions();
  361. if (!verifyResult) {
  362. return;
  363. }
  364. Store.user.isShowUserCard = false;
  365. final FaceRecognitionResult? result = await Get.to<FaceRecognitionResult>(
  366. () => const FacialRecognitionPage(
  367. mode: FacialRecognitionMode.faceRecognition,
  368. ),
  369. );
  370. if (result != null && result.success) {
  371. final patient = result.patientInfo;
  372. final hasConfirmed = await FaceResultDialog.show(patient, true);
  373. if (hasConfirmed) {
  374. await _checkinPatient(patient);
  375. }
  376. } else {
  377. print("识别取消");
  378. }
  379. Store.user.isShowUserCard = true;
  380. }
  381. void onIdcardInfoIsCreateRecord(
  382. String cardNo, [
  383. PatientBaseDTO? patientInfo,
  384. ]) async {
  385. PatientDTO? patientInfoDto = await _patientManager.getDetail(cardNo);
  386. if (patientInfoDto != null) {
  387. Store.user.currentSelectPatientInfo = patientInfoDto;
  388. }
  389. if (patientInfo != null) {
  390. final hasConfirmed =
  391. await FaceResultDialog.show(patientInfo, patientInfoDto != null);
  392. if (hasConfirmed) {
  393. if (patientInfoDto != null) {
  394. await Get.find<PatientListController>()
  395. .gotoDetail(patientInfo.cardNo!, patientInfoDto, patientInfo);
  396. } else {
  397. await Get.find<PatientListController>().gotoCreate(
  398. patientInfo.cardNo!,
  399. patientInfoDto,
  400. patientInfo,
  401. );
  402. }
  403. }
  404. }
  405. }
  406. /// 点击录入人脸
  407. Future<void> onFaceEntryClicked() async {
  408. final PatientDTO patientInfo = PatientDTO(
  409. patientName: state.name,
  410. phone: state.phoneNo,
  411. cardNo: state.cardNo,
  412. nationality: state.nation,
  413. birthday: state.birthday,
  414. cardType: state.cardType,
  415. patientGender: state.gender!,
  416. code: state.cardNo,
  417. );
  418. bool? result = await Get.to<bool>(
  419. () => FacialRecognitionPage(
  420. mode: FacialRecognitionMode.faceInput,
  421. patientInfo: patientInfo,
  422. ),
  423. );
  424. if (result != null && result) {
  425. PromptBox.toast('人脸数据存入成功');
  426. }
  427. }
  428. /// 处理 “同户籍地址” 勾选变更事件
  429. void onSyncAddressCheckChanged(bool isChecked) {
  430. state.isSyncAddresses = isChecked;
  431. if (isChecked) {
  432. // 同步户籍地址到现住地址
  433. state.address = state.censusRegister;
  434. } else {
  435. state.address = "";
  436. }
  437. }
  438. /// 处理户籍地址变更
  439. void onCensusRegisterChanged(String value) {
  440. state.censusRegister = value;
  441. if (state.isSyncAddresses) {
  442. state.address = value;
  443. }
  444. }
  445. Future<String> getPatientPhoto(String patientCode) async {
  446. final dto = await _patientManager.getDetail(patientCode);
  447. if (dto != null && dto.photos != null && dto.photos!.isNotEmpty) {
  448. return dto.photos![0];
  449. }
  450. return "";
  451. }
  452. Future<String?> _submitForm() async {
  453. setBusy("正在保存...");
  454. final crowdLabelCodes = crowdLabelsController.state.selectedCodes;
  455. final request = CreatePatientRequest(
  456. patientName: state.name,
  457. phone: state.phoneNo,
  458. patientGender: state.gender!,
  459. nationality: state.nation,
  460. birthday: state.birthday?.toUtc(),
  461. cardType: state.cardType,
  462. cardNo: state.cardNo,
  463. patientAddress: state.address,
  464. permanentResidenceAddress: state.censusRegister,
  465. crowdLabels: crowdLabelCodes,
  466. );
  467. final result = await _patientManager.create(request);
  468. return result;
  469. }
  470. bool validateIDCard(String idCard) {
  471. // 校验身份证号码长度
  472. if (idCard.length != 18) {
  473. return false;
  474. }
  475. // 校验前17位是否为数字
  476. String idCard17 = idCard.substring(0, 17);
  477. if (!isNumeric(idCard17)) {
  478. return false;
  479. }
  480. // 校验最后一位校验码
  481. String checkCode = getCheckCode(idCard17);
  482. if (idCard[17].toUpperCase() != checkCode) {
  483. print("checkCode: $checkCode");
  484. return false;
  485. }
  486. return true;
  487. }
  488. bool isNumeric(String str) {
  489. if (str.isEmpty) {
  490. return false;
  491. }
  492. return double.tryParse(str) != null;
  493. }
  494. bool isAlphaNumeric(String str) {
  495. final RegExp alphaNumericRegExp = RegExp(r'^[a-zA-Z0-9]+$');
  496. return alphaNumericRegExp.hasMatch(str);
  497. }
  498. bool isAlphaNumericChineseWithSpace(String str) {
  499. final RegExp alphaNumericChineseWithSpaceRegExp =
  500. RegExp(r'^[a-zA-Z0-9\u4e00-\u9fa5\s]+$');
  501. return alphaNumericChineseWithSpaceRegExp.hasMatch(str);
  502. }
  503. String getCheckCode(String idCard17) {
  504. List<int> coefficients = [
  505. 7,
  506. 9,
  507. 10,
  508. 5,
  509. 8,
  510. 4,
  511. 2,
  512. 1,
  513. 6,
  514. 3,
  515. 7,
  516. 9,
  517. 10,
  518. 5,
  519. 8,
  520. 4,
  521. 2
  522. ];
  523. List<String> checkCodes = [
  524. '1',
  525. '0',
  526. 'X',
  527. '9',
  528. '8',
  529. '7',
  530. '6',
  531. '5',
  532. '4',
  533. '3',
  534. '2'
  535. ];
  536. int sum = 0;
  537. for (int i = 0; i < idCard17.length; i++) {
  538. int digit = int.parse(idCard17[i]);
  539. sum += digit * coefficients[i];
  540. }
  541. int remainder = sum % 11;
  542. return checkCodes[remainder];
  543. }
  544. Future<String?> _validateForm() async {
  545. if (state.name.isEmpty) {
  546. return "请填写姓名";
  547. }
  548. // else {
  549. // if (!isAlphaNumericChineseWithSpace(state.name) ||
  550. // state.name.length >= 20) {
  551. // return "姓名只能由中文、字母或数字组成,并且小于20个字符";
  552. // }
  553. // }
  554. if (state.cardNo.isEmpty) {
  555. return "请填写证件号";
  556. }
  557. if (state.phoneNo.isNotEmpty) {
  558. if (state.phoneNo.length != 11 || !isNumeric(state.phoneNo)) {
  559. return "请填写正确的手机号";
  560. }
  561. }
  562. if (state.cardType == CardTypeEnum.Identity) {
  563. bool isNotIDCard = validateIDCard(state.cardNo);
  564. if (!isNotIDCard) {
  565. return "请填写正确的证件号";
  566. }
  567. }
  568. if (state.cardType == CardTypeEnum.SocialInsurance) {
  569. if (state.cardNo.length != 18 || !isNumeric(state.cardNo)) {
  570. return "请填写正确的社保号";
  571. }
  572. }
  573. if (state.cardType == CardTypeEnum.Passport) {
  574. if (state.cardNo.length != 9 || !isAlphaNumeric(state.cardNo)) {
  575. return "请填写正确的护照号";
  576. }
  577. }
  578. if (state.gender == null) {
  579. return "请选择性别";
  580. }
  581. /// TODO 需求变更暂时删除
  582. // final selectedNormalCodes = crowdLabelsController.state.selectedNormalCodes;
  583. // if (selectedNormalCodes.length > 1) {
  584. // return "人群分类:一般人群、儿童、孕妇、老年人,只可选择其一!";
  585. // }
  586. // final crowdLabelCodes = crowdLabelsController.state.selectedCodes;
  587. // if (crowdLabelCodes.isEmpty) {
  588. // return "请选择人群分类";
  589. // }
  590. // if (state.gender == GenderEnum.Male &&
  591. // crowdLabelCodes.contains('RQFL_YF')) {
  592. // return "当前居民性别为“男”,人群分类不可选择孕妇!";
  593. // }
  594. return null;
  595. }
  596. /// 切换当前登记居民
  597. Future<void> _checkinPatient(PatientBaseDTO patient) async {
  598. final patientDTO = PatientDTO(
  599. code: patient.cardNo,
  600. cardNo: patient.cardNo,
  601. patientName: patient.patientName,
  602. nationality: patient.nationality,
  603. patientGender: patient.patientGender,
  604. birthday: patient.birthday,
  605. patientAddress: patient.patientAddress,
  606. );
  607. Store.user.currentSelectPatientInfo = patientDTO;
  608. logger.i(
  609. 'create居民 当前居民是:${patientDTO.patientName} 居民code:${patientDTO.code}');
  610. onIdcardInfoIsCreateRecord(patientDTO.code!);
  611. await Get.find<PatientListController>().gotoDetail(
  612. patient.cardNo!,
  613. );
  614. }
  615. Future<void> setGender(String cardNo) async {
  616. if (cardNo.isNotEmpty && cardNo.length > 17) {
  617. var sexNum = cardNo.substring(16, 17);
  618. if (sexNum.isNotEmpty && RegExp(r'^\d+$').hasMatch(sexNum)) {
  619. if (int.parse(sexNum) % 2 == 1) {
  620. state.gender = GenderEnum.Male;
  621. } else {
  622. state.gender = GenderEnum.Female;
  623. }
  624. } else {
  625. state.gender = GenderEnum.Unknown;
  626. }
  627. }
  628. }
  629. }