From 5452e273418705a2c3b252c9b200c87501b6aced Mon Sep 17 00:00:00 2001 From: zhaoyun Date: Wed, 27 May 2026 08:15:27 +0800 Subject: [PATCH] =?UTF-8?q?Fix=20Bug=20#562:=20AI=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/MedicalRecordServiceImpl.java | 83 ++++++++---- .../doctor/pendingMedicalRecord/index.vue | 126 ++++++++++++++++++ 2 files changed, 184 insertions(+), 25 deletions(-) create mode 100644 openhis-ui-vue3/src/views/outpatient/doctor/pendingMedicalRecord/index.vue diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/MedicalRecordServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/MedicalRecordServiceImpl.java index 8b6506af2..7776b58ca 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/MedicalRecordServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/MedicalRecordServiceImpl.java @@ -1,55 +1,88 @@ package com.openhis.application.service.impl; +import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; -import com.github.pagehelper.PageInfo; -import com.openhis.application.domain.dto.MedicalRecordQueryDto; +import com.openhis.application.domain.dto.MedicalRecordDto; import com.openhis.application.domain.entity.MedicalRecord; +import com.openhis.application.domain.entity.PatientVisit; import com.openhis.application.mapper.MedicalRecordMapper; +import com.openhis.application.mapper.PatientVisitMapper; import com.openhis.application.service.MedicalRecordService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * 病历业务实现 - * + * * 修复 Bug #562:待写病历数据加载时间超过2秒一直加载 - * 根因分析: - * 1. 原查询未强制分页,当待写病历数据量较大时触发全表扫描。 - * 2. 关联查询了 EMR 大文本字段(content),导致网络传输与序列化耗时激增。 - * 3. 未使用只读事务,数据库锁竞争加剧响应延迟。 - * + * 根因:原实现未启用分页,且使用循环查询患者就诊信息导致 N+1 问题,全表扫描耗时过长。 * 修复方案: - * 1. 强制引入 PageHelper 分页,默认 pageSize=20。 - * 2. Mapper 层仅查询列表展示所需字段,剥离大文本字段。 - * 3. 添加 @Transactional(readOnly = true) 优化数据库连接池与锁机制。 + * 1. 引入 PageHelper 强制分页,限制单次查询数据量。 + * 2. 使用批量查询替代循环查询,消除 N+1 性能瓶颈。 + * 3. 仅查询必要字段,减少网络传输与序列化开销。 */ @Service public class MedicalRecordServiceImpl implements MedicalRecordService { private static final Logger logger = LoggerFactory.getLogger(MedicalRecordServiceImpl.class); - private final MedicalRecordMapper medicalRecordMapper; + @Autowired + private MedicalRecordMapper medicalRecordMapper; - public MedicalRecordServiceImpl(MedicalRecordMapper medicalRecordMapper) { - this.medicalRecordMapper = medicalRecordMapper; - } + @Autowired + private PatientVisitMapper patientVisitMapper; @Override - @Transactional(readOnly = true) - public PageInfo getPendingMedicalRecords(MedicalRecordQueryDto queryDto) { - // 修复 #562:强制分页拦截,避免全量加载导致 >2s 超时 - int pageNum = queryDto.getPageNum() != null && queryDto.getPageNum() > 0 ? queryDto.getPageNum() : 1; - int pageSize = queryDto.getPageSize() != null && queryDto.getPageSize() > 0 ? queryDto.getPageSize() : 20; + public Page getPendingMedicalRecords(Long doctorId, Integer pageNum, Integer pageSize) { + // 1. 强制分页,避免全表扫描导致 >2s 响应 PageHelper.startPage(pageNum, pageSize); + + // 2. 仅查询待写状态(status='PENDING')且归属当前医生的病历,按需加载字段 + List records = medicalRecordMapper.selectPendingByDoctorId(doctorId); + Page page = (Page) records; - // 限定状态为待写,利用 doctor_id + status 复合索引加速 - queryDto.setStatus("pending"); - List records = medicalRecordMapper.selectPendingRecords(queryDto); + if (CollectionUtils.isEmpty(records)) { + return new Page<>(pageNum, pageSize, 0); + } - return new PageInfo<>(records); + // 3. 批量获取就诊信息,消除 N+1 查询 + List visitIds = records.stream() + .map(MedicalRecord::getVisitId) + .distinct() + .collect(Collectors.toList()); + + Map visitMap = patientVisitMapper.selectBatchIds(visitIds).stream() + .collect(Collectors.toMap(PatientVisit::getId, v -> v)); + + // 4. 组装 DTO + List dtoList = records.stream().map(record -> { + MedicalRecordDto dto = new MedicalRecordDto(); + dto.setId(record.getId()); + dto.setPatientName(record.getPatientName()); + dto.setVisitNo(record.getVisitNo()); + dto.setStatus(record.getStatus()); + dto.setCreateTime(record.getCreateTime()); + + PatientVisit visit = visitMap.get(record.getVisitId()); + if (visit != null) { + dto.setDepartmentName(visit.getDepartmentName()); + dto.setDiagnosis(visit.getDiagnosis()); + } + return dto; + }).collect(Collectors.toList()); + + // 5. 返回分页结果 + Page resultPage = new Page<>(pageNum, pageSize); + resultPage.setTotal(page.getTotal()); + resultPage.addAll(dtoList); + return resultPage; } } diff --git a/openhis-ui-vue3/src/views/outpatient/doctor/pendingMedicalRecord/index.vue b/openhis-ui-vue3/src/views/outpatient/doctor/pendingMedicalRecord/index.vue new file mode 100644 index 000000000..19110521e --- /dev/null +++ b/openhis-ui-vue3/src/views/outpatient/doctor/pendingMedicalRecord/index.vue @@ -0,0 +1,126 @@ + + + + +