feat(menu): 优化菜单路径唯一性校验并更新前端界面

- 在SysLoginController中添加optionMap数据返回
- 添加JSQLParser依赖支持MyBatis Plus功能
- 实现selectMenuByPathExcludeId方法用于排除当前菜单的路径唯一性校验
- 在SysMenuServiceImpl中添加日志记录并优化路径唯一性判断逻辑
- 在SysMenuMapper.xml中添加LIMIT 1限制并实现排除ID查询
- 在前端路由中注释患者管理相关路由配置
- 在用户store中添加optionMap配置项并优先从optionMap获取医院名称
- 重构检查项目设置页面的操作按钮样式为统一的圆形按钮设计
- 更新检查项目设置页面的导航栏样式和交互体验
- 优化门诊记录页面的搜索条件和表格展示功能
- 添加性别和状态筛选条件并改进数据加载逻辑
This commit is contained in:
2026-01-03 23:47:09 +08:00
parent 61f4020487
commit 0c35044231
54 changed files with 5871 additions and 510 deletions

View File

@@ -0,0 +1,58 @@
package com.openhis.administration.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.core.common.core.domain.HisBaseEntity;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 医生患者关系管理Entity实体
*
* @author system
* @date 2026-01-02
*/
@Data
@TableName("adm_practitioner_patient")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class PractitionerPatient extends HisBaseEntity {
/** ID */
@TableId(type = IdType.ASSIGN_ID)
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/** 医生ID */
@JsonSerialize(using = ToStringSerializer.class)
private Long practitionerId;
/** 患者ID */
@JsonSerialize(using = ToStringSerializer.class)
private Long patientId;
/** 关系类型1-主治医生2-签约医生3-管床医生4-家庭医生5-会诊医生6-随访医生 */
private Integer relationshipType;
/** 机构ID */
@JsonSerialize(using = ToStringSerializer.class)
private Long organizationId;
/** 关系开始时间 */
private Date startDate;
/** 关系结束时间 */
private Date endDate;
/** 状态1-有效0-无效 */
private Integer status;
/** 备注信息 */
private String remark;
}

View File

@@ -0,0 +1,38 @@
package com.openhis.administration.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 医生患者关系DTO
*
* @author system
* @date 2026-01-02
*/
@Data
public class PractitionerPatientDto implements Serializable {
private static final long serialVersionUID = 1L;
/** 医生ID */
private Long practitionerId;
/** 患者ID */
private Long patientId;
/** 关系类型1-主治医生2-签约医生3-管床医生4-家庭医生5-会诊医生6-随访医生 */
private Integer relationshipType;
/** 机构ID */
private Long organizationId;
/** 关系开始时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date startDate;
/** 备注信息 */
private String remark;
}

View File

@@ -0,0 +1,16 @@
package com.openhis.administration.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.openhis.administration.domain.PractitionerPatient;
import org.springframework.stereotype.Repository;
/**
* 医生患者关系管理Mapper接口
*
* @author system
* @date 2026-01-02
*/
@Repository
public interface PractitionerPatientMapper extends BaseMapper<PractitionerPatient> {
}

View File

@@ -0,0 +1,65 @@
package com.openhis.administration.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.openhis.administration.domain.PractitionerPatient;
import java.util.List;
/**
* 医生患者关系管理Service接口
*
* @author system
* @date 2026-01-02
*/
public interface IPractitionerPatientService extends IService<PractitionerPatient> {
/**
* 获取医生的所有有效患者
*
* @param practitionerId 医生ID
* @return 患者关系列表
*/
List<PractitionerPatient> getValidPatientsByPractitioner(Long practitionerId);
/**
* 获取患者的所有有效医生
*
* @param patientId 患者ID
* @return 医生关系列表
*/
List<PractitionerPatient> getValidPractitionersByPatient(Long patientId);
/**
* 根据关系类型获取医生患者关系
*
* @param practitionerId 医生ID
* @param patientId 患者ID
* @param relationshipType 关系类型
* @return 医生患者关系
*/
PractitionerPatient getRelationship(Long practitionerId, Long patientId, Integer relationshipType);
/**
* 创建医生患者关系
*
* @param practitionerPatient 医生患者关系
* @return 是否成功
*/
boolean createRelationship(PractitionerPatient practitionerPatient);
/**
* 终止医生患者关系
*
* @param id 关系ID
* @return 是否成功
*/
boolean terminateRelationship(Long id);
/**
* 批量创建医生患者关系
*
* @param relationships 关系列表
* @return 是否成功
*/
boolean batchCreateRelationships(List<PractitionerPatient> relationships);
}

