patient.dart 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. import 'dart:convert';
  2. import 'package:fis_jsonrpc/rpc.dart';
  3. import 'package:flutter/foundation.dart';
  4. import 'package:vital_local_database/core/interface/queryable.dart';
  5. import 'package:vitalapp/database/db.dart';
  6. import 'package:vitalapp/database/entities/defines.dart';
  7. import 'package:vitalapp/database/entities/patient.dart';
  8. import 'package:vitalapp/global.dart';
  9. import 'package:vitalapp/managers/interfaces/models/patient_model_dto.dart';
  10. import 'package:vitalapp/managers/interfaces/patient.dart';
  11. import 'package:vitalapp/mock/services/patient.dart';
  12. import 'package:vitalapp/pages/patient/info/widgets/ext_model.dart';
  13. import 'package:vitalapp/rpc.dart';
  14. import 'package:fis_common/logger/logger.dart';
  15. import 'package:vitalapp/store/store.dart';
  16. class PatientManager implements IPatientManager {
  17. String? get userCode => Store.user.userCode;
  18. @override
  19. Future<String?> create(CreatePatientRequest2 request) async {
  20. request.token = Store.user.token;
  21. request.code = request.cardNo;
  22. final result = await rpc.vitalPatient.createPatientAsync(request);
  23. return result;
  24. }
  25. @override
  26. Future<List<PatientModelDTO>?> getPagedOfflineList(
  27. String? keyword,
  28. DateTime? startTime,
  29. DateTime? endTime,
  30. ) async {
  31. final isKeywordQuery = keyword != null && keyword.isNotEmpty;
  32. var query = db.repositories.patient.queryable.where((x) {
  33. final List<IDbColumnCondition> arr = [];
  34. arr.add(x.isValid.equals(true));
  35. arr.add(x.orgCode.equals(Store.user.organizationCode));
  36. arr.add(x.overallSyncState.notEquals(OfflineDataSyncState.success));
  37. if (!isKeywordQuery) {}
  38. return arr;
  39. });
  40. if (isKeywordQuery) {
  41. // 根据 姓名or身份证号 模糊查询
  42. query = query.whereCustom(
  43. " AND ( name like '%$keyword%' OR code like '%$keyword%' ) ");
  44. } else {
  45. if (startTime != null) {
  46. query = query.and((x) => x.createTime.gte(startTime));
  47. }
  48. if (endTime != null) {
  49. query = query.and((x) => x.createTime.lt(endTime));
  50. }
  51. }
  52. final entities =
  53. await query.orderBy((x) => x.updateTime, DbOrderByType.desc).toList();
  54. final dtos = entities.map((e) {
  55. var patientModel = PatientModelDTO.fromJson(jsonDecode(e.dataJson));
  56. patientModel.isExistLocalData = true;
  57. return patientModel;
  58. }).toList();
  59. return dtos;
  60. }
  61. @override
  62. Future<PatientDTO?> getDetail(String code) async {
  63. final request = GetPatientRequest(code: code, token: Store.user.token);
  64. try {
  65. if (kIsOnline && !kIsWeb) {
  66. //在线状态,先查询是否存在本地未提交数据
  67. final entity = await db.repositories.patient
  68. .singleByCodeWithUserCode(code, Store.user.userCode!);
  69. if (entity != null &&
  70. entity.dataJson.isNotEmpty &&
  71. entity.syncState != OfflineDataSyncState.success) {
  72. logger.i("PatientManager query patient detail location exist.");
  73. final jsonMap = jsonDecode(entity.dataJson);
  74. final dto = PatientDTO.fromJson(jsonMap);
  75. return dto;
  76. } else {
  77. logger.i("PatientManager query patient detail location not exist.");
  78. }
  79. }
  80. final result = await rpc.vitalPatient.getPatientDetailAsync(request);
  81. return result;
  82. } catch (e) {
  83. logger.e("PatientManager query patient detail error.", e);
  84. logger.i("GetPatientRequest: ${jsonEncode(request.toJson())}");
  85. return null;
  86. }
  87. }
  88. @override
  89. Future<PageCollection<PatientModelDTO>?> getPagedList(
  90. PatientPageRequest request) async {
  91. PageCollection<PatientModelDTO>? listPatientDto =
  92. PageCollection<PatientModelDTO>();
  93. try {
  94. request.token = Store.user.token;
  95. print(jsonEncode(request.toJson()));
  96. final result = await rpc.vitalPatient.getPatientPageAsync(request);
  97. listPatientDto.dataCount = result.dataCount;
  98. listPatientDto.pageData = [];
  99. for (var element in result.pageData!) {
  100. var patientModel = PatientModelDTO.fromJson(element.toJson());
  101. if (!kIsWeb) {
  102. var isNotUploadedPatient =
  103. await db.repositories.patient.isNotUploadedPatient(element.code!);
  104. if (isNotUploadedPatient) {
  105. patientModel.isExistLocalData = true;
  106. }
  107. }
  108. listPatientDto.pageData?.add(patientModel);
  109. }
  110. return listPatientDto;
  111. } catch (e) {
  112. logger.e("PatientManager query patient paged list error.", e);
  113. return null;
  114. }
  115. }
  116. @override
  117. Future<bool> updatePatientAsync(UpdatePatientRequest2 request) async {
  118. try {
  119. if (kIsOnline) {
  120. await _updateLocationPatientAsync(request);
  121. }
  122. final result = await rpc.vitalPatient.updatePatientAsync(request);
  123. return result;
  124. } catch (e) {
  125. return false;
  126. }
  127. }
  128. ///在线编辑居民信息时,同步更改本地缓存
  129. Future<bool> _updateLocationPatientAsync(
  130. UpdatePatientRequest2 request) async {
  131. final code = request.code!;
  132. final existEntity = await _checkPatientExist(code);
  133. PatientEntity entity;
  134. PatientDTO dto;
  135. if (existEntity == null) {
  136. entity = PatientEntity();
  137. entity.code = request.code!;
  138. entity.isValid = true;
  139. entity.name = request.patientName!;
  140. entity.userCode = Store.user.userCode!; //添加用户code
  141. entity.syncState = OfflineDataSyncState.success;
  142. dto = PatientDTO();
  143. ModelConverter.syncUpdate2Dto(dto, request);
  144. final dtoJson = dto.toJson();
  145. entity.dataJson = jsonEncode(dtoJson);
  146. final id = await db.repositories.patient.insert(entity);
  147. return id > 0;
  148. } else {
  149. entity = existEntity;
  150. final jsonMap = jsonDecode(entity.dataJson);
  151. dto = PatientDTO.fromJson(jsonMap);
  152. ModelConverter.syncUpdate2Dto(dto, request);
  153. final dtoJson = dto.toJson();
  154. entity.dataJson = jsonEncode(dtoJson);
  155. final rows = await db.repositories.patient.update(entity);
  156. return rows > 0;
  157. }
  158. }
  159. Future<PatientEntity?> _checkPatientExist(String code) async {
  160. try {
  161. final entity = await db.repositories.patient
  162. .singleByCodeWithUserCode(code, Store.user.userCode!);
  163. return entity;
  164. } catch (e) {
  165. logger.e(
  166. "PatientServiceMock - Check patient exist error. Code: $code.", e);
  167. }
  168. return null;
  169. }
  170. @override
  171. Future<bool> setCrowdLabelsAsync(
  172. String patientCode, List<String> crowLabels) async {
  173. try {
  174. final request = SetCrowdLabelsRequest(
  175. code: patientCode, crowdLabels: crowLabels, token: Store.user.token);
  176. final result = rpc.vitalPatient.setCrowdLabelsAsync(request);
  177. return result;
  178. } catch (e) {
  179. logger.e("PatientManager setCrowdLabelsAsync error.", e);
  180. return false;
  181. }
  182. }
  183. Future<String> createPatientExtension(
  184. String patientCode,
  185. PatientHealthInfoModel healthInfo,
  186. PatientDetailInfoModel detailInfo,
  187. String healthCode) async {
  188. final jsonMap = <String, dynamic>{};
  189. final detailJsonMap = detailInfo.toJson();
  190. final healthJsonMap = healthInfo.toJson();
  191. jsonMap.addAll(detailJsonMap);
  192. jsonMap.addAll(healthJsonMap);
  193. jsonMap.removeWhere((key, value) => value == null);
  194. if (!kIsOnline) {
  195. if (healthCode.startsWith("mock")) {
  196. healthCode = ""; // TODO:update from server
  197. }
  198. }
  199. if (healthCode.isNotEmpty) {
  200. var request = UpdatePatientExtensionRequest(
  201. code: healthCode,
  202. token: Store.user.token,
  203. patientCode: patientCode,
  204. key: "PatientHealthInfo",
  205. extensionData: jsonEncode(jsonMap),
  206. );
  207. var result = await updatePatientExtensionAsync(request);
  208. if (result) {}
  209. } else {
  210. var request = CreatePatientExtensionRequest(
  211. token: Store.user.token,
  212. patientCode: patientCode,
  213. key: "PatientHealthInfo",
  214. extensionData: jsonEncode(jsonMap),
  215. );
  216. var result = await createPatientExtensionAsync(request);
  217. if (result.isNotEmpty) {
  218. healthCode = result;
  219. }
  220. }
  221. ///更新
  222. return healthCode;
  223. }
  224. @override
  225. Future<String> createPatientExtensionAsync(
  226. CreatePatientExtensionRequest request) async {
  227. try {
  228. final result =
  229. await rpc.vitalPatientExtension.createPatientExtensionAsync(request);
  230. return result;
  231. } catch (e) {
  232. logger.e("PatientManager createPatientExtension error.", e);
  233. return '';
  234. }
  235. }
  236. @override
  237. Future<PatientExtensionDTO?> getPatientExtensionDetailByCodeAndKeyAsync(
  238. GetPatientExtensionByCodeAndKeyRequest request) async {
  239. try {
  240. final result = await rpc.vitalPatientExtension
  241. .getPatientExtensionDetailByCodeAndKeyAsync(request);
  242. return result;
  243. } catch (e) {
  244. return null;
  245. }
  246. }
  247. @override
  248. Future<bool> updatePatientExtensionAsync(
  249. UpdatePatientExtensionRequest request) async {
  250. try {
  251. final result =
  252. await rpc.vitalPatientExtension.updatePatientExtensionAsync(request);
  253. return result;
  254. } catch (e) {
  255. logger.e("PatientManager updatePatientExtension error.", e);
  256. return false;
  257. }
  258. }
  259. ///获取所有userCode为空的数据,并赋值
  260. @override
  261. Future<void> resettingUsercodeIsEmptyData() async {
  262. if (kIsWeb) return;
  263. var version = await db.database.getVersion();
  264. if (version > 0) {
  265. final list = await db.repositories.patient.queryable.where((x) {
  266. final List<IDbColumnCondition> arr = [];
  267. arr.add(x.isValid.equals(true));
  268. arr.add(x.userCode.equals(''));
  269. return arr;
  270. }).toList();
  271. logger.w(
  272. "PatientManager resettingUsercodeIsEmptyData list.count:${list.length}.");
  273. for (var element in list) {
  274. if (element.syncState == OfflineDataSyncState.success) {
  275. var result = await getDetail(element.code);
  276. if (result != null) {
  277. element.userCode = result.createdDoctor!;
  278. }
  279. } else {
  280. element.userCode = Store.user.userCode!;
  281. }
  282. await db.repositories.patient.update(element);
  283. }
  284. // 更新归属于该医生下的居民的组织Code
  285. final orgCode = Store.user.organizationCode;
  286. final userCode = Store.user.userCode;
  287. await db.database.execute(
  288. "UPDATE patients SET orgCode = '$orgCode' WHERE 1=1 AND isValid=1 AND orgCode='' AND userCode='$userCode';");
  289. }
  290. }
  291. @override
  292. Future<void> switchCurrentPatient(PatientDTO dto) async {
  293. try {
  294. if (!kIsWeb) {
  295. await _syncCloud2Offline(dto);
  296. }
  297. Store.user.currentSelectPatientInfo = dto;
  298. } catch (e) {
  299. logger.e("PatientManager switchCurrentPatient-${dto.code} error.", e);
  300. }
  301. }
  302. @override
  303. Future<void> switchCurrentPatientByCode(String code) async {
  304. final dto = await getDetail(code);
  305. if (dto != null) {
  306. await switchCurrentPatient(dto);
  307. }
  308. }
  309. @override
  310. Future<RegisterPersonInfoDTO?>
  311. getRegisterPersonInfoByPhysicalExamNumberAsync({
  312. required String physicalExamNumber,
  313. }) async {
  314. try {
  315. var request = GetRegisterPersonRequest();
  316. request.physicalExamNumber = physicalExamNumber;
  317. final registerPersonInfo = await rpc.vitalHealthExamBooking
  318. .getRegisterPersonInfoByPhysicalExamNumberAsync(
  319. request,
  320. );
  321. return registerPersonInfo;
  322. } catch (e) {
  323. logger.e(
  324. "PatientManager sync getRegisterPersonInfoByPhysicalExamNumberAsync error.",
  325. e);
  326. return null;
  327. }
  328. }
  329. @override
  330. Future<bool> removePatient(String code) async {
  331. bool result = false;
  332. try {
  333. final entity = await db.repositories.patient
  334. .singleByCodeWithUserCode(code, Store.user.userCode!);
  335. if (entity != null) {
  336. result = await db.repositories.patient.delete(entity.id);
  337. if (!result) {
  338. return false;
  339. }
  340. }
  341. if (kIsOnline) {
  342. try {
  343. // 先检查云端是否有数据
  344. final dto = await rpc.vitalPatient.getPatientDetailAsync(
  345. GetPatientRequest(code: code, token: Store.user.token),
  346. );
  347. // 然后再请求删除
  348. result = await rpc.vitalPatient.removePatientAsync(
  349. RemovePatientRequest(code: code, token: Store.user.token),
  350. );
  351. } catch (e) {
  352. logger.e("PatientManager remove cloud patient-$code error.", e);
  353. }
  354. }
  355. } catch (e) {
  356. logger.e("PatientManager remove patient-$code error.", e);
  357. result = false;
  358. }
  359. if (result) {
  360. if (Store.user.currentSelectPatientInfo?.code == code) {
  361. Store.user.currentSelectPatientInfo = null;
  362. }
  363. }
  364. return result;
  365. }
  366. @override
  367. Future<PatientStatisticDTO> getStatistic() async {
  368. try {
  369. if (!kIsOnline) {
  370. // TODO: offline statistic
  371. return PatientStatisticDTO();
  372. }
  373. final result = await rpc.vitalPatient.getPatientStatisticAsync(
  374. GetPatientStatisticRequest(token: Store.user.token));
  375. return result;
  376. } catch (e) {
  377. logger.e("PatientManager get patient statistic error.", e);
  378. return PatientStatisticDTO();
  379. }
  380. }
  381. Future<void> _syncCloud2Offline(PatientDTO dto) async {
  382. PatientEntity? entity = await db.repositories.patient
  383. .singleByCodeWithUserCode(dto.code!, Store.user.userCode!);
  384. if (entity == null) {
  385. entity = PatientEntity();
  386. entity.isValid = true;
  387. entity.code = dto.code!;
  388. entity.userCode = userCode!;
  389. entity.orgCode = Store.user.organizationCode;
  390. // 从在线数据中刚获取的,不需要同步
  391. entity.syncState = OfflineDataSyncState.success;
  392. entity.overallSyncState = OfflineDataSyncState.success;
  393. // 先创建,后面统一代码更新
  394. final id = await db.repositories.patient.insert(entity);
  395. entity.id = id;
  396. } else {
  397. if (entity.syncState != OfflineDataSyncState.success) {
  398. // 本地档案有更新,已本地数据为准
  399. return;
  400. }
  401. }
  402. entity.name = dto.patientName!;
  403. final dtoJsonMap = dto.toJson();
  404. entity.dataJson = jsonEncode(dtoJsonMap);
  405. var extDto = await getPatientExtensionDetailByCodeAndKeyAsync(
  406. GetPatientExtensionByCodeAndKeyRequest(
  407. token: Store.user.token,
  408. patientCode: dto.code,
  409. key: "PatientHealthInfo",
  410. ),
  411. );
  412. if (extDto != null && extDto.code != null) {
  413. entity.extJson = extDto.extensionData;
  414. entity.extCode = extDto.code;
  415. }
  416. await db.repositories.patient.update(entity);
  417. }
  418. }