diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/IEmrCompletenessAppService.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/IEmrCompletenessAppService.java new file mode 100644 index 000000000..d7ea9d242 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/IEmrCompletenessAppService.java @@ -0,0 +1,13 @@ +package com.healthlink.his.web.emr.appservice; + +import com.healthlink.his.emr.domain.EmrCompletenessCheck; + +import java.util.List; +import java.util.Map; + +public interface IEmrCompletenessAppService { + + Map checkCompleteness(Long emrId, Long encounterId); + + List getCheckResults(Long emrId); +} diff --git a/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/impl/EmrCompletenessAppServiceImpl.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/impl/EmrCompletenessAppServiceImpl.java new file mode 100644 index 000000000..914b8d1e2 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/appservice/impl/EmrCompletenessAppServiceImpl.java @@ -0,0 +1,112 @@ +package com.healthlink.his.web.emr.appservice.impl; + +import com.healthlink.his.document.domain.Emr; +import com.healthlink.his.document.service.IEmrService; +import com.healthlink.his.emr.domain.EmrCompletenessCheck; +import com.healthlink.his.emr.service.IEmrCompletenessCheckService; +import com.healthlink.his.web.emr.appservice.IEmrCompletenessAppService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; + +@Service +public class EmrCompletenessAppServiceImpl implements IEmrCompletenessAppService { + + @Resource + private IEmrCompletenessCheckService emrCompletenessCheckService; + + @Resource + private IEmrService emrService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Map checkCompleteness(Long emrId, Long encounterId) { + Emr emr = emrService.getById(emrId); + if (emr == null) { + throw new IllegalArgumentException("病历不存在: " + emrId); + } + + List checks = new ArrayList<>(); + int total = 0; + int requiredPassed = 0; + int requiredTotal = 0; + + String[][] checkDefs = { + {"chief_complaint", "basic", "true", "主诉"}, + {"medical_history", "basic", "true", "现病史"}, + {"past_history", "basic", "false", "既往史"}, + {"physical_exam", "basic", "true", "体格检查"}, + {"auxiliary_exam", "examination", "false", "辅助检查"}, + {"diagnosis", "diagnosis", "true", "诊断"}, + {"treatment_plan", "treatment", "true", "治疗计划"}, + {"signature", "signature", "false", "签名"} + }; + + Map contentMap = parseContent(emr.getContextJson()); + + for (String[] def : checkDefs) { + total++; + boolean isRequired = Boolean.parseBoolean(def[2]); + if (isRequired) requiredTotal++; + + boolean hasValue = contentMap.containsKey(def[0]) + && contentMap.get(def[0]) != null + && !contentMap.get(def[0]).toString().trim().isEmpty(); + + String result = hasValue ? "PASS" : "FAIL"; + String detail = def[3] + (hasValue ? " - 已填写" : " - 未填写"); + if (!isRequired && !hasValue) { + detail = def[3] + " - 未填写(选填项)"; + } + + if (isRequired && hasValue) requiredPassed++; + + EmrCompletenessCheck check = new EmrCompletenessCheck() + .setEmrId(emrId) + .setEncounterId(encounterId) + .setCheckItem(def[0]) + .setCheckCategory(def[1]) + .setIsRequired(isRequired) + .setCheckResult(result) + .setCheckDetail(detail) + .setCheckTime(new Date()); + + emrCompletenessCheckService.save(check); + checks.add(check); + } + + Map result = new LinkedHashMap<>(); + result.put("emrId", emrId); + result.put("encounterId", encounterId); + result.put("totalItems", total); + result.put("requiredTotal", requiredTotal); + result.put("requiredPassed", requiredPassed); + result.put("requiredFailed", requiredTotal - requiredPassed); + result.put("isComplete", requiredPassed == requiredTotal); + result.put("checks", checks); + return result; + } + + @Override + public List getCheckResults(Long emrId) { + return emrCompletenessCheckService.selectByEmrId(emrId); + } + + private Map parseContent(String contextJson) { + Map map = new HashMap<>(); + if (contextJson == null || contextJson.isEmpty()) { + return map; + } + try { + com.fasterxml.jackson.databind.ObjectMapper mapper = new com.fasterxml.jackson.databind.ObjectMapper(); + @SuppressWarnings("unchecked") + Map parsed = mapper.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/EmrCompletenessController.java b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/controller/EmrCompletenessController.java new file mode 100644 index 000000000..322b55279 --- /dev/null +++ b/healthlink-his-server/healthlink-his-application/src/main/java/com/healthlink/his/web/emr/controller/EmrCompletenessController.java @@ -0,0 +1,38 @@ +package com.healthlink.his.web.emr.controller; + +import com.core.common.core.domain.R; +import com.healthlink.his.web.emr.appservice.IEmrCompletenessAppService; +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.Map; + +@RestController +@RequestMapping("/emr/completeness") +@Slf4j +@AllArgsConstructor +@Tag(name = "病历完整性检查") +public class EmrCompletenessController { + + private final IEmrCompletenessAppService emrCompletenessAppService; + + @PostMapping("/check") + @PreAuthorize("@ss.hasPermi('inpatient:emr:edit')") + @Operation(summary = "执行病历完整性检查") + public R> checkCompleteness( + @RequestParam("emrId") Long emrId, + @RequestParam("encounterId") Long encounterId) { + return R.ok(emrCompletenessAppService.checkCompleteness(emrId, encounterId)); + } + + @GetMapping("/results/{emrId}") + @PreAuthorize("@ss.hasPermi('inpatient:emr:list')") + @Operation(summary = "获取完整性检查结果") + public R getCheckResults(@PathVariable Long emrId) { + return R.ok(emrCompletenessAppService.getCheckResults(emrId)); + } +} diff --git a/healthlink-his-ui/src/api/emr.js b/healthlink-his-ui/src/api/emr.js index 07f667130..d1e48aee4 100644 --- a/healthlink-his-ui/src/api/emr.js +++ b/healthlink-his-ui/src/api/emr.js @@ -13,3 +13,6 @@ export function compareEmrRevisions(id1, id2) { return request({ url: "/emr/revi export function saveEmrVersion(data) { return request({ url: "/emr/version/save", method: "post", data }) } export function getEmrVersionList(emrId) { return request({ url: "/emr/version/list/" + emrId, method: "get" }) } export function compareEmrVersions(id1, id2) { return request({ url: "/emr/version/compare", method: "get", params: { versionId1: id1, versionId2: id2 } }) } + +export function checkCompleteness(emrId, encounterId) { return request({ url: "/emr/completeness/check", method: "post", params: { emrId, encounterId } }) } +export function getCompletenessResults(emrId) { return request({ url: "/emr/completeness/results/" + emrId, method: "get" }) } diff --git a/healthlink-his-ui/src/views/emr/completeness-check/index.vue b/healthlink-his-ui/src/views/emr/completeness-check/index.vue new file mode 100644 index 000000000..5ea97470e --- /dev/null +++ b/healthlink-his-ui/src/views/emr/completeness-check/index.vue @@ -0,0 +1,156 @@ + + + + +