Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
package com.openhis.web.consultation.appservice;
|
||||
|
||||
import com.openhis.web.consultation.dto.ConsultationActivityDto;
|
||||
import com.openhis.web.consultation.dto.ConsultationRequestDto;
|
||||
import com.openhis.web.consultation.dto.DepartmentTreeDto;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 会诊管理AppService接口
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
public interface IConsultationAppService {
|
||||
|
||||
/**
|
||||
* 获取会诊列表
|
||||
*
|
||||
* @param encounterId 就诊ID(可选,如果为null则查询当前医生的所有会诊申请)
|
||||
* @return 会诊列表
|
||||
*/
|
||||
List<ConsultationRequestDto> getConsultationList(Long encounterId);
|
||||
|
||||
/**
|
||||
* 保存会诊申请
|
||||
*
|
||||
* @param dto 会诊申请DTO
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean saveConsultation(ConsultationRequestDto dto);
|
||||
|
||||
/**
|
||||
* 提交会诊申请
|
||||
*
|
||||
* @param consultationId 会诊申请单号
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean submitConsultation(String consultationId);
|
||||
|
||||
/**
|
||||
* 作废会诊申请
|
||||
*
|
||||
* @param consultationId 会诊申请单号
|
||||
* @param cancelReason 作废原因
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean cancelConsultation(String consultationId, String cancelReason);
|
||||
|
||||
/**
|
||||
* 结束会诊申请
|
||||
*
|
||||
* @param consultationId 会诊申请单号
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean completeConsultation(String consultationId);
|
||||
|
||||
/**
|
||||
* 获取科室医生树
|
||||
*
|
||||
* @return 科室医生树
|
||||
*/
|
||||
List<DepartmentTreeDto> getDepartmentTree();
|
||||
|
||||
/**
|
||||
* 获取主诊断
|
||||
*
|
||||
* @param encounterId 就诊ID
|
||||
* @return 主诊断信息
|
||||
*/
|
||||
Map<String, String> getMainDiagnosis(Long encounterId);
|
||||
|
||||
/**
|
||||
* 获取我的会诊邀请列表(被邀请的医生查看)
|
||||
*
|
||||
* @return 会诊邀请列表
|
||||
*/
|
||||
List<ConsultationRequestDto> getMyInvitations();
|
||||
|
||||
/**
|
||||
* 获取所有会诊项目及价格
|
||||
*
|
||||
* @return 会诊项目列表
|
||||
*/
|
||||
List<ConsultationActivityDto> getConsultationActivities();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,967 @@
|
||||
package com.openhis.web.consultation.appservice.impl;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.core.common.utils.SecurityUtils;
|
||||
import com.openhis.administration.domain.Encounter;
|
||||
import com.openhis.administration.domain.EncounterDiagnosis;
|
||||
import com.openhis.administration.domain.Organization;
|
||||
import com.openhis.administration.domain.Patient;
|
||||
import com.openhis.administration.domain.Practitioner;
|
||||
import com.openhis.administration.mapper.EncounterDiagnosisMapper;
|
||||
import com.openhis.administration.mapper.EncounterMapper;
|
||||
import com.openhis.administration.mapper.OrganizationMapper;
|
||||
import com.openhis.administration.mapper.PatientMapper;
|
||||
import com.openhis.administration.mapper.PractitionerMapper;
|
||||
import com.openhis.clinical.domain.Condition;
|
||||
import com.openhis.clinical.mapper.ConditionMapper;
|
||||
import com.openhis.workflow.domain.ServiceRequest;
|
||||
import com.openhis.workflow.service.IServiceRequestService;
|
||||
import com.openhis.common.enums.RequestStatus;
|
||||
import com.openhis.common.enums.GenerateSource;
|
||||
import com.openhis.common.enums.ItemType;
|
||||
import com.core.common.utils.AssignSeqUtil;
|
||||
import com.openhis.common.enums.AssignSeqEnum;
|
||||
import com.openhis.web.consultation.appservice.IConsultationAppService;
|
||||
import com.openhis.web.consultation.dto.ConsultationActivityDto;
|
||||
import com.openhis.web.consultation.dto.ConsultationRequestDto;
|
||||
import com.openhis.web.consultation.dto.DepartmentTreeDto;
|
||||
import com.openhis.web.consultation.dto.InvitedObjectDto;
|
||||
import com.openhis.web.consultation.dto.PhysicianNodeDto;
|
||||
import com.openhis.web.consultation.mapper.ConsultationRequestMapper;
|
||||
import com.openhis.web.consultation.mapper.ConsultationInvitedMapper;
|
||||
import com.openhis.web.consultation.domain.ConsultationRequest;
|
||||
import com.openhis.web.consultation.domain.ConsultationInvited;
|
||||
import com.openhis.web.consultation.enums.ConsultationStatusEnum;
|
||||
import com.openhis.web.consultation.enums.InvitedStatusEnum;
|
||||
import com.openhis.web.consultation.enums.ConsultationUrgencyEnum;
|
||||
import com.openhis.workflow.domain.ActivityDefinition;
|
||||
import com.openhis.workflow.mapper.ActivityDefinitionMapper;
|
||||
import com.openhis.administration.domain.ChargeItemDefinition;
|
||||
import com.openhis.administration.mapper.ChargeItemDefinitionMapper;
|
||||
import com.openhis.administration.domain.ChargeItem;
|
||||
import com.openhis.administration.service.IChargeItemService;
|
||||
import com.openhis.common.enums.ChargeItemStatus;
|
||||
import com.openhis.web.doctorstation.mapper.DoctorStationAdviceAppMapper;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 会诊管理AppService实现类
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class ConsultationAppServiceImpl implements IConsultationAppService {
|
||||
|
||||
@Resource
|
||||
private ConsultationRequestMapper consultationRequestMapper;
|
||||
|
||||
@Resource
|
||||
private ConsultationInvitedMapper consultationInvitedMapper;
|
||||
|
||||
@Resource
|
||||
private EncounterMapper encounterMapper;
|
||||
|
||||
@Resource
|
||||
private PatientMapper patientMapper;
|
||||
|
||||
@Resource
|
||||
private ConditionMapper conditionMapper;
|
||||
|
||||
@Resource
|
||||
private OrganizationMapper organizationMapper;
|
||||
|
||||
@Resource
|
||||
private PractitionerMapper practitionerMapper;
|
||||
|
||||
@Resource
|
||||
private EncounterDiagnosisMapper encounterDiagnosisMapper;
|
||||
|
||||
@Resource
|
||||
private IServiceRequestService iServiceRequestService;
|
||||
|
||||
@Resource
|
||||
private AssignSeqUtil assignSeqUtil;
|
||||
|
||||
@Resource
|
||||
private ActivityDefinitionMapper activityDefinitionMapper;
|
||||
|
||||
@Resource
|
||||
private ChargeItemDefinitionMapper chargeItemDefinitionMapper;
|
||||
|
||||
@Resource
|
||||
private IChargeItemService iChargeItemService;
|
||||
|
||||
@Resource
|
||||
private DoctorStationAdviceAppMapper doctorStationAdviceAppMapper;
|
||||
|
||||
/**
|
||||
* 用于生成唯一序列号的计数器
|
||||
* 每秒重置,范围 0000-9999
|
||||
*/
|
||||
private static final AtomicInteger SEQUENCE = new AtomicInteger(0);
|
||||
|
||||
/**
|
||||
* 记录上一次生成ID的时间(秒级)
|
||||
*/
|
||||
private static volatile long lastSecond = 0L;
|
||||
|
||||
@Override
|
||||
public List<ConsultationRequestDto> getConsultationList(Long encounterId) {
|
||||
// 查询会诊列表
|
||||
LambdaQueryWrapper<ConsultationRequest> wrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
|
||||
// 根据就诊ID,查询该患者的会诊申请
|
||||
wrapper.eq(ConsultationRequest::getEncounterId, encounterId);
|
||||
wrapper.orderByDesc(ConsultationRequest::getCreateTime);
|
||||
|
||||
List<ConsultationRequest> list = consultationRequestMapper.selectList(wrapper);
|
||||
// 转换为DTO
|
||||
return list.stream().map(this::convertToDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean saveConsultation(ConsultationRequestDto dto) {
|
||||
try {
|
||||
// 判断是新增还是更新
|
||||
boolean isUpdate = (dto.getId() != null);
|
||||
ConsultationRequest entity;
|
||||
|
||||
if (isUpdate) {
|
||||
// 更新:查询现有记录
|
||||
entity = consultationRequestMapper.selectById(dto.getId());
|
||||
if (entity == null) {
|
||||
throw new RuntimeException("会诊申请记录不存在,ID: " + dto.getId());
|
||||
}
|
||||
} else {
|
||||
// 新增:创建新记录
|
||||
entity = new ConsultationRequest();
|
||||
entity.setConsultationId(generateConsultationId());
|
||||
entity.setTenantId(SecurityUtils.getLoginUser().getTenantId().longValue());
|
||||
entity.setConsultationRequestDate(new Date());
|
||||
}
|
||||
|
||||
// 复制基本属性(现在字段名已统一,可以直接复制)
|
||||
BeanUtils.copyProperties(dto, entity, "id", "consultationId", "invitedList", "submitFlag", "provisionalDiagnosis", "consultationRequestDate");
|
||||
|
||||
// 如果前端没有传递申请医生ID,使用当前登录用户
|
||||
if (entity.getRequestingPhysicianId() == null) {
|
||||
entity.setRequestingPhysicianId(SecurityUtils.getLoginUser().getPractitionerId());
|
||||
}
|
||||
|
||||
// 设置邀请对象文本(拼接所有医生名称)
|
||||
if (dto.getInvitedList() != null && !dto.getInvitedList().isEmpty()) {
|
||||
String invitedObjectText = dto.getInvitedList().stream()
|
||||
.map(InvitedObjectDto::getPhysicianName)
|
||||
.collect(Collectors.joining(","));
|
||||
entity.setInvitedObject(invitedObjectText);
|
||||
}
|
||||
|
||||
// 处理门诊诊断:如果前端没有传递,自动从数据库获取
|
||||
if (!StringUtils.hasText(dto.getProvisionalDiagnosis()) && dto.getEncounterId() != null) {
|
||||
String diagnosis = getPatientDiagnosis(dto.getEncounterId());
|
||||
if (StringUtils.hasText(diagnosis)) {
|
||||
entity.setProvisionalDiagnosis(diagnosis);
|
||||
}
|
||||
} else {
|
||||
entity.setProvisionalDiagnosis(dto.getProvisionalDiagnosis());
|
||||
}
|
||||
|
||||
// 设置会诊状态(使用枚举)
|
||||
if (Boolean.TRUE.equals(dto.getSubmitFlag())) {
|
||||
entity.setConsultationStatus(ConsultationStatusEnum.SUBMITTED.getCode());
|
||||
entity.setConfirmingPhysician(SecurityUtils.getLoginUser().getUser().getNickName());
|
||||
entity.setConfirmingPhysicianId(SecurityUtils.getLoginUser().getPractitionerId());
|
||||
entity.setConfirmingDate(new Date());
|
||||
} else {
|
||||
entity.setConsultationStatus(ConsultationStatusEnum.NEW.getCode());
|
||||
}
|
||||
|
||||
// 保存或更新主表
|
||||
if (isUpdate) {
|
||||
consultationRequestMapper.updateById(entity);
|
||||
|
||||
// 删除旧的邀请对象
|
||||
LambdaQueryWrapper<ConsultationInvited> deleteWrapper = new LambdaQueryWrapper<>();
|
||||
deleteWrapper.eq(ConsultationInvited::getConsultationRequestId, entity.getId());
|
||||
consultationInvitedMapper.delete(deleteWrapper);
|
||||
|
||||
// 更新门诊医嘱表
|
||||
if (entity.getOrderId() != null) {
|
||||
updateConsultationServiceRequest(entity);
|
||||
}
|
||||
} else {
|
||||
consultationRequestMapper.insert(entity);
|
||||
|
||||
// 保存到门诊医嘱表
|
||||
saveConsultationServiceRequest(entity);
|
||||
}
|
||||
|
||||
// 保存邀请对象到关联表
|
||||
if (dto.getInvitedList() != null && !dto.getInvitedList().isEmpty()) {
|
||||
for (InvitedObjectDto invitedDto : dto.getInvitedList()) {
|
||||
ConsultationInvited invited = new ConsultationInvited();
|
||||
invited.setConsultationRequestId(entity.getId());
|
||||
invited.setInvitedDepartmentId(invitedDto.getDeptId());
|
||||
invited.setInvitedDepartmentName(invitedDto.getDeptName());
|
||||
invited.setInvitedPhysicianId(invitedDto.getPhysicianId());
|
||||
invited.setInvitedPhysicianName(invitedDto.getPhysicianName());
|
||||
invited.setInvitedStatus(InvitedStatusEnum.PENDING.getCode());
|
||||
invited.setTenantId(entity.getTenantId());
|
||||
|
||||
consultationInvitedMapper.insert(invited);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("保存会诊申请失败", e);
|
||||
throw new RuntimeException("保存会诊申请失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean submitConsultation(String consultationId) {
|
||||
try {
|
||||
if (!StringUtils.hasText(consultationId)) {
|
||||
throw new IllegalArgumentException("会诊申请单号不能为空");
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<ConsultationRequest> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(ConsultationRequest::getConsultationId, consultationId);
|
||||
|
||||
ConsultationRequest entity = consultationRequestMapper.selectOne(wrapper);
|
||||
if (entity == null) {
|
||||
throw new IllegalArgumentException("会诊申请不存在");
|
||||
}
|
||||
|
||||
// 只有新开状态才能提交
|
||||
if (!ConsultationStatusEnum.NEW.getCode().equals(entity.getConsultationStatus())) {
|
||||
throw new IllegalArgumentException("只有新开状态的会诊申请才能提交");
|
||||
}
|
||||
|
||||
// 更新状态为已提交
|
||||
entity.setConsultationStatus(ConsultationStatusEnum.SUBMITTED.getCode());
|
||||
|
||||
// 设置提交会诊的医生信息
|
||||
entity.setConfirmingPhysician(SecurityUtils.getLoginUser().getUser().getNickName());
|
||||
entity.setConfirmingPhysicianId(SecurityUtils.getLoginUser().getPractitionerId());
|
||||
entity.setConfirmingDate(new Date());
|
||||
|
||||
consultationRequestMapper.updateById(entity);
|
||||
|
||||
// 新增:更新门诊医嘱表状态为已提交
|
||||
updateServiceRequestStatus(entity.getOrderId(), RequestStatus.ACTIVE.getValue());
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("提交会诊申请失败", e);
|
||||
throw new RuntimeException("提交会诊申请失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean cancelConsultation(String consultationId, String cancelReason) {
|
||||
try {
|
||||
if (!StringUtils.hasText(consultationId)) {
|
||||
throw new IllegalArgumentException("会诊申请单号不能为空");
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<ConsultationRequest> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(ConsultationRequest::getConsultationId, consultationId);
|
||||
|
||||
ConsultationRequest entity = consultationRequestMapper.selectOne(wrapper);
|
||||
if (entity == null) {
|
||||
throw new IllegalArgumentException("会诊申请不存在");
|
||||
}
|
||||
|
||||
// 判断是"取消提交"还是"作废"
|
||||
if ("取消提交".equals(cancelReason) && ConsultationStatusEnum.SUBMITTED.getCode().equals(entity.getConsultationStatus())) {
|
||||
// 取消提交:将状态从"已提交"改回"新开"
|
||||
entity.setConsultationStatus(ConsultationStatusEnum.NEW.getCode());
|
||||
entity.setConfirmingPhysician(null);
|
||||
entity.setConfirmingPhysicianId(null);
|
||||
entity.setConfirmingDate(null);
|
||||
consultationRequestMapper.updateById(entity);
|
||||
|
||||
// 更新门诊医嘱表状态为新开
|
||||
updateServiceRequestStatus(entity.getOrderId(), RequestStatus.DRAFT.getValue());
|
||||
|
||||
} else {
|
||||
// 作废:将状态改为"已取消"
|
||||
entity.setConsultationStatus(ConsultationStatusEnum.CANCELLED.getCode());
|
||||
entity.setCancelReason(cancelReason);
|
||||
entity.setCancelNatureDate(new Date());
|
||||
consultationRequestMapper.updateById(entity);
|
||||
|
||||
// 更新门诊医嘱表状态为已作废
|
||||
updateServiceRequestStatus(entity.getOrderId(), RequestStatus.CANCELLED.getValue());
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("操作失败", e);
|
||||
throw new RuntimeException("操作失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean completeConsultation(String consultationId) {
|
||||
try {
|
||||
if (!StringUtils.hasText(consultationId)) {
|
||||
throw new IllegalArgumentException("会诊申请单号不能为空");
|
||||
}
|
||||
|
||||
LambdaQueryWrapper<ConsultationRequest> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(ConsultationRequest::getConsultationId, consultationId);
|
||||
|
||||
ConsultationRequest entity = consultationRequestMapper.selectOne(wrapper);
|
||||
if (entity == null) {
|
||||
throw new IllegalArgumentException("会诊申请不存在");
|
||||
}
|
||||
|
||||
// 更新状态为已完成
|
||||
entity.setConsultationStatus(ConsultationStatusEnum.COMPLETED.getCode());
|
||||
consultationRequestMapper.updateById(entity);
|
||||
|
||||
// 🎯 新增:更新门诊医嘱表状态为已完成
|
||||
updateServiceRequestStatus(entity.getOrderId(), RequestStatus.COMPLETED.getValue());
|
||||
|
||||
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
log.error("结束会诊申请失败", e);
|
||||
throw new RuntimeException("结束会诊申请失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DepartmentTreeDto> getDepartmentTree() {
|
||||
try {
|
||||
// 查询所有科室
|
||||
LambdaQueryWrapper<Organization> deptWrapper = new LambdaQueryWrapper<>();
|
||||
deptWrapper.eq(Organization::getDeleteFlag, "0")
|
||||
.orderByAsc(Organization::getName);
|
||||
List<Organization> deptList = organizationMapper.selectList(deptWrapper);
|
||||
|
||||
|
||||
// 查询所有医生
|
||||
LambdaQueryWrapper<Practitioner> practitionerWrapper = new LambdaQueryWrapper<>();
|
||||
practitionerWrapper.eq(Practitioner::getDeleteFlag, "0")
|
||||
.orderByAsc(Practitioner::getName);
|
||||
List<Practitioner> practitionerList = practitionerMapper.selectList(practitionerWrapper);
|
||||
|
||||
|
||||
// 按科室分组医生
|
||||
Map<Long, List<Practitioner>> practitionerMap = practitionerList.stream()
|
||||
.filter(p -> p.getOrgId() != null)
|
||||
.collect(Collectors.groupingBy(Practitioner::getOrgId));
|
||||
|
||||
// 构建树形结构
|
||||
List<DepartmentTreeDto> treeList = new ArrayList<>();
|
||||
for (Organization dept : deptList) {
|
||||
DepartmentTreeDto treeDto = new DepartmentTreeDto();
|
||||
treeDto.setId(dept.getId());
|
||||
treeDto.setLabel(dept.getName());
|
||||
|
||||
// 添加该科室的医生
|
||||
List<Practitioner> physicians = practitionerMap.get(dept.getId());
|
||||
if (physicians != null && !physicians.isEmpty()) {
|
||||
List<PhysicianNodeDto> children = physicians.stream()
|
||||
.map(p -> {
|
||||
PhysicianNodeDto node = new PhysicianNodeDto();
|
||||
node.setId(p.getId());
|
||||
node.setLabel(p.getName());
|
||||
return node;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
treeDto.setChildren(children);
|
||||
} else {
|
||||
treeDto.setChildren(new ArrayList<>());
|
||||
}
|
||||
|
||||
treeList.add(treeDto);
|
||||
}
|
||||
|
||||
|
||||
return treeList;
|
||||
} catch (Exception e) {
|
||||
log.error("获取科室医生树失败", e);
|
||||
throw new RuntimeException("获取科室医生树失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getMainDiagnosis(Long encounterId) {
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
||||
if (encounterId == null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
String diagnosis = getPatientDiagnosis(encounterId);
|
||||
if (StringUtils.hasText(diagnosis)) {
|
||||
result.put("diagnosis", diagnosis);
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("获取主诊断失败", e);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取患者诊断信息
|
||||
*
|
||||
* @param encounterId 就诊ID
|
||||
* @return 诊断信息字符串
|
||||
*/
|
||||
private String getPatientDiagnosis(Long encounterId) {
|
||||
try {
|
||||
// 查询该就诊的所有诊断,优先查询主诊断
|
||||
LambdaQueryWrapper<EncounterDiagnosis> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(EncounterDiagnosis::getEncounterId, encounterId)
|
||||
.orderByDesc(EncounterDiagnosis::getMaindiseFlag) // 主诊断排在前面
|
||||
.orderByAsc(EncounterDiagnosis::getDiagSrtNo) // 按诊断排序号排序
|
||||
.orderByDesc(EncounterDiagnosis::getCreateTime); // 按创建时间倒序
|
||||
|
||||
List<EncounterDiagnosis> diagnosisList = encounterDiagnosisMapper.selectList(wrapper);
|
||||
|
||||
if (diagnosisList == null || diagnosisList.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// 使用 LinkedHashSet 去重,保持顺序
|
||||
LinkedHashSet<String> diagnosisSet = new LinkedHashSet<>();
|
||||
int mainDiagnosisCount = 0;
|
||||
|
||||
for (EncounterDiagnosis ed : diagnosisList) {
|
||||
// 优先使用 name 字段,如果没有则使用 diagnosisDesc
|
||||
String diagName = StringUtils.hasText(ed.getName()) ? ed.getName() : ed.getDiagnosisDesc();
|
||||
|
||||
if (StringUtils.hasText(diagName)) {
|
||||
// 构建诊断文本
|
||||
StringBuilder itemBuilder = new StringBuilder();
|
||||
itemBuilder.append(diagName);
|
||||
|
||||
// 如果有诊断描述且与名称不同,添加到括号中
|
||||
if (StringUtils.hasText(ed.getDiagnosisDesc()) &&
|
||||
!ed.getDiagnosisDesc().equals(diagName)) {
|
||||
itemBuilder.append("(").append(ed.getDiagnosisDesc()).append(")");
|
||||
}
|
||||
|
||||
// 标记主诊断
|
||||
if (ed.getMaindiseFlag() != null && ed.getMaindiseFlag() == 1) {
|
||||
itemBuilder.append("[主]");
|
||||
mainDiagnosisCount++;
|
||||
}
|
||||
|
||||
// 添加到集合(自动去重)
|
||||
diagnosisSet.add(itemBuilder.toString());
|
||||
|
||||
// 限制最多显示 10 个诊断(包括主诊断)
|
||||
if (diagnosisSet.size() >= 10) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 拼接诊断信息
|
||||
String result = String.join(";", diagnosisSet);
|
||||
|
||||
|
||||
return result;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取患者诊断信息失败,encounterId: {}", encounterId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConsultationRequestDto> getMyInvitations() {
|
||||
try {
|
||||
// 获取当前登录医生ID
|
||||
Long currentPhysicianId = SecurityUtils.getLoginUser().getPractitionerId();
|
||||
|
||||
// 查询邀请我的会诊申请
|
||||
LambdaQueryWrapper<ConsultationInvited> invitedWrapper = new LambdaQueryWrapper<>();
|
||||
invitedWrapper.eq(ConsultationInvited::getInvitedPhysicianId, currentPhysicianId)
|
||||
.orderByDesc(ConsultationInvited::getCreateTime);
|
||||
|
||||
List<ConsultationInvited> invitedList = consultationInvitedMapper.selectList(invitedWrapper);
|
||||
|
||||
if (invitedList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 获取所有会诊申请ID
|
||||
List<Long> requestIds = invitedList.stream()
|
||||
.map(ConsultationInvited::getConsultationRequestId)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 查询会诊申请详情
|
||||
List<ConsultationRequest> requests = consultationRequestMapper.selectBatchIds(requestIds);
|
||||
|
||||
// 转换为DTO并添加邀请状态
|
||||
Map<Long, ConsultationInvited> invitedMap = invitedList.stream()
|
||||
.collect(Collectors.toMap(ConsultationInvited::getConsultationRequestId, v -> v, (v1, v2) -> v1));
|
||||
|
||||
return requests.stream().map(request -> {
|
||||
ConsultationRequestDto dto = convertToDto(request);
|
||||
// 添加我的邀请状态
|
||||
ConsultationInvited myInvited = invitedMap.get(request.getId());
|
||||
if (myInvited != null) {
|
||||
dto.setMyInvitedStatus(myInvited.getInvitedStatus());
|
||||
dto.setMyConfirmTime(myInvited.getConfirmTime());
|
||||
}
|
||||
return dto;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("获取我的会诊邀请失败", e);
|
||||
throw new RuntimeException("获取我的会诊邀请失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为DTO
|
||||
*/
|
||||
private ConsultationRequestDto convertToDto(ConsultationRequest entity) {
|
||||
ConsultationRequestDto dto = new ConsultationRequestDto();
|
||||
BeanUtils.copyProperties(entity, dto);
|
||||
|
||||
// 查询邀请对象列表
|
||||
if (entity.getId() != null) {
|
||||
LambdaQueryWrapper<ConsultationInvited> invitedWrapper = new LambdaQueryWrapper<>();
|
||||
invitedWrapper.eq(ConsultationInvited::getConsultationRequestId, entity.getId());
|
||||
List<ConsultationInvited> invitedList = consultationInvitedMapper.selectList(invitedWrapper);
|
||||
|
||||
if (invitedList != null && !invitedList.isEmpty()) {
|
||||
List<InvitedObjectDto> invitedDtoList = invitedList.stream().map(invited -> {
|
||||
InvitedObjectDto invitedDto = new InvitedObjectDto();
|
||||
invitedDto.setDeptId(invited.getInvitedDepartmentId());
|
||||
invitedDto.setDeptName(invited.getInvitedDepartmentName());
|
||||
invitedDto.setPhysicianId(invited.getInvitedPhysicianId());
|
||||
invitedDto.setPhysicianName(invited.getInvitedPhysicianName());
|
||||
return invitedDto;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
dto.setInvitedList(invitedDtoList);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果门诊诊断为空,尝试从数据库自动获取
|
||||
if (!StringUtils.hasText(entity.getProvisionalDiagnosis()) && entity.getEncounterId() != null) {
|
||||
String diagnosis = getPatientDiagnosis(entity.getEncounterId());
|
||||
if (StringUtils.hasText(diagnosis)) {
|
||||
dto.setProvisionalDiagnosis(diagnosis);
|
||||
}
|
||||
}
|
||||
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成会诊申请单号(高性能版本)
|
||||
* 格式:CS + 年月日时分秒 + 4位序列号
|
||||
* 例如:CS202601301425300001
|
||||
*
|
||||
* 优化说明:
|
||||
* 1. 使用 AtomicInteger 保证线程安全,性能远高于 synchronized
|
||||
* 2. 每秒最多支持 10000 个并发请求(0000-9999)
|
||||
* 3. 无需查询数据库,性能提升 100+ 倍
|
||||
* 4. 秒级时间戳 + 自增序列号,确保唯一性
|
||||
*/
|
||||
private String generateConsultationId() {
|
||||
|
||||
while (true) {
|
||||
long nowMillis = System.currentTimeMillis();
|
||||
long currentSecond = nowMillis / 1000;
|
||||
|
||||
// 跨秒则重置序列号(双重检查 + 类锁)
|
||||
if (currentSecond != lastSecond) {
|
||||
synchronized (ConsultationAppServiceImpl.class) {
|
||||
if (currentSecond != lastSecond) {
|
||||
lastSecond = currentSecond;
|
||||
SEQUENCE.set(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int sequence = SEQUENCE.getAndIncrement();
|
||||
|
||||
// 本秒内序列号耗尽:精确等待到下一秒再重试(避免递归、避免固定100ms)
|
||||
if (sequence >= 10000) {
|
||||
// 可选“回退自增”让 SEQUENCE 不乱飙
|
||||
// 回退这次自增(可选,但更“稳”,避免 SEQUENCE 无限增长)
|
||||
// 注意:回退可能在极端并发下导致轻微争用,但比不回退更可控
|
||||
SEQUENCE.decrementAndGet();
|
||||
|
||||
sleepUntilNextSecond(nowMillis);
|
||||
continue;
|
||||
}
|
||||
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyyMMddHHmmss");
|
||||
String dateTime = sdf.format(new Date());
|
||||
|
||||
String sequenceStr = String.format("%04d", sequence);
|
||||
return "CS" + dateTime + sequenceStr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 精确等到下一秒,等待更短、抖动更小,不在固定睡100ms
|
||||
private void sleepUntilNextSecond(long nowMillis) {
|
||||
long nextSecondMillis = (nowMillis / 1000 + 1) * 1000;
|
||||
long sleepMillis = nextSecondMillis - nowMillis;
|
||||
|
||||
// 防御:理论上 sleepMillis 范围是 1~1000ms
|
||||
if (sleepMillis <= 0) return;
|
||||
|
||||
try {
|
||||
Thread.sleep(sleepMillis);
|
||||
} catch (InterruptedException e) {
|
||||
// 恢复中断标记:把“有人希望我停下来”的信号传递给上层
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("生成会诊申请单号失败:线程被中断", e);
|
||||
}
|
||||
}
|
||||
|
||||
// private String generateConsultationId() {
|
||||
// java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyyMMddHHmmss");
|
||||
// long currentSecond = System.currentTimeMillis() / 1000;
|
||||
//
|
||||
// // 如果是新的一秒,重置序列号
|
||||
// // 跨秒检测:如果发现当前秒变了,说明进入下一秒
|
||||
// // 重置序列号:把 SEQUENCE 重新设置为 0,保证新的一秒从 0000 开始
|
||||
// // 双重锁检测:避免重复进入
|
||||
// if (currentSecond != lastSecond) {
|
||||
// synchronized (ConsultationAppServiceImpl.class) {
|
||||
// if (currentSecond != lastSecond) {
|
||||
// lastSecond = currentSecond;
|
||||
// SEQUENCE.set(0);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 获取当前序列号并自增(线程安全)
|
||||
// int sequence = SEQUENCE.getAndIncrement();
|
||||
//
|
||||
// // 如果同一秒内超过 10000 个请求,等待下一秒
|
||||
// if (sequence >= 10000) {
|
||||
// try {
|
||||
// Thread.sleep(100); // 等待 100ms
|
||||
// return generateConsultationId(); // 递归重试
|
||||
// } catch (InterruptedException e) {
|
||||
// Thread.currentThread().interrupt();
|
||||
// throw new RuntimeException("生成会诊申请单号失败", e);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 生成时间戳部分
|
||||
// String dateTime = sdf.format(new Date());
|
||||
//
|
||||
// // 生成4位序列号(补零)
|
||||
// String sequenceStr = String.format("%04d", sequence);
|
||||
//
|
||||
// return "CS" + dateTime + sequenceStr;
|
||||
// }
|
||||
|
||||
/**
|
||||
* 计算年龄
|
||||
*/
|
||||
private Integer calculateAge(Date birthDate) {
|
||||
if (birthDate == null) {
|
||||
return null;
|
||||
}
|
||||
java.util.Calendar now = java.util.Calendar.getInstance();
|
||||
java.util.Calendar birth = java.util.Calendar.getInstance();
|
||||
birth.setTime(birthDate);
|
||||
|
||||
int age = now.get(java.util.Calendar.YEAR) - birth.get(java.util.Calendar.YEAR);
|
||||
if (now.get(java.util.Calendar.DAY_OF_YEAR) < birth.get(java.util.Calendar.DAY_OF_YEAR)) {
|
||||
age--;
|
||||
}
|
||||
return age;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存会诊医嘱到门诊医嘱表(wor_service_request)
|
||||
* 同时创建费用项(adm_charge_item)
|
||||
*
|
||||
* @param consultationRequest 会诊申请实体
|
||||
*/
|
||||
private void saveConsultationServiceRequest(ConsultationRequest consultationRequest) {
|
||||
try {
|
||||
ServiceRequest serviceRequest = new ServiceRequest();
|
||||
|
||||
// 生成医嘱编号
|
||||
String busNo = assignSeqUtil.getSeqByDay(AssignSeqEnum.SERVICE_RES_NO.getPrefix(), 4);
|
||||
serviceRequest.setBusNo(busNo);
|
||||
|
||||
// 基本信息
|
||||
serviceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
|
||||
|
||||
// 🎯 使用前端选择的会诊项目ID
|
||||
Long activityDefinitionId = consultationRequest.getConsultationActivityId();
|
||||
if (activityDefinitionId == null) {
|
||||
// 如果前端没有传递,使用默认的"院内会诊"
|
||||
activityDefinitionId = 1983417749497446402L;
|
||||
log.warn("前端未传递会诊项目ID,使用默认的院内会诊: {}", activityDefinitionId);
|
||||
}
|
||||
|
||||
// 🎯 设置医嘱类型为会诊(31=会诊类型)
|
||||
// 医嘱类型分类:1-10=药品,22-30=诊疗,31=会诊,40+=其他
|
||||
serviceRequest.setCategoryEnum(31); // 会诊类型
|
||||
serviceRequest.setActivityId(activityDefinitionId); // 关联到会诊项目定义
|
||||
|
||||
serviceRequest.setPatientId(consultationRequest.getPatientId());
|
||||
serviceRequest.setEncounterId(consultationRequest.getEncounterId());
|
||||
serviceRequest.setRequesterId(consultationRequest.getRequestingPhysicianId());
|
||||
|
||||
// 🎯 设置执行科室(申请医生的科室)
|
||||
serviceRequest.setOrgId(consultationRequest.getDepartmentId());
|
||||
|
||||
// 🎯 设置执行次数为 1
|
||||
serviceRequest.setQuantity(BigDecimal.ONE);
|
||||
serviceRequest.setUnitCode("111"); // 单位:次
|
||||
|
||||
// 医嘱状态:新开
|
||||
serviceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());
|
||||
|
||||
// 医嘱内容:保存会诊申请的详细信息(JSON格式)
|
||||
Map<String, Object> contentMap = new HashMap<>();
|
||||
contentMap.put("consultationRequestId", consultationRequest.getId());
|
||||
contentMap.put("consultationId", consultationRequest.getConsultationId());
|
||||
contentMap.put("consultationType", consultationRequest.getConsultationActivityName());
|
||||
contentMap.put("consultationActivityId", activityDefinitionId);
|
||||
contentMap.put("patientName", consultationRequest.getPatientName());
|
||||
contentMap.put("provisionalDiagnosis", consultationRequest.getProvisionalDiagnosis());
|
||||
contentMap.put("consultationPurpose", consultationRequest.getConsultationPurpose());
|
||||
contentMap.put("requestingPhysician", consultationRequest.getRequestingPhysician());
|
||||
contentMap.put("department", consultationRequest.getDepartment());
|
||||
contentMap.put("adviceName", consultationRequest.getConsultationActivityName()); // 添加项目名称
|
||||
|
||||
serviceRequest.setContentJson(JSON.toJSONString(contentMap));
|
||||
|
||||
// 时间信息
|
||||
serviceRequest.setAuthoredTime(new Date());
|
||||
|
||||
// 审计字段
|
||||
serviceRequest.setTenantId(SecurityUtils.getLoginUser().getTenantId().intValue());
|
||||
serviceRequest.setCreateBy(SecurityUtils.getUsername());
|
||||
serviceRequest.setCreateTime(new Date());
|
||||
|
||||
// 保存到数据库
|
||||
iServiceRequestService.save(serviceRequest);
|
||||
|
||||
|
||||
// 🎯 新增:创建费用项(ChargeItem)
|
||||
// 查询会诊项目的价格定义
|
||||
LambdaQueryWrapper<ChargeItemDefinition> priceWrapper = new LambdaQueryWrapper<>();
|
||||
priceWrapper.eq(ChargeItemDefinition::getInstanceTable, "wor_activity_definition")
|
||||
.eq(ChargeItemDefinition::getInstanceId, activityDefinitionId)
|
||||
.eq(ChargeItemDefinition::getStatusEnum, 2) // 2=启用
|
||||
.eq(ChargeItemDefinition::getDeleteFlag, "0")
|
||||
.last("LIMIT 1");
|
||||
|
||||
ChargeItemDefinition chargeItemDef = chargeItemDefinitionMapper.selectOne(priceWrapper);
|
||||
|
||||
if (chargeItemDef != null) {
|
||||
// 🎯 查询患者的费用性质(account_id)
|
||||
// 从 adm_account 表获取患者的 account_id(费用性质)
|
||||
Long accountId = doctorStationAdviceAppMapper.getEncounterContract(consultationRequest.getEncounterId())
|
||||
.stream()
|
||||
.findFirst()
|
||||
.map(contract -> contract.getAccountId())
|
||||
.orElse(null);
|
||||
|
||||
if (accountId == null) {
|
||||
log.warn("未找到患者的费用性质,encounterId: {}", consultationRequest.getEncounterId());
|
||||
throw new RuntimeException("未找到患者的费用性质信息,无法创建费用项");
|
||||
}
|
||||
|
||||
ChargeItem chargeItem = new ChargeItem();
|
||||
chargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue()); // 草稿状态
|
||||
chargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(busNo));
|
||||
chargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
|
||||
chargeItem.setPatientId(consultationRequest.getPatientId());
|
||||
chargeItem.setContextEnum(ItemType.ACTIVITY.getValue()); // 诊疗类型
|
||||
chargeItem.setEncounterId(consultationRequest.getEncounterId());
|
||||
|
||||
// 🎯 设置费用性质(必填字段)
|
||||
chargeItem.setAccountId(accountId);
|
||||
|
||||
// 费用定价信息
|
||||
chargeItem.setDefinitionId(chargeItemDef.getId());
|
||||
chargeItem.setUnitPrice(chargeItemDef.getPrice());
|
||||
chargeItem.setQuantityValue(BigDecimal.ONE);
|
||||
chargeItem.setQuantityUnit("111"); // 次
|
||||
chargeItem.setTotalPrice(chargeItemDef.getPrice());
|
||||
|
||||
// 关联医嘱信息
|
||||
chargeItem.setServiceTable("wor_service_request");
|
||||
chargeItem.setServiceId(serviceRequest.getId());
|
||||
chargeItem.setProductTable("wor_activity_definition");
|
||||
chargeItem.setProductId(activityDefinitionId);
|
||||
|
||||
// 开立信息
|
||||
chargeItem.setEntererId(consultationRequest.getRequestingPhysicianId());
|
||||
chargeItem.setRequestingOrgId(consultationRequest.getDepartmentId());
|
||||
chargeItem.setEnteredDate(new Date());
|
||||
|
||||
// 审计字段
|
||||
chargeItem.setTenantId(SecurityUtils.getLoginUser().getTenantId());
|
||||
chargeItem.setCreateBy(SecurityUtils.getUsername());
|
||||
chargeItem.setCreateTime(new Date());
|
||||
|
||||
iChargeItemService.save(chargeItem);
|
||||
|
||||
} else {
|
||||
log.warn("未找到会诊项目的价格定义,activityId: {}", activityDefinitionId);
|
||||
}
|
||||
|
||||
// 将医嘱ID保存到会诊申请表
|
||||
consultationRequest.setOrderId(serviceRequest.getId());
|
||||
consultationRequestMapper.updateById(consultationRequest);
|
||||
} catch (Exception e) {
|
||||
log.error("保存会诊医嘱失败", e);
|
||||
throw new RuntimeException("保存会诊医嘱失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会诊医嘱
|
||||
*
|
||||
* @param consultationRequest 会诊申请实体
|
||||
*/
|
||||
private void updateConsultationServiceRequest(ConsultationRequest consultationRequest) {
|
||||
try {
|
||||
if (consultationRequest.getOrderId() == null) {
|
||||
log.warn("会诊申请没有关联的医嘱ID,跳过更新");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceRequest serviceRequest = iServiceRequestService.getById(consultationRequest.getOrderId());
|
||||
if (serviceRequest == null) {
|
||||
log.warn("未找到关联的医嘱记录,OrderId: {}", consultationRequest.getOrderId());
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新医嘱内容
|
||||
serviceRequest.setContentJson(JSON.toJSONString(consultationRequest));
|
||||
serviceRequest.setUpdateBy(SecurityUtils.getUsername());
|
||||
serviceRequest.setUpdateTime(new Date());
|
||||
|
||||
iServiceRequestService.updateById(serviceRequest);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("更新会诊医嘱失败", e);
|
||||
throw new RuntimeException("更新会诊医嘱失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新门诊医嘱状态
|
||||
*
|
||||
* @param orderId 医嘱ID
|
||||
* @param status 新状态
|
||||
*/
|
||||
private void updateServiceRequestStatus(Long orderId, Integer status) {
|
||||
try {
|
||||
if (orderId == null) {
|
||||
log.warn("医嘱ID为空,跳过状态更新");
|
||||
return;
|
||||
}
|
||||
|
||||
ServiceRequest serviceRequest = iServiceRequestService.getById(orderId);
|
||||
if (serviceRequest == null) {
|
||||
log.warn("未找到医嘱记录,OrderId: {}", orderId);
|
||||
return;
|
||||
}
|
||||
|
||||
serviceRequest.setStatusEnum(status);
|
||||
serviceRequest.setUpdateBy(SecurityUtils.getUsername());
|
||||
serviceRequest.setUpdateTime(new Date());
|
||||
|
||||
iServiceRequestService.updateById(serviceRequest);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("更新医嘱状态失败", e);
|
||||
throw new RuntimeException("更新医嘱状态失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConsultationActivityDto> getConsultationActivities() {
|
||||
try {
|
||||
// 查询所有会诊相关的诊疗活动
|
||||
LambdaQueryWrapper<ActivityDefinition> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.like(ActivityDefinition::getName, "会诊")
|
||||
.eq(ActivityDefinition::getDeleteFlag, "0")
|
||||
.orderBy(true, true, ActivityDefinition::getSortOrder);
|
||||
|
||||
List<ActivityDefinition> activityList = activityDefinitionMapper.selectList(wrapper);
|
||||
if (activityList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
// 转换为DTO并查询价格
|
||||
List<ConsultationActivityDto> resultList = new ArrayList<>();
|
||||
for (ActivityDefinition activity : activityList) {
|
||||
ConsultationActivityDto dto = new ConsultationActivityDto();
|
||||
dto.setId(activity.getId());
|
||||
dto.setName(activity.getName());
|
||||
dto.setBusNo(activity.getBusNo());
|
||||
dto.setTypeEnum(activity.getTypeEnum());
|
||||
dto.setCategoryCode(activity.getCategoryCode());
|
||||
dto.setUnitCode(activity.getPermittedUnitCode());
|
||||
dto.setStatusEnum(activity.getStatusEnum());
|
||||
|
||||
// 查询价格
|
||||
LambdaQueryWrapper<ChargeItemDefinition> priceWrapper = new LambdaQueryWrapper<>();
|
||||
priceWrapper.eq(ChargeItemDefinition::getInstanceTable, "wor_activity_definition")
|
||||
.eq(ChargeItemDefinition::getInstanceId, activity.getId())
|
||||
.eq(ChargeItemDefinition::getStatusEnum, 2) // 2=启用
|
||||
.eq(ChargeItemDefinition::getDeleteFlag, "0")
|
||||
.last("LIMIT 1");
|
||||
|
||||
ChargeItemDefinition chargeItem = chargeItemDefinitionMapper.selectOne(priceWrapper);
|
||||
if (chargeItem != null && chargeItem.getPrice() != null) {
|
||||
dto.setPrice(chargeItem.getPrice());
|
||||
} else {
|
||||
dto.setPrice(java.math.BigDecimal.ZERO);
|
||||
log.warn("会诊项目: {} 未找到价格定义", activity.getName());
|
||||
}
|
||||
|
||||
resultList.add(dto);
|
||||
}
|
||||
return resultList;
|
||||
} catch (Exception e) {
|
||||
log.error("查询会诊项目列表失败", e);
|
||||
throw new RuntimeException("查询会诊项目列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
package com.openhis.web.consultation.controller;
|
||||
|
||||
import com.core.common.core.domain.R;
|
||||
import com.openhis.web.consultation.appservice.IConsultationAppService;
|
||||
import com.openhis.web.consultation.dto.ConsultationActivityDto;
|
||||
import com.openhis.web.consultation.dto.ConsultationRequestDto;
|
||||
import com.openhis.web.consultation.dto.DepartmentTreeDto;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 会诊管理Controller
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@Slf4j
|
||||
@Api(tags = "会诊管理")
|
||||
@RestController
|
||||
@RequestMapping("/consultation")
|
||||
public class ConsultationController {
|
||||
|
||||
@Resource
|
||||
private IConsultationAppService consultationAppService;
|
||||
|
||||
/**
|
||||
* 获取会诊列表
|
||||
*/
|
||||
@ApiOperation("获取会诊列表")
|
||||
@GetMapping("/list")
|
||||
public R<List<ConsultationRequestDto>> getConsultationList(
|
||||
@ApiParam("就诊ID(可选,不传则查询当前医生的所有会诊申请)")
|
||||
@RequestParam(required = false) Long encounterId) {
|
||||
try {
|
||||
List<ConsultationRequestDto> list = consultationAppService.getConsultationList(encounterId);
|
||||
return R.ok(list);
|
||||
} catch (Exception e) {
|
||||
log.error("获取会诊列表失败", e);
|
||||
return R.fail("获取会诊列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存会诊申请
|
||||
*/
|
||||
@ApiOperation("保存会诊申请")
|
||||
@PostMapping("/save")
|
||||
public R<String> saveConsultation(@RequestBody ConsultationRequestDto dto) {
|
||||
try {
|
||||
Boolean result = consultationAppService.saveConsultation(dto);
|
||||
return result ? R.ok("保存成功") : R.fail("保存失败");
|
||||
} catch (Exception e) {
|
||||
log.error("保存会诊申请失败", e);
|
||||
return R.fail("保存会诊申请失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 提交会诊申请
|
||||
*/
|
||||
@ApiOperation("提交会诊申请")
|
||||
@PostMapping("/submit")
|
||||
public R<String> submitConsultation(
|
||||
@ApiParam("会诊申请单号") @RequestParam String consultationId) {
|
||||
try {
|
||||
Boolean result = consultationAppService.submitConsultation(consultationId);
|
||||
return result ? R.ok("提交成功") : R.fail("提交失败");
|
||||
} catch (Exception e) {
|
||||
log.error("提交会诊申请失败", e);
|
||||
return R.fail("提交会诊申请失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 作废会诊申请
|
||||
*/
|
||||
@ApiOperation("作废会诊申请")
|
||||
@PostMapping("/cancel")
|
||||
public R<String> cancelConsultation(
|
||||
@ApiParam("会诊申请单号") @RequestParam String consultationId,
|
||||
@ApiParam("作废原因") @RequestParam(required = false) String cancelReason) {
|
||||
try {
|
||||
Boolean result = consultationAppService.cancelConsultation(consultationId, cancelReason);
|
||||
return result ? R.ok("作废成功") : R.fail("作废失败");
|
||||
} catch (Exception e) {
|
||||
log.error("作废会诊申请失败", e);
|
||||
return R.fail("作废会诊申请失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束会诊申请
|
||||
*/
|
||||
@ApiOperation("结束会诊申请")
|
||||
@PostMapping("/complete")
|
||||
public R<String> completeConsultation(
|
||||
@ApiParam("会诊申请单号") @RequestParam String consultationId) {
|
||||
try {
|
||||
Boolean result = consultationAppService.completeConsultation(consultationId);
|
||||
return result ? R.ok("结束成功") : R.fail("结束失败");
|
||||
} catch (Exception e) {
|
||||
log.error("结束会诊申请失败", e);
|
||||
return R.fail("结束会诊申请失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取科室医生树
|
||||
*/
|
||||
@ApiOperation("获取科室医生树")
|
||||
@GetMapping("/departmentTree")
|
||||
public R<List<DepartmentTreeDto>> getDepartmentTree() {
|
||||
try {
|
||||
List<DepartmentTreeDto> tree = consultationAppService.getDepartmentTree();
|
||||
return R.ok(tree);
|
||||
} catch (Exception e) {
|
||||
log.error("获取科室医生树失败", e);
|
||||
return R.fail("获取科室医生树失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主诊断
|
||||
*/
|
||||
@ApiOperation("获取主诊断")
|
||||
@GetMapping("/mainDiagnosis")
|
||||
public R<Map<String, String>> getMainDiagnosis(
|
||||
@ApiParam("就诊ID") @RequestParam Long encounterId) {
|
||||
try {
|
||||
Map<String, String> diagnosis = consultationAppService.getMainDiagnosis(encounterId);
|
||||
return R.ok(diagnosis);
|
||||
} catch (Exception e) {
|
||||
log.error("获取主诊断失败", e);
|
||||
return R.fail("获取主诊断失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取我的会诊邀请列表
|
||||
*/
|
||||
@ApiOperation("获取我的会诊邀请列表")
|
||||
@GetMapping("/myInvitations")
|
||||
public R<List<ConsultationRequestDto>> getMyInvitations() {
|
||||
try {
|
||||
List<ConsultationRequestDto> list = consultationAppService.getMyInvitations();
|
||||
return R.ok(list);
|
||||
} catch (Exception e) {
|
||||
log.error("获取我的会诊邀请失败", e);
|
||||
return R.fail("获取我的会诊邀请失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有会诊项目及价格
|
||||
*/
|
||||
@ApiOperation("获取所有会诊项目及价格")
|
||||
@GetMapping("/activities")
|
||||
public R<List<ConsultationActivityDto>> getConsultationActivities() {
|
||||
try {
|
||||
List<ConsultationActivityDto> list = consultationAppService.getConsultationActivities();
|
||||
return R.ok(list);
|
||||
} catch (Exception e) {
|
||||
log.error("获取会诊项目列表失败", e);
|
||||
return R.fail("获取会诊项目列表失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.openhis.web.consultation.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 会诊邀请对象实体类
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-30
|
||||
*/
|
||||
@Data
|
||||
@TableName("consultation_invited")
|
||||
public class ConsultationInvited implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 会诊申请ID(外键)
|
||||
*/
|
||||
@TableField("consultation_request_id")
|
||||
private Long consultationRequestId;
|
||||
|
||||
/**
|
||||
* 邀请科室ID
|
||||
*/
|
||||
@TableField("invited_department_id")
|
||||
private Long invitedDepartmentId;
|
||||
|
||||
/**
|
||||
* 邀请科室名称
|
||||
*/
|
||||
@TableField("invited_department_name")
|
||||
private String invitedDepartmentName;
|
||||
|
||||
/**
|
||||
* 邀请医生ID
|
||||
*/
|
||||
@TableField("invited_physician_id")
|
||||
private Long invitedPhysicianId;
|
||||
|
||||
/**
|
||||
* 邀请医生姓名
|
||||
*/
|
||||
@TableField("invited_physician_name")
|
||||
private String invitedPhysicianName;
|
||||
|
||||
/**
|
||||
* 邀请状态(0-待确认,1-已确认,2-已拒绝)
|
||||
*/
|
||||
@TableField("invited_status")
|
||||
private Integer invitedStatus;
|
||||
|
||||
/**
|
||||
* 确认时间
|
||||
*/
|
||||
@TableField("confirm_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date confirmTime;
|
||||
|
||||
/**
|
||||
* 确认意见
|
||||
*/
|
||||
@TableField("confirm_opinion")
|
||||
private String confirmOpinion;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time", fill = FieldFill.INSERT)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@TableField(value = "create_by", fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@TableField("tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 删除标识(0-未删除,1-已删除)
|
||||
*/
|
||||
@TableField("is_deleted")
|
||||
@TableLogic
|
||||
private Integer isDeleted;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
package com.openhis.web.consultation.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.*;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 会诊申请单实体类
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@Data
|
||||
@TableName("consultation_request")
|
||||
public class ConsultationRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 会诊申请单号
|
||||
*/
|
||||
@TableField("consultation_id")
|
||||
private String consultationId;
|
||||
|
||||
/**
|
||||
* 患者ID
|
||||
*/
|
||||
@TableField("patient_id")
|
||||
private Long patientId;
|
||||
|
||||
/**
|
||||
* 就诊ID
|
||||
*/
|
||||
@TableField("encounter_id")
|
||||
private Long encounterId;
|
||||
|
||||
/**
|
||||
* 订单ID(关联门诊医嘱表 wor_service_request.id)
|
||||
*/
|
||||
@TableField("order_id")
|
||||
private Long orderId;
|
||||
|
||||
/**
|
||||
* 患者姓名
|
||||
*/
|
||||
@TableField("patient_name")
|
||||
private String patientName;
|
||||
|
||||
/**
|
||||
* 患者病历号
|
||||
*/
|
||||
@TableField("patient_bus_no")
|
||||
private String patientBusNo;
|
||||
|
||||
/**
|
||||
* 患者就诊卡号
|
||||
*/
|
||||
@TableField("patient_identifier_no")
|
||||
private String patientIdentifierNo;
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*/
|
||||
@TableField("gender_enum")
|
||||
private Integer genderEnum;
|
||||
|
||||
/**
|
||||
* 年龄
|
||||
*/
|
||||
@TableField("age")
|
||||
private Integer age;
|
||||
|
||||
/**
|
||||
* 申请科室名称
|
||||
*/
|
||||
@TableField("department")
|
||||
private String department;
|
||||
|
||||
/**
|
||||
* 申请科室ID
|
||||
*/
|
||||
@TableField("department_id")
|
||||
private Long departmentId;
|
||||
|
||||
/**
|
||||
* 申请医生姓名
|
||||
*/
|
||||
@TableField("requesting_physician")
|
||||
private String requestingPhysician;
|
||||
|
||||
/**
|
||||
* 申请医生ID
|
||||
*/
|
||||
@TableField("requesting_physician_id")
|
||||
private Long requestingPhysicianId;
|
||||
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
@TableField("consultation_request_date")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date consultationRequestDate;
|
||||
|
||||
/**
|
||||
* 邀请对象显示文本
|
||||
*/
|
||||
@TableField("invited_object")
|
||||
private String invitedObject;
|
||||
|
||||
/**
|
||||
* 会诊时间
|
||||
*/
|
||||
@TableField("consultation_date")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date consultationDate;
|
||||
|
||||
/**
|
||||
* 会诊目的
|
||||
*/
|
||||
@TableField("consultation_purpose")
|
||||
private String consultationPurpose;
|
||||
|
||||
/**
|
||||
* 门诊诊断
|
||||
*/
|
||||
@TableField("provisional_diagnosis")
|
||||
private String provisionalDiagnosis;
|
||||
|
||||
/**
|
||||
* 会诊项目ID(关联wor_activity_definition表)
|
||||
*/
|
||||
@TableField("consultation_activity_id")
|
||||
private Long consultationActivityId;
|
||||
|
||||
/**
|
||||
* 会诊项目名称(如:院内会诊、远程会诊等)
|
||||
*/
|
||||
@TableField("consultation_activity_name")
|
||||
private String consultationActivityName;
|
||||
|
||||
/**
|
||||
* 会诊意见
|
||||
*/
|
||||
@TableField("consultation_opinion")
|
||||
private String consultationOpinion;
|
||||
|
||||
/**
|
||||
* 会诊状态(0-新开,10-已提交,20-已确认,30-已签名,40-已完成,50-已取消)
|
||||
*/
|
||||
@TableField("consultation_status")
|
||||
private Integer consultationStatus;
|
||||
|
||||
/**
|
||||
* 紧急程度(一般/紧急)
|
||||
*/
|
||||
@TableField("consultation_urgency")
|
||||
private String consultationUrgency;
|
||||
|
||||
/**
|
||||
* 确认医生
|
||||
*/
|
||||
@TableField("confirming_physician")
|
||||
private String confirmingPhysician;
|
||||
|
||||
/**
|
||||
* 确认医生ID
|
||||
*/
|
||||
@TableField("confirming_physician_id")
|
||||
private Long confirmingPhysicianId;
|
||||
|
||||
/**
|
||||
* 确认时间
|
||||
*/
|
||||
@TableField("confirming_date")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date confirmingDate;
|
||||
|
||||
/**
|
||||
* 签名
|
||||
*/
|
||||
@TableField("signature")
|
||||
private String signature;
|
||||
|
||||
/**
|
||||
* 签名医生ID
|
||||
*/
|
||||
@TableField("signature_physician_id")
|
||||
private Long signaturePhysicianId;
|
||||
|
||||
/**
|
||||
* 签名时间
|
||||
*/
|
||||
@TableField("signature_date")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date signatureDate;
|
||||
|
||||
/**
|
||||
* 取消时间
|
||||
*/
|
||||
@TableField("cancel_nature_date")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date cancelNatureDate;
|
||||
|
||||
/**
|
||||
* 作废原因
|
||||
*/
|
||||
@TableField("cancel_reason")
|
||||
private String cancelReason;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(value = "create_time", fill = FieldFill.INSERT)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 创建人
|
||||
*/
|
||||
@TableField(value = "create_by", fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
/**
|
||||
* 更新人
|
||||
*/
|
||||
@TableField(value = "update_by", fill = FieldFill.INSERT_UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
/**
|
||||
* 租户ID
|
||||
*/
|
||||
@TableField("tenant_id")
|
||||
private Long tenantId;
|
||||
|
||||
/**
|
||||
* 删除标识(0-未删除,1-已删除)
|
||||
*/
|
||||
@TableField("is_deleted")
|
||||
@TableLogic
|
||||
private Integer isDeleted;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.openhis.web.consultation.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 会诊项目DTO
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-02-02
|
||||
*/
|
||||
@Data
|
||||
public class ConsultationActivityDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 项目ID
|
||||
* 使用 @JsonSerialize 注解将 Long 类型转换为 String,避免前端 JavaScript 精度丢失
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 项目名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 项目编号
|
||||
*/
|
||||
private String busNo;
|
||||
|
||||
/**
|
||||
* 价格
|
||||
*/
|
||||
private BigDecimal price;
|
||||
|
||||
/**
|
||||
* 类型枚举
|
||||
*/
|
||||
private Integer typeEnum;
|
||||
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
private String categoryCode;
|
||||
|
||||
/**
|
||||
* 单位编码
|
||||
*/
|
||||
private String unitCode;
|
||||
|
||||
/**
|
||||
* 单位名称
|
||||
*/
|
||||
private String unitCodeText;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
private Integer statusEnum;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
package com.openhis.web.consultation.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 会诊申请DTO
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@Data
|
||||
public class ConsultationRequestDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 会诊申请单号
|
||||
*/
|
||||
private String consultationId;
|
||||
|
||||
/**
|
||||
* 患者ID
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long patientId;
|
||||
|
||||
/**
|
||||
* 患者姓名
|
||||
*/
|
||||
private String patientName;
|
||||
|
||||
/**
|
||||
* 患者性别
|
||||
*/
|
||||
private Integer genderEnum;
|
||||
|
||||
/**
|
||||
* 患者年龄
|
||||
*/
|
||||
private Integer age;
|
||||
|
||||
/**
|
||||
* 病历号
|
||||
*/
|
||||
private String patientBusNo;
|
||||
|
||||
/**
|
||||
* 就诊卡号
|
||||
*/
|
||||
private String patientIdentifierNo;
|
||||
|
||||
/**
|
||||
* 就诊ID
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long encounterId;
|
||||
|
||||
/**
|
||||
* 申请科室ID
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long departmentId;
|
||||
|
||||
/**
|
||||
* 申请科室名称
|
||||
*/
|
||||
private String department;
|
||||
|
||||
/**
|
||||
* 申请医生ID
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long requestingPhysicianId;
|
||||
|
||||
/**
|
||||
* 申请医生姓名
|
||||
*/
|
||||
private String requestingPhysician;
|
||||
|
||||
/**
|
||||
* 邀请对象显示文本
|
||||
*/
|
||||
private String invitedObject;
|
||||
|
||||
/**
|
||||
* 邀请对象列表
|
||||
*/
|
||||
private List<InvitedObjectDto> invitedList;
|
||||
|
||||
/**
|
||||
* 会诊时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date consultationDate;
|
||||
|
||||
/**
|
||||
* 申请时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date consultationRequestDate;
|
||||
|
||||
/**
|
||||
* 会诊目的
|
||||
*/
|
||||
private String consultationPurpose;
|
||||
|
||||
/**
|
||||
* 门诊诊断
|
||||
*/
|
||||
private String provisionalDiagnosis;
|
||||
|
||||
/**
|
||||
* 会诊项目ID(关联wor_activity_definition表)
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long consultationActivityId;
|
||||
|
||||
/**
|
||||
* 会诊项目名称(如:院内会诊、远程会诊等)
|
||||
*/
|
||||
private String consultationActivityName;
|
||||
|
||||
/**
|
||||
* 紧急程度(1=普通,2=紧急)
|
||||
*/
|
||||
private String consultationUrgency;
|
||||
|
||||
/**
|
||||
* 会诊状态
|
||||
*/
|
||||
private Integer consultationStatus;
|
||||
|
||||
/**
|
||||
* 会诊意见
|
||||
*/
|
||||
private String consultationOpinion;
|
||||
|
||||
/**
|
||||
* 参与会诊医师
|
||||
*/
|
||||
private String consultingPhysicians;
|
||||
|
||||
/**
|
||||
* 签名医生ID
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long signingPhysicianId;
|
||||
|
||||
/**
|
||||
* 签名医生姓名
|
||||
*/
|
||||
private String signingPhysicianName;
|
||||
|
||||
/**
|
||||
* 签名时间
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date signingTime;
|
||||
|
||||
/**
|
||||
* 是否提交(保存时使用)
|
||||
*/
|
||||
private Boolean submitFlag;
|
||||
|
||||
/**
|
||||
* 我的邀请状态(查询我的邀请时使用,0-待确认,1-已确认,2-已拒绝)
|
||||
*/
|
||||
private Integer myInvitedStatus;
|
||||
|
||||
/**
|
||||
* 我的确认时间(查询我的邀请时使用)
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date myConfirmTime;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.openhis.web.consultation.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 科室医生树DTO
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@Data
|
||||
public class DepartmentTreeDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 科室ID(序列化为字符串,避免JavaScript精度丢失)
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 科室名称
|
||||
*/
|
||||
private String label;
|
||||
|
||||
/**
|
||||
* 子节点(医生列表)
|
||||
*/
|
||||
private List<PhysicianNodeDto> children;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.openhis.web.consultation.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 邀请对象DTO
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@Data
|
||||
public class InvitedObjectDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 科室ID(序列化为字符串,避免JavaScript精度丢失)
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 科室名称
|
||||
*/
|
||||
private String deptName;
|
||||
|
||||
/**
|
||||
* 医生ID(为空表示邀请整个科室)(序列化为字符串,避免JavaScript精度丢失)
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long physicianId;
|
||||
|
||||
/**
|
||||
* 医生姓名
|
||||
*/
|
||||
private String physicianName;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.openhis.web.consultation.dto;
|
||||
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 医生节点DTO
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@Data
|
||||
public class PhysicianNodeDto implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 医生ID(序列化为字符串,避免JavaScript精度丢失)
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 医生姓名
|
||||
*/
|
||||
private String label;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.openhis.web.consultation.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 会诊状态枚举
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-02-05
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ConsultationStatusEnum {
|
||||
|
||||
/**
|
||||
* 新开(草稿)
|
||||
*/
|
||||
NEW(0, "新开"),
|
||||
|
||||
/**
|
||||
* 已提交
|
||||
*/
|
||||
SUBMITTED(10, "已提交"),
|
||||
|
||||
/**
|
||||
* 已确认
|
||||
*/
|
||||
CONFIRMED(20, "已确认"),
|
||||
|
||||
/**
|
||||
* 已签名
|
||||
*/
|
||||
SIGNED(30, "已签名"),
|
||||
|
||||
/**
|
||||
* 已完成
|
||||
*/
|
||||
COMPLETED(40, "已完成"),
|
||||
|
||||
/**
|
||||
* 已取消
|
||||
*/
|
||||
CANCELLED(50, "已取消");
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
private final Integer code;
|
||||
|
||||
/**
|
||||
* 状态描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
/**
|
||||
* 根据状态码获取枚举
|
||||
*/
|
||||
public static ConsultationStatusEnum getByCode(Integer code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (ConsultationStatusEnum status : values()) {
|
||||
if (status.getCode().equals(code)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否可以编辑
|
||||
*/
|
||||
public boolean canEdit() {
|
||||
return this == NEW || this == SUBMITTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否可以取消
|
||||
*/
|
||||
public boolean canCancel() {
|
||||
return this == NEW || this == SUBMITTED || this == CONFIRMED;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.openhis.web.consultation.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 会诊紧急程度枚举
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-02-05
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ConsultationUrgencyEnum {
|
||||
|
||||
/**
|
||||
* 普通
|
||||
*/
|
||||
NORMAL("1", "普通"),
|
||||
|
||||
/**
|
||||
* 紧急
|
||||
*/
|
||||
URGENT("2", "紧急");
|
||||
|
||||
/**
|
||||
* 类型码
|
||||
*/
|
||||
private final String code;
|
||||
|
||||
/**
|
||||
* 类型描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
/**
|
||||
* 根据类型码获取枚举
|
||||
*/
|
||||
public static ConsultationUrgencyEnum getByCode(String code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (ConsultationUrgencyEnum urgency : values()) {
|
||||
if (urgency.getCode().equals(code)) {
|
||||
return urgency;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.openhis.web.consultation.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 邀请状态枚举
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-02-05
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum InvitedStatusEnum {
|
||||
|
||||
/**
|
||||
* 待确认
|
||||
*/
|
||||
PENDING(0, "待确认"),
|
||||
|
||||
/**
|
||||
* 已确认
|
||||
*/
|
||||
CONFIRMED(1, "已确认"),
|
||||
|
||||
/**
|
||||
* 已拒绝
|
||||
*/
|
||||
REJECTED(2, "已拒绝");
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
private final Integer code;
|
||||
|
||||
/**
|
||||
* 状态描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
/**
|
||||
* 根据状态码获取枚举
|
||||
*/
|
||||
public static InvitedStatusEnum getByCode(Integer code) {
|
||||
if (code == null) {
|
||||
return null;
|
||||
}
|
||||
for (InvitedStatusEnum status : values()) {
|
||||
if (status.getCode().equals(code)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.openhis.web.consultation.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.openhis.web.consultation.domain.ConsultationInvited;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 会诊邀请对象Mapper接口
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-30
|
||||
*/
|
||||
@Mapper
|
||||
public interface ConsultationInvitedMapper extends BaseMapper<ConsultationInvited> {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.openhis.web.consultation.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.openhis.web.consultation.domain.ConsultationRequest;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 会诊申请Mapper接口
|
||||
*
|
||||
* @author system
|
||||
* @date 2026-01-29
|
||||
*/
|
||||
@Mapper
|
||||
public interface ConsultationRequestMapper extends BaseMapper<ConsultationRequest> {
|
||||
|
||||
}
|
||||
|
||||
@@ -864,7 +864,17 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
||||
serviceRequest.setQuantity(adviceSaveDto.getQuantity()); // 请求数量
|
||||
serviceRequest.setUnitCode(adviceSaveDto.getUnitCode()); // 请求单位编码
|
||||
|
||||
serviceRequest.setCategoryEnum(adviceSaveDto.getCategoryEnum()); // 请求类型
|
||||
// 🎯 判断是否为会诊医嘱:如果categoryEnum为31,则为会诊类型
|
||||
Integer categoryEnum = adviceSaveDto.getCategoryEnum();
|
||||
if (categoryEnum != null && categoryEnum == 31) {
|
||||
// 会诊医嘱:category_enum设置为31
|
||||
serviceRequest.setCategoryEnum(31);
|
||||
log.info("保存会诊医嘱,category_enum=31");
|
||||
} else {
|
||||
// 普通诊疗医嘱
|
||||
serviceRequest.setCategoryEnum(adviceSaveDto.getCategoryEnum());
|
||||
}
|
||||
|
||||
serviceRequest.setActivityId(adviceSaveDto.getAdviceDefinitionId());// 诊疗定义id
|
||||
serviceRequest.setPatientId(adviceSaveDto.getPatientId()); // 患者
|
||||
serviceRequest.setRequesterId(adviceSaveDto.getPractitionerId()); // 开方医生
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?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.web.consultation.mapper.ConsultationRequestMapper">
|
||||
|
||||
<!-- 通用查询映射结果 -->
|
||||
<resultMap id="BaseResultMap" type="com.openhis.web.consultation.domain.ConsultationRequest">
|
||||
<id column="id" property="id" />
|
||||
<result column="consultation_id" property="consultationId" />
|
||||
<result column="patient_id" property="patientId" />
|
||||
<result column="encounter_id" property="encounterId" />
|
||||
<result column="order_id" property="orderId" />
|
||||
<result column="patient_name" property="patientName" />
|
||||
<result column="patient_bus_no" property="patientBusNo" />
|
||||
<result column="patient_identifier_no" property="patientIdentifierNo" />
|
||||
<result column="gender_enum" property="genderEnum" />
|
||||
<result column="age" property="age" />
|
||||
<result column="department" property="department" />
|
||||
<result column="department_id" property="departmentId" />
|
||||
<result column="requesting_physician" property="requestingPhysician" />
|
||||
<result column="requesting_physician_id" property="requestingPhysicianId" />
|
||||
<result column="consultation_request_date" property="consultationRequestDate" />
|
||||
<result column="invited_object" property="invitedObject" />
|
||||
<result column="invited_department_id" property="invitedDepartmentId" />
|
||||
<result column="invited_physician_id" property="invitedPhysicianId" />
|
||||
<result column="consultation_date" property="consultationDate" />
|
||||
<result column="consultation_purpose" property="consultationPurpose" />
|
||||
<result column="provisional_diagnosis" property="provisionalDiagnosis" />
|
||||
<result column="consultation_opinion" property="consultationOpinion" />
|
||||
<result column="consultation_status" property="consultationStatus" />
|
||||
<result column="consultation_urgency" property="consultationUrgency" />
|
||||
<result column="confirming_physician" property="confirmingPhysician" />
|
||||
<result column="confirming_physician_id" property="confirmingPhysicianId" />
|
||||
<result column="confirming_date" property="confirmingDate" />
|
||||
<result column="signature" property="signature" />
|
||||
<result column="signature_physician_id" property="signaturePhysicianId" />
|
||||
<result column="signature_date" property="signatureDate" />
|
||||
<result column="cancel_nature_date" property="cancelNatureDate" />
|
||||
<result column="cancel_reason" property="cancelReason" />
|
||||
<result column="create_time" property="createTime" />
|
||||
<result column="update_time" property="updateTime" />
|
||||
<result column="create_by" property="createBy" />
|
||||
<result column="update_by" property="updateBy" />
|
||||
<result column="tenant_id" property="tenantId" />
|
||||
<result column="is_deleted" property="isDeleted" />
|
||||
<result column="remark" property="remark" />
|
||||
</resultMap>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -465,7 +465,8 @@
|
||||
T2.part_percent AS part_percent,
|
||||
ccd.name AS condition_definition_name,
|
||||
T1.sort_number AS sort_number,
|
||||
T1.based_on_id AS based_on_id
|
||||
T1.based_on_id AS based_on_id,
|
||||
T1.category_enum AS category_enum
|
||||
FROM med_medication_request AS T1
|
||||
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
|
||||
AND T2.delete_flag = '0'
|
||||
@@ -516,7 +517,8 @@
|
||||
T2.part_percent AS part_percent,
|
||||
'' AS condition_definition_name,
|
||||
99 AS sort_number,
|
||||
T1.based_on_id AS based_on_id
|
||||
T1.based_on_id AS based_on_id,
|
||||
T1.category_enum AS category_enum
|
||||
FROM wor_device_request AS T1
|
||||
LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id
|
||||
AND T2.delete_flag = '0'
|
||||
@@ -564,7 +566,8 @@
|
||||
1 AS part_percent,
|
||||
'' AS condition_definition_name,
|
||||
99 AS sort_number,
|
||||
T1.based_on_id AS based_on_id
|
||||
T1.based_on_id AS based_on_id,
|
||||
T1.category_enum AS category_enum
|
||||
FROM wor_service_request AS T1
|
||||
LEFT JOIN wor_activity_definition AS T2
|
||||
ON T2.ID = T1.activity_id
|
||||
|
||||
Reference in New Issue
Block a user