fix: 修复剩余MEDIUM/LOW问题
This commit is contained in:
@@ -110,7 +110,63 @@ public class CdssAppServiceImpl implements ICdssAppService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean evaluateCondition(String conditionExpr, Long encounterId, Long patientId) {
|
private boolean evaluateCondition(String conditionExpr, Long encounterId, Long patientId) {
|
||||||
return conditionExpr.contains("encounterId") || conditionExpr.contains("patientId");
|
String expr = conditionExpr.trim();
|
||||||
|
if (expr.isEmpty()) return false;
|
||||||
|
|
||||||
|
if (expr.contains(" OR ")) {
|
||||||
|
for (String part : expr.split("(?i)\\s+OR\\s+")) {
|
||||||
|
if (evaluateCondition(part.trim(), encounterId, patientId)) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (expr.contains(" AND ")) {
|
||||||
|
for (String part : expr.split("(?i)\\s+AND\\s+")) {
|
||||||
|
if (!evaluateCondition(part.trim(), encounterId, patientId)) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] ops = {">=", "<=", "!=", "=", ">", "<"};
|
||||||
|
for (String op : ops) {
|
||||||
|
int idx = expr.indexOf(op);
|
||||||
|
if (idx > 0) {
|
||||||
|
String left = expr.substring(0, idx).trim();
|
||||||
|
String right = expr.substring(idx + op.length()).trim();
|
||||||
|
Object leftVal = resolveParam(left, encounterId, patientId);
|
||||||
|
if (leftVal == null) return false;
|
||||||
|
int cmp = compareValues(leftVal.toString(), right);
|
||||||
|
return switch (op) {
|
||||||
|
case ">=" -> cmp >= 0;
|
||||||
|
case "<=" -> cmp <= 0;
|
||||||
|
case "!=" -> cmp != 0;
|
||||||
|
case "=" -> cmp == 0;
|
||||||
|
case ">" -> cmp > 0;
|
||||||
|
case "<" -> cmp < 0;
|
||||||
|
default -> false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return !"0".equals(expr) && !"false".equalsIgnoreCase(expr) && !"null".equalsIgnoreCase(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object resolveParam(String name, Long encounterId, Long patientId) {
|
||||||
|
return switch (name.trim().toLowerCase()) {
|
||||||
|
case "encounterid" -> encounterId;
|
||||||
|
case "patientid" -> patientId;
|
||||||
|
default -> {
|
||||||
|
try { yield Long.parseLong(name); }
|
||||||
|
catch (NumberFormatException e) { yield name; }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private int compareValues(String left, String right) {
|
||||||
|
try {
|
||||||
|
return Long.compare(Long.parseLong(left), Long.parseLong(right));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
return left.compareTo(right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private CdssAlert buildAlert(CdssRule rule, Long encounterId, Long patientId) {
|
private CdssAlert buildAlert(CdssRule rule, Long encounterId, Long patientId) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.healthlink.his.web.esbmanage.appservice.impl;
|
package com.healthlink.his.web.esbmanage.appservice.impl;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.healthlink.his.administration.domain.Encounter;
|
||||||
|
import com.healthlink.his.administration.service.IEncounterService;
|
||||||
import com.healthlink.his.esb.domain.EsbServiceRegistry;
|
import com.healthlink.his.esb.domain.EsbServiceRegistry;
|
||||||
import com.healthlink.his.esb.domain.RegionalShareRecord;
|
import com.healthlink.his.esb.domain.RegionalShareRecord;
|
||||||
import com.healthlink.his.esb.service.IEsbServiceRegistryService;
|
import com.healthlink.his.esb.service.IEsbServiceRegistryService;
|
||||||
@@ -21,6 +23,7 @@ public class RegionalShareAppServiceImpl implements IRegionalShareAppService {
|
|||||||
|
|
||||||
private final IRegionalShareRecordService shareRecordService;
|
private final IRegionalShareRecordService shareRecordService;
|
||||||
private final IEsbServiceRegistryService registryService;
|
private final IEsbServiceRegistryService registryService;
|
||||||
|
private final IEncounterService encounterService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RegionalShareRecord sharePatientData(Long encounterId, String targetSystem) {
|
public RegionalShareRecord sharePatientData(Long encounterId, String targetSystem) {
|
||||||
@@ -34,7 +37,8 @@ public class RegionalShareAppServiceImpl implements IRegionalShareAppService {
|
|||||||
|
|
||||||
RegionalShareRecord record = new RegionalShareRecord();
|
RegionalShareRecord record = new RegionalShareRecord();
|
||||||
record.setEncounterId(encounterId);
|
record.setEncounterId(encounterId);
|
||||||
record.setPatientId(0L);
|
Encounter encounter = encounterService.getById(encounterId);
|
||||||
|
record.setPatientId(encounter != null ? encounter.getPatientId() : 0L);
|
||||||
record.setShareType("PATIENT_DATA");
|
record.setShareType("PATIENT_DATA");
|
||||||
record.setTargetSystem(targetSystem);
|
record.setTargetSystem(targetSystem);
|
||||||
record.setShareStatus("PENDING");
|
record.setShareStatus("PENDING");
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ public class InfectionEnhancedAppServiceImpl implements IInfectionEnhancedAppSer
|
|||||||
|
|
||||||
private Date parseDate(String s) {
|
private Date parseDate(String s) {
|
||||||
try { return new java.text.SimpleDateFormat("yyyy-MM-dd").parse(s); }
|
try { return new java.text.SimpleDateFormat("yyyy-MM-dd").parse(s); }
|
||||||
catch (Exception e) { return null; }
|
catch (Exception e) { log.warn("日期解析失败: {}", s); return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private int parseInt(Object val, int defaultVal) {
|
private int parseInt(Object val, int defaultVal) {
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class InfectionScreeningAppServiceImpl implements IInfectionScreeningAppS
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException ignored) {}
|
} catch (NumberFormatException e) { log.warn("minDays解析失败: {}", params.get("minDays")); }
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ public class TargetedSurveillanceAppServiceImpl implements ITargetedSurveillance
|
|||||||
try {
|
try {
|
||||||
java.time.LocalDate ld = java.time.LocalDate.parse(s, java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
java.time.LocalDate ld = java.time.LocalDate.parse(s, java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd"));
|
||||||
return java.util.Date.from(ld.atStartOfDay(java.time.ZoneId.systemDefault()).toInstant());
|
return java.util.Date.from(ld.atStartOfDay(java.time.ZoneId.systemDefault()).toInstant());
|
||||||
} catch (Exception e) { return null; }
|
} catch (Exception e) { log.warn("日期解析失败: {}", s); return null; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private int parseInt(Object val, int defaultVal) {
|
private int parseInt(Object val, int defaultVal) {
|
||||||
|
|||||||
@@ -32,9 +32,22 @@ public class EmrQualityAppServiceImpl implements IEmrQualityAppService {
|
|||||||
List<Map<String, Object>> checks = new ArrayList<>();
|
List<Map<String, Object>> checks = new ArrayList<>();
|
||||||
String[] items = {"入院记录24h完成", "首次病程8h完成", "日常病程及时", "出院记录完整", "签名完整"};
|
String[] items = {"入院记录24h完成", "首次病程8h完成", "日常病程及时", "出院记录完整", "签名完整"};
|
||||||
int pass = 0;
|
int pass = 0;
|
||||||
|
List<EmrDefect> defects = defectMapper.selectList(new LambdaQueryWrapper<EmrDefect>()
|
||||||
|
.eq(EmrDefect::getEncounterId, encounterId).eq(EmrDefect::getDelFlag, "0"));
|
||||||
|
Set<String> defectTypes = new HashSet<>();
|
||||||
|
for (EmrDefect d : defects) {
|
||||||
|
if (d.getDefectType() != null) defectTypes.add(d.getDefectType());
|
||||||
|
}
|
||||||
for (String item : items) {
|
for (String item : items) {
|
||||||
Map<String, Object> check = new HashMap<>();
|
Map<String, Object> check = new HashMap<>();
|
||||||
check.put("item", item); check.put("result", "PASS"); checks.add(check); pass++;
|
boolean passed = true;
|
||||||
|
if ("入院记录24h完成".equals(item) && defectTypes.contains("TIMELY")) passed = false;
|
||||||
|
if ("首次病程8h完成".equals(item) && defectTypes.contains("TIMELY")) passed = false;
|
||||||
|
if ("日常病程及时".equals(item) && defectTypes.contains("TIMELY")) passed = false;
|
||||||
|
if ("出院记录完整".equals(item) && defectTypes.contains("COMPLETENESS")) passed = false;
|
||||||
|
if ("签名完整".equals(item) && defectTypes.contains("SIGNATURE")) passed = false;
|
||||||
|
check.put("item", item); check.put("result", passed ? "PASS" : "FAIL"); checks.add(check);
|
||||||
|
if (passed) pass++;
|
||||||
}
|
}
|
||||||
result.put("encounterId", encounterId); result.put("checks", checks);
|
result.put("encounterId", encounterId); result.put("checks", checks);
|
||||||
result.put("totalItems", items.length); result.put("passItems", pass);
|
result.put("totalItems", items.length); result.put("passItems", pass);
|
||||||
@@ -78,8 +91,41 @@ public class EmrQualityAppServiceImpl implements IEmrQualityAppService {
|
|||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> getCompletionRate(String startDate, String endDate) {
|
public Map<String, Object> getCompletionRate(String startDate, String endDate) {
|
||||||
|
LambdaQueryWrapper<EmrDefect> wrapper = new LambdaQueryWrapper<>();
|
||||||
|
wrapper.eq(EmrDefect::getDelFlag, "0");
|
||||||
|
if (startDate != null && !startDate.isEmpty()) {
|
||||||
|
wrapper.ge(EmrDefect::getReportTime, startDate);
|
||||||
|
}
|
||||||
|
if (endDate != null && !endDate.isEmpty()) {
|
||||||
|
wrapper.le(EmrDefect::getReportTime, endDate);
|
||||||
|
}
|
||||||
|
long totalDefects = defectMapper.selectCount(wrapper);
|
||||||
|
LambdaQueryWrapper<EmrDefect> overdueWrapper = new LambdaQueryWrapper<>();
|
||||||
|
overdueWrapper.eq(EmrDefect::getDelFlag, "0").eq(EmrDefect::getDefectType, "TIMELY");
|
||||||
|
if (startDate != null && !startDate.isEmpty()) {
|
||||||
|
overdueWrapper.ge(EmrDefect::getReportTime, startDate);
|
||||||
|
}
|
||||||
|
if (endDate != null && !endDate.isEmpty()) {
|
||||||
|
overdueWrapper.le(EmrDefect::getReportTime, endDate);
|
||||||
|
}
|
||||||
|
long overdueEmr = defectMapper.selectCount(overdueWrapper);
|
||||||
|
LambdaQueryWrapper<QualityScore> scoreWrapper = new LambdaQueryWrapper<>();
|
||||||
|
scoreWrapper.eq(QualityScore::getDelFlag, "0");
|
||||||
|
if (startDate != null && !startDate.isEmpty()) {
|
||||||
|
scoreWrapper.ge(QualityScore::getCreateTime, startDate);
|
||||||
|
}
|
||||||
|
if (endDate != null && !endDate.isEmpty()) {
|
||||||
|
scoreWrapper.le(QualityScore::getCreateTime, endDate);
|
||||||
|
}
|
||||||
|
long totalEncounters = scoreMapper.selectCount(scoreWrapper);
|
||||||
|
long completedEmr = totalEncounters - overdueEmr;
|
||||||
|
if (completedEmr < 0) completedEmr = 0;
|
||||||
|
double completionRate = totalEncounters > 0 ? Math.round(completedEmr * 100.0 / totalEncounters) : 100;
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
result.put("totalEncounters", 0); result.put("completedEmr", 0); result.put("overdueEmr", 0); result.put("completionRate", 100);
|
result.put("totalEncounters", totalEncounters);
|
||||||
|
result.put("completedEmr", completedEmr);
|
||||||
|
result.put("overdueEmr", overdueEmr);
|
||||||
|
result.put("completionRate", completionRate);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,24 +26,41 @@ public class TerminalQualityAppServiceImpl implements ITerminalQualityAppService
|
|||||||
result.put("encounterId", encounterId);
|
result.put("encounterId", encounterId);
|
||||||
result.put("checkTime", new Date());
|
result.put("checkTime", new Date());
|
||||||
|
|
||||||
// 检查各项指标
|
|
||||||
List<Map<String, Object>> checks = new ArrayList<>();
|
List<Map<String, Object>> checks = new ArrayList<>();
|
||||||
String[] items = {"入院记录24h完成", "首次病程8h完成", "日常病程及时", "出院记录完整", "签名完整"};
|
String[] items = {"入院记录24h完成", "首次病程8h完成", "日常病程及时", "出院记录完整", "签名完整"};
|
||||||
int passCount = 0;
|
int passCount = 0;
|
||||||
|
|
||||||
|
List<EmrDefect> defects = defectMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<EmrDefect>()
|
||||||
|
.eq(EmrDefect::getEncounterId, encounterId)
|
||||||
|
.eq(EmrDefect::getDelFlag, "0")
|
||||||
|
.orderByDesc(EmrDefect::getReportTime)
|
||||||
|
);
|
||||||
|
|
||||||
|
Set<String> defectTypes = new HashSet<>();
|
||||||
|
for (EmrDefect d : defects) {
|
||||||
|
if (d.getDefectType() != null) defectTypes.add(d.getDefectType());
|
||||||
|
}
|
||||||
|
boolean hasCritical = defects.stream().anyMatch(d -> "CRITICAL".equals(d.getSeverity()));
|
||||||
|
boolean hasPending = defects.stream().anyMatch(d -> "PENDING".equals(d.getRectifyStatus()));
|
||||||
|
|
||||||
for (String item : items) {
|
for (String item : items) {
|
||||||
Map<String, Object> check = new HashMap<>();
|
Map<String, Object> check = new HashMap<>();
|
||||||
check.put("item", item);
|
check.put("item", item);
|
||||||
check.put("result", "PASS");
|
boolean passed = true;
|
||||||
|
if ("入院记录24h完成".equals(item) && defectTypes.contains("TIMELY")) passed = false;
|
||||||
|
if ("首次病程8h完成".equals(item) && defectTypes.contains("TIMELY")) passed = false;
|
||||||
|
if ("日常病程及时".equals(item) && defectTypes.contains("TIMELY")) passed = false;
|
||||||
|
if ("出院记录完整".equals(item) && (defectTypes.contains("COMPLETENESS") || hasCritical)) passed = false;
|
||||||
|
if ("签名完整".equals(item) && defectTypes.contains("SIGNATURE")) passed = false;
|
||||||
|
check.put("result", passed ? "PASS" : "FAIL");
|
||||||
checks.add(check);
|
checks.add(check);
|
||||||
passCount++;
|
if (passed) passCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算总分
|
|
||||||
BigDecimal score = new BigDecimal(passCount * 20);
|
BigDecimal score = new BigDecimal(passCount * 20);
|
||||||
String grade = calculateGrade(score);
|
String grade = calculateGrade(score);
|
||||||
|
|
||||||
// 保存评分记录
|
|
||||||
QualityScore qualityScore = new QualityScore();
|
QualityScore qualityScore = new QualityScore();
|
||||||
qualityScore.setEncounterId(encounterId);
|
qualityScore.setEncounterId(encounterId);
|
||||||
qualityScore.setScore(score);
|
qualityScore.setScore(score);
|
||||||
|
|||||||
Reference in New Issue
Block a user