diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/IEmrDataWarehouseAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/IEmrDataWarehouseAppService.java new file mode 100644 index 000000000..54f7b148b --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/IEmrDataWarehouseAppService.java @@ -0,0 +1,18 @@ +package com.healthlink.his.web.emr.appservice; + +import com.healthlink.his.emr.domain.EmrQualityScore; +import com.healthlink.his.emr.domain.EmrStructuredData; + +import java.util.List; +import java.util.Map; + +public interface IEmrDataWarehouseAppService { + + List extractStructuredData(Long emrId); + + List getStructuredData(Long encounterId); + + EmrQualityScore calculateQualityScore(Long encounterId); + + List getQualityScores(Long encounterId); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/impl/EmrDataWarehouseAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/impl/EmrDataWarehouseAppServiceImpl.java new file mode 100644 index 000000000..41a07995c --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/impl/EmrDataWarehouseAppServiceImpl.java @@ -0,0 +1,190 @@ +package com.healthlink.his.web.emr.appservice.impl; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.healthlink.his.document.domain.Emr; +import com.healthlink.his.document.service.IEmrService; +import com.healthlink.his.emr.domain.EmrQualityScore; +import com.healthlink.his.emr.domain.EmrStructuredData; +import com.healthlink.his.emr.service.IEmrQualityScoreService; +import com.healthlink.his.emr.service.IEmrStructuredDataService; +import com.healthlink.his.web.emr.appservice.IEmrDataWarehouseAppService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.*; + +@Service +public class EmrDataWarehouseAppServiceImpl implements IEmrDataWarehouseAppService { + + @Resource + private IEmrStructuredDataService emrStructuredDataService; + + @Resource + private IEmrQualityScoreService emrQualityScoreService; + + @Resource + private IEmrService emrService; + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private static final Map STRUCTURED_KEYS = new LinkedHashMap<>(); + + static { + STRUCTURED_KEYS.put("vital_signs", new String[]{"temperature", "pulse", "respiration", "blood_pressure_systolic", "blood_pressure_diastolic", "spo2"}); + STRUCTURED_KEYS.put("lab_results", new String[]{"wbc", "rbc", "hemoglobin", "platelet", "ALT", "AST", "creatinine", "BUN", "glucose"}); + STRUCTURED_KEYS.put("diagnosis", new String[]{"primary_diagnosis", "secondary_diagnosis"}); + STRUCTURED_KEYS.put("medication", new String[]{"medication_name", "dosage", "frequency", "route"}); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public List extractStructuredData(Long emrId) { + Emr emr = emrService.getById(emrId); + if (emr == null) { + throw new IllegalArgumentException("病历不存在: " + emrId); + } + + List result = new ArrayList<>(); + Map contentMap = parseContent(emr.getContextJson()); + + for (Map.Entry entry : STRUCTURED_KEYS.entrySet()) { + String dataType = entry.getKey(); + for (String key : entry.getValue()) { + Object value = contentMap.get(key); + if (value != null && !value.toString().trim().isEmpty()) { + String dataValue = value.toString().trim(); + String dataUnit = inferUnit(key); + EmrStructuredData data = new EmrStructuredData() + .setEmrId(emrId) + .setEncounterId(emr.getEncounterId()) + .setPatientId(emr.getPatientId()) + .setDataType(dataType) + .setDataKey(key) + .setDataValue(dataValue) + .setDataUnit(dataUnit) + .setRecordTime(new Date()); + emrStructuredDataService.save(data); + result.add(data); + } + } + } + return result; + } + + @Override + public List getStructuredData(Long encounterId) { + return emrStructuredDataService.selectByEncounterId(encounterId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public EmrQualityScore calculateQualityScore(Long encounterId) { + List dataList = emrStructuredDataService.selectByEncounterId(encounterId); + + BigDecimal completeness = calculateCompleteness(dataList); + BigDecimal timeliness = calculateTimeliness(dataList); + BigDecimal accuracy = calculateAccuracy(dataList); + BigDecimal total = completeness.add(timeliness).add(accuracy).divide(BigDecimal.valueOf(3), 2, RoundingMode.HALF_UP); + + EmrQualityScore score = new EmrQualityScore() + .setEncounterId(encounterId) + .setEmrType("STANDARD") + .setTotalScore(total) + .setCompletenessScore(completeness) + .setTimelinessScore(timeliness) + .setAccuracyScore(accuracy) + .setCheckTime(new Date()); + emrQualityScoreService.save(score); + return score; + } + + @Override + public List getQualityScores(Long encounterId) { + return emrQualityScoreService.selectByEncounterId(encounterId); + } + + private BigDecimal calculateCompleteness(List dataList) { + if (dataList.isEmpty()) { + return BigDecimal.ZERO; + } + Set expectedKeys = new HashSet<>(); + for (String[] keys : STRUCTURED_KEYS.values()) { + expectedKeys.addAll(Arrays.asList(keys)); + } + Set actualKeys = new HashSet<>(); + for (EmrStructuredData data : dataList) { + actualKeys.add(data.getDataKey()); + } + actualKeys.retainAll(expectedKeys); + if (expectedKeys.isEmpty()) return BigDecimal.ZERO; + return BigDecimal.valueOf(actualKeys.size()) + .divide(BigDecimal.valueOf(expectedKeys.size()), 2, RoundingMode.HALF_UP) + .multiply(BigDecimal.valueOf(100)); + } + + private BigDecimal calculateTimeliness(List dataList) { + if (dataList.isEmpty()) { + return BigDecimal.ZERO; + } + int timely = 0; + for (EmrStructuredData data : dataList) { + if (data.getRecordTime() != null) { + timely++; + } + } + return BigDecimal.valueOf(timely) + .divide(BigDecimal.valueOf(dataList.size()), 2, RoundingMode.HALF_UP) + .multiply(BigDecimal.valueOf(100)); + } + + private BigDecimal calculateAccuracy(List dataList) { + if (dataList.isEmpty()) { + return BigDecimal.ZERO; + } + int accurate = 0; + for (EmrStructuredData data : dataList) { + if (data.getDataValue() != null && !data.getDataValue().trim().isEmpty()) { + accurate++; + } + } + return BigDecimal.valueOf(accurate) + .divide(BigDecimal.valueOf(dataList.size()), 2, RoundingMode.HALF_UP) + .multiply(BigDecimal.valueOf(100)); + } + + private String inferUnit(String key) { + return switch (key) { + case "temperature" -> "°C"; + case "pulse", "respiration" -> "次/分"; + case "blood_pressure_systolic", "blood_pressure_diastolic" -> "mmHg"; + case "spo2" -> "%"; + case "wbc" -> "10^9/L"; + case "rbc" -> "10^12/L"; + case "hemoglobin" -> "g/L"; + case "platelet" -> "10^9/L"; + case "ALT", "AST" -> "U/L"; + case "creatinine", "BUN" -> "mmol/L"; + case "glucose" -> "mmol/L"; + case "dosage" -> "mg"; + default -> null; + }; + } + + private Map parseContent(String contextJson) { + Map map = new HashMap<>(); + if (contextJson == null || contextJson.isEmpty()) { + return map; + } + try { + @SuppressWarnings("unchecked") + Map parsed = objectMapper.readValue(contextJson, Map.class); + map.putAll(parsed); + } catch (Exception e) { + map.put("raw", contextJson); + } + return map; + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/controller/EmrDataWarehouseController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/controller/EmrDataWarehouseController.java new file mode 100644 index 000000000..f33183ad7 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/controller/EmrDataWarehouseController.java @@ -0,0 +1,52 @@ +package com.healthlink.his.web.emr.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.emr.domain.EmrQualityScore; +import com.healthlink.his.emr.domain.EmrStructuredData; +import com.healthlink.his.web.emr.appservice.IEmrDataWarehouseAppService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/emr/warehouse") +@Slf4j +@AllArgsConstructor +@Tag(name = "电子病历数据仓库") +public class EmrDataWarehouseController { + + private final IEmrDataWarehouseAppService emrDataWarehouseAppService; + + @PostMapping("/extract") + @PreAuthorize("@ss.hasPermi('infection:emr:edit')") + @Operation(summary = "提取结构化数据") + public R> extractStructuredData(@RequestParam("emrId") Long emrId) { + return R.ok(emrDataWarehouseAppService.extractStructuredData(emrId)); + } + + @GetMapping("/data/{encounterId}") + @PreAuthorize("@ss.hasPermi('infection:emr:list')") + @Operation(summary = "查询结构化数据") + public R> getStructuredData(@PathVariable Long encounterId) { + return R.ok(emrDataWarehouseAppService.getStructuredData(encounterId)); + } + + @PostMapping("/quality-score") + @PreAuthorize("@ss.hasPermi('infection:emr:edit')") + @Operation(summary = "计算质控评分") + public R calculateQualityScore(@RequestParam("encounterId") Long encounterId) { + return R.ok(emrDataWarehouseAppService.calculateQualityScore(encounterId)); + } + + @GetMapping("/quality-scores") + @PreAuthorize("@ss.hasPermi('infection:emr:list')") + @Operation(summary = "查询质控评分列表") + public R> getQualityScores(@RequestParam("encounterId") Long encounterId) { + return R.ok(emrDataWarehouseAppService.getQualityScores(encounterId)); + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/IRegionalShareAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/IRegionalShareAppService.java new file mode 100644 index 000000000..0c10cb2b2 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/IRegionalShareAppService.java @@ -0,0 +1,12 @@ +package com.healthlink.his.web.esbmanage.appservice; + +import com.healthlink.his.esb.domain.RegionalShareRecord; + +import java.util.List; +import java.util.Map; + +public interface IRegionalShareAppService { + RegionalShareRecord sharePatientData(Long encounterId, String targetSystem); + List getShareRecords(Long encounterId); + Map getShareStats(); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/impl/RegionalShareAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/impl/RegionalShareAppServiceImpl.java new file mode 100644 index 000000000..a12b36aea --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/appservice/impl/RegionalShareAppServiceImpl.java @@ -0,0 +1,76 @@ +package com.healthlink.his.web.esbmanage.appservice.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.healthlink.his.esb.domain.EsbServiceRegistry; +import com.healthlink.his.esb.domain.RegionalShareRecord; +import com.healthlink.his.esb.service.IEsbServiceRegistryService; +import com.healthlink.his.esb.service.IRegionalShareRecordService; +import com.healthlink.his.web.esbmanage.appservice.IRegionalShareAppService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Service +@Slf4j +@RequiredArgsConstructor +public class RegionalShareAppServiceImpl implements IRegionalShareAppService { + + private final IRegionalShareRecordService shareRecordService; + private final IEsbServiceRegistryService registryService; + + @Override + public RegionalShareRecord sharePatientData(Long encounterId, String targetSystem) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(EsbServiceRegistry::getServiceName, targetSystem) + .eq(EsbServiceRegistry::getServiceStatus, "启用"); + boolean registered = registryService.count(wrapper) > 0; + if (!registered) { + throw new IllegalArgumentException("目标系统 '" + targetSystem + "' 未注册或已停用"); + } + + RegionalShareRecord record = new RegionalShareRecord(); + record.setEncounterId(encounterId); + record.setPatientId(0L); + record.setShareType("PATIENT_DATA"); + record.setTargetSystem(targetSystem); + record.setShareStatus("PENDING"); + record.setRetryCount(0); + record.setRequestData("{\"encounterId\":" + encounterId + ",\"targetSystem\":\"" + targetSystem + "\"}"); + shareRecordService.save(record); + + log.info("区域共享请求已提交: encounterId={}, targetSystem={}", encounterId, targetSystem); + return record; + } + + @Override + public List getShareRecords(Long encounterId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(RegionalShareRecord::getEncounterId, encounterId) + .orderByDesc(RegionalShareRecord::getCreateTime); + return shareRecordService.list(wrapper); + } + + @Override + public Map getShareStats() { + Map stats = new LinkedHashMap<>(); + long total = shareRecordService.count(); + stats.put("total", total); + + long pending = shareRecordService.count( + new LambdaQueryWrapper().eq(RegionalShareRecord::getShareStatus, "PENDING")); + long success = shareRecordService.count( + new LambdaQueryWrapper().eq(RegionalShareRecord::getShareStatus, "SUCCESS")); + long failed = shareRecordService.count( + new LambdaQueryWrapper().eq(RegionalShareRecord::getShareStatus, "FAILED")); + + stats.put("pending", pending); + stats.put("success", success); + stats.put("failed", failed); + stats.put("successRate", total > 0 ? Math.round(success * 100.0 / total) : 100); + return stats; + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/RegionalShareController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/RegionalShareController.java new file mode 100644 index 000000000..58eb0c57c --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/esbmanage/controller/RegionalShareController.java @@ -0,0 +1,49 @@ +package com.healthlink.his.web.esbmanage.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.esb.domain.RegionalShareRecord; +import com.healthlink.his.web.esbmanage.appservice.IRegionalShareAppService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +/** + * 区域医疗信息共享 Controller + */ +@RestController +@RequestMapping("/regional/share") +@Slf4j +@RequiredArgsConstructor +public class RegionalShareController { + + private final IRegionalShareAppService regionalShareAppService; + + @PostMapping + @PreAuthorize("hasAuthority('infection:regional:edit')") + public R sharePatientData(@RequestParam Long encounterId, @RequestParam String targetSystem) { + try { + RegionalShareRecord record = regionalShareAppService.sharePatientData(encounterId, targetSystem); + return R.ok(record); + } catch (IllegalArgumentException e) { + return R.fail(e.getMessage()); + } + } + + @GetMapping("/records/{encounterId}") + @PreAuthorize("hasAuthority('infection:regional:list')") + public R getShareRecords(@PathVariable Long encounterId) { + List records = regionalShareAppService.getShareRecords(encounterId); + return R.ok(records); + } + + @GetMapping("/stats") + @PreAuthorize("hasAuthority('infection:regional:list')") + public R getShareStats() { + Map stats = regionalShareAppService.getShareStats(); + return R.ok(stats); + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/ICdssAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/ICdssAppService.java new file mode 100644 index 000000000..8502ed885 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/ICdssAppService.java @@ -0,0 +1,14 @@ +package com.healthlink.his.web.infection.appservice; + +import com.healthlink.his.infection.domain.CdssAlert; +import com.healthlink.his.infection.domain.CdssRule; + +import java.util.List; +import java.util.Map; + +public interface ICdssAppService { + Map evaluateRules(Long encounterId); + List getAlerts(Long encounterId); + boolean acknowledgeAlert(Long alertId); + List getRules(Map params); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/IInfectionDetailAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/IInfectionDetailAppService.java new file mode 100644 index 000000000..c6c7ba159 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/IInfectionDetailAppService.java @@ -0,0 +1,11 @@ +package com.healthlink.his.web.infection.appservice; + +import java.util.List; +import java.util.Map; + +public interface IInfectionDetailAppService { + + Map getInfectionRateByDept(Long deptId); + + List> getInfectionTrend(String startDate, String endDate); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/impl/CdssAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/impl/CdssAppServiceImpl.java new file mode 100644 index 000000000..85f2513ba --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/impl/CdssAppServiceImpl.java @@ -0,0 +1,104 @@ +package com.healthlink.his.web.infection.appservice.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.healthlink.his.infection.domain.CdssAlert; +import com.healthlink.his.infection.domain.CdssRule; +import com.healthlink.his.infection.service.ICdssAlertService; +import com.healthlink.his.infection.service.ICdssRuleService; +import com.healthlink.his.web.infection.appservice.ICdssAppService; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +@Slf4j +@AllArgsConstructor +public class CdssAppServiceImpl implements ICdssAppService { + + private final ICdssRuleService cdssRuleService; + private final ICdssAlertService cdssAlertService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Map evaluateRules(Long encounterId) { + log.info("CDSS规则评估开始, encounterId={}", encounterId); + + List enabledRules = cdssRuleService.list( + new LambdaQueryWrapper() + .eq(CdssRule::getEnabled, true) + ); + + List newAlerts = new ArrayList<>(); + for (CdssRule rule : enabledRules) { + CdssAlert alert = new CdssAlert(); + alert.setEncounterId(encounterId); + alert.setPatientId(0L); + alert.setRuleId(rule.getId()); + alert.setAlertType(rule.getRuleType()); + alert.setAlertMessage("[" + rule.getRuleName() + "] " + rule.getSuggestion()); + alert.setSeverity(rule.getSeverity()); + alert.setAcknowledged(false); + cdssAlertService.save(alert); + newAlerts.add(alert); + } + + Map result = new HashMap<>(); + result.put("totalRules", enabledRules.size()); + result.put("newAlertCount", newAlerts.size()); + result.put("newAlerts", newAlerts); + result.put("evaluateTime", new Date()); + + log.info("CDSS规则评估完成: {}条规则, 生成{}条告警", enabledRules.size(), newAlerts.size()); + return result; + } + + @Override + public List getAlerts(Long encounterId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(CdssAlert::getEncounterId, encounterId); + wrapper.orderByDesc(CdssAlert::getCreateTime); + return cdssAlertService.list(wrapper); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public boolean acknowledgeAlert(Long alertId) { + CdssAlert alert = cdssAlertService.getById(alertId); + if (alert == null) { + return false; + } + alert.setAcknowledged(true); + alert.setAcknowledgedTime(new Date()); + return cdssAlertService.updateById(alert); + } + + @Override + public List getRules(Map params) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + + String ruleType = getStr(params, "ruleType"); + if (ruleType != null && !ruleType.isEmpty()) { + wrapper.eq(CdssRule::getRuleType, ruleType); + } + String severity = getStr(params, "severity"); + if (severity != null && !severity.isEmpty()) { + wrapper.eq(CdssRule::getSeverity, severity); + } + String keyword = getStr(params, "keyword"); + if (keyword != null && !keyword.isEmpty()) { + wrapper.and(w -> w.like(CdssRule::getRuleName, keyword) + .or().like(CdssRule::getRuleCode, keyword)); + } + wrapper.orderByDesc(CdssRule::getCreateTime); + return cdssRuleService.list(wrapper); + } + + private String getStr(Map params, String key) { + Object v = params.get(key); + return v != null ? v.toString() : null; + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/impl/InfectionDetailAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/impl/InfectionDetailAppServiceImpl.java new file mode 100644 index 000000000..5bc2e0d6e --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/appservice/impl/InfectionDetailAppServiceImpl.java @@ -0,0 +1,90 @@ +package com.healthlink.his.web.infection.appservice.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.healthlink.his.infection.domain.HirInfectionCase; +import com.healthlink.his.infection.service.IHirInfectionCaseService; +import com.healthlink.his.web.infection.appservice.IInfectionDetailAppService; +import lombok.AllArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +@Service +@AllArgsConstructor +public class InfectionDetailAppServiceImpl implements IInfectionDetailAppService { + + private final IHirInfectionCaseService infectionCaseService; + + @Override + public Map getInfectionRateByDept(Long deptId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + if (deptId != null) { + wrapper.eq(HirInfectionCase::getEncounterId, deptId); + } + List cases = infectionCaseService.list(wrapper); + + Map result = new HashMap<>(); + result.put("totalCases", cases.size()); + + long confirmed = cases.stream() + .filter(c -> "CONFIRMED".equals(c.getStatus())) + .count(); + result.put("confirmedCases", confirmed); + + long reported = cases.stream() + .filter(c -> "REPORTED".equals(c.getStatus())) + .count(); + result.put("reportedCases", reported); + + result.put("infectionRate", cases.isEmpty() ? 0 : + Math.round(confirmed * 1000.0 / cases.size()) / 10.0); + + Map byType = cases.stream() + .filter(c -> c.getInfectionType() != null) + .collect(Collectors.groupingBy(HirInfectionCase::getInfectionType, Collectors.counting())); + result.put("byType", byType); + + Map bySite = cases.stream() + .filter(c -> c.getInfectionSite() != null) + .collect(Collectors.groupingBy(HirInfectionCase::getInfectionSite, Collectors.counting())); + result.put("bySite", bySite); + + return result; + } + + @Override + public List> getInfectionTrend(String startDate, String endDate) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.ge(StringUtils.hasText(startDate), HirInfectionCase::getReportTime, startDate) + .le(StringUtils.hasText(endDate), HirInfectionCase::getReportTime, endDate) + .orderByAsc(HirInfectionCase::getReportTime); + List cases = infectionCaseService.list(wrapper); + + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + Map> dailyTrend = cases.stream() + .filter(c -> c.getReportTime() != null) + .collect(Collectors.groupingBy( + c -> sdf.format(c.getReportTime()), + LinkedHashMap::new, + Collectors.groupingBy( + c -> c.getStatus() != null ? c.getStatus() : "UNKNOWN", + Collectors.counting() + ) + )); + + List> trend = new ArrayList<>(); + dailyTrend.forEach((date, statusMap) -> { + Map entry = new HashMap<>(); + entry.put("date", date); + entry.putAll(statusMap); + long total = statusMap.values().stream().mapToLong(Long::longValue).sum(); + entry.put("total", total); + trend.add(entry); + }); + + return trend; + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/controller/CdssController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/controller/CdssController.java new file mode 100644 index 000000000..b946a1f18 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/controller/CdssController.java @@ -0,0 +1,61 @@ +package com.healthlink.his.web.infection.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.infection.domain.CdssAlert; +import com.healthlink.his.infection.domain.CdssRule; +import com.healthlink.his.web.infection.appservice.ICdssAppService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@Tag(name = "CDSS临床决策支持") +@RestController +@RequestMapping("/infection/cdss") +@Slf4j +@AllArgsConstructor +public class CdssController { + + private final ICdssAppService cdssAppService; + + @Operation(summary = "评估规则生成告警") + @PreAuthorize("@ss.hasPermi('infection:cdss:edit')") + @PostMapping("/evaluate") + public R evaluateRules(@RequestParam Long encounterId) { + log.info("CDSS规则评估, encounterId={}", encounterId); + return R.ok(cdssAppService.evaluateRules(encounterId)); + } + + @Operation(summary = "获取告警列表") + @PreAuthorize("@ss.hasPermi('infection:cdss:list')") + @GetMapping("/alerts/{encounterId}") + public R getAlerts(@PathVariable Long encounterId) { + return R.ok(cdssAppService.getAlerts(encounterId)); + } + + @Operation(summary = "确认告警") + @PreAuthorize("@ss.hasPermi('infection:cdss:edit')") + @PostMapping("/alerts/{id}/acknowledge") + public R acknowledgeAlert(@PathVariable Long id) { + return R.ok(cdssAppService.acknowledgeAlert(id)); + } + + @Operation(summary = "查询规则列表") + @PreAuthorize("@ss.hasPermi('infection:cdss:list')") + @GetMapping("/rules") + public R getRules( + @RequestParam(value = "ruleType", required = false) String ruleType, + @RequestParam(value = "severity", required = false) String severity, + @RequestParam(value = "keyword", required = false) String keyword) { + Map params = new java.util.HashMap<>(); + if (ruleType != null) params.put("ruleType", ruleType); + if (severity != null) params.put("severity", severity); + if (keyword != null) params.put("keyword", keyword); + return R.ok(cdssAppService.getRules(params)); + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/controller/InfectionDetailController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/controller/InfectionDetailController.java new file mode 100644 index 000000000..a387e7773 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/infection/controller/InfectionDetailController.java @@ -0,0 +1,40 @@ +package com.healthlink.his.web.infection.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.infection.appservice.IInfectionDetailAppService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Map; + +@Tag(name = "院感监测统计") +@RestController +@RequestMapping("/infection-detail") +@Slf4j +@AllArgsConstructor +public class InfectionDetailController { + + private final IInfectionDetailAppService infectionDetailAppService; + + @Operation(summary = "科室感染率统计") + @PreAuthorize("@ss.hasPermi('infection:infection:list')") + @GetMapping("/rate-by-dept") + public R> getInfectionRateByDept( + @RequestParam(value = "deptId", required = false) Long deptId) { + return R.ok(infectionDetailAppService.getInfectionRateByDept(deptId)); + } + + @Operation(summary = "感染趋势统计") + @PreAuthorize("@ss.hasPermi('infection:infection:list')") + @GetMapping("/trend") + public R>> getInfectionTrend( + @RequestParam(value = "startDate", required = false) String startDate, + @RequestParam(value = "endDate", required = false) String endDate) { + return R.ok(infectionDetailAppService.getInfectionTrend(startDate, endDate)); + } +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V66__update_menu_icons.sql b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V66__update_menu_icons.sql index a2875aa34..1107f9cbe 100644 --- a/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V66__update_menu_icons.sql +++ b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V66__update_menu_icons.sql @@ -1,4 +1,4 @@ --- V66__update_menu_icons.sql +-- V66__update_menu_icons.sql -- 更新菜单图标 - 根据菜单功能名称匹配合适的图标 -- 仅使用 src/assets/icons/svg/ 目录下实际存在的图标 @@ -30,7 +30,7 @@ UPDATE sys_menu SET icon = 'surgery' WHERE menu_id = 2119; -- 手术管理 UPDATE sys_menu SET icon = 'user' WHERE menu_id = 2140; -- 患者管理 UPDATE sys_menu SET icon = 'consultation' WHERE menu_id = 2147; -- 会诊管理 UPDATE sys_menu SET icon = 'report' WHERE menu_id = 2159; -- 疾病报告管理 -UPDATE sys_MENU SET icon = 'infection' WHERE menu_id = 10001; -- 院感管理 +UPDATE sys_menu SET icon = 'infection' WHERE menu_id = 10001; -- 院感管理 UPDATE sys_menu SET icon = 'log' WHERE menu_id = 10011; -- 药品追溯管理 UPDATE sys_menu SET icon = 'edit' WHERE menu_id = 10021; -- 电子签名管理 UPDATE sys_menu SET icon = 'alert' WHERE menu_id = 10031; -- 危急值管理 @@ -109,7 +109,7 @@ UPDATE sys_menu SET icon = 'laboratory' WHERE menu_id = 277; -- 医技工作 UPDATE sys_menu SET icon = 'billing' WHERE menu_id = 282; -- 门诊收费工作站 -- 门诊工作站子菜单 -UPDATE sys_MENU SET icon = 'drug' WHERE menu_id = 272; -- 门诊退药 +UPDATE sys_menu SET icon = 'drug' WHERE menu_id = 272; -- 门诊退药 UPDATE sys_menu SET icon = 'registration' WHERE menu_id = 274; -- 门诊退号 -- 门诊收费工作站子菜单 diff --git a/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V71__cdss.sql b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V71__cdss.sql new file mode 100644 index 000000000..d540c2d3f --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V71__cdss.sql @@ -0,0 +1,33 @@ +CREATE TABLE cdss_rule ( + id BIGSERIAL PRIMARY KEY, + rule_code VARCHAR(32) NOT NULL, + rule_name VARCHAR(100) NOT NULL, + rule_type VARCHAR(20) NOT NULL, + condition_expr TEXT NOT NULL, + suggestion TEXT NOT NULL, + severity VARCHAR(16) DEFAULT 'INFO', + enabled BOOLEAN DEFAULT TRUE, + tenant_id BIGINT DEFAULT 0, + delete_flag CHAR(1) DEFAULT '0', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + create_by VARCHAR(64), + update_time TIMESTAMP, + update_by VARCHAR(64) +); + +CREATE TABLE cdss_alert ( + id BIGSERIAL PRIMARY KEY, + encounter_id BIGINT NOT NULL, + patient_id BIGINT NOT NULL, + rule_id BIGINT NOT NULL, + alert_type VARCHAR(20) NOT NULL, + alert_message TEXT NOT NULL, + severity VARCHAR(16) NOT NULL, + acknowledged BOOLEAN DEFAULT FALSE, + acknowledged_by BIGINT, + acknowledged_time TIMESTAMP, + tenant_id BIGINT DEFAULT 0, + delete_flag CHAR(1) DEFAULT '0', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + create_by VARCHAR(64) +); diff --git a/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V72__regional_sharing.sql b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V72__regional_sharing.sql new file mode 100644 index 000000000..34bf37907 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V72__regional_sharing.sql @@ -0,0 +1,22 @@ +CREATE TABLE regional_share_record ( + id BIGSERIAL PRIMARY KEY, + encounter_id BIGINT NOT NULL, + patient_id BIGINT NOT NULL, + share_type VARCHAR(32) NOT NULL, + target_system VARCHAR(64) NOT NULL, + share_status VARCHAR(20) DEFAULT 'PENDING', + request_data TEXT, + response_data TEXT, + error_message TEXT, + retry_count INTEGER DEFAULT 0, + tenant_id BIGINT DEFAULT 0, + delete_flag CHAR(1) DEFAULT '0', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + create_by VARCHAR(64), + update_time TIMESTAMP, + update_by VARCHAR(64) +); + +CREATE INDEX idx_regional_share_encounter ON regional_share_record(encounter_id); +CREATE INDEX idx_regional_share_patient ON regional_share_record(patient_id); +CREATE INDEX idx_regional_share_status ON regional_share_record(share_status); diff --git a/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V73__emr_data_warehouse.sql b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V73__emr_data_warehouse.sql new file mode 100644 index 000000000..2edeb9bf8 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V73__emr_data_warehouse.sql @@ -0,0 +1,40 @@ +-- V73: 电子病历5级 - 结构化数据仓库+质控评分 + +-- 结构化数据表 +CREATE TABLE IF NOT EXISTS emr_structured_data ( + id BIGSERIAL PRIMARY KEY, + emr_id BIGINT NOT NULL, + encounter_id BIGINT NOT NULL, + patient_id BIGINT NOT NULL, + data_type VARCHAR(32) NOT NULL, + data_key VARCHAR(64) NOT NULL, + data_value TEXT, + data_unit VARCHAR(32), + record_time TIMESTAMP, + tenant_id BIGINT DEFAULT 0, + delete_flag CHAR(1) DEFAULT '0', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + create_by VARCHAR(64) +); + +CREATE INDEX idx_structured_data_emr ON emr_structured_data(emr_id); +CREATE INDEX idx_structured_data_encounter ON emr_structured_data(encounter_id); +CREATE INDEX idx_structured_data_patient ON emr_structured_data(patient_id); + +-- 质控评分表 +CREATE TABLE IF NOT EXISTS emr_quality_score ( + id BIGSERIAL PRIMARY KEY, + encounter_id BIGINT NOT NULL, + emr_type VARCHAR(32) NOT NULL, + total_score DECIMAL(5,2), + completeness_score DECIMAL(5,2), + timeliness_score DECIMAL(5,2), + accuracy_score DECIMAL(5,2), + check_time TIMESTAMP, + tenant_id BIGINT DEFAULT 0, + delete_flag CHAR(1) DEFAULT '0', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + create_by VARCHAR(64) +); + +CREATE INDEX idx_quality_score_encounter ON emr_quality_score(encounter_id); diff --git a/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V74__infection_detail_stats.sql b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V74__infection_detail_stats.sql new file mode 100644 index 000000000..9fe546441 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/V74__infection_detail_stats.sql @@ -0,0 +1,3 @@ +ALTER TABLE hir_infection_case ADD COLUMN IF NOT EXISTS department_id BIGINT; +COMMENT ON COLUMN hir_infection_case.department_id IS '科室ID'; +CREATE INDEX IF NOT EXISTS idx_hir_infection_case_dept ON hir_infection_case(department_id); diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/domain/EmrQualityScore.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/domain/EmrQualityScore.java new file mode 100644 index 000000000..8a2040d9a --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/domain/EmrQualityScore.java @@ -0,0 +1,47 @@ +package com.healthlink.his.emr.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +@Data +@TableName("emr_quality_score") +@Accessors(chain = true) +public class EmrQualityScore implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private Long id; + + private Long encounterId; + + private String emrType; + + private BigDecimal totalScore; + + private BigDecimal completenessScore; + + private BigDecimal timelinessScore; + + private BigDecimal accuracyScore; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date checkTime; + + private Integer tenantId; + + private String deleteFlag; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + private String createBy; +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/domain/EmrStructuredData.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/domain/EmrStructuredData.java new file mode 100644 index 000000000..4f0fef668 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/domain/EmrStructuredData.java @@ -0,0 +1,48 @@ +package com.healthlink.his.emr.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +@Data +@TableName("emr_structured_data") +@Accessors(chain = true) +public class EmrStructuredData implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(type = IdType.ASSIGN_ID) + private Long id; + + private Long emrId; + + private Long encounterId; + + private Long patientId; + + private String dataType; + + private String dataKey; + + private String dataValue; + + private String dataUnit; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date recordTime; + + private Integer tenantId; + + private String deleteFlag; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + private String createBy; +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/mapper/EmrQualityScoreMapper.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/mapper/EmrQualityScoreMapper.java new file mode 100644 index 000000000..d33bfac38 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/mapper/EmrQualityScoreMapper.java @@ -0,0 +1,14 @@ +package com.healthlink.his.emr.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.healthlink.his.emr.domain.EmrQualityScore; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface EmrQualityScoreMapper extends BaseMapper { + + List selectByEncounterId(@Param("encounterId") Long encounterId); +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/mapper/EmrStructuredDataMapper.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/mapper/EmrStructuredDataMapper.java new file mode 100644 index 000000000..8c001b8b7 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/mapper/EmrStructuredDataMapper.java @@ -0,0 +1,16 @@ +package com.healthlink.his.emr.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.healthlink.his.emr.domain.EmrStructuredData; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +@Mapper +public interface EmrStructuredDataMapper extends BaseMapper { + + List selectByEncounterId(@Param("encounterId") Long encounterId); + + List selectByEmrId(@Param("emrId") Long emrId); +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/IEmrQualityScoreService.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/IEmrQualityScoreService.java new file mode 100644 index 000000000..3913a53e5 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/IEmrQualityScoreService.java @@ -0,0 +1,11 @@ +package com.healthlink.his.emr.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.healthlink.his.emr.domain.EmrQualityScore; + +import java.util.List; + +public interface IEmrQualityScoreService extends IService { + + List selectByEncounterId(Long encounterId); +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/IEmrStructuredDataService.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/IEmrStructuredDataService.java new file mode 100644 index 000000000..0e0918b01 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/IEmrStructuredDataService.java @@ -0,0 +1,13 @@ +package com.healthlink.his.emr.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.healthlink.his.emr.domain.EmrStructuredData; + +import java.util.List; + +public interface IEmrStructuredDataService extends IService { + + List selectByEncounterId(Long encounterId); + + List selectByEmrId(Long emrId); +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/impl/EmrQualityScoreServiceImpl.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/impl/EmrQualityScoreServiceImpl.java new file mode 100644 index 000000000..a9b853720 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/impl/EmrQualityScoreServiceImpl.java @@ -0,0 +1,20 @@ +package com.healthlink.his.emr.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.healthlink.his.emr.domain.EmrQualityScore; +import com.healthlink.his.emr.mapper.EmrQualityScoreMapper; +import com.healthlink.his.emr.service.IEmrQualityScoreService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class EmrQualityScoreServiceImpl + extends ServiceImpl + implements IEmrQualityScoreService { + + @Override + public List selectByEncounterId(Long encounterId) { + return baseMapper.selectByEncounterId(encounterId); + } +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/impl/EmrStructuredDataServiceImpl.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/impl/EmrStructuredDataServiceImpl.java new file mode 100644 index 000000000..51594eb74 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/emr/service/impl/EmrStructuredDataServiceImpl.java @@ -0,0 +1,25 @@ +package com.healthlink.his.emr.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.healthlink.his.emr.domain.EmrStructuredData; +import com.healthlink.his.emr.mapper.EmrStructuredDataMapper; +import com.healthlink.his.emr.service.IEmrStructuredDataService; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class EmrStructuredDataServiceImpl + extends ServiceImpl + implements IEmrStructuredDataService { + + @Override + public List selectByEncounterId(Long encounterId) { + return baseMapper.selectByEncounterId(encounterId); + } + + @Override + public List selectByEmrId(Long emrId) { + return baseMapper.selectByEmrId(emrId); + } +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/RegionalShareRecord.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/RegionalShareRecord.java new file mode 100644 index 000000000..48b94fadb --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/domain/RegionalShareRecord.java @@ -0,0 +1,26 @@ +package com.healthlink.his.esb.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.core.common.core.domain.HisBaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 区域医疗信息共享记录 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("regional_share_record") +public class RegionalShareRecord extends HisBaseEntity { + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + private Long encounterId; + private Long patientId; + private String shareType; + private String targetSystem; + private String shareStatus; + private String requestData; + private String responseData; + private String errorMessage; + private Integer retryCount; +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/RegionalShareRecordMapper.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/RegionalShareRecordMapper.java new file mode 100644 index 000000000..a45c7a706 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/mapper/RegionalShareRecordMapper.java @@ -0,0 +1,9 @@ +package com.healthlink.his.esb.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.healthlink.his.esb.domain.RegionalShareRecord; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface RegionalShareRecordMapper extends BaseMapper { +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IRegionalShareRecordService.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IRegionalShareRecordService.java new file mode 100644 index 000000000..184211599 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/IRegionalShareRecordService.java @@ -0,0 +1,7 @@ +package com.healthlink.his.esb.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.healthlink.his.esb.domain.RegionalShareRecord; + +public interface IRegionalShareRecordService extends IService { +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/RegionalShareRecordServiceImpl.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/RegionalShareRecordServiceImpl.java new file mode 100644 index 000000000..aae155c3f --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/esb/service/impl/RegionalShareRecordServiceImpl.java @@ -0,0 +1,11 @@ +package com.healthlink.his.esb.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.healthlink.his.esb.domain.RegionalShareRecord; +import com.healthlink.his.esb.mapper.RegionalShareRecordMapper; +import com.healthlink.his.esb.service.IRegionalShareRecordService; +import org.springframework.stereotype.Service; + +@Service +public class RegionalShareRecordServiceImpl extends ServiceImpl implements IRegionalShareRecordService { +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/domain/CdssAlert.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/domain/CdssAlert.java new file mode 100644 index 000000000..58c23f128 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/domain/CdssAlert.java @@ -0,0 +1,35 @@ +package com.healthlink.his.infection.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.core.common.core.domain.HisBaseEntity; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("cdss_alert") +public class CdssAlert extends HisBaseEntity { + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + @TableField("encounter_id") + private Long encounterId; + @TableField("patient_id") + private Long patientId; + @TableField("rule_id") + private Long ruleId; + @TableField("alert_type") + private String alertType; + @TableField("alert_message") + private String alertMessage; + @TableField("severity") + private String severity; + @TableField("acknowledged") + private Boolean acknowledged; + @TableField("acknowledged_by") + private Long acknowledgedBy; + @TableField("acknowledged_time") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date acknowledgedTime; +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/domain/CdssRule.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/domain/CdssRule.java new file mode 100644 index 000000000..0774ab288 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/domain/CdssRule.java @@ -0,0 +1,30 @@ +package com.healthlink.his.infection.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.core.common.core.domain.HisBaseEntity; +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.Data; +import lombok.EqualsAndHashCode; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("cdss_rule") +public class CdssRule extends HisBaseEntity { + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + @TableField("rule_code") + private String ruleCode; + @TableField("rule_name") + private String ruleName; + @TableField("rule_type") + private String ruleType; + @TableField("condition_expr") + private String conditionExpr; + @TableField("suggestion") + private String suggestion; + @TableField("severity") + private String severity; + @TableField("enabled") + private Boolean enabled; +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/mapper/CdssAlertMapper.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/mapper/CdssAlertMapper.java new file mode 100644 index 000000000..46e956005 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/mapper/CdssAlertMapper.java @@ -0,0 +1,9 @@ +package com.healthlink.his.infection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.healthlink.his.infection.domain.CdssAlert; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface CdssAlertMapper extends BaseMapper { +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/mapper/CdssRuleMapper.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/mapper/CdssRuleMapper.java new file mode 100644 index 000000000..44e5f66e3 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/mapper/CdssRuleMapper.java @@ -0,0 +1,9 @@ +package com.healthlink.his.infection.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.healthlink.his.infection.domain.CdssRule; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface CdssRuleMapper extends BaseMapper { +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/ICdssAlertService.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/ICdssAlertService.java new file mode 100644 index 000000000..2bdfdee86 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/ICdssAlertService.java @@ -0,0 +1,7 @@ +package com.healthlink.his.infection.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.healthlink.his.infection.domain.CdssAlert; + +public interface ICdssAlertService extends IService { +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/ICdssRuleService.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/ICdssRuleService.java new file mode 100644 index 000000000..4c8b8f104 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/ICdssRuleService.java @@ -0,0 +1,7 @@ +package com.healthlink.his.infection.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.healthlink.his.infection.domain.CdssRule; + +public interface ICdssRuleService extends IService { +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/impl/CdssAlertServiceImpl.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/impl/CdssAlertServiceImpl.java new file mode 100644 index 000000000..75c38e3ff --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/impl/CdssAlertServiceImpl.java @@ -0,0 +1,11 @@ +package com.healthlink.his.infection.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.healthlink.his.infection.domain.CdssAlert; +import com.healthlink.his.infection.mapper.CdssAlertMapper; +import com.healthlink.his.infection.service.ICdssAlertService; +import org.springframework.stereotype.Service; + +@Service +public class CdssAlertServiceImpl extends ServiceImpl implements ICdssAlertService { +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/impl/CdssRuleServiceImpl.java b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/impl/CdssRuleServiceImpl.java new file mode 100644 index 000000000..ca45560aa --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/java/com/healthlink/his/infection/service/impl/CdssRuleServiceImpl.java @@ -0,0 +1,11 @@ +package com.healthlink.his.infection.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.healthlink.his.infection.domain.CdssRule; +import com.healthlink.his.infection.mapper.CdssRuleMapper; +import com.healthlink.his.infection.service.ICdssRuleService; +import org.springframework.stereotype.Service; + +@Service +public class CdssRuleServiceImpl extends ServiceImpl implements ICdssRuleService { +} diff --git a/healthlink-his-server/healthlink-his-domain/src/main/resources/mapper/emr/EmrQualityScoreMapper.xml b/healthlink-his-server/healthlink-his-domain/src/main/resources/mapper/emr/EmrQualityScoreMapper.xml new file mode 100644 index 000000000..d05656118 --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/resources/mapper/emr/EmrQualityScoreMapper.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/healthlink-his-server/healthlink-his-domain/src/main/resources/mapper/emr/EmrStructuredDataMapper.xml b/healthlink-his-server/healthlink-his-domain/src/main/resources/mapper/emr/EmrStructuredDataMapper.xml new file mode 100644 index 000000000..181821e9c --- /dev/null +++ b/healthlink-his-server/healthlink-his-domain/src/main/resources/mapper/emr/EmrStructuredDataMapper.xml @@ -0,0 +1,19 @@ + + + + + + + + + diff --git a/healthlink-his-ui/src/api/emr/index.js b/healthlink-his-ui/src/api/emr/index.js index 3a7487460..5494732b0 100644 --- a/healthlink-his-ui/src/api/emr/index.js +++ b/healthlink-his-ui/src/api/emr/index.js @@ -14,3 +14,8 @@ export function getEmrRevisionList(emrId) { return request({ url: '/emr/revision export function getEmrRevisionPage(params) { return request({ url: '/emr/revision/page', method: 'get', params }) } export function getEmrRevisionDetail(id) { return request({ url: '/emr/revision/' + id, method: 'get' }) } export function compareEmrRevisions(id1, id2) { return request({ url: '/emr/revision/compare', method: 'get', params: { revisionId1: id1, revisionId2: id2 } }) } + +export function extractStructuredData(emrId) { return request({ url: '/emr/warehouse/extract', method: 'post', params: { emrId } }) } +export function getStructuredData(encounterId) { return request({ url: '/emr/warehouse/data/' + encounterId, method: 'get' }) } +export function calculateQualityScore(encounterId) { return request({ url: '/emr/warehouse/quality-score', method: 'post', params: { encounterId } }) } +export function getQualityScores(encounterId) { return request({ url: '/emr/warehouse/quality-scores', method: 'get', params: { encounterId } }) }