package thyyxxk.webserver.service.zhuyuanyisheng.yizhuverify; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.spring.SpringUtil; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; import thyyxxk.webserver.config.envionment.YzConfig; import thyyxxk.webserver.constants.Capacity; import thyyxxk.webserver.dao.his.zhuyuanyisheng.YiZhuLuRuDao; import thyyxxk.webserver.entity.login.UserInfo; import thyyxxk.webserver.entity.yzcheck.ChargeLimitations; import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYiZhu; import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.XinZhenYzActOrder; import thyyxxk.webserver.entity.zhuyuanyisheng.yizhuluru.YzZdOrderItemConfirm; import thyyxxk.webserver.service.hutoolcache.ExtraCache; import thyyxxk.webserver.utils.*; import java.util.*; import java.util.function.Consumer; @Slf4j public class YiZhuCheckData { private final YiZhuLuRuDao dao; private final ExtraCache extraCache = SpringUtil.getBean(ExtraCache.class); private final YzConfig yzConfig = SpringUtil.getBean(YzConfig.class); /** * 医嘱数组 */ private List list; /** * 药品 */ private final CacheOnce drug = new CacheOnce<>(); /** * 医生等级 */ private final CacheOnce authorizedDoctorLevel = new CacheOnce<>(); /** * 项目 */ private final CacheOnce> project = new CacheOnce<>(); /** * 医嘱 */ private final CacheOnce yzItem = new CacheOnce<>(); /** * 医保限制 */ private final CacheOnce yiBaoLimitation = new CacheOnce<>(); /** * 患者信息 */ private XinZhenYiZhu patientInformation; private Boolean strictVerification = false; /** * 错误信息 */ List errorMessage = new ArrayList<>(); /** * 警告信息 */ List warningMessage = new ArrayList<>(); Map returnMap = new HashMap<>(); private UserInfo userInfo; @Getter private Boolean passTheAudit = true; private final List groupList = Arrays.asList("71", "73"); private boolean checkForRestrictedMedication = false; /** * 全排斥医嘱 */ @Getter private Repel repel = null; private final String ONCE = "ONCE"; public YiZhuCheckData(YiZhuLuRuDao dao) { this.dao = dao; } public YiZhuCheckData init(List list, XinZhenYiZhu patientInformation) { userInfo = dao.selectedUserInfoByCode(TokenUtil.getInstance().getTokenUserId()); this.list = list; this.patientInformation = patientInformation; strictVerification = patientInformation != null; return this; } public YiZhuCheckData init(XinZhenYzActOrder orderData, XinZhenYiZhu patientInformation) { List temp = Collections.singletonList(orderData); init(temp, patientInformation); return this; } public void judgeExclusion() { repel = new Repel(); } public Map startCheck(Consumer action) { for (XinZhenYzActOrder item : list) { clearErrorMessage(); if (strictVerification) { strictVerificationFunc(item); } publicCheck(item); String ITEM = "00"; if (item.getSerial().equals(ITEM)) { itemCheck(item); } else { drugCheck(item); } if (action != null) { action.accept(item); } setReturnMap(item.getActOrderNo().stripTrailingZeros().toPlainString()); } return getReturnMap(); } /** * 公共校验 * * @param item 医嘱 */ private void publicCheck(XinZhenYzActOrder item) { if (StringUtil.isBlank(item.getOrderCode())) { errorMessage.add("项目编码不能为空"); } if (StringUtil.isBlank(item.getOrderName())) { errorMessage.add("项目名称不能为空"); } if (StringUtil.isBlank(item.getExecUnit())) { errorMessage.add("执行科室不能为空"); } else if (item.getExecUnit().startsWith("8")) { errorMessage.add("执行科室不能选择为病区"); } if (StringUtil.isBlank(item.getFrequCode())) { errorMessage.add("频次不能为空"); } else if (dao.getTheFrequency(item.getFrequCode()) == 0) { errorMessage.add("该执行频率已被停用,请更改,不然会导致无法执行。"); } } private void itemCheck(XinZhenYzActOrder item) { List projectDetails = project.get(item.getOrderCode(), dao::itemDataOne); XinZhenYzActOrder yzItemInio = yzItem.get(item.getOrderCode(), dao::yzItem); if (yzItemInio != null) { if (yzItemInio.getDelFlag() == 1) { errorMessage.add("该医嘱已被停用,请联系物价。"); } } List ZK_CODE_LIST = new ArrayList<>(); Map specialMedicalAdvice = new HashMap<>(); List value = extraCache.getYzZdOrderItemConfirm(); if (value != null) { for (YzZdOrderItemConfirm yzCode : value) { if (yzCode.getItemName().equals("转科")) { ZK_CODE_LIST.add(yzCode.getOrderCode()); } specialMedicalAdvice.put(yzCode.getOrderCode(), yzCode); } } if (strictVerification && specialMedicalAdvice.containsKey(item.getOrderCode())) { YzZdOrderItemConfirm confirm = specialMedicalAdvice.get(item.getOrderCode()); if (confirm.getCount() > 0 && dao.selectCountByOrderCode(patientInformation.getInpatientNo(), patientInformation.getAdmissTimes(), item.getOrderCode()) > confirm.getCount()) { errorMessage.add("该医嘱只能开一条,请先作废上一条医嘱"); } } if (ZK_CODE_LIST.contains(item.getOrderCode())) { if (StringUtil.isBlank(item.getZkWardCode())) { errorMessage.add("转科病房不能为空"); } if (StringUtil.isBlank(item.getZkDeptCode())) { errorMessage.add("转科科室不能为空"); } } // 如果这个项目下面没有费用明细,那么这就是一条口头医嘱,或者特殊医嘱 if (ListUtil.notBlank(projectDetails)) { for (XinZhenYzActOrder detailed : projectDetails) { if (detailed.getDelFlag() == 1) { errorMessage.add(String.format("项目:【%s】,已经被物价停用了", detailed.getOrderName())); } if (StringUtil.isBlank(detailed.getNationalCode())) { warningMessage.add(String.format("项目:【%s】,没有匹配医保码", detailed.getOrderName())); } } } // 是否是排斥医嘱 if (repel != null) { Integer paiChiYiZhu = dao.shiFouPaiChiYiZhu(item.getOrderCode()); if (paiChiYiZhu != null && paiChiYiZhu.equals(1)) { repel.setCount(repel.getCount() + 1); repel.setOrderNo(item.getActOrderNo()); repel.setDate(item.getStartTime()); } if (yzConfig.getExceedingDischargeDays() != -1) { List strings = extraCache.getYzZdOrderItemMap().get("出院"); if (strings.contains(item.getOrderCode())) { Date admissDate = cn.hutool.core.date.DateUtil.beginOfDay(patientInformation.getAdmissDate()); Date orderTime = cn.hutool.core.date.DateUtil.beginOfDay(item.getOrderTime()); long betweenDay = cn.hutool.core.date.DateUtil.betweenDay(orderTime, admissDate, false); if (betweenDay <= yzConfig.getExceedingDischargeDays()) { if (item.getSuperiorDoctor() == null || !item.getSuperiorDoctor().equals(patientInformation.getDeptDirector())) { errorMessage.add("患者的住院天数小于等于4请科主任授权,开出院医嘱。"); } } } } } item.setDrugOcc(item.getDrugQuan()); } private void drugCheck(XinZhenYzActOrder item) { if (StringUtil.isBlank(item.getGroupNo())) { errorMessage.add("没有药房请重新开。"); return; } if (!groupList.contains(item.getGroupNo())) { errorMessage.add("药房错误,请重新选择药房。"); } String key = item.getOrderCode().trim() + item.getSerial().trim() + item.getGroupNo().trim(); XinZhenYzActOrder detailsOfDrugs = getDrugData(key, item.getSupplyCode()); if (BigUtils.bigXiaoYu(item.getDose(), 0)) { errorMessage.add(String.format("医嘱:【%s】,计量不能开负数", item.getOrderName())); } if (StringUtil.isBlank(item.getDrugSpecification())) { errorMessage.add("药品规格不能为空"); } if (StringUtil.isBlank(item.getSupplyCode())) { errorMessage.add("给药方式不能为空"); } else if (detailsOfDrugs.getSupplyCode() == null || "1".equals(detailsOfDrugs.getSupplyCode())) { errorMessage.add("给药方式已被停用。"); } if (item.getDose() == null || BigUtils.dengYu(item.getDose(), 0)) { errorMessage.add("一次计量不能为空"); } if (StringUtil.isBlank(item.getDoseUnit())) { errorMessage.add("计量单位不能为空"); } if (StringUtil.isBlank(item.getSerial())) { errorMessage.add("包装大小不能为空"); } if (detailsOfDrugs == null) { errorMessage.add("没有找到对应的药品,请联系药房。"); return; } if (StringUtil.isBlank(item.getMiniUnit())) { if (item.getSerial().equals("01")) { item.setMiniUnit(detailsOfDrugs.getMiniUnit()); } else { item.setMiniUnit(detailsOfDrugs.getPackUnit()); } } if (detailsOfDrugs.getDelFlag() == 1) { errorMessage.add("药品已经被停用了,请联系药剂科"); } if (detailsOfDrugs.getYpLevel() > userInfo.getDoctorLevel()) { Integer superiorPhysicianRank = authorizedDoctorLevel.get(item.getSuperiorDoctor(), (code) -> { Integer yiShenDengJi = dao.huoQuYiShenDengJi(code); return yiShenDengJi == null ? 0 : yiShenDengJi; }); if (detailsOfDrugs.getYpLevel() > superiorPhysicianRank) { errorMessage.add("您没有开此药品的权限"); } } if (StringUtil.isBlank(detailsOfDrugs.getNationalCode())) { warningMessage.add("该药品没有医保编码"); } if (BigUtils.bigXiaoYu(detailsOfDrugs.getStockAmount(), 10)) { warningMessage.add(String.format("该药品剩余数量为:【%s】", detailsOfDrugs.getStockAmount().stripTrailingZeros().toPlainString())); } if (BigUtils.bigDaYu(item.getDrugQuan(), detailsOfDrugs.getStockAmount())) { errorMessage.add("药品领量大于药品的库存,当前库存量" + detailsOfDrugs.getStockAmount().stripTrailingZeros().toPlainString()); } // 严格校验 if (strictVerification) { if (detailsOfDrugs.getDeptRestrictions() > 0) { errorMessage.add("该药品禁止在患者所在的科室使用。"); } if (detailsOfDrugs.getVisibleFlagZy() == 1) { errorMessage.add("该药品禁止住院患者使用。"); } item.setKjywFlag(detailsOfDrugs.getKjywFlag()); if (detailsOfDrugs.getKjywFlag() == 1) { if (item.getYyfs() == null) { errorMessage.add("请填写抗菌药物医嘱附注信息录入"); } else if (item.getYyfs() == 1 || item.getYyfs() == 2) { if (item.getSsqk() == null) { errorMessage.add("当用药方式为 1 或 2 时,手术切口和用药时间不能为空"); } } } // 校验医保限制用药(item); } String 出院带药 = "007"; if (item.getSupplyCode() != null && 出院带药.equals(item.getSupplyCode())) { if (!ONCE.equals(item.getFrequCode())) { errorMessage.add("出院带药不能是长期医嘱。"); } item.setDrugOcc(item.getDrugQuan()); } else { // 计算普通药品的领量 durg_quan durg_occ calculateDrugAmount(item, detailsOfDrugs); if (item.getDrugOcc() == null) { errorMessage.add("医嘱领量错误,请重新选择【剂量单位】,或这可能药房剂量维护错误。"); } } } void 校验医保限制用药(XinZhenYzActOrder item) { if (!checkForRestrictedMedication) return; // 自费不管 if ("1".equals(item.getYbSelfFlag())) return; ChargeLimitations chargeLimitations = yiBaoLimitation.get(item.getOrderCode(), dao::hasCharge); if (chargeLimitations == null) { return; } List data = dao.getChargeDay(patientInformation.getInpatientNo(), patientInformation.getAdmissTimes(), patientInformation.getLedgerSn(), item.getOrderCode()); // 已经使用 int usedAlready = ListUtil.isBlank(data) ? 0 : data.size(); //可以使用天数 int canBeUsed = chargeLimitations.getLimitDay() - usedAlready; Date latestNumberOfDays = DateUtil.addNaturalDays(item.getStartTime(), canBeUsed); int compare = DateUtil.compare(item.getEndTime(), latestNumberOfDays); if (item.getEndTime() == null) { errorMessage.add(StrUtil.format( "医保限制:【{}】天,请设置停止时间,不得超过【{}】", chargeLimitations.getLimitDay(), DateUtil.formatDate(latestNumberOfDays, DateUtil.DEFAULT_PATTERN))); } else if (compare > 0) { errorMessage.add(StrUtil.format( "医保限制:【{}】天,请设置停止时间,不得超过【{}】", chargeLimitations.getLimitDay(), DateUtil.formatDate(latestNumberOfDays, DateUtil.DEFAULT_PATTERN))); } } private void strictVerificationFunc(@NotNull XinZhenYzActOrder item) { if (item.getParentNo() != null && item.getActOrderNo() != null) { if (BigUtils.bigXiaoYu(item.getActOrderNo(), item.getParentNo())) { errorMessage.add("子医嘱的医嘱号,小于父医嘱号,无法成组。【原因如果子医嘱的医嘱号小于父医嘱,会导致打印乱码】"); } } // 获取患者的入院时间 if (item.getOrderTime() == null) { errorMessage.add("医嘱时间不能为空"); } else if (item.getStartTime() == null) { errorMessage.add("开始时间不能为空"); } else if (patientInformation.getAdmissDate() == null) { errorMessage.add("没有查询到患者的入院时间"); } else if (DateUtil.shiJianDaXiao(item.getStartTime(), patientInformation.getAdmissDate(), "<")) { errorMessage.add("开始时间不能在患者入院之前,患者入院时间" + DateUtil.formatDatetime(patientInformation.getAdmissDate())); } else if (DateUtil.shiJianDaXiao(item.getStartTime(), item.getOrderTime(), "<") && !userInfo.getDeptCode().equals("1160000")) { errorMessage.add("开始时间不能在开医嘱之前"); } if (item.getEndTime() != null) { if (ONCE.equals(item.getFrequCode().trim())) { item.setEndTime(null); } else { if (DateUtil.shiJianDaXiao(item.getEndTime(), item.getStartTime(), "<")) { errorMessage.add("结束时间不能在开始时间之前"); } else { item.setModifier(TokenUtil.getInstance().getTokenUserId()); } } } else { item.setModifier(null); } } public XinZhenYzActOrder getDrugData(String code) { return drug.get(code, (temp) -> dao.drugDataOne(temp, patientInformation != null ? patientInformation.getZkWard() : "", null)); } public XinZhenYzActOrder getDrugData(String code, String supplyCode) { return drug.get(code, (temp) -> dao.drugDataOne(temp, patientInformation != null ? patientInformation.getZkWard() : "", supplyCode)); } public static void calculateDrugAmount(XinZhenYzActOrder item, XinZhenYzActOrder feiYongXinXi) { if (feiYongXinXi == null) { return; } item.setDrugWeight(feiYongXinXi.getDrugWeight()); item.setDrugWeightUnit(feiYongXinXi.getDrugWeightUnit()); item.setDrugVolume(feiYongXinXi.getDrugVolume()); item.setDrugVolUnit(feiYongXinXi.getDrugWeightUnit()); String doseUnit = StringUtil.isBlank(item.getDoseUnit()) ? "" : item.getDoseUnit().trim(); if (StringUtil.notBlank(feiYongXinXi.getDrugWeightUnit()) && doseUnit.equals(feiYongXinXi.getDrugWeightUnit().trim())) { item.setDrugOcc(DecimalUtil.divide(item.getDose(), feiYongXinXi.getDrugWeight(), 2)); } else if (StringUtil.notBlank(feiYongXinXi.getDrugVolUnit()) && doseUnit.equals(feiYongXinXi.getDrugVolUnit().trim())) { item.setDrugOcc(DecimalUtil.divide(item.getDose(), feiYongXinXi.getDrugVolume(), 2)); } else if (StringUtil.notBlank(feiYongXinXi.getPackUnit()) && doseUnit.equals(feiYongXinXi.getPackUnit().trim())) { item.setDrugOcc(DecimalUtil.divide(item.getDose(), feiYongXinXi.getPackSize(), 2)); } } private void clearErrorMessage() { errorMessage.clear(); warningMessage.clear(); } private void setReturnMap(String orderNo) { Map map = new HashMap<>(Capacity.TWO); if (ListUtil.notBlank(errorMessage)) { List list = new ArrayList<>(errorMessage); map.put("error", list); passTheAudit = false; } if (ListUtil.notBlank(warningMessage)) { List list = new ArrayList<>(warningMessage); map.put("warning", list); } if (!map.isEmpty()) { returnMap.put(orderNo, map); } } private Map getReturnMap() { return returnMap; } public Boolean getFailed() { return !passTheAudit; } public Boolean multipleExclusions() { if (repel == null) { return false; } return repel.getCount() > 1; } public YiZhuCheckData checkForRestrictedMedication() { checkForRestrictedMedication = true; return this; } }