Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
@@ -22,6 +22,8 @@ import com.openhis.common.enums.ybenums.YbPayment;
|
|||||||
import com.openhis.common.utils.EnumUtils;
|
import com.openhis.common.utils.EnumUtils;
|
||||||
import com.openhis.common.utils.HisPageUtils;
|
import com.openhis.common.utils.HisPageUtils;
|
||||||
import com.openhis.common.utils.HisQueryUtils;
|
import com.openhis.common.utils.HisQueryUtils;
|
||||||
|
import com.openhis.appointmentmanage.domain.SchedulePool;
|
||||||
|
import com.openhis.appointmentmanage.domain.ScheduleSlot;
|
||||||
import com.openhis.appointmentmanage.mapper.SchedulePoolMapper;
|
import com.openhis.appointmentmanage.mapper.SchedulePoolMapper;
|
||||||
import com.openhis.appointmentmanage.mapper.ScheduleSlotMapper;
|
import com.openhis.appointmentmanage.mapper.ScheduleSlotMapper;
|
||||||
import com.openhis.clinical.domain.Order;
|
import com.openhis.clinical.domain.Order;
|
||||||
@@ -52,6 +54,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.LocalTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -111,6 +114,9 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
@Resource
|
@Resource
|
||||||
SchedulePoolMapper schedulePoolMapper;
|
SchedulePoolMapper schedulePoolMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
com.openhis.document.service.IEmrService iEmrService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 门诊挂号 - 查询患者信息
|
* 门诊挂号 - 查询患者信息
|
||||||
*
|
*
|
||||||
@@ -256,14 +262,24 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public R<?> returnRegister(CancelRegPaymentDto cancelRegPaymentDto) {
|
public R<?> returnRegister(CancelRegPaymentDto cancelRegPaymentDto) {
|
||||||
Encounter byId = iEncounterService.getById(cancelRegPaymentDto.getEncounterId());
|
Encounter byId = iEncounterService.getById(cancelRegPaymentDto.getEncounterId());
|
||||||
|
if (byId == null) {
|
||||||
|
return R.fail(null, "就诊记录不存在");
|
||||||
|
}
|
||||||
if (EncounterStatus.CANCELLED.getValue().equals(byId.getStatusEnum())) {
|
if (EncounterStatus.CANCELLED.getValue().equals(byId.getStatusEnum())) {
|
||||||
return R.fail(null, "该患者已经退号,请勿重复退号");
|
return R.fail(null, "该患者已经退号,请勿重复退号");
|
||||||
}
|
}
|
||||||
// 只有待诊状态才能退号
|
// 只有待诊状态才能退号
|
||||||
if (!EncounterStatus.PLANNED.getValue().equals(byId.getStatusEnum())) {
|
if (!EncounterStatus.PLANNED.getValue().equals(byId.getStatusEnum())) {
|
||||||
return R.fail(null, "该患者医生已接诊,不能退号!");
|
return R.fail(null, "该患者已开始就诊,不能退号!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 诊前退号检查:病历、费用明细、班段时间
|
||||||
|
R<?> checkResult = checkPreConsultationRefund(byId);
|
||||||
|
if (checkResult != null) {
|
||||||
|
return checkResult;
|
||||||
}
|
}
|
||||||
iEncounterService.returnRegister(cancelRegPaymentDto.getEncounterId());
|
iEncounterService.returnRegister(cancelRegPaymentDto.getEncounterId());
|
||||||
// 查询账户信息
|
// 查询账户信息
|
||||||
@@ -317,6 +333,149 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
return R.ok(paymentRecon, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"退号"}));
|
return R.ok(paymentRecon, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"退号"}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 诊前退号检查
|
||||||
|
* 检查项:病历记录、费用明细、当日就诊、班段结束时间
|
||||||
|
*
|
||||||
|
* @param encounter 就诊记录
|
||||||
|
* @return null 表示通过检查,否则返回失败原因
|
||||||
|
*/
|
||||||
|
private R<?> checkPreConsultationRefund(Encounter encounter) {
|
||||||
|
Long encounterId = encounter.getId();
|
||||||
|
|
||||||
|
// 当日时间范围:今天 00:00:00 到 明天 00:00:00
|
||||||
|
LocalDate today = LocalDate.now();
|
||||||
|
LocalDateTime todayStart = today.atStartOfDay();
|
||||||
|
LocalDateTime tomorrowStart = today.plusDays(1).atStartOfDay();
|
||||||
|
Date todayStartDate = Date.from(todayStart.atZone(ZoneId.systemDefault()).toInstant());
|
||||||
|
Date tomorrowStartDate = Date.from(tomorrowStart.atZone(ZoneId.systemDefault()).toInstant());
|
||||||
|
|
||||||
|
// 1. 检查是否有当日病历记录(医生已写病历则不能退号)
|
||||||
|
// 只检查当天的病历,避免误判历史数据
|
||||||
|
// 条件:(recordTime在当天范围内) OR (recordTime为空 AND createTime在当天范围内)
|
||||||
|
long emrCount = iEmrService.count(new LambdaQueryWrapper<com.openhis.document.domain.Emr>()
|
||||||
|
.eq(com.openhis.document.domain.Emr::getEncounterId, encounterId)
|
||||||
|
.and(wrapper -> wrapper
|
||||||
|
.and(w -> w
|
||||||
|
.ge(com.openhis.document.domain.Emr::getRecordTime, todayStartDate)
|
||||||
|
.lt(com.openhis.document.domain.Emr::getRecordTime, tomorrowStartDate)
|
||||||
|
)
|
||||||
|
.or()
|
||||||
|
.and(w -> w
|
||||||
|
.isNull(com.openhis.document.domain.Emr::getRecordTime)
|
||||||
|
.ge(com.openhis.document.domain.Emr::getCreateTime, todayStartDate)
|
||||||
|
.lt(com.openhis.document.domain.Emr::getCreateTime, tomorrowStartDate)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
if (emrCount > 0) {
|
||||||
|
return R.fail(null, "该患者已有病历记录,不能退号!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 检查是否有当日费用明细(除挂号费外的其他费用)
|
||||||
|
// 只检查当天的费用明细,避免误判历史数据
|
||||||
|
// 条件:(occurrenceTime在当天范围内) OR (occurrenceTime为空 AND createTime在当天范围内)
|
||||||
|
long chargeItemCount = iChargeItemService.count(new LambdaQueryWrapper<ChargeItem>()
|
||||||
|
.eq(ChargeItem::getEncounterId, encounterId)
|
||||||
|
.ne(ChargeItem::getContextEnum, ChargeItemContext.REGISTER.getValue())
|
||||||
|
.ne(ChargeItem::getStatusEnum, ChargeItemStatus.REFUNDED.getValue())
|
||||||
|
.and(wrapper -> wrapper
|
||||||
|
.and(w -> w
|
||||||
|
.ge(ChargeItem::getOccurrenceTime, todayStartDate)
|
||||||
|
.lt(ChargeItem::getOccurrenceTime, tomorrowStartDate)
|
||||||
|
)
|
||||||
|
.or()
|
||||||
|
.and(w -> w
|
||||||
|
.isNull(ChargeItem::getOccurrenceTime)
|
||||||
|
.ge(ChargeItem::getCreateTime, todayStartDate)
|
||||||
|
.lt(ChargeItem::getCreateTime, tomorrowStartDate)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
if (chargeItemCount > 0) {
|
||||||
|
return R.fail(null, "该患者已产生诊疗费用,不能退号!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 检查是否当日就诊(防止隔日财务封账)
|
||||||
|
if (encounter.getCreateTime() != null) {
|
||||||
|
LocalDate encounterDate = encounter.getCreateTime().toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault()).toLocalDate();
|
||||||
|
if (encounterDate.isBefore(today)) {
|
||||||
|
return R.fail(null, "非当日就诊记录,不能退号!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 检查班段是否已结束(通过预约订单获取班段信息)
|
||||||
|
R<?> shiftCheckResult = checkShiftEnded(encounter);
|
||||||
|
if (shiftCheckResult != null) {
|
||||||
|
return shiftCheckResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // 检查通过
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查班段是否已结束
|
||||||
|
* 截止时间 = 班段结束时间
|
||||||
|
*
|
||||||
|
* @param encounter 就诊记录
|
||||||
|
* @return null 表示通过检查,否则返回失败原因
|
||||||
|
*/
|
||||||
|
private R<?> checkShiftEnded(Encounter encounter) {
|
||||||
|
try {
|
||||||
|
// 通过患者、科室、日期查找关联的预约订单
|
||||||
|
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
|
||||||
|
.eq(Order::getPatientId, encounter.getPatientId())
|
||||||
|
.in(Order::getStatus, CommonConstants.AppointmentOrderStatus.BOOKED,
|
||||||
|
CommonConstants.AppointmentOrderStatus.CHECKED_IN)
|
||||||
|
.orderByDesc(Order::getUpdateTime)
|
||||||
|
.orderByDesc(Order::getCreateTime)
|
||||||
|
.last("LIMIT 1");
|
||||||
|
|
||||||
|
if (encounter.getOrganizationId() != null) {
|
||||||
|
queryWrapper.eq(Order::getDepartmentId, encounter.getOrganizationId());
|
||||||
|
}
|
||||||
|
if (encounter.getTenantId() != null) {
|
||||||
|
queryWrapper.eq(Order::getTenantId, encounter.getTenantId());
|
||||||
|
}
|
||||||
|
if (encounter.getCreateTime() != null) {
|
||||||
|
LocalDate encounterDate = encounter.getCreateTime().toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault()).toLocalDate();
|
||||||
|
Date startOfDay = Date.from(encounterDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||||
|
Date nextDayStart = Date.from(encounterDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||||
|
queryWrapper.ge(Order::getAppointmentDate, startOfDay)
|
||||||
|
.lt(Order::getAppointmentDate, nextDayStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
Order appointmentOrder = orderService.getOne(queryWrapper, false);
|
||||||
|
if (appointmentOrder == null || appointmentOrder.getSlotId() == null) {
|
||||||
|
// 没有关联的预约订单,跳过班段检查(非预约挂号的场景)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取号源槽位
|
||||||
|
ScheduleSlot slot = scheduleSlotMapper.selectById(appointmentOrder.getSlotId());
|
||||||
|
if (slot == null || slot.getPoolId() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取号源池(班段信息)
|
||||||
|
SchedulePool pool = schedulePoolMapper.selectById(slot.getPoolId());
|
||||||
|
if (pool == null || pool.getEndTime() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// 检查当前时间是否已过班段结束时间
|
||||||
|
LocalTime now = LocalTime.now();
|
||||||
|
if (now.isAfter(pool.getEndTime())) {
|
||||||
|
return R.fail(null, "当前班段已结束,不能退号!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("检查班段结束时间失败, encounterId={}", encounter.getId(), e);
|
||||||
|
// 异常情况下允许退号,避免阻断正常业务
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询当日就诊数据
|
* 查询当日就诊数据
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -41,11 +41,18 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 分页查询检验申请单列表(根据就诊ID查询,按申请时间降序)
|
<!-- 分页查询检验申请单列表(根据就诊ID查询,按申请时间降序)
|
||||||
直接查询申请单表,不关联明细表,避免重复记录-->
|
从明细表聚合项目名称和金额-->
|
||||||
<select id="getInspectionApplyListPage" resultType="com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto">
|
<select id="getInspectionApplyListPage" resultType="com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto">
|
||||||
SELECT t1.id AS applicationId,
|
SELECT t1.id AS applicationId,
|
||||||
t1.apply_no AS applyNo,
|
t1.apply_no AS applyNo,
|
||||||
t1.inspection_item AS itemName,
|
(SELECT STRING_AGG(t2.item_name, '+')
|
||||||
|
FROM lab_apply_item t2
|
||||||
|
WHERE t2.apply_no = t1.apply_no AND t2.delete_flag = '0'
|
||||||
|
) AS itemName,
|
||||||
|
(SELECT SUM(t2.item_amount)
|
||||||
|
FROM lab_apply_item t2
|
||||||
|
WHERE t2.apply_no = t1.apply_no AND t2.delete_flag = '0'
|
||||||
|
) AS itemAmount,
|
||||||
t1.apply_doc_name AS applyDocName,
|
t1.apply_doc_name AS applyDocName,
|
||||||
t1.priority_code AS priorityCode,
|
t1.priority_code AS priorityCode,
|
||||||
t1.apply_status AS applyStatus,
|
t1.apply_status AS applyStatus,
|
||||||
|
|||||||
@@ -164,7 +164,8 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||||||
long cancelledCount = orderService.countPatientCancellations(patientId, tenantId, startTime);
|
long cancelledCount = orderService.countPatientCancellations(patientId, tenantId, startTime);
|
||||||
if (cancelledCount >= config.getCancelAppointmentCount()) {
|
if (cancelledCount >= config.getCancelAppointmentCount()) {
|
||||||
String periodName = getPeriodName(config.getCancelAppointmentType());
|
String periodName = getPeriodName(config.getCancelAppointmentType());
|
||||||
throw new RuntimeException("由于您在" + periodName + "内累计取消预约已达" + cancelledCount + "次,触发系统限制,暂时无法在线预约,请联系分诊台或咨询客服。");
|
int limitCount = config.getCancelAppointmentCount();
|
||||||
|
throw new RuntimeException("由于您在" + periodName + "内累计取消预约已达" + limitCount + "次,触发系统限制,暂时无法在线预约,请联系分诊台或咨询客服。");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-container class="inspection-application-container">
|
<el-container class="inspection-application-container">
|
||||||
|
|
||||||
<!-- 顶部操作按钮区 - 隐藏,按钮移到卡片标题行 -->
|
<!-- 占位 header,保持 el-container 布局结构 -->
|
||||||
<el-header class="top-action-bar" height="0" style="overflow: hidden">
|
<el-header height="0" />
|
||||||
</el-header>
|
|
||||||
|
|
||||||
<!-- 检验信息表格区 -->
|
<!-- 检验信息表格区 -->
|
||||||
<el-main class="inspection-section" style="width: 100%; max-width: 100%">
|
<el-main class="inspection-section" style="width: 100%; max-width: 100%">
|
||||||
@@ -1710,14 +1709,6 @@ defineExpose({
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Bug#334: 顶部操作按钮区 - 隐藏原区域,按钮移到卡片标题行 */
|
|
||||||
.top-action-bar {
|
|
||||||
height: 0 !important;
|
|
||||||
overflow: hidden !important;
|
|
||||||
border: none !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 表格卡片标题行:标题在左,按钮在右 */
|
/* 表格卡片标题行:标题在左,按钮在右 */
|
||||||
.table-card-header-bar {
|
.table-card-header-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -2473,10 +2464,6 @@ defineExpose({
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-action-bar {
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
|||||||
Reference in New Issue
Block a user