View File

@@ -0,0 +1,135 @@
package com.openhis.administration.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.openhis.administration.domain.PractitionerPatient;
import com.openhis.administration.mapper.PractitionerPatientMapper;
import com.openhis.administration.service.IPractitionerPatientService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
/**
* 医生患者关系管理Service实现
*
* @author system
* @date 2026-01-02
*/
@Slf4j
@Service
public class PractitionerPatientServiceImpl extends ServiceImpl<PractitionerPatientMapper, PractitionerPatient>
implements IPractitionerPatientService {
@Override
public List<PractitionerPatient> getValidPatientsByPractitioner(Long practitionerId) {
LambdaQueryWrapper<PractitionerPatient> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PractitionerPatient::getPractitionerId, practitionerId)
.eq(PractitionerPatient::getStatus, 1)
.orderByDesc(PractitionerPatient::getCreateTime);
return list(wrapper);
}
@Override
public List<PractitionerPatient> getValidPractitionersByPatient(Long patientId) {
LambdaQueryWrapper<PractitionerPatient> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PractitionerPatient::getPatientId, patientId)
.eq(PractitionerPatient::getStatus, 1)
.orderByDesc(PractitionerPatient::getCreateTime);
return list(wrapper);
}
@Override
public PractitionerPatient getRelationship(Long practitionerId, Long patientId, Integer relationshipType) {
LambdaQueryWrapper<PractitionerPatient> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(PractitionerPatient::getPractitionerId, practitionerId)
.eq(PractitionerPatient::getPatientId, patientId)
.eq(PractitionerPatient::getRelationshipType, relationshipType)
.eq(PractitionerPatient::getStatus, 1);
return getOne(wrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean createRelationship(PractitionerPatient practitionerPatient) {
// 设置默认值
if (practitionerPatient.getStatus() == null) {
practitionerPatient.setStatus(1);
}
if (practitionerPatient.getStartDate() == null) {
practitionerPatient.setStartDate(new Date());
}
// 检查是否已存在相同的关系
PractitionerPatient existing = getRelationship(
practitionerPatient.getPractitionerId(),
practitionerPatient.getPatientId(),
practitionerPatient.getRelationshipType()
);
if (existing != null) {
// 如果关系已存在,更新结束时间
existing.setEndDate(new Date());
existing.setStatus(0);
updateById(existing);
log.info("已终止旧的医患关系doctorId={}, patientId={}, relationshipType={}",
practitionerPatient.getPractitionerId(),
practitionerPatient.getPatientId(),
practitionerPatient.getRelationshipType());
}
// 创建新关系
boolean result = save(practitionerPatient);
if (result) {
log.info("创建医患关系成功doctorId={}, patientId={}, relationshipType={}",
practitionerPatient.getPractitionerId(),
practitionerPatient.getPatientId(),
practitionerPatient.getRelationshipType());
}
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean terminateRelationship(Long id) {
PractitionerPatient relationship = getById(id);
if (relationship == null) {
log.warn("医患关系不存在id={}", id);
return false;
}
relationship.setEndDate(new Date());
relationship.setStatus(0);
boolean result = updateById(relationship);
if (result) {
log.info("终止医患关系成功id={}, doctorId={}, patientId={}",
id, relationship.getPractitionerId(), relationship.getPatientId());
}
return result;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean batchCreateRelationships(List<PractitionerPatient> relationships) {
if (relationships == null || relationships.isEmpty()) {
return false;
}
boolean allSuccess = true;
for (PractitionerPatient relationship : relationships) {
boolean success = createRelationship(relationship);
if (!success) {
allSuccess = false;
log.error("批量创建医患关系失败doctorId={}, patientId={}",
relationship.getPractitionerId(), relationship.getPatientId());
}
}
if (allSuccess) {
log.info("批量创建医患关系成功count={}", relationships.size());
}
return allSuccess;
}
}

View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.openhis.administration.mapper.PractitionerPatientMapper">
<resultMap type="com.openhis.administration.domain.PractitionerPatient" id="PractitionerPatientResult">
<result property="id" column="id" />
<result property="practitionerId" column="practitioner_id" />
<result property="patientId" column="patient_id" />
<result property="relationshipType" column="relationship_type" />
<result property="organizationId" column="organization_id" />
<result property="startDate" column="start_date" />
<result property="endDate" column="end_date" />
<result property="status" column="status" />
<result property="remark" column="remark" />
<result property="tenantId" column="tenant_id" />
<result property="deleteFlag" column="delete_flag" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectPractitionerPatientVo">
select id, practitioner_id, patient_id, relationship_type, organization_id,
start_date, end_date, status, remark, tenant_id,
delete_flag, create_by, create_time, update_by, update_time
from adm_practitioner_patient
</sql>
<select id="selectPractitionerPatientList" parameterType="com.openhis.administration.domain.PractitionerPatient" resultMap="PractitionerPatientResult">
<include refid="selectPractitionerPatientVo"/>
<where>
delete_flag = '0'
<if test="practitionerId != null">
and practitioner_id = #{practitionerId}
</if>
<if test="patientId != null">
and patient_id = #{patientId}
</if>
<if test="relationshipType != null">
and relationship_type = #{relationshipType}
</if>
<if test="organizationId != null">
and organization_id = #{organizationId}
</if>
<if test="status != null">
and status = #{status}
</if>
</where>
order by create_time desc
</select>
<select id="selectPractitionerPatientById" parameterType="Long" resultMap="PractitionerPatientResult">
<include refid="selectPractitionerPatientVo"/>
where id = #{id} and delete_flag = '0'
</select>
<!-- 获取医生的所有有效患者(带详细信息) -->
<select id="getValidPatientsByPractitionerWithDetail" parameterType="Long" resultType="java.util.Map">
SELECT
pp.id as relationship_id,
pp.practitioner_id,
pp.patient_id,
pp.relationship_type,
pp.start_date,
pp.end_date,
pp.status,
pp.remark,
pt.name as patient_name,
pt.bus_no as patient_bus_no,
pt.gender_enum as patient_gender,
pt.phone as patient_phone,
pt.id_card as patient_id_card,
pt.birth_date as patient_birth_date
FROM adm_practitioner_patient pp
LEFT JOIN adm_patient pt ON pp.patient_id = pt.ID AND pt.delete_flag = '0'
WHERE pp.practitioner_id = #{practitionerId}
AND pp.status = 1
AND pp.delete_flag = '0'
ORDER BY pp.create_time DESC
</select>
<!-- 获取患者的所有有效医生(带详细信息) -->
<select id="getValidPractitionersByPatientWithDetail" parameterType="Long" resultType="java.util.Map">
SELECT
pp.id as relationship_id,
pp.practitioner_id,
pp.patient_id,
pp.relationship_type,
pp.start_date,
pp.end_date,
pp.status,
pp.remark,
prac.name as practitioner_name,
prac.bus_no as practitioner_bus_no,
prac.gender_enum as practitioner_gender,
prac.phone as practitioner_phone,
prac.dr_profttl_code as practitioner_title,
org.name as organization_name
FROM adm_practitioner_patient pp
LEFT JOIN adm_practitioner prac ON pp.practitioner_id = prac.ID AND prac.delete_flag = '0'
LEFT JOIN adm_organization org ON pp.organization_id = org.ID AND org.delete_flag = '0'
WHERE pp.patient_id = #{patientId}
AND pp.status = 1
AND pp.delete_flag = '0'
ORDER BY pp.relationship_type, pp.create_time DESC
</select>
</mapper>