package thyyxxk.webserver.service.inpatient; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import thyyxxk.webserver.config.exception.BizException; import thyyxxk.webserver.config.exception.ExceptionEnum; import thyyxxk.webserver.constants.Capacity; import thyyxxk.webserver.constants.sidicts.MedType; import thyyxxk.webserver.constants.sidicts.PsnCertType; import thyyxxk.webserver.dao.his.inpatient.PatientDao; import thyyxxk.webserver.dao.his.inpatient.Routines; import thyyxxk.webserver.dao.his.zhuyuanyisheng.YiZhuLuRuDao; import thyyxxk.webserver.entity.ResultVo; import thyyxxk.webserver.entity.dictionary.CodeName; import thyyxxk.webserver.entity.drg.BaseInfo; import thyyxxk.webserver.entity.drg.DiseInfoList; import thyyxxk.webserver.entity.drg.OprtInfoList; import thyyxxk.webserver.entity.inpatient.dismiss.ZyDisYbDiag; import thyyxxk.webserver.entity.inpatient.patient.*; import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.HuanZheFeiYong; import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYiZhu; import thyyxxk.webserver.http.drg.DrgWebApi; import thyyxxk.webserver.service.hutoolcache.UserCache; import thyyxxk.webserver.service.zhuyuanyisheng.emr.EmrServer; import thyyxxk.webserver.utils.*; import java.text.SimpleDateFormat; import java.util.*; /** * @author dj */ @Slf4j @Service public class PatientService { private static final String ZD_MEDCN = "yp_zd_dict"; private final PatientDao dao; private final Routines routines; private final YiZhuLuRuDao yiZhuLuRuDao; private final EmrServer emrServer; private final DrgWebApi drgWebApi; private final UserCache userCache; @Autowired public PatientService(PatientDao dao, Routines routines, YiZhuLuRuDao yiZhuLuRuDao, EmrServer emrServer, DrgWebApi drgWebApi, UserCache userCache) { this.dao = dao; this.routines = routines; this.yiZhuLuRuDao = yiZhuLuRuDao; this.emrServer = emrServer; this.drgWebApi = drgWebApi; this.userCache = userCache; } public ResultVo> getOverView(String ward, Boolean viewBabies) { ward = "%" + ward + "%"; String sql = ""; if (!viewBabies) { sql = "and charindex('$',a.inpatient_no)=0 "; } return ResultVoUtil.success(dao.getOverView(ward, TokenUtil.getInstance().getTokenUserId(), sql)); } public ResultVo getPatientInfo(String inpatientNo) { Patient data = dao.getPatientInfo(inpatientNo, "zy_actpatient", 0); if (null == data) { return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有住院号【" + inpatientNo + "】的在院业务!"); } if (null != data.getAdmdvs()) { Integer parentRegion = dao.selectParentRegion(data.getAdmdvs()); if (null != parentRegion) { if (parentRegion == 100000) { parentRegion = data.getAdmdvs(); } data.setAdmdvsCascader(new Integer[]{parentRegion, data.getAdmdvs()}); } } setExpenseInformation(data); return ResultVoUtil.success(data); } public ResultVo getDisPatient(String inpatientNo, Integer times) { Patient data = dao.getPatientInfo(inpatientNo, "zy_inactpatient", times); if (null == data) { return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有住院号【" + inpatientNo + "】的出院业务!"); } setExpenseInformation(data); return ResultVoUtil.success(data); } public ResultVo getPatientAll(String inpatientNo, Integer times) { Patient data = dao.getPatientInfo(inpatientNo, "view_zy_patient_all", times); if (null == data) { return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有住院号【" + inpatientNo + "】住院业务!"); } setExpenseInformation(data); return ResultVoUtil.success(data); } public Patient getPatientBaseInfo(String inpatientNo, Integer times, String inOutStatusFlag) { Patient data = dao.getPatientInfo(inpatientNo, "1".equals(inOutStatusFlag) ? "zy_inactpatient" : "zy_actpatient", times); String msg = "1".equals(inOutStatusFlag) ? "出院" : "在院"; if (null == data) { throw new BizException(ExceptionEnum.LOGICAL_ERROR, "没有住院号【" + inpatientNo + "】的" + msg + "业务!"); } setExpenseInformation(data); return data; } public ResultVo getDrgPatInfo(Patient p) { BaseInfo bf = new BaseInfo(); bf.setVisitId(p.getInpatientNo() + "_" + p.getAdmissTimes() + "_" + p.getLedgerSn()) .setGend(p.getSex().toString()) .setBrdy(p.getBirthDate()) .setAge(p.getAge().toString()) .setNwbAge("") .setNwbBirWt("") .setNwbAdmWt("") .setAdmTime(p.getAdmissDate()) .setActIptDays(String.valueOf(DateUtil.daysBetween(new Date(), p.getAdmissDate()))) .setTotalFee(p.getTotalCharge()) .setCdntnPay("") .setIllPay(""); JSONObject upload = new JSONObject(); upload.put("base_info", bf); upload.put("dise_info_list", setDrgDisList(p)); upload.put("oprt_info_list", setOprtInfoList(p)); JSONObject res = drgWebApi.getDrgCaseQualityControlGroup(upload); if (res.getInteger("code") == 0) { if (res.getJSONObject("result") != null) { JSONArray groupInfo = res.getJSONObject("result").getJSONArray("group_info"); if (groupInfo != null) { JSONObject item = groupInfo.getJSONObject(0); return ResultVoUtil.success(item); } } } return ResultVoUtil.success(); } private List setDrgDisList(Patient p) { List list = new ArrayList<>(); JSONObject emrJs = emrServer.getEmrPatientData(p.getInpatientNo(), p.getAdmissTimes()); String id = p.getInpatientNo() + "_" + p.getAdmissTimes() + "_" + p.getLedgerSn(); try { JSONArray disList = emrJs.getJSONArray("入院诊断"); for (int i = 0; i < disList.size(); i++) { DiseInfoList temp = new DiseInfoList(); JSONObject item = disList.getJSONObject(i); try { temp.setVisitId(id) .setDiagCode(item.getString("code")) .setDiagName(item.getString("name")) .setMaindiagFlag(i == 0 ? "1" : "0") .setSortNo(String.valueOf(i + 1)); list.add(temp); } catch (Exception ignored) { } } } catch (Exception ignored) { } return list; } private List setOprtInfoList(Patient p) { String id = p.getInpatientNo() + "_" + p.getAdmissTimes() + "_" + p.getLedgerSn(); List list = new ArrayList<>(); JSONArray emrList = emrServer.getPatientSurgery(p.getInpatientNo(), p.getAdmissTimes()); for (int i = 0; i < emrList.size(); i++) { JSONObject item = emrList.getJSONObject(i); JSONObject oprtName; try { oprtName = item.getJSONObject("手术名称"); } catch (Exception e) { continue; } if (oprtName == null) { continue; } JSONArray oprtNameVals = null; try { oprtNameVals = oprtName.getJSONArray("value"); } catch (Exception ignored) { } if (null == oprtNameVals) { continue; } for (int j = 0; j < oprtNameVals.size(); j++) { JSONObject opList = oprtNameVals.getJSONObject(j); OprtInfoList op = new OprtInfoList(); op.setVisitId(id) .setOprnOprtType((i + j) == 0 ? "1" : "2") .setOprnOprtCode(opList.getString("code")) .setOprnOprtName(opList.getString("name")) .setSortNo(String.valueOf((i + j) + 1)); list.add(op); } } return list; } /** * 设置患者费用信息 * * @param data 患者数据 */ private void setExpenseInformation(@NotNull Patient data) { data.setMedTypeName(MedType.getName(data.getMedType())); data.setDutyNurseName(userCache.getEmployeeName(data.getDutyNurse())); HuanZheFeiYong feiYongZhanBi = yiZhuLuRuDao.feiYongXinXi(data.getInpatientNo(), data.getAdmissTimes(), data.getLedgerSn()); if (feiYongZhanBi != null) { // 余额 data.setBalance(feiYongZhanBi.getBalance()); // 总费用 data.setTotalCharge(feiYongZhanBi.getTotalCharge()); // 药品 百分比 data.setYp(DecimalUtil.getPercent(Double.parseDouble(feiYongZhanBi.getYp()), Double.parseDouble(feiYongZhanBi.getTotalCharge()))); // 检验检查 百分比 data.setJyjc(DecimalUtil.getPercent(Double.parseDouble(feiYongZhanBi.getJyjc()), Double.parseDouble(feiYongZhanBi.getTotalCharge()))); // 医保 费用 data.setChargeYb(feiYongZhanBi.getChargeYb()); // 医保百分比 data.setYb(DecimalUtil.getPercent(Double.parseDouble(feiYongZhanBi.getChargeYb()), Double.parseDouble(feiYongZhanBi.getTotalCharge()))); } XinZhenYiZhu xinZhenYiZhu = yiZhuLuRuDao.queryPatientInfo(data.getInpatientNo(), data.getAdmissTimes()); if (xinZhenYiZhu != null) { // 是否出纳 data.setTimesBilled(xinZhenYiZhu.getTimesBilled()); } if (null != data.getSocialNo() && data.getSocialNo().trim().length() == 18 && !data.getSocialNo().startsWith("K")) { try { // 根据身份证计算出生年龄 data.setBirthDate(getBirthdayFromSocialNo(data.getSocialNo())); } catch (Exception e) { log.error("设置出生日期出错"); } } data.setCrmName(getCrm(data.getSocialNo())); try { // 年龄 data.setAge(DateUtil.calculateAge(new SimpleDateFormat("yyyy-MM-dd").parse(data.getBirthDate()), data.getAdmissDate())); } catch (Exception e) { log.error("计算年龄出错"); } } private @NotNull String getCrm(String socialNo) { String chronicDiseaseTypes = dao.getCrmBySocialNo(socialNo); if (StringUtil.isBlank(chronicDiseaseTypes)) { return ""; } String[] types = chronicDiseaseTypes.split(","); StringBuilder sb = new StringBuilder(); for (String type : types) { sb.append(",'").append(type).append("'"); } List typeList = dao.getCrmTypeName(sb.substring(1)); if (ListUtil.isBlank(typeList)) { return ""; } return String.join(",", typeList); } private String getBirthdayFromSocialNo(String socialNo) { String birth = socialNo.substring(6, 14); String year = birth.substring(0, 4); String month = birth.substring(4, 6); String day = birth.substring(6, 8); return year + "-" + month + "-" + day; } public ResultVo> getDisDiag(String inpatientNo, Integer admissTimes) { HashMap map = new HashMap<>(Capacity.TWO); map.put("yb", dao.getYibaoDisDiags(inpatientNo, admissTimes)); map.put("bl", dao.getBingliDisDiags(inpatientNo, admissTimes)); return ResultVoUtil.success(map); } public ResultVo> getNotUploadedFees(GetFeesParam param) { Integer ledgerSn = routines.selectMaxLedgerSn(param.getPatNo(), param.getTimes()); if (null == ledgerSn) { ledgerSn = 1; } IPage iPage = new Page<>(param.getCurrentPage(), param.getPageSize()); Map map = new HashMap<>(Capacity.THREE); String serial1 = "00"; String serial2 = ""; if (param.getZdTable().equals(ZD_MEDCN)) { serial1 = "01"; serial2 = "99"; } iPage = param.getInjuryMode() ? routines.selectInjuryNotUploadedFees(iPage, param.getZdTable(), param.getPatNo(), param.getTimes(), ledgerSn, DateUtil.getTodayEndTime(), serial1, serial2) : routines.selectNotUploadedFees(iPage, param.getZdTable(), param.getPatNo(), param.getTimes(), ledgerSn, DateUtil.getTodayEndTime(), serial1, serial2); map.put("totalSize", iPage.getTotal()); map.put("list", iPage.getRecords()); map.put("sum", routines.selectSumChargeFee(param.getPatNo(), param.getTimes(), ledgerSn, DateUtil.getTodayEndTime(), serial1, serial2)); return ResultVoUtil.success(map); } public ResultVo> getIdCardInfo(String inpatientNo, Integer admissTimes) { Patient patient = dao.getPatientInfo(inpatientNo, "zy_actpatient", 0); if (null == patient) { patient = dao.getPatientInfo(inpatientNo, "zy_inactpatient", admissTimes); } String birthDate = DateUtil.calculateBirthDateFromIdNumber(patient.getSocialNo()); if (null != birthDate) { patient.setBirthDate(birthDate); } List idCard = dao.selectIdCard(patient.getSocialNo()); if (idCard.isEmpty()) { idCard = dao.getIdCard(inpatientNo, admissTimes); if (idCard.isEmpty()) { idCard = dao.getScanFile(inpatientNo, admissTimes); } } if (idCard.isEmpty()) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "没有查询到此患者的身份证或扫描件,请检查身份证号是否有误。"); } Map map = new HashMap<>(); map.put("idCard", idCard.get(0)); map.put("patient", patient); return ResultVoUtil.success(map); } /** * requestType: 1 - 取消医保登记申请 2 - 出院结算申请 */ public ResultVo> getCancelRegisterRequests(String inpatientNo, Integer admissTimes, Integer requestType) { // settleType: 0-其他, 1-已结算未出纳, 4-已出纳, 3-中间结算 Integer settleType = dao.getSettleType(inpatientNo, admissTimes); if (settleType > 1) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "此患者已经出纳,不可进行取消医保登记的操作。"); } else { return ResultVoUtil.success(dao.getRetractRequests(inpatientNo, admissTimes, requestType)); } } public ResultVo submitCancelRegisterRequest(ToYbkRequest param) { param.setInputId(TokenUtil.getInstance().getTokenUserId()); Integer count = dao.getRequestCount(param.getInpatientNo(), param.getAdmissTimes(), param.getRequestType()); param.setInputTimes(++count); log.info("提交取消医保登记请求>>> {}", param); dao.submitNewRequest(param); return ResultVoUtil.success(); } @Transactional(rollbackFor = Exception.class) public ResultVo submitSiPatientYbInfo(SubmitSiPtnt param) { Patient patient = param.getPatient(); patient.setStaffId(TokenUtil.getInstance().getTokenUserId()); MedType medType = MedType.get(patient.getMedType()); if (null == medType) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "请选择患者的医疗类别!"); } if (medType == MedType.MATERNITY_HOSPITALIZATION) { if (StringUtil.isBlank(patient.getMatnType())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "生育类别不能为空!"); } if (StringUtil.isBlank(patient.getLatechbFlag())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "是否晚育不能为空!"); } if (StringUtil.isBlank(patient.getPretFlag())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "是否早产不能为空!"); } } if (medType == MedType.MATERNITY_HOSPITALIZATION || medType == MedType.SINGLE_DISEASE_HOSPITALIZATION) { if (StringUtil.isBlank(patient.getDiseCode())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者病种不能为空!"); } } if (StringUtil.isBlank(patient.getPsnCertType())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "证件类型不能为空!"); } if (StringUtil.isBlank(patient.getDutyNurse())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "责任护士不能为空!"); } if (StringUtil.isBlank(patient.getReferPhysician())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "管床医生不能为空!"); } if (StringUtil.isBlank(patient.getCountry())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "国籍不能为空!"); } if (StringUtil.isBlank(patient.getNation())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "民族不能为空!"); } if (StringUtil.isBlank(patient.getContactName())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "联系人不能为空!"); } if (StringUtil.isBlank(patient.getContactRelation())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "联系人关系不能为空!"); } if (StringUtil.isBlank(patient.getContactAddrName())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "联系人地址不能为空!"); } if (StringUtil.isBlank(patient.getContactPhone())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "联系人电话不能为空!"); } Integer age = patient.getAge(); if (patient.getPsnCertType().equals(PsnCertType.RESIDENT_IDENTITY_CARD.getCode())) { if (!IdCardUtil.isValidatedIdCard(patient.getSocialNo())) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "身份证不合法!"); } age = IdCardUtil.getAgeByIdCard(patient.getSocialNo()); patient.setSocialNo(patient.getSocialNo().toUpperCase()); } if (null != age && (age < 16 || age > 60)) { if (patient.getName().equals(patient.getContactName()) || patient.getContactRelation().equals("0")) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "16岁以下或60岁以上的患者,联系人不能填写本人。"); } } String zyh = patient.getInpatientNo(); int times = patient.getAdmissTimes(); for (int i = 0; i < param.getDiags().size(); i++) { ZyInYbDiag diag = param.getDiags().get(i); diag.setInpatientNo(zyh); diag.setAdmissTimes(times); } patient.setResponceType(medType.getResponceType()); log.info("【操作员:{}】保存患者信息:{} ", patient.getStaffId(), param); if (dao.isBatjBa2Exist(patient.getInpatientNo(), patient.getAdmissTimes()) == 0) { dao.createBatjBa2(patient.getInpatientNo(), patient.getAdmissTimes(), patient.getDutyNurse()); } else { dao.updateBatjBa2(patient.getInpatientNo(), patient.getAdmissTimes(), patient.getDutyNurse()); } dao.updateZyActpatient(patient); dao.updateAPatientMi(patient); dao.deleteOldZyInYbDiag(zyh, times); if (ListUtil.notBlank(param.getDiags())) { for (ZyInYbDiag diag : param.getDiags()) { if (null == diag.getOpDate()) { diag.setOpDate(new Date()); } } dao.insertNewZyInYbDiag(patient.getStaffId(), param.getDiags()); } return ResultVoUtil.success(); } public ResultVo> getZyInYbDiags(String inpatientNo, int admissTimes) { return ResultVoUtil.success(dao.getZyInYbDiag(inpatientNo, admissTimes)); } public ResultVo> getZyDisYbDiags(String inpatientNo, int admissTimes) { return ResultVoUtil.success(dao.getZyDisYbDiags(inpatientNo, admissTimes)); } @Transactional(rollbackFor = Exception.class) public ResultVo saveZyInYbDiags(List list) { final String opId = TokenUtil.getInstance().getTokenUserId(); log.info("保存医保诊断表:操作员:{},诊断:{}", opId, list); if (list == null || list.isEmpty()) { return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有要保存的数据。"); } final String inpatientNo = list.get(0).getInpatientNo(); final Integer times = list.get(0).getAdmissTimes(); dao.deleteOldZyInYbDiag(inpatientNo, times); dao.insertNewZyInYbDiag(opId, list); return ResultVoUtil.success(); } @Transactional(rollbackFor = Exception.class) public ResultVo saveSiZyInDiags(SaveSiZyDiags param) { param.setStaffId(TokenUtil.getInstance().getTokenUserId()); log.info("保存医保诊断表:操作员:{},诊断:{}", param.getStaffId(), param); if (param.getDiags() == null || param.getDiags().isEmpty()) { return ResultVoUtil.fail(ExceptionEnum.NULL_POINTER, "没有要保存的数据。"); } dao.deleteOldZyInYbDiag(param.getInpatientNo(), param.getAdmissTimes()); dao.insertSiZyInYbDiag(param); return ResultVoUtil.success(); } public ResultVo genDismissActOrder(Patient param) { String disdate = dao.getActOrderDisDate(param.getInpatientNo(), param.getAdmissTimes()); if (null != disdate) { return ResultVoUtil.fail(ExceptionEnum.LOGICAL_ERROR, "患者【" + param.getName() + "】已经存在出院医嘱!"); } String staffId = TokenUtil.getInstance().getTokenUserId(); float orderNo = dao.getActOrderNo(); dao.updateActorOrderNo(orderNo + 1); dao.insertNewDismissActOrder(orderNo, param.getInpatientNo(), param.getAdmissTimes(), param.getDismissOrderDate(), staffId, param.getAdmissWard()); List zyDisYbDiags = dao.getDisDiags(param.getInpatientNo(), param.getAdmissTimes()); if (null == zyDisYbDiags || zyDisYbDiags.isEmpty()) { List inYbDiags = dao.getZyInYbDiag(param.getInpatientNo(), param.getAdmissTimes()); if (null == inYbDiags || inYbDiags.isEmpty()) { CodeName diag = dao.getAdmissDiag(param.getInpatientNo(), param.getAdmissTimes()); dao.insertDisDiag(param.getInpatientNo(), param.getAdmissTimes(), diag.getCode(), diag.getName(), staffId); } else { inYbDiags.forEach(itm -> { itm.setSiDiagType(1); }); dao.insertDisDiags(staffId, inYbDiags); } } return ResultVoUtil.success(String.valueOf(orderNo)); } public ResultVo receiveAndRecalculateCost(Patient p) { String zyh = p.getInpatientNo(); int times = p.getAdmissTimes(); int infant = zyh.startsWith("$") ? 1 : 0; int ledger = p.getLedgerSn(); dao.correctFeeChargeTimeBeforeAdmiss(zyh, times, p.getAdmissDate(), DateUtil.timePlusSecond(p.getAdmissDate(), 60)); Date disdate = dao.selectActOrderDisDate(zyh, times); if (null != disdate) { // 如果费用发生时间小于入院时间那么就加一分钟。 dao.correctFeeChargeTimeAfterDismiss(zyh, times, disdate); } dao.recountDeposit(zyh, times, ledger); dao.zyReceiveDrug(zyh, times, infant); dao.zyReceiveOne(zyh, times, infant); dao.zyCnglFyjsListYz(zyh, times); dao.updateZyDetailCharge(zyh, times, ledger); dao.zyCalcDetailAgainNew(zyh, times, ledger); dao.updateBalance(zyh, times, ledger); String balance = dao.selectLedgerBalance(zyh, times, ledger); if (StringUtil.isBlank(balance)) { balance = "0"; } dao.updateZyActPatientBalance(zyh, balance); return getPatientInfo(zyh); } }