|
@@ -1,13 +1,19 @@
|
|
|
package com.jyxt.getdatabyview;
|
|
package com.jyxt.getdatabyview;
|
|
|
|
|
|
|
|
|
|
+import com.jyxt.getdatabyview.view.QualityIndicator;
|
|
|
import com.jyxt.getdatabyview.view.repository.LISViewRepository;
|
|
import com.jyxt.getdatabyview.view.repository.LISViewRepository;
|
|
|
import com.jyxt.getdatabyview.view.repository.QualityIndicatorRepository;
|
|
import com.jyxt.getdatabyview.view.repository.QualityIndicatorRepository;
|
|
|
|
|
+import javafx.beans.binding.ObjectExpression;
|
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.stereotype.Component;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
|
|
|
|
|
|
+import java.math.BigDecimal;
|
|
|
|
|
+import java.math.RoundingMode;
|
|
|
|
|
+import java.time.LocalDate;
|
|
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
|
|
|
|
|
@Component
|
|
@Component
|
|
@@ -20,6 +26,9 @@ public class HandleData {
|
|
|
@Value("${resultWithUnit}")
|
|
@Value("${resultWithUnit}")
|
|
|
private String resultWithUnit;
|
|
private String resultWithUnit;
|
|
|
|
|
|
|
|
|
|
+ @Value("${autoCountDay}")
|
|
|
|
|
+ private String autoCountDay;
|
|
|
|
|
+
|
|
|
@Autowired
|
|
@Autowired
|
|
|
private QualityIndicatorRepository qualityIndicatorRepository;
|
|
private QualityIndicatorRepository qualityIndicatorRepository;
|
|
|
|
|
|
|
@@ -41,14 +50,30 @@ public class HandleData {
|
|
|
"TAT时间合格率 常规检验报告发放TAT时间符合率", // 11
|
|
"TAT时间合格率 常规检验报告发放TAT时间符合率", // 11
|
|
|
"报告准确率 检验报告不正确率", // 12
|
|
"报告准确率 检验报告不正确率", // 12
|
|
|
"危急值通报符合率 危急值通报及时率", // 13
|
|
"危急值通报符合率 危急值通报及时率", // 13
|
|
|
- "危急值通报符合率 危急值通报率", // 14
|
|
|
|
|
- "标本合格率 ", // 15
|
|
|
|
|
- "TAT时间合格率 ", // 16
|
|
|
|
|
- "报告准确率 ", // 17
|
|
|
|
|
- "危急值通报符合率 " // 18
|
|
|
|
|
|
|
+ "危急值通报符合率 危急值通报率" // 14
|
|
|
|
|
+// "标本合格率 ", // 15
|
|
|
|
|
+// "TAT时间合格率 ", // 16
|
|
|
|
|
+// "报告准确率 ", // 17
|
|
|
|
|
+// "危急值通报符合率 " // 18
|
|
|
)
|
|
)
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
|
|
+ //质量目标指标对应关系
|
|
|
|
|
+ private static final Map<String, List<String>> indicatorRelationList = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ static {
|
|
|
|
|
+ // 初始化映射关系
|
|
|
|
|
+ indicatorRelationList.put("TAT时间合格率", Arrays.asList("常规检验报告发放TAT时间符合率"));
|
|
|
|
|
+ indicatorRelationList.put("危急值通报符合率", Arrays.asList("危急值通报及时率"));
|
|
|
|
|
+ indicatorRelationList.put("培训符合率", Arrays.asList("员工培训符合率"));
|
|
|
|
|
+ indicatorRelationList.put("报告准确率", Arrays.asList("检验报告不正确率"));
|
|
|
|
|
+ indicatorRelationList.put("服务与沟通达标率", Arrays.asList("患者满意度", "医护满意度"));
|
|
|
|
|
+ indicatorRelationList.put("标本合格率", Arrays.asList("总标本不合格率"));
|
|
|
|
|
+ indicatorRelationList.put("设备开机率", Arrays.asList("分析设备故障率"));
|
|
|
|
|
+ indicatorRelationList.put("试剂耗材使用符合率", Arrays.asList("试剂、耗材有效期内使用符合率"));
|
|
|
|
|
+ indicatorRelationList.put("质控达标率", Arrays.asList("室间质评项目不合格率"));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
public void startHandleData(String pingjiaId,String zhiliangzhibia,String zhiliangmubia, String bianzhishijian, String yuanshishuju) {
|
|
public void startHandleData(String pingjiaId,String zhiliangzhibia,String zhiliangmubia, String bianzhishijian, String yuanshishuju) {
|
|
|
log.info("startHandleData:ID: {}, zhiliangmubia+zhiliangzhibia: {}, bianzhishijian: {}, yuanshishuju: {}", pingjiaId, zhiliangmubia.replace(" ","")+" "+zhiliangzhibia.replace(" ",""), bianzhishijian, yuanshishuju);
|
|
log.info("startHandleData:ID: {}, zhiliangmubia+zhiliangzhibia: {}, bianzhishijian: {}, yuanshishuju: {}", pingjiaId, zhiliangmubia.replace(" ","")+" "+zhiliangzhibia.replace(" ",""), bianzhishijian, yuanshishuju);
|
|
|
int QIIndex = qualityIndicatorList.indexOf(zhiliangmubia.replace(" ","")+" "+zhiliangzhibia.replace(" ",""));
|
|
int QIIndex = qualityIndicatorList.indexOf(zhiliangmubia.replace(" ","")+" "+zhiliangzhibia.replace(" ",""));
|
|
@@ -130,4 +155,212 @@ public class HandleData {
|
|
|
log.info("---zhiliangmubia+zhiliangzhibia: {} not configed!---", pingjiaId, zhiliangmubia.replace(" ","")+" "+zhiliangzhibia.replace(" ",""), bianzhishijian, yuanshishuju);
|
|
log.info("---zhiliangmubia+zhiliangzhibia: {} not configed!---", pingjiaId, zhiliangmubia.replace(" ","")+" "+zhiliangzhibia.replace(" ",""), bianzhishijian, yuanshishuju);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ public void countTargetValue() {
|
|
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMdd");
|
|
|
|
|
+ String currentDayStr = today.format(formatter);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果不是指定自动计算日期,直接返回
|
|
|
|
|
+ if (!currentDayStr.equals(autoCountDay)) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ LocalDate lastYearDate = today.minusYears(1);
|
|
|
|
|
+ String lastYearValue = String.valueOf(lastYearDate.getYear());
|
|
|
|
|
+
|
|
|
|
|
+ // 遍历所有质量目标指标映射关系
|
|
|
|
|
+ for (Map.Entry<String, List<String>> entry : indicatorRelationList.entrySet()) {
|
|
|
|
|
+ String targetStr = entry.getKey();
|
|
|
|
|
+ List<String> indicatorNames = entry.getValue();
|
|
|
|
|
+ // 查询对应的指标数据
|
|
|
|
|
+ List<QualityIndicator> retIndicator = qualityIndicatorRepository.getIndicator(indicatorNames, lastYearValue);
|
|
|
|
|
+ if (retIndicator != null && !retIndicator.isEmpty()) {
|
|
|
|
|
+ log.info("查询到指标: {}, 年度: {}, 数据条数: {}", targetStr, lastYearValue, retIndicator.size());
|
|
|
|
|
+ List<QualityIndicator> retTarget = qualityIndicatorRepository.getTarget(targetStr, lastYearValue);
|
|
|
|
|
+ if (retTarget != null && !retTarget.isEmpty()) {
|
|
|
|
|
+ processIndicatorData(retTarget, retIndicator);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ log.info("未查询到指标: {}, 年度: {} 的数据", targetStr, lastYearValue);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void processIndicatorData(List<QualityIndicator> retTarget, List<QualityIndicator> retIndicator) {
|
|
|
|
|
+ // 1. 获取基础信息
|
|
|
|
|
+ String qiId = retTarget.get(0).getId();
|
|
|
|
|
+ String targetName = retTarget.get(0).getZhiliangmubia();
|
|
|
|
|
+ String yuanshishuju = retTarget.get(0).getYuanshishuju();
|
|
|
|
|
+ Boolean isReverse = false;
|
|
|
|
|
+ if(targetName.equals("标本合格率") || targetName.equals("报告准确率") || targetName.equals("设备开机率") || targetName.equals("质控达标率")){
|
|
|
|
|
+ isReverse = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 2. 调用计算方法
|
|
|
|
|
+ Map<String, Object> retVal = calRes(retIndicator, yuanshishuju, isReverse);
|
|
|
|
|
+ // 3. 定义需要存入数据库的变量
|
|
|
|
|
+ String finalRes = "";
|
|
|
|
|
+ String numerator = "";
|
|
|
|
|
+ String denominator = "";
|
|
|
|
|
+ String DataDetail = "";
|
|
|
|
|
+ String IsQualified = "";
|
|
|
|
|
+ // 4. 解析 retVal 并赋值
|
|
|
|
|
+ if (retVal != null && !retVal.isEmpty()) {
|
|
|
|
|
+ if (retVal.get("resultValue") != null) {
|
|
|
|
|
+ finalRes = retVal.get("resultValue").toString();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (retVal.get("numerator") != null) {
|
|
|
|
|
+ numerator = retVal.get("numerator").toString();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (retVal.get("denominator") != null) {
|
|
|
|
|
+ denominator = retVal.get("denominator").toString();
|
|
|
|
|
+ }
|
|
|
|
|
+ if (retVal.get("IsQualified") != null) {
|
|
|
|
|
+ IsQualified = retVal.get("IsQualified").toString();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // 5. 调用 Repository 保存数据
|
|
|
|
|
+ log.info("ready to update:target->{}, id->{}, finalRes->{}, numerator->{}, denominator->{},DataDetail->{}, IsQualified->{}, yuanshishuju->{} ", targetName, qiId, finalRes, numerator, denominator, DataDetail, IsQualified, yuanshishuju);
|
|
|
|
|
+ qualityIndicatorRepository.save(qiId, finalRes, numerator, denominator, DataDetail, IsQualified);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 计算指标结果
|
|
|
|
|
+ * @param indicatorList 指标列表
|
|
|
|
|
+ * @param yuanshishuju 原始数据(用于评估)
|
|
|
|
|
+ * @param isReverse 是否反转结果 (false: 保持原样, true: 用 1 减去计算结果)
|
|
|
|
|
+ * @return 结果 Map
|
|
|
|
|
+ */
|
|
|
|
|
+ public Map<String, Object> calRes(List<QualityIndicator> indicatorList, String yuanshishuju, boolean isReverse) {
|
|
|
|
|
+ Map<String, Object> retVal = new HashMap<>();
|
|
|
|
|
+
|
|
|
|
|
+ if (indicatorList == null || indicatorList.isEmpty()) {
|
|
|
|
|
+ return retVal;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 定义累加变量
|
|
|
|
|
+ BigDecimal sumFenzi = BigDecimal.ZERO;
|
|
|
|
|
+ BigDecimal sumFenmu = BigDecimal.ZERO;
|
|
|
|
|
+ List<BigDecimal> shijishuzhiList = new ArrayList<>();
|
|
|
|
|
+
|
|
|
|
|
+ boolean hasEmptyFenziOrFenmu = false;
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 遍历列表提取数据
|
|
|
|
|
+ for (QualityIndicator item : indicatorList) {
|
|
|
|
|
+ Object fenziObj = item.getFenzi();
|
|
|
|
|
+ Object fenmuObj = item.getFenmu();
|
|
|
|
|
+ Object shijiObj = item.getShijishuzhi();
|
|
|
|
|
+
|
|
|
|
|
+ boolean isFenziEmpty = isEmpty(fenziObj);
|
|
|
|
|
+ boolean isFenmuEmpty = isEmpty(fenmuObj);
|
|
|
|
|
+ boolean isShijiEmpty = isEmpty(shijiObj);
|
|
|
|
|
+
|
|
|
|
|
+ if (isFenziEmpty && isFenmuEmpty && isShijiEmpty) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ BigDecimal currentFenzi = null;
|
|
|
|
|
+ BigDecimal currentFenmu = null;
|
|
|
|
|
+
|
|
|
|
|
+ if (!isFenziEmpty) {
|
|
|
|
|
+ currentFenzi = new BigDecimal(fenziObj.toString());
|
|
|
|
|
+ sumFenzi = sumFenzi.add(currentFenzi);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (!isFenmuEmpty) {
|
|
|
|
|
+ currentFenmu = new BigDecimal(fenmuObj.toString());
|
|
|
|
|
+ sumFenmu = sumFenmu.add(currentFenmu);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (isFenziEmpty || isFenmuEmpty) {
|
|
|
|
|
+ hasEmptyFenziOrFenmu = true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!isShijiEmpty) {
|
|
|
|
|
+ shijishuzhiList.add(new BigDecimal(shijiObj.toString()));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 计算 resultValue
|
|
|
|
|
+ BigDecimal resultValue = BigDecimal.ZERO;
|
|
|
|
|
+ BigDecimal HUNDRED = new BigDecimal("100");
|
|
|
|
|
+
|
|
|
|
|
+ // 用于返回的分子变量
|
|
|
|
|
+ BigDecimal returnNumerator = sumFenzi;
|
|
|
|
|
+
|
|
|
|
|
+ if (!hasEmptyFenziOrFenmu) {
|
|
|
|
|
+ // 场景A: 分子分母都不为空
|
|
|
|
|
+ if (sumFenmu.compareTo(BigDecimal.ZERO) != 0) {
|
|
|
|
|
+ // 计算原始比例
|
|
|
|
|
+ BigDecimal rawRatio = sumFenzi.divide(sumFenmu, 4, RoundingMode.HALF_UP);
|
|
|
|
|
+
|
|
|
|
|
+ if (isReverse) {
|
|
|
|
|
+ // --- 反转逻辑 ---
|
|
|
|
|
+ // 1. 先转为百分数数值
|
|
|
|
|
+ BigDecimal percentageValue = rawRatio.multiply(HUNDRED);
|
|
|
|
|
+ // 2. 计算反转
|
|
|
|
|
+ resultValue = HUNDRED.subtract(percentageValue);
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 计算反转后的分子 (分母 - 原分子)
|
|
|
|
|
+ returnNumerator = sumFenmu.subtract(sumFenzi);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // --- 不反转逻辑 ---
|
|
|
|
|
+ resultValue = rawRatio.multiply(HUNDRED);
|
|
|
|
|
+ returnNumerator = sumFenzi;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 场景B: 求平均值
|
|
|
|
|
+ if (!shijishuzhiList.isEmpty()) {
|
|
|
|
|
+ BigDecimal sumShiji = BigDecimal.ZERO;
|
|
|
|
|
+ for (BigDecimal val : shijishuzhiList) {
|
|
|
|
|
+ sumShiji = sumShiji.add(val);
|
|
|
|
|
+ }
|
|
|
|
|
+ BigDecimal rawAvg = sumShiji.divide(new BigDecimal(shijishuzhiList.size()), 4, RoundingMode.HALF_UP);
|
|
|
|
|
+
|
|
|
|
|
+ if (isReverse) {
|
|
|
|
|
+ // 平均值反转: 100 - 平均值
|
|
|
|
|
+ resultValue = HUNDRED.subtract(rawAvg);
|
|
|
|
|
+ returnNumerator = null;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 平均值不反转: 直接返回平均值
|
|
|
|
|
+ resultValue = rawAvg;
|
|
|
|
|
+ returnNumerator = null;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 4. 评估
|
|
|
|
|
+ String isQualified = ValueEvaluator.evaluateValue(resultValue.toPlainString(), yuanshishuju);
|
|
|
|
|
+
|
|
|
|
|
+ // 5. 组装返回
|
|
|
|
|
+ Map<String, Object> resultMap = new HashMap<>();
|
|
|
|
|
+ resultMap.put("resultValue", resultValue);
|
|
|
|
|
+ resultMap.put("IsQualified", isQualified);
|
|
|
|
|
+
|
|
|
|
|
+ if (!hasEmptyFenziOrFenmu) {
|
|
|
|
|
+ resultMap.put("numerator", returnNumerator);
|
|
|
|
|
+ resultMap.put("denominator", sumFenmu);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ resultMap.put("numerator", null);
|
|
|
|
|
+ resultMap.put("denominator", null);
|
|
|
|
|
+ }
|
|
|
|
|
+ return resultMap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 辅助方法:统一判断对象是否为空 (null 或 空字符串)
|
|
|
|
|
+ */
|
|
|
|
|
+ private boolean isEmpty(Object obj) {
|
|
|
|
|
+ return obj == null || "".equals(obj.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void countAvaValue(){
|
|
|
|
|
+ LocalDate today = LocalDate.now();
|
|
|
|
|
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMdd");
|
|
|
|
|
+ String currentDayStr = today.format(formatter);
|
|
|
|
|
+ if (!currentDayStr.equals(autoCountDay)) {
|
|
|
|
|
+ // 如果不是指定日期,直接返回
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|