import 'dart:convert'; import 'package:fis_jsonrpc/rpc.dart'; import 'package:flutter/foundation.dart'; import 'package:get/get.dart'; import 'package:vital_local_database/core/interface/queryable.dart'; import 'package:vitalapp/database/db.dart'; import 'package:vitalapp/database/entities/defines.dart'; import 'package:vitalapp/database/entities/patient.dart'; import 'package:vitalapp/global.dart'; import 'package:vitalapp/managers/interfaces/data_sync.dart'; import 'package:vitalapp/managers/interfaces/models/patient_model_dto.dart'; import 'package:vitalapp/managers/interfaces/patient.dart'; import 'package:vitalapp/mock/services/patient.dart'; import 'package:vitalapp/pages/patient/info/widgets/ext_model.dart'; import 'package:vitalapp/rpc.dart'; import 'package:fis_common/logger/logger.dart'; import 'package:vitalapp/store/store.dart'; import 'interfaces/models/crowd_labels.dart'; import 'interfaces/models/patient.dart'; class PatientManager implements IPatientManager { String? get userCode => Store.user.userCode; @override Future create(CreatePatientRequest2 request) async { request.token = Store.user.token; request.code = request.cardNo; if (request.code == null || request.code!.isEmpty) { logger.i("PatientManager create request.cardNo is null."); return null; } print(jsonEncode(request.toJson())); final result = await rpc.vitalPatient.createPatientAsync(request); /// 在线状态,先查询是否存在本地未提交数据 /// 在线的时候删除本地数据库数据 if (kIsOnline) { if (result.isNotEmpty) { final entity = await db.repositories.patient .singleByCodeWithUserCode(request.code!, Store.user.userCode!); if (entity != null) { final deletePatient = await db.repositories.patient.delete(entity.id); if (!deletePatient) { logger.i("PatientManager deletePatient error."); return null; } } } } return result; } @override Future?> getPagedOfflineList( String? keyword, DateTime? startTime, DateTime? endTime, ) async { final isKeywordQuery = keyword != null && keyword.isNotEmpty; var query = db.repositories.patient.queryable.where((x) { final List arr = []; arr.add(x.isValid.equals(true)); arr.add(x.userCode.equals(Store.user.userCode)); arr.add(x.overallSyncState.notEquals(OfflineDataSyncState.success)); if (!isKeywordQuery) {} return arr; }); if (isKeywordQuery) { // 根据 姓名or身份证号 模糊查询 query = query.whereCustom( " AND ( name like '%$keyword%' OR code like '%$keyword%' ) "); } else { if (startTime != null) { query = query.and((x) => x.createTime.gte(startTime)); } if (endTime != null) { query = query.and((x) => x.createTime.lt(endTime)); } } final entities = await query.orderBy((x) => x.updateTime, DbOrderByType.desc).toList(); final dtos = entities.map((e) { var patientModel = PatientModelDTO.fromJson(jsonDecode(e.dataJson)); patientModel.isExistLocalData = true; return patientModel; }).toList(); return dtos; } @override Future getDetail( String code, { bool isValidOperationDoctor = true, bool allowOfflineData = true, }) async { final request = GetPatientRequest( code: code, token: Store.user.token, isValidOperationDoctor: isValidOperationDoctor, ); try { if (kIsOnline) { if (!kIsWeb && allowOfflineData) { //在线状态,先查询是否存在本地未提交数据 final entity = await db.repositories.patient .singleByCodeWithUserCode(code, Store.user.userCode!); if (entity != null && entity.dataJson.isNotEmpty && entity.syncState != OfflineDataSyncState.success) { logger.i("PatientManager query patient detail location exist."); final jsonMap = jsonDecode(entity.dataJson); final dto = PatientDTO.fromJson(jsonMap); return dto; } else { logger.i("PatientManager query patient detail location not exist."); } } } else { if (!allowOfflineData) { return null; } } final result = await rpc.vitalPatient.getPatientDetailAsync(request); return result; } catch (e) { logger.e("PatientManager query patient detail error.", e); logger.i("GetPatientRequest: ${jsonEncode(request.toJson())}"); return null; } } @override Future getOfflineFullInfo(String code) async { try { if (kIsWeb) { return null; } final entity = await db.repositories.patient .singleByCodeWithUserCode(code, Store.user.userCode!); if (entity == null) { return null; } final jsonMap = jsonDecode(entity.dataJson); final model = PatientFullInfoModel().fromJson(jsonMap); if (entity.extJson != null && entity.extJson!.isNotEmpty) { model.extJsonMap = jsonDecode(entity.extJson!); } return model; } catch (e) { logger.e("PatientManager getOfflineFullInfo error.", e); return null; } } @override Future?> getPagedList( PatientPageRequest request) async { PageCollection? listPatientDto = PageCollection(); try { request.token = Store.user.token; print(jsonEncode(request.toJson())); final result = await rpc.vitalPatient.getPatientPageAsync(request); listPatientDto.dataCount = result.dataCount; listPatientDto.pageData = []; for (var element in result.pageData!) { var patientModel = PatientModelDTO.fromJson(element.toJson()); if (!kIsWeb) { var isNotUploadedPatient = await db.repositories.patient .isNotUploadedPatient(element.code!, Store.user.userCode!); if (isNotUploadedPatient) { patientModel.isExistLocalData = true; } } listPatientDto.pageData?.add(patientModel); } return listPatientDto; } catch (e) { logger.e("PatientManager query patient paged list error.", e); return null; } } @override Future updatePatientAsync(UpdatePatientRequest2 request) async { try { if (kIsOnline && !kIsWeb) { await _updateLocalPatientAsync(request); } final result = await rpc.vitalPatient.updatePatientAsync(request); return result; } catch (e) { return false; } } ///在线编辑居民信息时,同步更改本地缓存 Future _updateLocalPatientAsync(UpdatePatientRequest2 request) async { final code = request.code!; final existEntity = await _checkPatientExist(code); PatientEntity entity; PatientDTO dto; if (existEntity == null) { entity = PatientEntity(); entity.code = request.code!; entity.isValid = true; entity.name = request.patientName!; entity.userCode = Store.user.userCode!; //添加用户code entity.syncState = OfflineDataSyncState.success; entity.overallSyncState = OfflineDataSyncState.success; dto = PatientDTO(); ModelConverter.syncUpdate2Dto(dto, request); final dtoJson = dto.toJson(); entity.dataJson = jsonEncode(dtoJson); final id = await db.repositories.patient.insert(entity); return id > 0; } else { entity = existEntity; final jsonMap = jsonDecode(entity.dataJson); dto = PatientDTO.fromJson(jsonMap); ModelConverter.syncUpdate2Dto(dto, request); final dtoJson = dto.toJson(); entity.dataJson = jsonEncode(dtoJson); if (entity.syncState == OfflineDataSyncState.success && entity.gxyFollowUpCount == 0 && entity.tnbFollowUpCount == 0 && entity.examCount == 0 && entity.diagnosisCount == 0 && entity.tcmConsitutionCount == 0) { entity.overallSyncState = OfflineDataSyncState.success; } final rows = await db.repositories.patient.update(entity); return rows > 0; } } Future _checkPatientExist(String code) async { try { final entity = await db.repositories.patient .singleByCodeWithUserCode(code, Store.user.userCode!); return entity; } catch (e) { logger.e( "PatientServiceMock - Check patient exist error. Code: $code.", e); } return null; } @override Future setCrowdLabelsAsync( String patientCode, List crowLabels) async { try { final request = SetCrowdLabelsRequest( code: patientCode, crowdLabels: crowLabels, token: Store.user.token); final result = rpc.vitalPatient.setCrowdLabelsAsync(request); return result; } catch (e) { logger.e("PatientManager setCrowdLabelsAsync error.", e); return false; } } Future createPatientExtension( String patientCode, PatientHealthInfoModel healthInfo, PatientDetailInfoModel detailInfo, String healthCode) async { final jsonMap = {}; final detailJsonMap = detailInfo.toJson(); final healthJsonMap = healthInfo.toJson(); jsonMap.addAll(detailJsonMap); jsonMap.addAll(healthJsonMap); jsonMap.removeWhere((key, value) => value == null); if (!kIsOnline) { if (healthCode.startsWith("mock")) { healthCode = ""; // TODO:update from server } } if (healthCode.isNotEmpty) { var request = UpdatePatientExtensionRequest( code: healthCode, token: Store.user.token, patientCode: patientCode, key: "PatientHealthInfo", extensionData: jsonEncode(jsonMap), ); var result = await updatePatientExtensionAsync(request); if (result) {} } else { var request = CreatePatientExtensionRequest( token: Store.user.token, patientCode: patientCode, key: "PatientHealthInfo", extensionData: jsonEncode(jsonMap), ); var result = await createPatientExtensionAsync(request); if (result.isNotEmpty) { healthCode = result; } } ///更新 return healthCode; } @override Future createPatientExtensionAsync( CreatePatientExtensionRequest request) async { try { final result = await rpc.vitalPatientExtension.createPatientExtensionAsync(request); return result; } catch (e) { logger.e("PatientManager createPatientExtension error.", e); return ''; } } @override Future getPatientExtensionDetailByCodeAndKeyAsync( GetPatientExtensionByCodeAndKeyRequest request) async { try { final result = await rpc.vitalPatientExtension .getPatientExtensionDetailByCodeAndKeyAsync(request); return result; } catch (e) { return null; } } @override Future updatePatientExtensionAsync( UpdatePatientExtensionRequest request) async { try { final result = await rpc.vitalPatientExtension.updatePatientExtensionAsync(request); return result; } catch (e) { logger.e("PatientManager updatePatientExtension error.", e); return false; } } ///获取所有userCode为空的数据,并赋值 @override Future resettingUsercodeIsEmptyData() async { if (kIsWeb) return; var version = await db.database.getVersion(); if (version > 0) { final list = await db.repositories.patient.queryable.where((x) { final List arr = []; arr.add(x.isValid.equals(true)); arr.add(x.userCode.equals('')); return arr; }).toList(); logger.w( "PatientManager resettingUsercodeIsEmptyData list.count:${list.length}."); for (var element in list) { if (element.syncState == OfflineDataSyncState.success) { var result = await getDetail(element.code); if (result != null) { element.userCode = result.createdDoctor!; } } else { element.userCode = Store.user.userCode!; } await db.repositories.patient.update(element); } // 更新归属于该医生下的居民的组织Code final orgCode = Store.user.organizationCode; final userCode = Store.user.userCode; await db.database.execute( "UPDATE patients SET orgCode = '$orgCode' WHERE 1=1 AND isValid=1 AND orgCode='' AND userCode='$userCode';"); } } @override Future switchCurrentPatient(PatientDTO dto) async { try { if (!kIsWeb) { await _syncCloud2Offline(dto); } Store.user.currentSelectPatientInfo = dto; } catch (e) { logger.e("PatientManager switchCurrentPatient-${dto.code} error.", e); } } @override Future switchCurrentPatientByCode(String code) async { final dto = await getDetail(code); if (dto != null) { await switchCurrentPatient(dto); } } @override Future getRegisterPersonInfoByPhysicalExamNumberAsync({ required String physicalExamNumber, }) async { try { var request = GetRegisterPersonRequest(); request.physicalExamNumber = physicalExamNumber; final registerPersonInfo = await rpc.vitalHealthExamBooking .getRegisterPersonInfoByPhysicalExamNumberAsync( request, ); return registerPersonInfo; } catch (e) { logger.e( "PatientManager sync getRegisterPersonInfoByPhysicalExamNumberAsync error.", e); return null; } } @override Future removePatient(String code) async { bool result = false; try { final entity = await db.repositories.patient .singleByCodeWithUserCode(code, Store.user.userCode!); if (entity != null) { result = await db.repositories.patient.delete(entity.id); if (!result) { return false; } } if (kIsOnline) { try { // 先检查云端是否有数据 final dto = await rpc.vitalPatient.getPatientDetailAsync( GetPatientRequest(code: code, token: Store.user.token), ); // 然后再请求删除 result = await rpc.vitalPatient.removePatientAsync( RemovePatientRequest(code: code, token: Store.user.token), ); } catch (e) { logger.e("PatientManager remove cloud patient-$code error.", e); } } } catch (e) { logger.e("PatientManager remove patient-$code error.", e); result = false; } if (result) { if (Store.user.currentSelectPatientInfo?.code == code) { Store.user.currentSelectPatientInfo = null; } } return result; } @override Future getStatistic() async { try { if (!kIsOnline) { // TODO: offline statistic return PatientStatisticDTO(); } final result = await rpc.vitalPatient.getPatientStatisticAsync( GetPatientStatisticRequest(token: Store.user.token)); return result; } catch (e) { logger.e("PatientManager get patient statistic error.", e); return PatientStatisticDTO(); } } Future _syncCloud2Offline(PatientDTO dto) async { PatientEntity? entity = await db.repositories.patient .singleByCodeWithUserCode(dto.code!, Store.user.userCode!); if (entity == null) { entity = PatientEntity(); entity.isValid = true; entity.code = dto.code!; entity.userCode = userCode!; entity.orgCode = Store.user.organizationCode; // 从在线数据中刚获取的,不需要同步 entity.syncState = OfflineDataSyncState.success; entity.overallSyncState = OfflineDataSyncState.success; // 先创建,后面统一代码更新 final id = await db.repositories.patient.insert(entity); entity.id = id; } else { if (entity.syncState != OfflineDataSyncState.success) { return; } } if (Get.find().checkPatientSyncCompleted(entity)) { entity.overallSyncState = OfflineDataSyncState.success; } entity.name = dto.patientName!; final dtoJsonMap = dto.toJson(); entity.dataJson = jsonEncode(dtoJsonMap); var extDto = await getPatientExtensionDetailByCodeAndKeyAsync( GetPatientExtensionByCodeAndKeyRequest( token: Store.user.token, patientCode: dto.code, key: "PatientHealthInfo", ), ); if (extDto != null && extDto.code != null) { entity.extJson = extDto.extensionData; entity.extCode = extDto.code; } await db.repositories.patient.update(entity); } //显示的标签转换成可提交至接口的标签 List crowdLabelsConvert(List labels) { final List result = []; for (var l in labels) { //儿童和老年人这俩个标签不需要传给Server if (l != CrowdLabels.CHILDREN && l != CrowdLabels.ELDERLY) { switch (l) { case CrowdLabels.HYPERTENSION: result.add(CrowdLabelKeys.HYPERTENSION); break; case CrowdLabels.TYPE2_DIABETES: result.add(CrowdLabelKeys.TYPE2_DIABETES); break; case CrowdLabels.SUSPECTED_HYPERTENSION: result.add("CJJB_GXY_Suspected"); break; case CrowdLabels.SUSPECTED_TYPE2_DIABETES: result.add("CJJB_TNB_Suspected"); break; case CrowdLabels.MENTAlDISORDER: result.add(CrowdLabelKeys.MENTAlDISORDER); break; case CrowdLabels.TUBERCULOSIS: result.add(CrowdLabelKeys.TUBERCULOSIS); break; case CrowdLabels.PREGNAMTWOMAN: result.add(CrowdLabelKeys.PREGNAMTWOMAN); break; case CrowdLabels.SUSPECTEDTUBERCULOSIS: result.add(CrowdLabelKeys.SUSPECTEDTUBERCULOSIS); break; case CrowdLabels.SUPECTEDPSYCHOSIS: result.add(CrowdLabelKeys.SUPECTEDPSYCHOSIS); break; } } } return result; } ///将Dto中的标签转为可显示的标签 List convertLabelsFormDto(List labels) { List result = []; for (var label in labels) { switch (label) { case "RQFL_LNR": result.add(CrowdLabels.ELDERLY); break; case "RQFL_ET": result.add(CrowdLabels.CHILDREN); break; case "CJJB_GXY": result.add(CrowdLabels.HYPERTENSION); break; case "CJJB_TNB": result.add(CrowdLabels.TYPE2_DIABETES); break; case "CJJB_GXY_Suspected": result.add(CrowdLabels.SUSPECTED_HYPERTENSION); break; case "CJJB_TNB_Suspected": result.add(CrowdLabels.SUSPECTED_TYPE2_DIABETES); break; case CrowdLabelKeys.MENTAlDISORDER: result.add(CrowdLabels.MENTAlDISORDER); break; case CrowdLabelKeys.TUBERCULOSIS: result.add(CrowdLabels.TUBERCULOSIS); break; case CrowdLabelKeys.PREGNAMTWOMAN: result.add(CrowdLabels.PREGNAMTWOMAN); break; case CrowdLabelKeys.SUSPECTEDTUBERCULOSIS: result.add(CrowdLabels.SUSPECTEDTUBERCULOSIS); break; case CrowdLabelKeys.SUPECTEDPSYCHOSIS: result.add(CrowdLabels.SUPECTEDPSYCHOSIS); break; } } return result; } }