feat(menu): 添加菜单完整路径功能和待写病历管理

- 在SysMenu实体类中新增fullPath字段用于存储完整路径
- 实现buildMenuTreeWithFullPath方法构建带完整路径的菜单树
- 添加getMenuFullPath和generateFullPath服务方法获取和生成完整路径
- 在菜单控制器中增加获取完整路径的API接口
- 前端菜单组件显示完整路径并在新增修改时使用后端返回的路径
- 添加待写病历管理功能包括获取待写病历列表、数量统计和检查接口
- 在医生工作站界面集成待写病历选项卡和相关处理逻辑
- 更新首页统计数据接口路径并添加待写病历数量获取功能
- 重构首页快捷功能配置为动态从数据库获取用户自定义配置
- 优化菜单列表查询使用异步方式处理带完整路径的菜单数据
- 添加菜单完整路径的数据库映射配置和前端API调用支持
This commit is contained in:
2026-02-01 14:50:22 +08:00
parent 29ecfd90f2
commit 0a08088ada
14 changed files with 1240 additions and 163 deletions

View File

@@ -58,4 +58,28 @@ public interface IDoctorStationEmrAppService {
* @return 病历详情
*/
R<?> getEmrDetail(Long encounterId);
/**
* 获取待写病历列表
*
* @param doctorId 医生ID
* @return 待写病历列表
*/
R<?> getPendingEmrList(Long doctorId);
/**
* 获取待写病历数量
*
* @param doctorId 医生ID
* @return 待写病历数量
*/
R<?> getPendingEmrCount(Long doctorId);
/**
* 检查患者是否需要写病历
*
* @param encounterId 就诊ID
* @return 患者是否需要写病历
*/
R<?> checkNeedWriteEmr(Long encounterId);
}

View File

@@ -7,7 +7,15 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.utils.SecurityUtils;
import com.openhis.administration.domain.Encounter;
import com.openhis.administration.domain.Patient;
import com.openhis.administration.mapper.EncounterMapper;
import com.openhis.administration.mapper.PatientMapper;
import java.util.Date;
import java.sql.Timestamp;
import com.openhis.common.enums.BindingType;
import com.openhis.common.enums.EncounterStatus;
import com.openhis.document.domain.Emr;
import com.openhis.document.domain.EmrDetail;
import com.openhis.document.domain.EmrDict;
@@ -46,6 +54,15 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
@Resource
IEmrDictService emrDictService;
@Resource
private EncounterMapper encounterMapper;
@Resource
private PatientMapper patientMapper;
@Resource
private com.openhis.administration.mapper.EncounterParticipantMapper encounterParticipantMapper;
/**
* 添加病人病历信息
*
@@ -175,4 +192,131 @@ public class DoctorStationEmrAppServiceImpl implements IDoctorStationEmrAppServi
return emrTemplateService.removeById(id) ? R.ok() : R.fail();
}
/**
* 获取待写病历列表
*
* @param doctorId 医生ID
* @return 待写病历列表
*/
@Override
public R<?> getPendingEmrList(Long doctorId) {
// 由于Encounter实体中没有jzPractitionerUserId字段我们需要通过关联查询来获取相关信息
// 使用医生工作站的mapper来查询相关数据
// 这里我们直接使用医生工作站的查询逻辑
// 查询当前医生负责的、状态为"就诊中"但还没有写病历的患者
// 需要通过EncounterParticipant表来关联医生信息
List<Encounter> encounters = encounterMapper.selectList(
new LambdaQueryWrapper<Encounter>()
.eq(Encounter::getStatusEnum, EncounterStatus.IN_PROGRESS.getValue())
);
// 过滤出由指定医生负责且还没有写病历的就诊记录
List<Map<String, Object>> pendingEmrs = new ArrayList<>();
for (Encounter encounter : encounters) {
// 检查该就诊记录是否已经有病历
Emr existingEmr = emrService.getOne(
new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounter.getId())
);
// 检查该就诊是否由指定医生负责
boolean isAssignedToDoctor = isEncounterAssignedToDoctor(encounter.getId(), doctorId);
if (existingEmr == null && isAssignedToDoctor) {
// 如果没有病历且由该医生负责,则添加到待写病历列表
Map<String, Object> pendingEmr = new java.util.HashMap<>();
// 获取患者信息
Patient patient = patientMapper.selectById(encounter.getPatientId());
pendingEmr.put("encounterId", encounter.getId());
pendingEmr.put("patientId", encounter.getPatientId());
pendingEmr.put("patientName", patient != null ? patient.getName() : "未知");
pendingEmr.put("gender", patient != null ? patient.getGenderEnum() : null);
// 使用出生日期计算年龄
pendingEmr.put("age", patient != null && patient.getBirthDate() != null ?
calculateAge(patient.getBirthDate()) : null);
// 使用创建时间作为挂号时间
pendingEmr.put("registerTime", encounter.getCreateTime());
pendingEmr.put("busNo", encounter.getBusNo()); // 病历号
pendingEmrs.add(pendingEmr);
}
}
return R.ok(pendingEmrs);
}
/**
* 获取待写病历数量
*
* @param doctorId 医生ID
* @return 待写病历数量
*/
@Override
public R<?> getPendingEmrCount(Long doctorId) {
// 获取待写病历列表,然后返回数量
R<?> result = getPendingEmrList(doctorId);
if (result.getCode() == 200) {
List<?> pendingEmrs = (List<?>) result.getData();
return R.ok(pendingEmrs.size());
}
return R.ok(0);
}
/**
* 检查患者是否需要写病历
*
* @param encounterId 就诊ID
* @return 患者是否需要写病历
*/
@Override
public R<?> checkNeedWriteEmr(Long encounterId) {
// 检查该就诊记录是否已经有病历
Emr existingEmr = emrService.getOne(
new LambdaQueryWrapper<Emr>().eq(Emr::getEncounterId, encounterId)
);
// 如果没有病历,则需要写病历
boolean needWrite = existingEmr == null;
return R.ok(needWrite);
}
/**
* 检查就诊是否分配给指定医生
*
* @param encounterId 就诊ID
* @param doctorId 医生ID
* @return 是否分配给指定医生
*/
private boolean isEncounterAssignedToDoctor(Long encounterId, Long doctorId) {
// 查询就诊参与者表,检查是否有指定医生的接诊记录
com.openhis.administration.domain.EncounterParticipant participant =
encounterParticipantMapper.selectOne(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<com.openhis.administration.domain.EncounterParticipant>()
.eq(com.openhis.administration.domain.EncounterParticipant::getEncounterId, encounterId)
.eq(com.openhis.administration.domain.EncounterParticipant::getPractitionerId, doctorId)
);
return participant != null;
}
/**
* 根据出生日期计算年龄
*
* @param birthDate 出生日期
* @return 年龄
*/
private String calculateAge(Date birthDate) {
if (birthDate == null) {
return null;
}
// 将java.util.Date转换为java.time.LocalDate
java.time.LocalDate birthLocalDate = new java.sql.Timestamp(birthDate.getTime()).toLocalDateTime().toLocalDate();
java.time.LocalDate currentDate = java.time.LocalDate.now();
int age = java.time.Period.between(birthLocalDate, currentDate).getYears();
return String.valueOf(age);
}
}