controller.dart 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. import 'dart:async';
  2. import 'package:fis_common/helpers/encrypt.dart';
  3. import 'package:fis_common/index.dart';
  4. import 'package:fis_common/logger/logger.dart';
  5. import 'package:fis_i18n/i18n.dart';
  6. import 'package:fis_jsonrpc/rpc.dart';
  7. import 'package:fis_ui/index.dart';
  8. import 'package:fis_ui/interface/interactive_container.dart';
  9. import 'package:flutter/material.dart';
  10. import 'package:get/get.dart';
  11. import 'package:vitalapp/architecture/utils/prompt_box.dart';
  12. import 'package:vitalapp/architecture/values/features.dart';
  13. import 'package:vitalapp/components/alert_dialog.dart';
  14. import 'package:vitalapp/managers/interfaces/language.dart';
  15. import 'package:vitalapp/managers/interfaces/models/consultations_record_data.dart';
  16. import 'package:vitalapp/managers/interfaces/models/image_report_list_params.dart';
  17. import 'package:vitalapp/managers/interfaces/models/role_type.dart';
  18. import 'package:vitalapp/managers/interfaces/models/selected_model.dart';
  19. import 'package:vitalapp/managers/interfaces/patient.dart';
  20. import 'package:vitalapp/managers/interfaces/remedical.dart';
  21. import 'package:vitalapp/managers/interfaces/report.dart';
  22. import 'package:vitalapp/managers/interfaces/scanning_image.dart';
  23. import 'package:vitalapp/pages/consultation_record_view/widgets/capture_page.dart';
  24. import 'package:vitalapp/pages/image_report_inner_view/controller.dart';
  25. import 'package:vitalapp/rpc.dart';
  26. import 'package:vitalapp/store/store.dart';
  27. import 'controllers/capture_live_controller.dart';
  28. import 'controllers/check_controller.dart';
  29. import 'controllers/remedical_controller.dart';
  30. import 'state.dart';
  31. import 'widgets/inspection_details_dialog.dart';
  32. class ConsultationRecordViewController extends GetxController
  33. with GetSingleTickerProviderStateMixin {
  34. late final RemedicalController remedicalController;
  35. late final CheckController checkController;
  36. late final CaptureLiveController captureLiveController;
  37. final languageConfigManager = Get.find<ILanguageConfigManager>();
  38. final remedicalManager = Get.find<IRemedicalManager>();
  39. final searchInputFocusNode = FocusNode();
  40. final searchSelectPatientFocusNode = FocusNode();
  41. final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
  42. List<ConsultationsRecordData> consultationsRecordDataList = [];
  43. ///医院筛选框
  44. final orgFilterController = TextEditingController();
  45. ///设备筛选框
  46. final deviceFilterController = TextEditingController();
  47. ConsultationRecordViewController() {
  48. remedicalController = RemedicalController(this);
  49. checkController = CheckController(this);
  50. captureLiveController = CaptureLiveController(this);
  51. }
  52. final state = ConsultationRecordViewState();
  53. final reportManager = Get.find<IReportManager>();
  54. ///是否抽屉显示历史检查
  55. bool isDrawerOpen = false;
  56. /// FisBuilder 中用到的 UI 数据
  57. // **表格数据**
  58. bool isTableLoading = false;
  59. ///当前检查详情
  60. QueryRecordResult? checkInfo;
  61. ConsultationsRecordData? get currentRecordData =>
  62. selectedIndex > -1 ? consultationsRecordDataList[selectedIndex] : null;
  63. ///转诊状态0-普通,1-转入,2-转出
  64. ReferralTypeEnum? get referralType => currentRecordData?.referralType;
  65. ///是否转诊
  66. bool get isReferral => referralType != null && referralType!.index > 0;
  67. String get desktopListSelectedRecordCode =>
  68. currentRecordData?.recordCode ?? '';
  69. String get deviceCode => currentRecordData?.deviceCode ?? '';
  70. String get patientCode => currentRecordData?.patientCode ?? '';
  71. String get patientName => currentRecordData?.patientName ?? '';
  72. RecordStatusEnum? get recordStatus => currentRecordData?.recordStatus;
  73. bool get canCollcetImg => currentRecordData?.canCollcetImg ?? false;
  74. ///是否能本地采图
  75. bool get canScreenshot => currentRecordData?.canScreenshot ?? false;
  76. bool get isCanTransfer => false;
  77. bool get isCanShowTransferHisHistory => [
  78. ReferralTypeEnum.ReferralIn,
  79. ReferralTypeEnum.ReferralOut
  80. ].contains(currentRecordData?.referralType); // 是否可以显示转诊历史
  81. /// 是否拥有删除的权限
  82. bool get isCanDelete => Store.user.hasFeature(FeatureKeys.DeleteRecord);
  83. /// **分页器**
  84. int totalDataCount = 0;
  85. int pageIndex = 1;
  86. // **操作栏**
  87. bool isShowOperationButtonsRow = false;
  88. // **筛选**
  89. RecordProcessStateEnum typeFilter = RecordProcessStateEnum.Wait;
  90. bool isFilterOptionsExpanded = false;
  91. // 筛选条件中的机构列表
  92. List<FMutiSelectModel> organizationLocatedList = [];
  93. // 所有机构列表
  94. List<FMutiSelectModel> allOrganizationLocatedList = [];
  95. ///机构总数量
  96. int organizationsCount = 0;
  97. // 所属机构
  98. List<String> get selectedOrganizationLocated =>
  99. organizationLocatedList.map((e) => e.code).toList();
  100. //筛选条件中的设备列表
  101. List<FMutiSelectModel> personDeviceList = [];
  102. //所有设备列表
  103. List<FMutiSelectModel> allPersonDeviceList = [];
  104. ///设备总数量
  105. int personDeviceCount = 0;
  106. ///设备编码集合
  107. List<String> get selectedpersonDevice =>
  108. personDeviceList.map((e) => e.code).toList(); // 当前选择设备
  109. ///是否全选组织
  110. bool isSelectAllOrg = true;
  111. ///是否全选设备
  112. bool isSelectAllDevice = true;
  113. List<FSelectOptionModel> recordStatusList = [
  114. FSelectOptionModel(
  115. title: i18nBook.common.all.t,
  116. value: RecordQueryStateEnum.All,
  117. ),
  118. FSelectOptionModel(
  119. title: i18nBook.remedical.toScan4Label.t,
  120. value: RecordQueryStateEnum.NotScanned,
  121. ),
  122. FSelectOptionModel(
  123. title: i18nBook.remedical.imageUploaded4Label.t,
  124. value: RecordQueryStateEnum.Uploaded,
  125. ),
  126. FSelectOptionModel(
  127. title: i18nBook.remedical.scanned4Label.t,
  128. value: RecordQueryStateEnum.NotReport,
  129. ),
  130. FSelectOptionModel(
  131. title: i18nBook.remedical.reported4Label.t,
  132. value: RecordQueryStateEnum.Completed,
  133. ),
  134. ]; // 状态列表
  135. RecordQueryStateEnum selectRecordStatus = RecordQueryStateEnum.All;
  136. int selectedIndex = -1;
  137. String keyWord = '';
  138. String organizationName = '';
  139. OrganizationPatientTypeEnum organizationPatientType =
  140. OrganizationPatientTypeEnum.Person;
  141. bool _isHasFocus = false;
  142. bool isSelectPatientHasFocus = false;
  143. DateTime startDateTime = DateTime.now().subtract(Duration(days: 365 * 3));
  144. DateTime endDateTime = DateTime.now();
  145. late AnimationController animationController;
  146. late Animation<double> animation;
  147. /// 是否展示结束扫查
  148. late bool isShowEndScan = false;
  149. /// 移动端详情页展示的记录 code
  150. String mobileDetailPageRecordCode = '';
  151. // **转诊**
  152. List<FSelectOptionModel<String>> referOrg = []; // 可转诊机构
  153. String? referralOrganizationCode; // 转诊机构code
  154. List<FSelectOptionModel> userRoleList = []; // 角色列表
  155. List<UserDoctorModel> referUserList = []; // 转诊医师列表
  156. String? referralUserCode; // 转诊医师code
  157. String subjectMatter = ''; // 拒绝原因
  158. List<ReferralHistoryDetailData> referralHistoryDetailList = []; // 转诊历史列表
  159. // **历史记录*
  160. bool isShowHistory = false; // 是否显示历史记录
  161. String histroyPatientCode = ''; // 历史记录病人的code
  162. ///选择病人弹窗,当前选中的病人
  163. String currentSelectPatientCode = '';
  164. @override
  165. void onEnterPressed() {
  166. if (_isHasFocus) {
  167. searchFindRecordPages();
  168. }
  169. if (isSelectPatientHasFocus) {
  170. checkController.searchPatient();
  171. }
  172. }
  173. void _listenSearchFocusNode() {
  174. searchInputFocusNode.addListener(() {
  175. if (searchInputFocusNode.hasFocus) {
  176. _isHasFocus = true;
  177. } else {
  178. Future.delayed(
  179. const Duration(milliseconds: 10),
  180. () {
  181. _isHasFocus = false;
  182. },
  183. );
  184. }
  185. });
  186. }
  187. /// 点击了某一行
  188. Future<void> onTableRowTap(int index) async {
  189. print("onTableRowTap: $index");
  190. selectedIndex = index;
  191. checkInfo = await remedicalManager
  192. .queryRecordInfoAsync(desktopListSelectedRecordCode);
  193. isShowOperationButtonsRow = true;
  194. /// 结束扫查的逻辑
  195. /// (待扫查 || 已传图) && (不可开始采图)
  196. isShowEndScan = [RecordStatusEnum.Uploaded, RecordStatusEnum.NotScanned]
  197. .contains(recordStatus) &&
  198. !canCollcetImg;
  199. Get.find<ImagereportinnerviewController>().changeRecord(
  200. ImageReportListParams(
  201. recordCode: desktopListSelectedRecordCode,
  202. ),
  203. );
  204. update(["operation_buttons_row"]);
  205. }
  206. /// 分页器翻页
  207. Future<void> onChangePage(int pageIndex, int listLength,
  208. {bool isLoadMore = false}) async {
  209. print("onChangePage: $pageIndex, $listLength");
  210. this.pageIndex = pageIndex;
  211. isShowOperationButtonsRow = false;
  212. if (isShowHistory) {
  213. await queryRecordByCurrentPatient(histroyPatientCode);
  214. } else {
  215. await findRecordPagesAsync(
  216. isLoadMore: isLoadMore,
  217. );
  218. }
  219. state.measureImages = [];
  220. state.aiImages = [];
  221. state.reports = [];
  222. state.remedicalListResult = RemedicalListResult();
  223. update(["operation_buttons_row"]);
  224. update(["record_table_pagination", "record_data_table"]);
  225. }
  226. /// 加载角色集合
  227. Future<void> loadRoles() async {
  228. final roles = await rpc.role.findAuthenticationRolesAsync(
  229. FindAuthenticationRolesRequest(
  230. token: Store.user.token,
  231. language: i18nBook.locale.toCodeString('-'),
  232. ),
  233. );
  234. List<FSelectOptionModel> _userRoleList = [];
  235. roles.forEach(
  236. (e) => _userRoleList.add(
  237. FSelectOptionModel(
  238. value: e.roleCode ?? '',
  239. title: e.roleName ?? '',
  240. ),
  241. ),
  242. );
  243. userRoleList = _userRoleList;
  244. }
  245. /// 获取转入机构下面的医生用户
  246. Future<void> getUserListAsync(String organizationCode) async {
  247. final result = await rpc.user.getUserListAsync(
  248. GetUserListRequest(
  249. token: Store.user.token,
  250. language: i18nBook.locale.toCodeString('-'),
  251. organizationCode: organizationCode,
  252. // 全部和待分配的枚举
  253. organizationQueryType: OrganizationQueryTypeEnum.All,
  254. roleCodes: [RoleType.certifiedPhysician, RoleType.certifiedExpert],
  255. ),
  256. );
  257. final List<UserDoctorModel> _referUserList = [];
  258. result.forEach(
  259. (element) {
  260. final referUserName = element.displayName!;
  261. _referUserList.add(
  262. UserDoctorModel(
  263. name: referUserName,
  264. code: element.userCode ?? '',
  265. roleCodes: element.roleCodes ?? [],
  266. roleName: element.roleName,
  267. fieldList: element.fieldList ?? [],
  268. headImageUrl: element.headImageUrl ?? '',
  269. ),
  270. );
  271. },
  272. );
  273. referUserList = _referUserList;
  274. update(['transfer_doctor']);
  275. }
  276. Future<void> findReferralHistoryAsync([
  277. String? mobileRecordCode,
  278. ]) async {
  279. try {
  280. String currentRecordCode = desktopListSelectedRecordCode;
  281. if (mobileRecordCode != null && mobileRecordCode.isNotEmpty) {
  282. currentRecordCode = mobileRecordCode;
  283. }
  284. final result = await rpc.recordInfo.findReferralHistoryAsync(
  285. FindReferralHistoryRequest(
  286. token: Store.user.token,
  287. recordCode: currentRecordCode,
  288. ),
  289. );
  290. List<ReferralHistoryDetailData> _referralHistoryDetailList = [];
  291. for (ReferralHistoryDetail i in result) {
  292. _referralHistoryDetailList
  293. .add(ReferralHistoryDetailData.fromJson(i.toJson()));
  294. }
  295. referralHistoryDetailList = _referralHistoryDetailList;
  296. } catch (e) {
  297. printError(
  298. info: "queryReferralOrganizationsAsync exception:" + e.toString());
  299. logger.e("queryReferralOrganizationsAsync exception:", e);
  300. }
  301. }
  302. /// 转诊提交
  303. Future<void> submitRefer(
  304. String patientCode, [
  305. String? mobileRecordCode,
  306. ]) async {
  307. try {
  308. if (subjectMatter.isNullOrWhiteSpace ||
  309. referralUserCode == '' ||
  310. referralUserCode == null ||
  311. referralOrganizationCode == '') {
  312. PromptBox.toast(i18nBook.user.requiredFieldsCannotBeEmpty.t);
  313. } else {
  314. String currentRecordCode = desktopListSelectedRecordCode;
  315. if (mobileRecordCode != null && mobileRecordCode.isNotEmpty) {
  316. currentRecordCode = mobileRecordCode;
  317. }
  318. /// 创建转诊
  319. final applyReferralRecord =
  320. await rpc.recordInfo.applyReferralForRecordInfoListAsync(
  321. CreateReferralRecordNewRequest(
  322. recordCode: currentRecordCode,
  323. token: Store.user.token,
  324. subjectMatter: subjectMatter,
  325. referralOrganizationCode: referralOrganizationCode,
  326. referralUserCode: referralUserCode,
  327. ),
  328. );
  329. // 转诊成功
  330. if (applyReferralRecord) {
  331. initReferStatus();
  332. await searchFindRecordPages();
  333. PromptBox.toast(i18nBook.remedical.submitSuccessToTransferList.t);
  334. }
  335. }
  336. } catch (e) {
  337. printError(
  338. info:
  339. "applyReferralForRecordInfoListAsync exception:" + e.toString());
  340. logger.e("applyReferralForRecordInfoListAsync exception:", e);
  341. }
  342. }
  343. void initReferStatus() {
  344. Get.back();
  345. subjectMatter = '';
  346. referralOrganizationCode = null;
  347. referralUserCode = null;
  348. }
  349. //**操作栏按钮 */
  350. // 查看病人信息
  351. Future<void> showPatientInfoDialog() async {
  352. // consultationController =
  353. // Get.put<ConsultationController>(ConsultationController());
  354. // consultationController?.state.checkLists = [];
  355. // consultationController?.changePatientInfo(patientCode);
  356. isDrawerOpen = true;
  357. update(['record_body']);
  358. }
  359. ///关闭病人信息
  360. void closePatientInfoDialog() {
  361. //Get.delete<ConsultationController>();
  362. isDrawerOpen = false;
  363. update(['record_body']);
  364. }
  365. // 查看检查详情
  366. Future<void> showInspectionDetailsDialog() async {
  367. checkInfo = await remedicalManager
  368. .queryRecordInfoAsync(desktopListSelectedRecordCode);
  369. var createTime = checkInfo!.createTime?.toLocal();
  370. var defaultTime = DateTime.utc(0001, 01, 01, 00, 00, 00, 00);
  371. if (checkInfo?.examTime != null && checkInfo?.examTime != defaultTime) {
  372. createTime = checkInfo?.examTime!.toLocal();
  373. }
  374. ClientPatientInfoDTO patientInfoDto =
  375. await remedicalManager.findPatientByCode(patientCode);
  376. Get.dialog(
  377. InspectionDetailsDiaLog(
  378. recordCode: desktopListSelectedRecordCode,
  379. checkInfo: GetRecordsPageDTO(
  380. createTime: createTime,
  381. creatorName: checkInfo!.creatorName,
  382. deptName: checkInfo!.deptName,
  383. displayName: checkInfo!.displayName,
  384. ),
  385. patientInfoExts: checkInfo?.patientInfoExtList ?? [],
  386. patientInfo: patientInfoDto,
  387. patientType: state.patientType,
  388. ),
  389. );
  390. }
  391. /// 获取组织信息
  392. Future<void> getOrgType() async {
  393. try {
  394. final result = await rpc.user.getUserInfoAsync(
  395. GetUserInfoRequest(token: Store.user.token),
  396. );
  397. final org = await rpc.organization.getOrganizationByCodeAsync(
  398. GetOrganizationByCodeRequest(
  399. organizationCode: result.rootOrganizationCode,
  400. token: Store.user.token,
  401. ),
  402. );
  403. state.patientType = org.patientType;
  404. } catch (e) {
  405. printError(info: "getOrgType exception:" + e.toString());
  406. logger.e("getOrgType exception:", e);
  407. }
  408. }
  409. /// 开始扫查
  410. ///
  411. /// [desktopListSelectedRecordCode] 设备code
  412. Future<bool> startScan(
  413. FInteractiveContainer businessParent,
  414. ) async {
  415. try {
  416. bool checkSuccess = await rpc.recordInfo
  417. .checkCollectingImgAsync(CheckCollectingImgRequest(
  418. deviceCode: deviceCode,
  419. token: Store.user.token,
  420. ));
  421. var startSuccess = false;
  422. if (checkSuccess) {
  423. startSuccess = await rpc.recordInfo
  424. .startCollectingImgAsync(StartCollectingImgRequest(
  425. recordCode: desktopListSelectedRecordCode,
  426. token: Store.user.token,
  427. ));
  428. if (startSuccess) {
  429. PromptBox.toast(i18nBook.remedical.startScanSuccess.t);
  430. }
  431. await findRecordPages();
  432. } else {
  433. FConfirmAlert.show(
  434. businessParent: businessParent,
  435. context: Get.context!,
  436. title: i18nBook.common.tip.t,
  437. subTitle: i18nBook.remedical.scanOcuppiedDetailTip.t,
  438. cancelLabel: i18nBook.common.cancel.t,
  439. confrimLabel: i18nBook.common.confirm.t,
  440. onCancel: () async {
  441. return;
  442. },
  443. onConfirm: () async {
  444. startSuccess = await rpc.recordInfo
  445. .startCollectingImgAsync(StartCollectingImgRequest(
  446. recordCode: desktopListSelectedRecordCode,
  447. token: Store.user.token,
  448. ));
  449. if (startSuccess) {
  450. PromptBox.toast(i18nBook.remedical.startScanSuccess.t);
  451. }
  452. await findRecordPages();
  453. },
  454. );
  455. }
  456. } catch (e) {
  457. printError(info: "StartScan:" + e.toString());
  458. logger.e("StartScan exception:", e);
  459. }
  460. return false;
  461. }
  462. // 当前页数不变
  463. Future<void> findRecordPages() async {
  464. await findRecordPagesAsync();
  465. isShowOperationButtonsRow = false;
  466. update(["operation_buttons_row"]);
  467. update(["record_table_pagination", "record_data_table"]);
  468. }
  469. // 编辑报告
  470. void editReport() {
  471. reportManager.openReportEdit(
  472. patientCode,
  473. recordCode: desktopListSelectedRecordCode,
  474. referralRecordCode: isReferral ? desktopListSelectedRecordCode : "",
  475. );
  476. }
  477. // 转诊
  478. Future<void> transfer() async {
  479. // await Get.dialog(RecordReferDoctorDiaLog(
  480. // patientName: patientName,
  481. // );
  482. subjectMatter = '';
  483. referUserList = [];
  484. referralOrganizationCode = null;
  485. referralUserCode = null;
  486. }
  487. // 撤销转诊
  488. Future<void> revokefer([
  489. String? mobileRecordCode,
  490. ]) async {
  491. try {
  492. String currentRecordCode = desktopListSelectedRecordCode;
  493. if (mobileRecordCode != null && mobileRecordCode.isNotEmpty) {
  494. currentRecordCode = mobileRecordCode;
  495. }
  496. final result =
  497. await rpc.recordInfo.withdrawReferralForRecordInfoListAsync(
  498. WithdrawReferralForRecordListRequest(
  499. token: Store.user.token,
  500. recordCode: currentRecordCode,
  501. ),
  502. );
  503. if (result) {
  504. Future.delayed(Duration(milliseconds: 500), () {
  505. PromptBox.toast(i18nBook.realTimeConsultation.withdrawalSucceeded.t);
  506. });
  507. Get.back();
  508. }
  509. searchFindRecordPages();
  510. } catch (e) {
  511. printError(info: "getOrgType exception:" + e.toString());
  512. logger.e("getOrgType exception:", e);
  513. }
  514. }
  515. // 查看历史记录
  516. Future<void> showReferralHistory([
  517. String? mobileRecordCode,
  518. ]) async {
  519. await findReferralHistoryAsync(mobileRecordCode);
  520. update(['record_refer_history_table']);
  521. print('showTransferHistory');
  522. }
  523. void showHistory() async {
  524. isShowHistory = true;
  525. pageIndex = 1;
  526. isShowOperationButtonsRow = false;
  527. histroyPatientCode = patientCode;
  528. await queryRecordByCurrentPatient(histroyPatientCode);
  529. update([
  530. "record_data_table_header",
  531. "record_data_table",
  532. "record_table_pagination",
  533. 'operation_buttons_row'
  534. ]);
  535. }
  536. // 离开历史记录模式
  537. void exitHistoryMode() async {
  538. isShowHistory = false;
  539. pageIndex = 1;
  540. isShowOperationButtonsRow = false;
  541. await searchFindRecordPages();
  542. update([
  543. "record_data_table_header",
  544. "record_data_table",
  545. "record_table_pagination",
  546. 'operation_buttons_row'
  547. ]);
  548. }
  549. /// 查询根据病人code查询
  550. Future<void> queryRecordByCurrentPatient(String patientCode) async {
  551. try {
  552. if (startDateTime.isAfter(endDateTime)) {
  553. PromptBox.toast(i18nBook.errorCodes.errorCode4022.t);
  554. return;
  555. }
  556. //busy = true;
  557. final result = await remedicalManager.findRecordPages(
  558. pageIndex: pageIndex,
  559. organizationCodes: selectedOrganizationLocated,
  560. deviceCodes: selectedpersonDevice,
  561. recordQueryState: selectRecordStatus,
  562. recordProcessState: typeFilter,
  563. patientCode: patientCode,
  564. startTime: startDateTime,
  565. endTime: endDateTime,
  566. );
  567. totalDataCount = result.totalCount;
  568. List<ConsultationsRecordData> _consultationsRecordDataList = [];
  569. for (SimpleRecordInfoDTO i in result.pageData ?? []) {
  570. i.patientName = FEncryptHelper.decryptBase64(i.patientName ?? '');
  571. var consultationsRecordData = ConsultationsRecordData.fromJson(
  572. i.toJson(),
  573. );
  574. consultationsRecordData.diagnosisInfos = i.diagnosisInfos ?? [];
  575. _consultationsRecordDataList.add(consultationsRecordData);
  576. }
  577. consultationsRecordDataList = _consultationsRecordDataList;
  578. //busy = false;
  579. } catch (e) {
  580. printError(info: "findRecordPagesAsync exception:" + e.toString());
  581. logger.e("findRecordPagesAsync exception:", e);
  582. //busy = false;
  583. }
  584. }
  585. // 切换筛选表格类型
  586. Future<void> changeTypeFilter(RecordProcessStateEnum value) async {
  587. remedicalController.clear();
  588. typeFilter = value;
  589. if (value == RecordProcessStateEnum.Done) {
  590. state.selectedTabIndex = 2;
  591. } else {
  592. state.selectedTabIndex = 0;
  593. }
  594. await searchFindRecordPages();
  595. isDrawerOpen = false;
  596. update(['record_body']);
  597. update(["record_filter_tab"]);
  598. update(["operation_buttons_row"]);
  599. update(["record_table_pagination", "record_data_table"]);
  600. }
  601. // 打开更多筛选项
  602. void openOrCloseMoreFilter() {
  603. isDrawerOpen = false;
  604. update(['record_body']);
  605. }
  606. Future<void> changeSelectedOrganizationLocated(List<String> value) async {
  607. await getPersonDeviceDropdownPageAsync();
  608. update(["record_more_filter"]);
  609. }
  610. /// 在 widget 内存中分配后立即调用。
  611. @override
  612. void onInit() async {
  613. super.onInit();
  614. reportManager.initFluwx();
  615. // userInfoManager
  616. // .getUserInfoAsync()
  617. // .then((value) => update(["record_data_table_header"]));
  618. _listenSearchFocusNode();
  619. _initListener();
  620. animationController = AnimationController(
  621. duration: Duration(milliseconds: 300),
  622. vsync: this,
  623. );
  624. animation = CurvedAnimation(
  625. parent: animationController,
  626. curve: Curves.easeInOut,
  627. );
  628. await getOrganizationByUserAndDevicesAsync(); // 筛选所有的机构
  629. allOrganizationLocatedList.addAll(organizationLocatedList);
  630. await getPersonDeviceDropdownPageAsync(); // 筛选所有的设备
  631. allPersonDeviceList.addAll(personDeviceList);
  632. await searchFindRecordPages(); // 查询列表
  633. }
  634. /// 获取机构列表
  635. Future<void> findRecordPagesAsync({
  636. bool isLoadMore = false,
  637. }) async {
  638. try {
  639. //busy = true;
  640. List<ConsultationsRecordData> _consultationsRecordDataList = [];
  641. if (startDateTime.isAfter(endDateTime)) {
  642. PromptBox.toast(i18nBook.errorCodes.errorCode4022.t);
  643. return;
  644. }
  645. final result = await remedicalManager.findRecordPages(
  646. pageIndex: pageIndex,
  647. organizationCodes: null,
  648. deviceCodes: null,
  649. recordQueryState: selectRecordStatus,
  650. recordProcessState: typeFilter,
  651. keyWord: keyWord,
  652. startTime: startDateTime,
  653. endTime: endDateTime,
  654. );
  655. totalDataCount = result.totalCount;
  656. for (SimpleRecordInfoDTO i in result.pageData ?? []) {
  657. // i.patientName = FEncryptHelper.decryptBase64(i.patientName ?? '');
  658. var consultationsRecordData = ConsultationsRecordData.fromJson(
  659. i.toJson(),
  660. );
  661. consultationsRecordData.diagnosisInfos = i.diagnosisInfos ?? [];
  662. _consultationsRecordDataList.add(consultationsRecordData);
  663. }
  664. if (isLoadMore) {
  665. consultationsRecordDataList.addAll(_consultationsRecordDataList);
  666. } else {
  667. consultationsRecordDataList = _consultationsRecordDataList;
  668. }
  669. //busy = false;
  670. } catch (e) {
  671. printError(info: "findRecordPagesAsync exception:" + e.toString());
  672. logger.e("findRecordPagesAsync exception:", e);
  673. //busy = false;
  674. }
  675. //if (busy) busy = false;
  676. }
  677. // 搜索
  678. Future<void> searchFindRecordPages() async {
  679. pageIndex = 1;
  680. await findRecordPagesAsync();
  681. openOrCloseMoreFilter();
  682. scaffoldKey.currentState?.closeEndDrawer();
  683. isShowOperationButtonsRow = false;
  684. isDrawerOpen = false;
  685. update(['record_body']);
  686. update(["operation_buttons_row"]);
  687. update(["record_table_pagination", "record_data_table"]);
  688. }
  689. // 重置
  690. Future<void> resetFilter() async {
  691. isSelectAllDevice = true;
  692. isSelectAllOrg = true;
  693. await getOrganizationByUserAndDevicesAsync();
  694. allOrganizationLocatedList.clear();
  695. allOrganizationLocatedList.addAll(organizationLocatedList);
  696. await getPersonDeviceDropdownPageAsync();
  697. allPersonDeviceList.clear();
  698. allPersonDeviceList.addAll(personDeviceList);
  699. selectRecordStatus = RecordQueryStateEnum.All;
  700. keyWord = '';
  701. startDateTime = DateTime.now().subtract(Duration(days: 365 * 3));
  702. endDateTime = DateTime.now();
  703. update(["record_time_filter"]);
  704. await searchFindRecordPages();
  705. }
  706. Future<void> refreshData() async {
  707. ///置空右侧的图像列表和报告列表
  708. selectedIndex = -1;
  709. state.selectedTabIndex = 0;
  710. state.measureImages = [];
  711. state.aiImages = [];
  712. state.reports = [];
  713. state.remedicalListResult = RemedicalListResult();
  714. await searchFindRecordPages();
  715. }
  716. /// 获取机构列表
  717. Future<void> getOrganizationByUserAndDevicesAsync() async {
  718. try {
  719. //busy = true;
  720. // var result = await userInfoManager.getOrganizationByUserAndDevices(
  721. // pageIndex: 1,
  722. // pageSize: 50,
  723. // );
  724. // organizationsCount = result.dataCount;
  725. // organizationLocatedList = result.pageData
  726. // ?.map((e) => FMutiSelectModel(
  727. // name: e.organizationName!, code: e.organizationCode!))
  728. // .toList() ??
  729. // [];
  730. // orgFilterController.text =
  731. // organizationLocatedList.map((element) => element.name).join('、');
  732. // busy = false;
  733. } catch (e) {
  734. printError(
  735. info:
  736. "getOrganizationByUserAndDevicesAsync exception:" + e.toString());
  737. logger.e("getOrganizationByUserAndDevicesAsync exception:", e);
  738. //busy = false;
  739. }
  740. }
  741. /// 结束扫查
  742. ///
  743. /// [desktopListSelectedRecordCode] 检查code
  744. Future<void> endScan(
  745. FInteractiveContainer businessParent,
  746. ) async {
  747. try {
  748. FConfirmAlert.show(
  749. businessParent: businessParent,
  750. context: Get.context!,
  751. title: i18nBook.common.tip.t,
  752. subTitle: i18nBook.remedical.finishScan.t,
  753. cancelLabel: i18nBook.common.cancel.t,
  754. confrimLabel: i18nBook.common.confirm.t,
  755. onCancel: () async {
  756. // await busyHandle(
  757. // () async {},
  758. // text: i18nBook.remedical.finishing.t,
  759. // );
  760. },
  761. onConfirm: () async {
  762. // await busyHandle(
  763. // () async {
  764. // final finishRecordAsync = await rpc.recordInfo.finishRecordAsync(
  765. // FinishRecordRequest(
  766. // recordCode: desktopListSelectedRecordCode,
  767. // token: Store.user.token,
  768. // ),
  769. // );
  770. // if (finishRecordAsync) {
  771. // PromptBox.toast(i18nBook.user.operationSuccess.t);
  772. // await findRecordPages();
  773. // } else {
  774. // PromptBox.toast(i18nBook.user.operationFailed.t);
  775. // }
  776. // },
  777. // text: i18nBook.remedical.finishing.t,
  778. // );
  779. },
  780. );
  781. } catch (e) {
  782. printError(info: "setVaildPatient exception:" + e.toString());
  783. logger.e("setVaildPatient exception:", e);
  784. }
  785. }
  786. /// 删除检查
  787. ///
  788. /// [desktopListSelectedRecordCode] 检查code
  789. Future<bool> deleteRecord(
  790. String recordCode,
  791. FInteractiveContainer businessParent,
  792. ) async {
  793. Completer deleteCompleter = Completer<bool>();
  794. FConfirmAlert.show(
  795. businessParent: businessParent,
  796. context: Get.context!,
  797. title: i18nBook.common.tip.t,
  798. subTitle: i18nBook.setting.confirmDeletion.t,
  799. cancelLabel: i18nBook.common.cancel.t,
  800. confrimLabel: i18nBook.common.confirm.t,
  801. onCancel: () {
  802. deleteCompleter.complete(false);
  803. },
  804. onConfirm: () async {
  805. try {
  806. final result = await rpc.recordInfo.deleteRecordAsync(
  807. DeleteRecordRequest(
  808. recordCode: recordCode,
  809. token: Store.user.token,
  810. ),
  811. );
  812. if (result) {
  813. Get.find<ImagereportinnerviewController>().clear();
  814. /// 下一帧执行
  815. await findRecordPages();
  816. await Future.delayed(Duration(milliseconds: 200));
  817. PromptBox.toast(i18nBook.measure.annotationDeleted.translate([""]));
  818. deleteCompleter.complete(true);
  819. } else {
  820. PromptBox.toast(i18nBook.user.deleteFailed.t);
  821. deleteCompleter.complete(false);
  822. }
  823. } catch (e) {
  824. deleteCompleter.complete(false);
  825. if (e is JsonRpcException) {
  826. if (e.data.code == 4068) {
  827. PromptBox.toast(i18nBook.errorCodes.errorCode4001.t);
  828. }
  829. }
  830. }
  831. },
  832. );
  833. bool success = await deleteCompleter.future;
  834. return success;
  835. }
  836. ///打开采集页面
  837. Future<void> openCapturePage(String medicalNumber) async {
  838. if (medicalNumber.isEmpty) {
  839. return;
  840. }
  841. var queryData = await Get.find<IPatientManager>()
  842. .getRegisterPersonInfoByPhysicalExamNumberAsync(
  843. physicalExamNumber: medicalNumber);
  844. if (queryData != null && queryData.code != null) {
  845. var scanningImageManager = Get.find<IScanningImage>();
  846. bool canScanning = await scanningImageManager.checkCollectingImgAsync();
  847. if (canScanning) {
  848. var recordInfo = await scanningImageManager
  849. .getVitalRecordByPhysicalExamNumberAsync(medicalNumber);
  850. scanningImageManager.startScan(recordInfo.recordCode ?? '');
  851. Get.dialog(
  852. VAlertDialog(
  853. title: "图像采集-居民[${queryData.name}]",
  854. width: 500,
  855. content: CapturePage(),
  856. showCancel: false,
  857. confirmLabel: "完成",
  858. onConfirm: () {
  859. Get.back();
  860. scanningImageManager.endScan(recordInfo.recordCode ?? '');
  861. },
  862. ),
  863. );
  864. }
  865. } else {
  866. PromptBox.toast("体检号不存在");
  867. }
  868. }
  869. /// 获取设备列表
  870. Future<void> getPersonDeviceDropdownPageAsync() async {
  871. try {
  872. if (organizationLocatedList.isEmpty) {
  873. personDeviceList = [];
  874. personDeviceCount = 0;
  875. isSelectAllDevice = false;
  876. } else {
  877. // var result = await userInfoManager.getPersonDeviceDropdownPage(
  878. // index: 1,
  879. // pageSize: 50,
  880. // restrictOrgCodes: selectedOrganizationLocated,
  881. // isIncloudReferral: true,
  882. // );
  883. // personDeviceList = result.pageData
  884. // ?.map((e) =>
  885. // FMutiSelectModel(code: e.key ?? '', name: e.value ?? ''))
  886. // .toList() ??
  887. // [];
  888. // personDeviceCount = result.dataCount;
  889. }
  890. deviceFilterController.text =
  891. personDeviceList.map((e) => e.name).join('、');
  892. } catch (e) {
  893. printError(
  894. info: "getPersonDeviceDropdownPageAsync exception:" + e.toString());
  895. logger.e("getPersonDeviceDropdownPageAsync exception:", e);
  896. }
  897. }
  898. // 移动端查看检查详情
  899. void openRecordDetailPage(
  900. String recordCode, String patientCode, String devicePatientID) async {
  901. print('openRecordDetailPage $recordCode');
  902. QueryRecordResult? newCheckInfo =
  903. await remedicalManager.queryRecordInfoAsync(recordCode);
  904. // 数据载入
  905. if (newCheckInfo != null) {
  906. checkInfo = newCheckInfo;
  907. mobileDetailPageRecordCode = recordCode;
  908. }
  909. }
  910. /// 翻译
  911. String getValues(String code) {
  912. try {
  913. return languageConfigManager.getExamLanguageValue(code);
  914. } catch (e) {
  915. print(e);
  916. }
  917. return code;
  918. }
  919. @override
  920. void onReady() {
  921. super.onReady();
  922. }
  923. /// 在 [onDelete] 方法之前调用。
  924. @override
  925. void onClose() {
  926. super.onClose();
  927. }
  928. /// dispose 释放内存
  929. @override
  930. void dispose() {
  931. reportManager.onSubmitReport
  932. .removeListener(remedicalController.onSubmitReport);
  933. remedicalController.dispose();
  934. super.dispose();
  935. animationController.dispose();
  936. }
  937. void _initListener() {
  938. reportManager.onSubmitReport
  939. .addListener(remedicalController.onSubmitReport);
  940. }
  941. }