Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a4c2b6354 | ||
|
|
6626c8f1cd | ||
|
|
e2f4996f47 | ||
|
|
37b57e8b12 | ||
|
|
9bd39c06e7 | ||
|
|
bde42d6b14 | ||
|
|
01bf3177c9 | ||
|
|
2a9f8376e6 | ||
|
|
0774d9f877 | ||
|
|
cee38eceae | ||
|
|
bbc740b6ce | ||
|
|
256b986c0e | ||
|
|
eaac16769d | ||
|
|
df6c5f3824 | ||
|
|
08075c90e2 | ||
|
|
4bd0d2dcc8 |
@@ -10,7 +10,7 @@ import com.openhis.clinical.service.ITicketService;
|
|||||||
import com.openhis.web.appointmentmanage.appservice.ITicketAppService;
|
import com.openhis.web.appointmentmanage.appservice.ITicketAppService;
|
||||||
import com.openhis.web.appointmentmanage.dto.TicketDto;
|
import com.openhis.web.appointmentmanage.dto.TicketDto;
|
||||||
import com.openhis.common.constant.CommonConstants.SlotStatus;
|
import com.openhis.common.constant.CommonConstants.SlotStatus;
|
||||||
import com.openhis.common.constant.CommonConstants.AppointmentOrderStatus;
|
import com.openhis.common.enums.OrderStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -198,10 +198,11 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
|
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
|
||||||
dto.setStatus("已取号");
|
dto.setStatus("已取号");
|
||||||
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
|
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
|
||||||
if (AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus())) {
|
// order_main.status: 0=患者取消(已退号) 2=系统取消 其余=已预约
|
||||||
dto.setStatus("已取号");
|
if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) {
|
||||||
} else if (AppointmentOrderStatus.RETURNED.equals(raw.getOrderStatus())) {
|
|
||||||
dto.setStatus("已退号");
|
dto.setStatus("已退号");
|
||||||
|
} else if (OrderStatus.SYSTEM_CANCELLED.getValue().equals(raw.getOrderStatus())) {
|
||||||
|
dto.setStatus("系统取消");
|
||||||
} else {
|
} else {
|
||||||
dto.setStatus("已预约");
|
dto.setStatus("已预约");
|
||||||
}
|
}
|
||||||
@@ -372,10 +373,11 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
|
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
|
||||||
dto.setStatus("已取号");
|
dto.setStatus("已取号");
|
||||||
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
|
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
|
||||||
if (AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus())) {
|
// order_main.status: 0=患者取消(已退号) 2=系统取消 其余=已预约
|
||||||
dto.setStatus("已取号");
|
if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) {
|
||||||
} else if (AppointmentOrderStatus.RETURNED.equals(raw.getOrderStatus())) {
|
|
||||||
dto.setStatus("已退号");
|
dto.setStatus("已退号");
|
||||||
|
} else if (OrderStatus.SYSTEM_CANCELLED.getValue().equals(raw.getOrderStatus())) {
|
||||||
|
dto.setStatus("系统取消");
|
||||||
} else {
|
} else {
|
||||||
dto.setStatus("已预约");
|
dto.setStatus("已预约");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,7 +135,8 @@ public class OrganizationLocationAppServiceImpl implements IOrganizationLocation
|
|||||||
BeanUtils.copyProperties(orgLocQueryDto, orgLoc);
|
BeanUtils.copyProperties(orgLocQueryDto, orgLoc);
|
||||||
|
|
||||||
Long activityDefinitionId = orgLoc.getActivityDefinitionId();
|
Long activityDefinitionId = orgLoc.getActivityDefinitionId();
|
||||||
String activityName = activityDefinitionId != null ? activityDefinitionMapper.selectById(activityDefinitionId).getName() : "";
|
String activityName = activityDefinitionId != null
|
||||||
|
? activityDefinitionMapper.selectById(activityDefinitionId).getName() : "";
|
||||||
|
|
||||||
List<OrganizationLocation> organizationLocationList =
|
List<OrganizationLocation> organizationLocationList =
|
||||||
organizationLocationService.getOrgLocListByOrgIdAndActivityDefinitionId(orgLoc.getActivityDefinitionId());
|
organizationLocationService.getOrgLocListByOrgIdAndActivityDefinitionId(orgLoc.getActivityDefinitionId());
|
||||||
@@ -147,8 +148,8 @@ public class OrganizationLocationAppServiceImpl implements IOrganizationLocation
|
|||||||
for (OrganizationLocation organizationLocation : organizationLocationList)
|
for (OrganizationLocation organizationLocation : organizationLocationList)
|
||||||
if (DateTimeUtils.isOverlap(organizationLocation.getStartTime(), organizationLocation.getEndTime(),
|
if (DateTimeUtils.isOverlap(organizationLocation.getStartTime(), organizationLocation.getEndTime(),
|
||||||
orgLoc.getStartTime(), orgLoc.getEndTime())) {
|
orgLoc.getStartTime(), orgLoc.getEndTime())) {
|
||||||
String organizationName =
|
Organization org = organizationService.getById(organizationLocation.getOrganizationId());
|
||||||
organizationService.getById(organizationLocation.getOrganizationId()).getName();
|
String organizationName = org != null ? org.getName() : "未知科室";
|
||||||
return R.fail("当前诊疗:" + activityName + CommonConstants.Common.DASH + orgLoc.getStartTime()
|
return R.fail("当前诊疗:" + activityName + CommonConstants.Common.DASH + orgLoc.getStartTime()
|
||||||
+ CommonConstants.Common.DASH + orgLoc.getEndTime() + "与" + organizationName + "时间冲突");
|
+ CommonConstants.Common.DASH + orgLoc.getEndTime() + "与" + organizationName + "时间冲突");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.openhis.web.chargemanage.appservice.impl;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.core.common.core.domain.R;
|
import com.core.common.core.domain.R;
|
||||||
@@ -329,16 +330,14 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果本次门诊挂号来自预约签到,同步把预约订单与号源槽位状态改为已退号
|
// 退费成功后,同步回滚预约订单状态及号源;同时移除分诊队列
|
||||||
|
Long refundOrderMainId = null;
|
||||||
if (result != null && result.getCode() == 200) {
|
if (result != null && result.getCode() == 200) {
|
||||||
syncAppointmentReturnStatus(byId, cancelRegPaymentDto.getReason());
|
refundOrderMainId = syncAppointmentReturnStatus(byId, cancelRegPaymentDto.getReason());
|
||||||
|
|
||||||
// 同步移除分诊队列中的记录
|
|
||||||
removeTriageQueueItem(byId.getId());
|
removeTriageQueueItem(byId.getId());
|
||||||
}
|
}
|
||||||
|
// 退号日志独立事务写入,无论退费成功与否均记录
|
||||||
// 记录退号日志
|
recordRefundLog(cancelRegPaymentDto, byId, result, paymentRecon, refundOrderMainId);
|
||||||
recordRefundLog(cancelRegPaymentDto, byId, result, paymentRecon);
|
|
||||||
|
|
||||||
// 2025/05/05 该处保存费用项后,会通过统一收费处理进行收费
|
// 2025/05/05 该处保存费用项后,会通过统一收费处理进行收费
|
||||||
return R.ok(paymentRecon, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"退号"}));
|
return R.ok(paymentRecon, MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] {"退号"}));
|
||||||
@@ -435,8 +434,6 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
// 通过患者、科室、日期查找关联的预约订单
|
// 通过患者、科室、日期查找关联的预约订单
|
||||||
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
|
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
|
||||||
.eq(Order::getPatientId, encounter.getPatientId())
|
.eq(Order::getPatientId, encounter.getPatientId())
|
||||||
.in(Order::getStatus, CommonConstants.AppointmentOrderStatus.BOOKED,
|
|
||||||
CommonConstants.AppointmentOrderStatus.CHECKED_IN)
|
|
||||||
.orderByDesc(Order::getUpdateTime)
|
.orderByDesc(Order::getUpdateTime)
|
||||||
.orderByDesc(Order::getCreateTime)
|
.orderByDesc(Order::getCreateTime)
|
||||||
.last("LIMIT 1");
|
.last("LIMIT 1");
|
||||||
@@ -590,20 +587,25 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 同步预约号源状态为已退号。
|
* 诊前退号:回滚预约订单、号源槽位、号源池统计。
|
||||||
* 说明:
|
*
|
||||||
* 1) 门诊退号主流程不依赖该步骤成功与否,因此此方法内部异常仅记录日志,不向上抛出。
|
* <p>处理四件事:
|
||||||
* 2) 通过患者、科室、日期以及状态筛选最近一条预约订单,尽量避免误匹配。
|
* <ol>
|
||||||
|
* <li>order_main → status=0(患者取消), pay_status=3(已退费), 写入取消时间和原因</li>
|
||||||
|
* <li>adm_schedule_slot → status=0(待约), order_id=NULL(释放号源)</li>
|
||||||
|
* <li>adm_schedule_pool → 重算统计值 + version+1</li>
|
||||||
|
* <li>返回 order_main.id 供 refund_log 关联</li>
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* <p>异常仅记录日志不向上抛,不影响主流程返回成功。
|
||||||
*/
|
*/
|
||||||
private void syncAppointmentReturnStatus(Encounter encounter, String reason) {
|
private Long syncAppointmentReturnStatus(Encounter encounter, String reason) {
|
||||||
if (encounter == null || encounter.getPatientId() == null) {
|
if (encounter == null || encounter.getPatientId() == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
|
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
|
||||||
.eq(Order::getPatientId, encounter.getPatientId())
|
.eq(Order::getPatientId, encounter.getPatientId())
|
||||||
.in(Order::getStatus, CommonConstants.AppointmentOrderStatus.BOOKED,
|
|
||||||
CommonConstants.AppointmentOrderStatus.CHECKED_IN)
|
|
||||||
.orderByDesc(Order::getUpdateTime)
|
.orderByDesc(Order::getUpdateTime)
|
||||||
.orderByDesc(Order::getCreateTime)
|
.orderByDesc(Order::getCreateTime)
|
||||||
.last("LIMIT 1");
|
.last("LIMIT 1");
|
||||||
@@ -625,35 +627,55 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
|
|
||||||
Order appointmentOrder = orderService.getOne(queryWrapper, false);
|
Order appointmentOrder = orderService.getOne(queryWrapper, false);
|
||||||
if (appointmentOrder == null) {
|
if (appointmentOrder == null) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Date now = new Date();
|
// 只有有效订单(1)才能退号
|
||||||
if (!CommonConstants.AppointmentOrderStatus.RETURNED.equals(appointmentOrder.getStatus())) {
|
if (!OrderStatus.ACTIVE.getValue().equals(appointmentOrder.getStatus())) {
|
||||||
Order updateOrder = new Order();
|
log.warn("退号跳过:订单状态非有效, orderId={}, status={}",
|
||||||
updateOrder.setId(appointmentOrder.getId());
|
appointmentOrder.getId(), appointmentOrder.getStatus());
|
||||||
updateOrder.setStatus(CommonConstants.AppointmentOrderStatus.RETURNED);
|
return null;
|
||||||
updateOrder.setPayStatus(0);
|
}
|
||||||
updateOrder.setCancelTime(now);
|
|
||||||
updateOrder.setCancelReason("门诊退号");
|
// 乐观锁更新:WHERE version = 旧值,防并发重复退号
|
||||||
updateOrder.setUpdateTime(now);
|
boolean updated = orderService.update(
|
||||||
orderService.updateById(updateOrder);
|
new LambdaUpdateWrapper<Order>()
|
||||||
|
.set(Order::getStatus, OrderStatus.PATIENT_CANCELLED.getValue())
|
||||||
|
.set(Order::getPayStatus, PaymentStatus.REFUND_ALL.getValue())
|
||||||
|
.set(Order::getCancelTime, new Date())
|
||||||
|
.set(Order::getCancelReason,
|
||||||
|
StringUtils.isNotEmpty(reason) ? reason : "诊前退号")
|
||||||
|
.set(Order::getUpdateTime, new Date())
|
||||||
|
.setSql("version = version + 1")
|
||||||
|
.eq(Order::getId, appointmentOrder.getId())
|
||||||
|
.eq(Order::getVersion, appointmentOrder.getVersion())
|
||||||
|
);
|
||||||
|
if (!updated) {
|
||||||
|
log.warn("退号乐观锁冲突,订单已被其他操作修改, orderId={}", appointmentOrder.getId());
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Long slotId = appointmentOrder.getSlotId();
|
Long slotId = appointmentOrder.getSlotId();
|
||||||
if (slotId == null) {
|
if (slotId == null) {
|
||||||
return;
|
return appointmentOrder.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
int slotRows = scheduleSlotMapper.updateSlotStatus(slotId, CommonConstants.SlotStatus.RETURNED);
|
int slotRows = scheduleSlotMapper.updateSlotStatus(slotId, CommonConstants.SlotStatus.AVAILABLE);
|
||||||
if (slotRows > 0) {
|
if (slotRows > 0) {
|
||||||
Long poolId = scheduleSlotMapper.selectPoolIdBySlotId(slotId);
|
Long poolId = scheduleSlotMapper.selectPoolIdBySlotId(slotId);
|
||||||
if (poolId != null) {
|
if (poolId != null) {
|
||||||
schedulePoolMapper.refreshPoolStats(poolId);
|
schedulePoolMapper.refreshPoolStats(poolId);
|
||||||
|
schedulePoolMapper.update(null,
|
||||||
|
new LambdaUpdateWrapper<SchedulePool>()
|
||||||
|
.setSql("version = version + 1")
|
||||||
|
.set(SchedulePool::getUpdateTime, new Date())
|
||||||
|
.eq(SchedulePool::getId, poolId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return appointmentOrder.getId();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("同步预约号源已退号状态失败, encounterId={}", encounter.getId(), e);
|
log.warn("同步预约号源已退号状态失败, encounterId={}", encounter.getId(), e);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,22 +694,29 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 记录退号日志
|
* 记录退号日志(独立事务)。
|
||||||
|
*
|
||||||
|
* <p>REQUIRES_NEW 确保即使主事务回滚,退号审计日志也不丢失。
|
||||||
|
* orderMainId 优先使用 order_main.id,若退费失败则 fallback 到 encounterId。
|
||||||
*
|
*
|
||||||
* @param cancelRegPaymentDto 退号请求对象
|
* @param cancelRegPaymentDto 退号请求对象
|
||||||
* @param encounter 就诊信息
|
* @param encounter 就诊信息
|
||||||
* @param result 退号结果
|
* @param result 退号结果
|
||||||
* @param paymentRecon 支付对账信息
|
* @param paymentRecon 支付对账信息
|
||||||
|
* @param orderMainId 预约订单主键(order_main.id),用于关联业务数据
|
||||||
*/
|
*/
|
||||||
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
public void recordRefundLog(CancelRegPaymentDto cancelRegPaymentDto,
|
public void recordRefundLog(CancelRegPaymentDto cancelRegPaymentDto,
|
||||||
Encounter encounter,
|
Encounter encounter,
|
||||||
R<?> result,
|
R<?> result,
|
||||||
PaymentReconciliation paymentRecon) {
|
PaymentReconciliation paymentRecon,
|
||||||
|
Long orderMainId) {
|
||||||
RefundLog refundLog = new RefundLog();
|
RefundLog refundLog = new RefundLog();
|
||||||
try {
|
try {
|
||||||
// 1. 订单ID(唯一)
|
// 1. 订单ID(关联 order_main.id)
|
||||||
String orderId = String.valueOf(cancelRegPaymentDto.getEncounterId());
|
String orderId = orderMainId != null
|
||||||
|
? String.valueOf(orderMainId)
|
||||||
|
: String.valueOf(cancelRegPaymentDto.getEncounterId());
|
||||||
refundLog.setOrderId(orderId);
|
refundLog.setOrderId(orderId);
|
||||||
|
|
||||||
// 已存在则不重复插入(防止唯一约束异常)
|
// 已存在则不重复插入(防止唯一约束异常)
|
||||||
|
|||||||
@@ -1991,7 +1991,7 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
Order appointmentOrder = iOrderService.getOne(
|
Order appointmentOrder = iOrderService.getOne(
|
||||||
new LambdaQueryWrapper<Order>()
|
new LambdaQueryWrapper<Order>()
|
||||||
.eq(Order::getPatientId, encounterFormData.getPatientId())
|
.eq(Order::getPatientId, encounterFormData.getPatientId())
|
||||||
.eq(Order::getStatus, CommonConstants.AppointmentOrderStatus.CHECKED_IN)
|
.eq(Order::getStatus, OrderStatus.ACTIVE.getValue()) // 有效订单(1)
|
||||||
.eq(Order::getDeleteFlag, "0")
|
.eq(Order::getDeleteFlag, "0")
|
||||||
.orderByDesc(Order::getCreateTime)
|
.orderByDesc(Order::getCreateTime)
|
||||||
.last("LIMIT 1")
|
.last("LIMIT 1")
|
||||||
@@ -2114,11 +2114,11 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
Long queuePoolId = null;
|
Long queuePoolId = null;
|
||||||
Long queueSlotId = null;
|
Long queueSlotId = null;
|
||||||
try {
|
try {
|
||||||
// 查询患者当天的待签到预约订单(status = 1 或 2 表示已预约或已取号)
|
// 查询患者当天有效订单(1);已取消(0/2)和已完成(3)的不参与排队
|
||||||
Order order = iOrderService.getOne(
|
Order order = iOrderService.getOne(
|
||||||
new LambdaQueryWrapper<Order>()
|
new LambdaQueryWrapper<Order>()
|
||||||
.eq(Order::getPatientId, encounter.getPatientId())
|
.eq(Order::getPatientId, encounter.getPatientId())
|
||||||
.in(Order::getStatus, 1, 2) // 1=BOOKED 已预约, 2=CHECKED_IN 已取号
|
.eq(Order::getStatus, OrderStatus.ACTIVE.getValue()) // 有效(1)
|
||||||
.eq(Order::getDeleteFlag, "0")
|
.eq(Order::getDeleteFlag, "0")
|
||||||
.orderByDesc(Order::getCreateTime)
|
.orderByDesc(Order::getCreateTime)
|
||||||
.last("LIMIT 1")
|
.last("LIMIT 1")
|
||||||
|
|||||||
@@ -95,13 +95,6 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
|
|||||||
prescriptionNo = assignSeqUtil.getSeq(AssignSeqEnum.ACTIVITY_PSYCHOTROPIC_NO.getPrefix(), 8);
|
prescriptionNo = assignSeqUtil.getSeq(AssignSeqEnum.ACTIVITY_PSYCHOTROPIC_NO.getPrefix(), 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 诊疗执行科室配置校验(必须在数据库操作之前执行)
|
|
||||||
List<ActivityOrganizationConfigDto> activityOrganizationConfig =
|
|
||||||
requestFormManageAppMapper.getActivityOrganizationConfig(typeCode);
|
|
||||||
if (activityOrganizationConfig.isEmpty()) {
|
|
||||||
throw new ServiceException("请先配置当前时间段的执行科室");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 当前时间
|
// 当前时间
|
||||||
Date curDate = new Date();
|
Date curDate = new Date();
|
||||||
// 请求类型
|
// 请求类型
|
||||||
@@ -146,6 +139,12 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
|
|||||||
// 诊疗集合
|
// 诊疗集合
|
||||||
List<ActivitySaveDto> activityList = requestFormSaveDto.getActivityList();
|
List<ActivitySaveDto> activityList = requestFormSaveDto.getActivityList();
|
||||||
log.info("保存申请单,typeCode={}, activityListSize={}, encounterId={}", typeCode, activityList != null ? activityList.size() : 0, encounterId);
|
log.info("保存申请单,typeCode={}, activityListSize={}, encounterId={}", typeCode, activityList != null ? activityList.size() : 0, encounterId);
|
||||||
|
// 诊疗执行科室配置
|
||||||
|
List<ActivityOrganizationConfigDto> activityOrganizationConfig =
|
||||||
|
requestFormManageAppMapper.getActivityOrganizationConfig(typeCode);
|
||||||
|
if (activityOrganizationConfig.isEmpty()) {
|
||||||
|
throw new ServiceException("请先配置当前时间段的执行科室");
|
||||||
|
}
|
||||||
|
|
||||||
for (ActivitySaveDto activitySaveDto : activityList) {
|
for (ActivitySaveDto activitySaveDto : activityList) {
|
||||||
serviceRequest = new ServiceRequest();
|
serviceRequest = new ServiceRequest();
|
||||||
@@ -435,7 +434,7 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
|
|||||||
return new java.util.ArrayList<>(); // 返回空列表而不是查询数据库
|
return new java.util.ArrayList<>(); // 返回空列表而不是查询数据库
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RequestFormQueryDto> requestFormList = requestFormManageAppMapper.getRequestForm(encounterId, typeCode, startDate, endDate, status);
|
List<RequestFormQueryDto> requestFormList = requestFormManageAppMapper.getRequestForm(encounterId, typeCode, startDate, endDate, status, null);
|
||||||
for (RequestFormQueryDto requestFormQueryDto : requestFormList) {
|
for (RequestFormQueryDto requestFormQueryDto : requestFormList) {
|
||||||
// 查询处方详情
|
// 查询处方详情
|
||||||
List<RequestFormDetailQueryDto> requestFormDetail =
|
List<RequestFormDetailQueryDto> requestFormDetail =
|
||||||
|
|||||||
@@ -81,21 +81,14 @@ public class RequestFormManageController {
|
|||||||
* 查询检查申请单
|
* 查询检查申请单
|
||||||
*
|
*
|
||||||
* @param encounterId 就诊id
|
* @param encounterId 就诊id
|
||||||
* @param startDate 开始日期(可选,格式:yyyy-MM-dd)
|
|
||||||
* @param endDate 结束日期(可选,格式:yyyy-MM-dd)
|
|
||||||
* @param status 单据状态(可选)
|
|
||||||
* @return 检查申请单
|
* @return 检查申请单
|
||||||
*/
|
*/
|
||||||
@GetMapping(value = "/get-check")
|
@GetMapping(value = "/get-check")
|
||||||
public R<?> getCheckRequestForm(
|
public R<?> getCheckRequestForm(@RequestParam(required = false) Long encounterId) {
|
||||||
@RequestParam(required = false) Long encounterId,
|
|
||||||
@RequestParam(required = false) String startDate,
|
|
||||||
@RequestParam(required = false) String endDate,
|
|
||||||
@RequestParam(required = false) String status) {
|
|
||||||
if (encounterId == null) {
|
if (encounterId == null) {
|
||||||
return R.fail("就诊ID不能为空");
|
return R.fail("就诊ID不能为空");
|
||||||
}
|
}
|
||||||
return R.ok(iRequestFormManageAppService.getRequestForm(encounterId, ActivityDefCategory.TEST.getCode(), startDate, endDate, status));
|
return R.ok(iRequestFormManageAppService.getRequestForm(encounterId, ActivityDefCategory.TEST.getCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -37,13 +37,15 @@ public interface RequestFormManageAppMapper {
|
|||||||
* @param startDate 开始日期(可选,格式:yyyy-MM-dd)
|
* @param startDate 开始日期(可选,格式:yyyy-MM-dd)
|
||||||
* @param endDate 结束日期(可选,格式:yyyy-MM-dd)
|
* @param endDate 结束日期(可选,格式:yyyy-MM-dd)
|
||||||
* @param status 单据状态(可选)
|
* @param status 单据状态(可选)
|
||||||
|
* @param keyword 关键字(可选,申请单号/检查项目名称模糊匹配)
|
||||||
* @return 申请单列表
|
* @return 申请单列表
|
||||||
*/
|
*/
|
||||||
List<RequestFormQueryDto> getRequestForm(@Param("encounterId") Long encounterId,
|
List<RequestFormQueryDto> getRequestForm(@Param("encounterId") Long encounterId,
|
||||||
@Param("typeCode") String typeCode,
|
@Param("typeCode") String typeCode,
|
||||||
@Param("startDate") String startDate,
|
@Param("startDate") String startDate,
|
||||||
@Param("endDate") String endDate,
|
@Param("endDate") String endDate,
|
||||||
@Param("status") String status);
|
@Param("status") String status,
|
||||||
|
@Param("keyword") String keyword);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询申请单详情
|
* 查询申请单详情
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright ©2023 CJB-CNIT Team. All rights reserved
|
||||||
|
*/
|
||||||
|
package com.openhis.common.enums;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单状态 (order_main.status)
|
||||||
|
*
|
||||||
|
* <pre>
|
||||||
|
* 状态流转:
|
||||||
|
* 创建订单 → ACTIVE(1)
|
||||||
|
* 签到 → ACTIVE(1) 不变
|
||||||
|
* 患者退号 → PATIENT_CANCELLED(0)
|
||||||
|
* 系统取消 → SYSTEM_CANCELLED(2)
|
||||||
|
* 就诊完成 → COMPLETED(3)
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @author wangjian963
|
||||||
|
* @date 2026-05-09
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum OrderStatus implements HisEnumInterface {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 患者取消
|
||||||
|
*/
|
||||||
|
PATIENT_CANCELLED(0, "0", "患者取消"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有效
|
||||||
|
*/
|
||||||
|
ACTIVE(1, "1", "有效"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统取消
|
||||||
|
*/
|
||||||
|
SYSTEM_CANCELLED(2, "2", "系统取消"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已完成
|
||||||
|
*/
|
||||||
|
COMPLETED(3, "3", "已完成");
|
||||||
|
|
||||||
|
private Integer value;
|
||||||
|
private String code;
|
||||||
|
private String info;
|
||||||
|
|
||||||
|
public static OrderStatus getByValue(Integer value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (OrderStatus val : values()) {
|
||||||
|
if (val.getValue().equals(value)) {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@ import com.core.common.utils.AssignSeqUtil;
|
|||||||
import com.openhis.clinical.domain.Order;
|
import com.openhis.clinical.domain.Order;
|
||||||
import com.openhis.clinical.mapper.OrderMapper;
|
import com.openhis.clinical.mapper.OrderMapper;
|
||||||
import com.openhis.clinical.service.IOrderService;
|
import com.openhis.clinical.service.IOrderService;
|
||||||
import com.openhis.common.constant.CommonConstants.AppointmentOrderStatus;
|
|
||||||
import com.openhis.common.enums.AssignSeqEnum;
|
import com.openhis.common.enums.AssignSeqEnum;
|
||||||
|
import com.openhis.common.enums.OrderStatus;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -124,7 +124,8 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
|||||||
: new Date(); // 兜底:正常业务不应走到这里
|
: new Date(); // 兜底:正常业务不应走到这里
|
||||||
order.setAppointmentDate(appointmentDateTime);
|
order.setAppointmentDate(appointmentDateTime);
|
||||||
order.setAppointmentTime(appointmentDateTime);
|
order.setAppointmentTime(appointmentDateTime);
|
||||||
order.setStatus(AppointmentOrderStatus.BOOKED);
|
// 订单状态: 0=患者取消 1=有效 2=系统取消 3=已完成
|
||||||
|
order.setStatus(OrderStatus.ACTIVE.getValue());
|
||||||
order.setPayStatus(0);
|
order.setPayStatus(0);
|
||||||
order.setVersion(0);
|
order.setVersion(0);
|
||||||
|
|
||||||
@@ -169,10 +170,13 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
|||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw new RuntimeException("订单不存在");
|
throw new RuntimeException("订单不存在");
|
||||||
}
|
}
|
||||||
if (AppointmentOrderStatus.CANCELLED.equals(order.getStatus())) {
|
// 已取消(患者取消0 或 系统取消2)不可再次取消
|
||||||
|
if (OrderStatus.PATIENT_CANCELLED.getValue().equals(order.getStatus())
|
||||||
|
|| OrderStatus.SYSTEM_CANCELLED.getValue().equals(order.getStatus())) {
|
||||||
throw new RuntimeException("订单已取消");
|
throw new RuntimeException("订单已取消");
|
||||||
}
|
}
|
||||||
if (AppointmentOrderStatus.CHECKED_IN.equals(order.getStatus())) {
|
// 已完成(3)的订单不可取消
|
||||||
|
if (OrderStatus.COMPLETED.getValue().equals(order.getStatus())) {
|
||||||
throw new RuntimeException("订单已完成,无法取消");
|
throw new RuntimeException("订单已完成,无法取消");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +193,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
|||||||
.eq(Order::getPatientId, patientId)
|
.eq(Order::getPatientId, patientId)
|
||||||
.eq(Order::getTenantId, tenantId)
|
.eq(Order::getTenantId, tenantId)
|
||||||
.ge(Order::getCancelTime, startTime)
|
.ge(Order::getCancelTime, startTime)
|
||||||
.eq(Order::getStatus, AppointmentOrderStatus.CANCELLED));
|
// 只统计患者主动取消(0),不含系统取消(2)
|
||||||
|
.eq(Order::getStatus, OrderStatus.PATIENT_CANCELLED.getValue()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import com.openhis.clinical.domain.Ticket;
|
|||||||
import com.openhis.clinical.mapper.TicketMapper;
|
import com.openhis.clinical.mapper.TicketMapper;
|
||||||
import com.openhis.clinical.service.IOrderService;
|
import com.openhis.clinical.service.IOrderService;
|
||||||
import com.openhis.clinical.service.ITicketService;
|
import com.openhis.clinical.service.ITicketService;
|
||||||
import com.openhis.common.constant.CommonConstants.AppointmentOrderStatus;
|
|
||||||
import com.openhis.common.constant.CommonConstants.SlotStatus;
|
import com.openhis.common.constant.CommonConstants.SlotStatus;
|
||||||
|
import com.openhis.common.enums.OrderStatus;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -195,8 +195,8 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||||||
Date startTime = Date.from(periodStart.atZone(ZoneId.systemDefault()).toInstant());
|
Date startTime = Date.from(periodStart.atZone(ZoneId.systemDefault()).toInstant());
|
||||||
Date endTime = Date.from(periodEnd.atZone(ZoneId.systemDefault()).toInstant());
|
Date endTime = Date.from(periodEnd.atZone(ZoneId.systemDefault()).toInstant());
|
||||||
|
|
||||||
// 预约去重以订单为准(order_main),因为预约成功会先落订单;clinical_ticket 不一定在此链路写入
|
// 预约去重以订单为准(order_main),有效订单(1)才参与去重
|
||||||
List<Integer> effectiveOrderStatuses = Arrays.asList(AppointmentOrderStatus.BOOKED, AppointmentOrderStatus.CHECKED_IN);
|
List<Integer> effectiveOrderStatuses = Arrays.asList(OrderStatus.ACTIVE.getValue());
|
||||||
int exists = orderMapper.countPatientDeptOrdersInPeriod(dto.getPatientId(), slot.getDepartmentId(), slot.getDepartmentName(),
|
int exists = orderMapper.countPatientDeptOrdersInPeriod(dto.getPatientId(), slot.getDepartmentId(), slot.getDepartmentName(),
|
||||||
startTime, endTime, effectiveOrderStatuses);
|
startTime, endTime, effectiveOrderStatuses);
|
||||||
if (exists > 0) {
|
if (exists > 0) {
|
||||||
@@ -314,9 +314,8 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||||||
}
|
}
|
||||||
Order latestOrder = orders.get(0);
|
Order latestOrder = orders.get(0);
|
||||||
|
|
||||||
// 1. 更新订单状态为已取号,并更新支付状态和支付时间
|
// 1. 签到不改变订单状态(仍为有效1),更新支付状态为已支付并记录支付时间
|
||||||
orderService.updateOrderStatusById(latestOrder.getId(), AppointmentOrderStatus.CHECKED_IN);
|
orderService.updateOrderStatusById(latestOrder.getId(), OrderStatus.ACTIVE.getValue());
|
||||||
// 更新支付状态为已支付,记录支付时间
|
|
||||||
orderMapper.updatePayStatus(latestOrder.getId(), 1, new Date());
|
orderMapper.updatePayStatus(latestOrder.getId(), 1, new Date());
|
||||||
|
|
||||||
// 2. 查询号源槽位信息
|
// 2. 查询号源槽位信息
|
||||||
|
|||||||
@@ -160,11 +160,12 @@
|
|||||||
AND delete_flag = '0'
|
AND delete_flag = '0'
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<!-- status=0(待约)时清空order_id,释放号源,使退号后号源可再被预约 -->
|
||||||
<update id="updateSlotStatus">
|
<update id="updateSlotStatus">
|
||||||
UPDATE adm_schedule_slot
|
UPDATE adm_schedule_slot
|
||||||
SET
|
SET
|
||||||
status = #{status},
|
status = #{status},
|
||||||
<if test="status != null and '0'.equals(status.toString())">
|
<if test="status != null and status == 0">
|
||||||
order_id = NULL,
|
order_id = NULL,
|
||||||
</if>
|
</if>
|
||||||
update_time = now()
|
update_time = now()
|
||||||
|
|||||||
@@ -117,12 +117,14 @@
|
|||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- status=1: 只查有效订单(0=患者取消 1=有效 2=系统取消 3=已完成) -->
|
||||||
<select id="selectOrderById" resultMap="OrderResult">
|
<select id="selectOrderById" resultMap="OrderResult">
|
||||||
select * from order_main where id = #{id}
|
select * from order_main where id = #{id}
|
||||||
and status = 1
|
and status = 1
|
||||||
order by create_time desc
|
order by create_time desc
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- status=1: 只查有效订单 -->
|
||||||
<select id="selectOrderBySlotId" resultMap="OrderResult">
|
<select id="selectOrderBySlotId" resultMap="OrderResult">
|
||||||
select * from order_main where slot_id = #{slotId} and status = 1
|
select * from order_main where slot_id = #{slotId} and status = 1
|
||||||
</select>
|
</select>
|
||||||
@@ -248,8 +250,9 @@
|
|||||||
update order_main set status = #{status} where id = #{id}
|
update order_main set status = #{status} where id = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<!-- status=0: 患者取消 (OrderStatus.PATIENT_CANCELLED) -->
|
||||||
<update id="updateOrderCancelInfoById">
|
<update id="updateOrderCancelInfoById">
|
||||||
update order_main set status = 3, cancel_time = #{cancelTime}, cancel_reason = #{cancelReason} where id = #{id}
|
update order_main set status = 0, cancel_time = #{cancelTime}, cancel_reason = #{cancelReason} where id = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
<update id="updatePayStatus">
|
<update id="updatePayStatus">
|
||||||
|
|||||||
@@ -522,6 +522,7 @@ const categoryList = ref([]); // 原始分类+项目数据
|
|||||||
const dictSearchKey = ref('');
|
const dictSearchKey = ref('');
|
||||||
const activeNames = ref(''); // 当前展开的折叠项
|
const activeNames = ref(''); // 当前展开的折叠项
|
||||||
const categoryLoadingSet = ref(new Set()); // Bug #500: 正在加载方法的分类集合
|
const categoryLoadingSet = ref(new Set()); // Bug #500: 正在加载方法的分类集合
|
||||||
|
const isAnimating = ref(false); // Bug #500: 防止快速切换时折叠动画重叠导致抖动
|
||||||
|
|
||||||
const allMethods = ref([]);
|
const allMethods = ref([]);
|
||||||
|
|
||||||
@@ -669,8 +670,13 @@ async function handleCategoryExpand(cat) {
|
|||||||
categoryLoadingSet.value.delete(cat.typeId);
|
categoryLoadingSet.value.delete(cat.typeId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Bug #500: 改为非 async 函数,避免 el-collapse 的 @change 等待异步完成导致抖动
|
// Bug #500: 添加防抖逻辑,快速切换时跳过中间状态的动画,避免高度跳变和白屏闪烁
|
||||||
function handleCollapseChange(activeName) {
|
function handleCollapseChange(activeName) {
|
||||||
|
if (isAnimating.value) return; // 动画进行中,忽略后续点击
|
||||||
|
|
||||||
|
isAnimating.value = true;
|
||||||
|
setTimeout(() => { isAnimating.value = false; }, 300); // 与 CSS 过渡时长一致
|
||||||
|
|
||||||
if (activeName) {
|
if (activeName) {
|
||||||
const cat = filteredCategoryList.value.find(c => c.typeId == activeName);
|
const cat = filteredCategoryList.value.find(c => c.typeId == activeName);
|
||||||
if (cat && (!cat.methods || cat.methods.length === 0)) {
|
if (cat && (!cat.methods || cat.methods.length === 0)) {
|
||||||
@@ -1307,6 +1313,7 @@ defineExpose({ getList });
|
|||||||
.collapse-scroll {
|
.collapse-scroll {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden; /* Bug #500: 防止切换时水平方向溢出导致抖动 */
|
||||||
}
|
}
|
||||||
.empty-hint {
|
.empty-hint {
|
||||||
color: #909399;
|
color: #909399;
|
||||||
@@ -1479,10 +1486,10 @@ defineExpose({ getList });
|
|||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
/* Bug #500: 折叠面板展开/收起动画使用 will-change 优化性能 */
|
/* Bug #500: 折叠面板动画容器,添加 overflow:hidden 防止展开时内容溢出导致闪烁 */
|
||||||
:deep(.el-collapse-item__wrap) {
|
:deep(.el-collapse-item__wrap) {
|
||||||
border: none;
|
border: none;
|
||||||
will-change: height;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
:deep(.el-collapse-item) {
|
:deep(.el-collapse-item) {
|
||||||
transition: margin 0.2s ease;
|
transition: margin 0.2s ease;
|
||||||
|
|||||||
@@ -175,10 +175,9 @@ const hasMatchedFields = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/** 查询科室 */
|
/** 查询科室 */
|
||||||
const getLocationInfo = () => {
|
const getLocationInfo = async () => {
|
||||||
getOrgList().then((res) => {
|
const res = await getOrgList();
|
||||||
orgOptions.value = res.data.records;
|
orgOptions.value = res.data.records;
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const recursionFun = (targetDepartment) => {
|
const recursionFun = (targetDepartment) => {
|
||||||
@@ -199,7 +198,12 @@ const recursionFun = (targetDepartment) => {
|
|||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleViewDetail = (row) => {
|
const handleViewDetail = async (row) => {
|
||||||
|
// 确保科室数据已加载,以便将 ID 解析为名称
|
||||||
|
if (!orgOptions.value || orgOptions.value.length === 0) {
|
||||||
|
await getLocationInfo();
|
||||||
|
}
|
||||||
|
|
||||||
currentDetail.value = row;
|
currentDetail.value = row;
|
||||||
// 解析 descJson
|
// 解析 descJson
|
||||||
if (row.descJson) {
|
if (row.descJson) {
|
||||||
@@ -220,10 +224,9 @@ const handleViewDetail = (row) => {
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => patientInfo.value?.encounterId,
|
() => patientInfo.value?.encounterId,
|
||||||
(val) => {
|
async (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
fetchData();
|
await Promise.all([fetchData(), getLocationInfo()]);
|
||||||
getLocationInfo();
|
|
||||||
} else {
|
} else {
|
||||||
tableData.value = [];
|
tableData.value = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,15 +49,6 @@
|
|||||||
<el-option label="已作废" value="7" />
|
<el-option label="已作废" value="7" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="关键字">
|
|
||||||
<el-input
|
|
||||||
v-model="filterForm.keyword"
|
|
||||||
placeholder="申请单号/检查项目"
|
|
||||||
clearable
|
|
||||||
style="width: 200px"
|
|
||||||
@keyup.enter="handleSearch"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleSearch" :loading="loading">
|
<el-button type="primary" @click="handleSearch" :loading="loading">
|
||||||
<el-icon><Search /></el-icon>
|
<el-icon><Search /></el-icon>
|
||||||
@@ -86,62 +77,18 @@
|
|||||||
</template>
|
</template>
|
||||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
<el-table-column prop="patientName" label="患者姓名" width="120" />
|
<el-table-column prop="patientName" label="患者姓名" width="120" />
|
||||||
<el-table-column label="申请单名称" width="140">
|
<el-table-column prop="name" label="申请单名称" width="140" />
|
||||||
<template #default="scope">
|
|
||||||
<span>{{ getItemName(scope.row) }}</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column prop="createTime" label="创建时间" width="160" />
|
<el-table-column prop="createTime" label="创建时间" width="160" />
|
||||||
<el-table-column prop="prescriptionNo" label="申请单号" width="140" />
|
<el-table-column prop="prescriptionNo" label="处方号" width="140" />
|
||||||
<el-table-column prop="requesterId_dictText" label="申请者" width="120" />
|
<el-table-column prop="requesterId_dictText" label="申请者" width="120" />
|
||||||
<el-table-column label="申请单状态" width="120" align="center">
|
<el-table-column label="申请单状态" width="120" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>{{ parseStatus(scope.row.status) }}</span>
|
<span>{{ parseStatus(scope.row.status) }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="操作" align="center" fixed="right" width="240">
|
<el-table-column label="操作" align="center" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button link type="primary" @click="handleViewDetail(scope.row)">详情</el-button>
|
<el-button link type="primary" @click="handleViewDetail(scope.row)">详情</el-button>
|
||||||
<!-- 待签发:修改、删除 -->
|
|
||||||
<template v-if="scope.row.status === '0' || scope.row.status === 0">
|
|
||||||
<el-button link type="primary" @click="handleEdit(scope.row)">修改</el-button>
|
|
||||||
<el-popconfirm
|
|
||||||
title="确认删除该申请单?"
|
|
||||||
@confirm="handleDelete(scope.row)"
|
|
||||||
width="200"
|
|
||||||
>
|
|
||||||
<template #reference>
|
|
||||||
<el-button link type="danger">删除</el-button>
|
|
||||||
</template>
|
|
||||||
</el-popconfirm>
|
|
||||||
</template>
|
|
||||||
<!-- 已签发(护士未校对):撤回 -->
|
|
||||||
<template v-else-if="scope.row.status === '1' || scope.row.status === 1">
|
|
||||||
<el-popconfirm
|
|
||||||
title="确认撤回该申请单?撤回后将回滚至待签发状态"
|
|
||||||
@confirm="handleWithdraw(scope.row)"
|
|
||||||
width="260"
|
|
||||||
>
|
|
||||||
<template #reference>
|
|
||||||
<el-button link type="warning">撤回</el-button>
|
|
||||||
</template>
|
|
||||||
</el-popconfirm>
|
|
||||||
</template>
|
|
||||||
<!-- 已校对/待接收:打印 -->
|
|
||||||
<template v-else-if="scope.row.status === '2' || scope.row.status === 2 || scope.row.status === '3' || scope.row.status === 3">
|
|
||||||
<el-button link type="primary" @click="handlePrint(scope.row)">打印</el-button>
|
|
||||||
</template>
|
|
||||||
<!-- 已接收/已检查:打印、看报告 -->
|
|
||||||
<template v-else-if="scope.row.status === '4' || scope.row.status === 4 || scope.row.status === '5' || scope.row.status === 5">
|
|
||||||
<el-button link type="primary" @click="handlePrint(scope.row)">打印</el-button>
|
|
||||||
<el-button link type="primary" @click="handleViewReport(scope.row)">看报告</el-button>
|
|
||||||
</template>
|
|
||||||
<!-- 已出报告:打印、看报告 -->
|
|
||||||
<template v-else-if="scope.row.status === '6' || scope.row.status === 6">
|
|
||||||
<el-button link type="primary" @click="handlePrint(scope.row)">打印</el-button>
|
|
||||||
<el-button link type="success" @click="handleViewReport(scope.row)">看报告</el-button>
|
|
||||||
</template>
|
|
||||||
<!-- 已作废:仅详情 -->
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -163,7 +110,7 @@
|
|||||||
currentDetail.patientName || '-'
|
currentDetail.patientName || '-'
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="申请单名称">{{
|
<el-descriptions-item label="申请单名称">{{
|
||||||
getItemName(currentDetail)
|
currentDetail.name || '-'
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="申请单状态">{{
|
<el-descriptions-item label="申请单状态">{{
|
||||||
parseStatus(currentDetail.status)
|
parseStatus(currentDetail.status)
|
||||||
@@ -171,7 +118,7 @@
|
|||||||
<el-descriptions-item label="创建时间">{{
|
<el-descriptions-item label="创建时间">{{
|
||||||
currentDetail.createTime || '-'
|
currentDetail.createTime || '-'
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="申请单号">{{
|
<el-descriptions-item label="处方号">{{
|
||||||
currentDetail.prescriptionNo || '-'
|
currentDetail.prescriptionNo || '-'
|
||||||
}}</el-descriptions-item>
|
}}</el-descriptions-item>
|
||||||
<el-descriptions-item label="申请者">{{
|
<el-descriptions-item label="申请者">{{
|
||||||
@@ -213,101 +160,6 @@
|
|||||||
<el-button @click="detailDialogVisible = false">关闭</el-button>
|
<el-button @click="detailDialogVisible = false">关闭</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<!-- 修改申请单弹窗 -->
|
|
||||||
<el-dialog
|
|
||||||
v-model="editDialogVisible"
|
|
||||||
title="修改检查申请"
|
|
||||||
width="800px"
|
|
||||||
destroy-on-close
|
|
||||||
top="5vh"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
>
|
|
||||||
<div v-if="editDetail" class="applicationShow-container">
|
|
||||||
<el-form :model="editForm" label-width="120px">
|
|
||||||
<el-form-item label="申请单名称">
|
|
||||||
<el-input v-model="editForm.name" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="发往科室">
|
|
||||||
<el-tree-select
|
|
||||||
clearable
|
|
||||||
style="width: 100%"
|
|
||||||
v-model="editForm.targetDepartment"
|
|
||||||
filterable
|
|
||||||
:data="orgOptions"
|
|
||||||
:props="{
|
|
||||||
value: 'id',
|
|
||||||
label: 'name',
|
|
||||||
children: 'children',
|
|
||||||
}"
|
|
||||||
value-key="id"
|
|
||||||
check-strictly
|
|
||||||
placeholder="请选择科室"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="紧急程度">
|
|
||||||
<el-select v-model="editForm.urgencyLevel" placeholder="请选择紧急程度" clearable style="width: 100%">
|
|
||||||
<el-option label="普通" value="routine" />
|
|
||||||
<el-option label="急诊" value="emergency" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="过敏史">
|
|
||||||
<el-input v-model="editForm.allergyHistory" type="textarea" :rows="2" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="检查目的">
|
|
||||||
<el-input v-model="editForm.examinationPurpose" type="textarea" :rows="2" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="病史摘要">
|
|
||||||
<el-input v-model="editForm.medicalHistorySummary" type="textarea" :rows="2" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="期望检查时间">
|
|
||||||
<el-date-picker
|
|
||||||
v-model="editForm.expectedExaminationTime"
|
|
||||||
type="datetime"
|
|
||||||
placeholder="请选择期望检查时间"
|
|
||||||
style="width: 100%"
|
|
||||||
value-format="YYYY-MM-DD HH:mm:ss"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="临床诊断">
|
|
||||||
<el-input v-model="editForm.clinicalDiagnosis" type="textarea" :rows="2" />
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="注意事项">
|
|
||||||
<el-input v-model="editForm.attention" type="textarea" :rows="2" />
|
|
||||||
</el-form-item>
|
|
||||||
<div v-if="editDetail.requestFormDetailList && editDetail.requestFormDetailList.length">
|
|
||||||
<el-divider>申请项目</el-divider>
|
|
||||||
<el-table :data="editDetail.requestFormDetailList" border size="small">
|
|
||||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
|
||||||
<el-table-column prop="adviceName" label="医嘱名称" />
|
|
||||||
<el-table-column prop="quantity" label="数量" width="80" align="center" />
|
|
||||||
<el-table-column prop="unitCode_dictText" label="单位" width="100" />
|
|
||||||
<el-table-column prop="totalPrice" label="总价" width="100" align="right" />
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
<template #footer>
|
|
||||||
<el-button @click="editDialogVisible = false">取消</el-button>
|
|
||||||
<el-button type="primary" @click="handleSaveEdit" :loading="saveLoading">保存</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
<!-- 报告查看弹窗 -->
|
|
||||||
<el-dialog
|
|
||||||
v-model="reportDialogVisible"
|
|
||||||
title="检查报告"
|
|
||||||
width="900px"
|
|
||||||
destroy-on-close
|
|
||||||
top="5vh"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
>
|
|
||||||
<div v-if="reportUrl" style="min-height: 500px;">
|
|
||||||
<iframe :src="reportUrl" style="width: 100%; height: 500px; border: none;" />
|
|
||||||
</div>
|
|
||||||
<el-empty v-else description="暂无报告数据" />
|
|
||||||
<template #footer>
|
|
||||||
<el-button @click="reportDialogVisible = false">关闭</el-button>
|
|
||||||
</template>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -315,7 +167,7 @@
|
|||||||
import {computed, getCurrentInstance, ref, watch} from 'vue';
|
import {computed, getCurrentInstance, ref, watch} from 'vue';
|
||||||
import {Refresh, Search} from '@element-plus/icons-vue';
|
import {Refresh, Search} from '@element-plus/icons-vue';
|
||||||
import {patientInfo} from '../../store/patient.js';
|
import {patientInfo} from '../../store/patient.js';
|
||||||
import {getCheck, deleteRequestForm, withdrawRequestForm, getTestResult} from './api';
|
import {getCheck} from './api';
|
||||||
import {getOrgList} from '@/views/doctorstation/components/api.js';
|
import {getOrgList} from '@/views/doctorstation/components/api.js';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
@@ -327,33 +179,10 @@ const currentDetail = ref(null);
|
|||||||
const descJsonData = ref(null);
|
const descJsonData = ref(null);
|
||||||
const orgOptions = ref([]);
|
const orgOptions = ref([]);
|
||||||
|
|
||||||
// 修改申请单相关
|
|
||||||
const editDialogVisible = ref(false);
|
|
||||||
const editDetail = ref(null);
|
|
||||||
const editForm = ref({});
|
|
||||||
const saveLoading = ref(false);
|
|
||||||
|
|
||||||
// 报告查看相关
|
|
||||||
const reportDialogVisible = ref(false);
|
|
||||||
const reportUrl = ref('');
|
|
||||||
|
|
||||||
// 筛选表单数据
|
// 筛选表单数据
|
||||||
const getDefaultDateRange = () => {
|
|
||||||
const now = new Date();
|
|
||||||
const weekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
||||||
const formatDate = (d) => {
|
|
||||||
const year = d.getFullYear();
|
|
||||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
|
||||||
const day = String(d.getDate()).padStart(2, '0');
|
|
||||||
return `${year}-${month}-${day}`;
|
|
||||||
};
|
|
||||||
return [formatDate(weekAgo), formatDate(now)];
|
|
||||||
};
|
|
||||||
|
|
||||||
const filterForm = ref({
|
const filterForm = ref({
|
||||||
dateRange: getDefaultDateRange(), // 默认近一周
|
dateRange: [], // [startDate, endDate]
|
||||||
status: '', // 申请单状态
|
status: '', // 申请单状态
|
||||||
keyword: '', // 关键字搜索
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
@@ -378,11 +207,6 @@ const fetchData = async () => {
|
|||||||
params.status = filterForm.value.status;
|
params.status = filterForm.value.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加关键字搜索
|
|
||||||
if (filterForm.value.keyword && filterForm.value.keyword.trim()) {
|
|
||||||
params.keyword = filterForm.value.keyword.trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await getCheck(params);
|
const res = await getCheck(params);
|
||||||
if (res.code === 200 && res.data) {
|
if (res.code === 200 && res.data) {
|
||||||
const raw = res.data?.records || res.data;
|
const raw = res.data?.records || res.data;
|
||||||
@@ -419,9 +243,8 @@ const handleSearch = async () => {
|
|||||||
* 重置按钮处理
|
* 重置按钮处理
|
||||||
*/
|
*/
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
filterForm.value.dateRange = getDefaultDateRange();
|
filterForm.value.dateRange = [];
|
||||||
filterForm.value.status = '';
|
filterForm.value.status = '';
|
||||||
filterForm.value.keyword = '';
|
|
||||||
fetchData();
|
fetchData();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -444,36 +267,9 @@ const parseStatus = (status) => {
|
|||||||
return statusMap[String(status)] || '-';
|
return statusMap[String(status)] || '-';
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取申请单展示名称:优先使用具体医嘱名称列表
|
|
||||||
*/
|
|
||||||
const getItemName = (row) => {
|
|
||||||
const items = row?.requestFormDetailList;
|
|
||||||
if (items && items.length > 0) {
|
|
||||||
return items.map(item => item.adviceName).filter(Boolean).join('、') || row.name || '-';
|
|
||||||
}
|
|
||||||
return row.name || '-';
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建打印用项目名称字符串(同步函数,用于模板字符串)
|
|
||||||
*/
|
|
||||||
const buildItemNames = (row) => {
|
|
||||||
const items = row?.requestFormDetailList;
|
|
||||||
if (items && items.length > 0) {
|
|
||||||
return items.map(item => item.adviceName).filter(Boolean).join('、') || row.name || '';
|
|
||||||
}
|
|
||||||
return row.name || '';
|
|
||||||
};
|
|
||||||
|
|
||||||
const labelMap = {
|
const labelMap = {
|
||||||
categoryType: '项目类别',
|
categoryType: '项目类别',
|
||||||
targetDepartment: '发往科室',
|
targetDepartment: '发往科室',
|
||||||
urgencyLevel: '紧急程度',
|
|
||||||
allergyHistory: '过敏史',
|
|
||||||
examinationPurpose: '检查目的',
|
|
||||||
medicalHistorySummary: '病史摘要',
|
|
||||||
expectedExaminationTime: '期望检查时间',
|
|
||||||
symptom: '症状',
|
symptom: '症状',
|
||||||
sign: '体征',
|
sign: '体征',
|
||||||
clinicalDiagnosis: '临床诊断',
|
clinicalDiagnosis: '临床诊断',
|
||||||
@@ -503,26 +299,19 @@ const getLocationInfo = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const recursionFun = (targetDepartment) => {
|
const recursionFun = (targetDepartment) => {
|
||||||
if (!targetDepartment) return '';
|
|
||||||
if (!Array.isArray(orgOptions.value) || orgOptions.value.length === 0) return '';
|
|
||||||
let name = '';
|
let name = '';
|
||||||
for (let index = 0; index < orgOptions.value.length; index++) {
|
for (let index = 0; index < orgOptions.value.length; index++) {
|
||||||
const obj = orgOptions.value[index];
|
const obj = orgOptions.value[index];
|
||||||
if (obj.id == targetDepartment) {
|
if (obj.id == targetDepartment) {
|
||||||
name = obj.name;
|
name = obj.name;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
const subObjArray = obj['children'];
|
const subObjArray = obj['children'];
|
||||||
if (Array.isArray(subObjArray)) {
|
for (let index = 0; index < subObjArray.length; index++) {
|
||||||
for (let i = 0; i < subObjArray.length; i++) {
|
const item = subObjArray[index];
|
||||||
const item = subObjArray[i];
|
if (item.id == targetDepartment) {
|
||||||
if (item.id == targetDepartment) {
|
name = item.name;
|
||||||
name = item.name;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (name) break;
|
|
||||||
}
|
}
|
||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
@@ -535,15 +324,7 @@ const handleViewDetail = (row) => {
|
|||||||
if (row.descJson) {
|
if (row.descJson) {
|
||||||
try {
|
try {
|
||||||
const obj = JSON.parse(row.descJson);
|
const obj = JSON.parse(row.descJson);
|
||||||
if (obj.targetDepartment) {
|
obj.targetDepartment = recursionFun(obj.targetDepartment);
|
||||||
const deptName = recursionFun(obj.targetDepartment);
|
|
||||||
obj.targetDepartment = deptName || obj.targetDepartment;
|
|
||||||
}
|
|
||||||
// 紧急程度转换为显示文本
|
|
||||||
const urgencyMap = { routine: '普通', emergency: '急诊' };
|
|
||||||
if (obj.urgencyLevel) {
|
|
||||||
obj.urgencyLevel = urgencyMap[obj.urgencyLevel] || obj.urgencyLevel;
|
|
||||||
}
|
|
||||||
descJsonData.value = obj;
|
descJsonData.value = obj;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('解析 descJson 失败:', e);
|
console.error('解析 descJson 失败:', e);
|
||||||
@@ -555,229 +336,6 @@ const handleViewDetail = (row) => {
|
|||||||
detailDialogVisible.value = true;
|
detailDialogVisible.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改申请单
|
|
||||||
*/
|
|
||||||
const handleEdit = (row) => {
|
|
||||||
editDetail.value = row;
|
|
||||||
// 解析 descJson 为表单数据
|
|
||||||
const form = { name: row.name || '' };
|
|
||||||
if (row.descJson) {
|
|
||||||
try {
|
|
||||||
const desc = JSON.parse(row.descJson);
|
|
||||||
form.targetDepartment = desc.targetDepartment || '';
|
|
||||||
form.urgencyLevel = desc.urgencyLevel || '';
|
|
||||||
form.allergyHistory = desc.allergyHistory || '';
|
|
||||||
form.examinationPurpose = desc.examinationPurpose || '';
|
|
||||||
form.medicalHistorySummary = desc.medicalHistorySummary || '';
|
|
||||||
form.expectedExaminationTime = desc.expectedExaminationTime || '';
|
|
||||||
form.clinicalDiagnosis = desc.clinicalDiagnosis || '';
|
|
||||||
form.attention = desc.attention || '';
|
|
||||||
form.symptom = desc.symptom || '';
|
|
||||||
form.sign = desc.sign || '';
|
|
||||||
} catch (e) {
|
|
||||||
console.error('解析 descJson 失败:', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
editForm.value = form;
|
|
||||||
editDialogVisible.value = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 保存修改
|
|
||||||
*/
|
|
||||||
const handleSaveEdit = async () => {
|
|
||||||
if (!editDetail.value?.requestFormId) {
|
|
||||||
proxy.$modal?.msgWarning?.('申请单ID不存在');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
saveLoading.value = true;
|
|
||||||
try {
|
|
||||||
// 复用 save-check 接口进行更新(传入 requestFormId 即为编辑场景)
|
|
||||||
const res = await proxy.$http?.post?.('/reg-doctorstation/request-form/save-check', {
|
|
||||||
requestFormId: editDetail.value.requestFormId,
|
|
||||||
encounterId: editDetail.value.encounterId,
|
|
||||||
patientId: editDetail.value.patientId,
|
|
||||||
name: editForm.value.name,
|
|
||||||
organizationId: editDetail.value.inHospitalOrgId || patientInfo.value?.inHospitalOrgId,
|
|
||||||
descJson: JSON.stringify({
|
|
||||||
targetDepartment: editForm.value.targetDepartment,
|
|
||||||
urgencyLevel: editForm.value.urgencyLevel,
|
|
||||||
allergyHistory: editForm.value.allergyHistory,
|
|
||||||
examinationPurpose: editForm.value.examinationPurpose,
|
|
||||||
medicalHistorySummary: editForm.value.medicalHistorySummary,
|
|
||||||
expectedExaminationTime: editForm.value.expectedExaminationTime,
|
|
||||||
clinicalDiagnosis: editForm.value.clinicalDiagnosis,
|
|
||||||
attention: editForm.value.attention,
|
|
||||||
symptom: editForm.value.symptom,
|
|
||||||
sign: editForm.value.sign,
|
|
||||||
}),
|
|
||||||
activityList: [], // 修改场景仅更新描述信息,不修改项目
|
|
||||||
});
|
|
||||||
if (res?.code === 200) {
|
|
||||||
proxy.$modal?.msgSuccess?.('修改成功');
|
|
||||||
editDialogVisible.value = false;
|
|
||||||
await fetchData();
|
|
||||||
} else {
|
|
||||||
proxy.$modal?.msgError?.(res?.msg || '修改失败');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('修改申请单失败:', e.message);
|
|
||||||
proxy.$modal?.msgError?.('修改失败: ' + (e.message || '网络异常'));
|
|
||||||
} finally {
|
|
||||||
saveLoading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除申请单(仅待签发状态可删除)
|
|
||||||
*/
|
|
||||||
const handleDelete = async (row) => {
|
|
||||||
if (!row.requestFormId) {
|
|
||||||
proxy.$modal?.msgWarning?.('申请单ID不存在');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const res = await deleteRequestForm({ requestFormId: row.requestFormId });
|
|
||||||
if (res?.code === 200) {
|
|
||||||
proxy.$modal?.msgSuccess?.('删除成功');
|
|
||||||
await fetchData();
|
|
||||||
} else {
|
|
||||||
proxy.$modal?.msgError?.(res?.msg || '删除失败');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('删除申请单失败:', e.message);
|
|
||||||
proxy.$modal?.msgError?.('删除失败: ' + (e.message || '网络异常'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 撤回申请单(已签发状态撤回至待签发)
|
|
||||||
*/
|
|
||||||
const handleWithdraw = async (row) => {
|
|
||||||
if (!row.requestFormId) {
|
|
||||||
proxy.$modal?.msgWarning?.('申请单ID不存在');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const res = await withdrawRequestForm({ requestFormId: row.requestFormId });
|
|
||||||
if (res?.code === 200) {
|
|
||||||
proxy.$modal?.msgSuccess?.('撤回成功');
|
|
||||||
await fetchData();
|
|
||||||
} else {
|
|
||||||
proxy.$modal?.msgError?.(res?.msg || '撤回失败');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('撤回申请单失败:', e.message);
|
|
||||||
proxy.$modal?.msgError?.('撤回失败: ' + (e.message || '网络异常'));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 打印申请单
|
|
||||||
*/
|
|
||||||
const handlePrint = (row) => {
|
|
||||||
// 打开新窗口进行打印
|
|
||||||
const printWindow = window.open('', '_blank');
|
|
||||||
if (!printWindow) {
|
|
||||||
proxy.$modal?.msgWarning?.('请允许浏览器弹出窗口以进行打印');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const content = buildPrintContent(row);
|
|
||||||
printWindow.document.write(`
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>检查申请单打印</title>
|
|
||||||
<style>
|
|
||||||
body { font-family: "Microsoft YaHei", sans-serif; padding: 20px; font-size: 14px; }
|
|
||||||
h2 { text-align: center; margin-bottom: 20px; }
|
|
||||||
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
|
|
||||||
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
|
||||||
th { background: #f5f5f5; }
|
|
||||||
.info-row { margin: 8px 0; }
|
|
||||||
.label { font-weight: bold; display: inline-block; width: 100px; }
|
|
||||||
@media print { .no-print { display: none; } }
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
${content}
|
|
||||||
<div class="no-print" style="text-align: center; margin-top: 20px;">
|
|
||||||
<button onclick="window.print()">打印</button>
|
|
||||||
<button onclick="window.close()">关闭</button>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
`);
|
|
||||||
printWindow.document.close();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建打印内容
|
|
||||||
*/
|
|
||||||
const buildPrintContent = (row) => {
|
|
||||||
let descHtml = '';
|
|
||||||
if (row.descJson) {
|
|
||||||
try {
|
|
||||||
const desc = JSON.parse(row.descJson);
|
|
||||||
descHtml = Object.entries(labelMap)
|
|
||||||
.filter(([key]) => desc[key])
|
|
||||||
.map(([key, label]) => `<div class="info-row"><span class="label">${label}:</span>${desc[key]}</div>`)
|
|
||||||
.join('');
|
|
||||||
} catch (e) {
|
|
||||||
console.error('解析 descJson 失败:', e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let itemsHtml = '';
|
|
||||||
if (row.requestFormDetailList && row.requestFormDetailList.length) {
|
|
||||||
itemsHtml = `
|
|
||||||
<h3>申请项目</h3>
|
|
||||||
<table>
|
|
||||||
<tr><th>序号</th><th>医嘱名称</th><th>数量</th><th>单位</th><th>总价</th></tr>
|
|
||||||
${row.requestFormDetailList.map((item, i) => `
|
|
||||||
<tr>
|
|
||||||
<td>${i + 1}</td>
|
|
||||||
<td>${item.adviceName || '-'}</td>
|
|
||||||
<td>${item.quantity || '-'}</td>
|
|
||||||
<td>${item.unitCode_dictText || '-'}</td>
|
|
||||||
<td>${item.totalPrice || '-'}</td>
|
|
||||||
</tr>
|
|
||||||
`).join('')}
|
|
||||||
</table>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
return `
|
|
||||||
<h2>检查申请单</h2>
|
|
||||||
<div class="info-row"><span class="label">患者姓名:</span>${row.patientName || '-'}</div>
|
|
||||||
<div class="info-row"><span class="label">申请单名称:</span>${buildItemNames(row) || '-'}</div>
|
|
||||||
<div class="info-row"><span class="label">创建时间:</span>${row.createTime || '-'}</div>
|
|
||||||
<div class="info-row"><span class="label">申请单号:</span>${row.prescriptionNo || '-'}</div>
|
|
||||||
<div class="info-row"><span class="label">申请者:</span>${row.requesterId_dictText || '-'}</div>
|
|
||||||
<div class="info-row"><span class="label">申请单状态:</span>${parseStatus(row.status)}</div>
|
|
||||||
${descHtml ? `<h3>申请单描述</h3>${descHtml}` : ''}
|
|
||||||
${itemsHtml}
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查看报告
|
|
||||||
*/
|
|
||||||
const handleViewReport = async (row) => {
|
|
||||||
reportUrl.value = '';
|
|
||||||
reportDialogVisible.value = true;
|
|
||||||
try {
|
|
||||||
const res = await getTestResult({ encounterId: row.encounterId, requestFormId: row.requestFormId });
|
|
||||||
if (res?.code === 200 && res?.data) {
|
|
||||||
reportUrl.value = res.data;
|
|
||||||
} else {
|
|
||||||
console.warn('获取检查报告失败:', res?.msg || '无数据');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn('获取检查报告异常:', e.message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => patientInfo.value?.encounterId,
|
() => patientInfo.value?.encounterId,
|
||||||
(val) => {
|
(val) => {
|
||||||
@@ -786,9 +344,8 @@ watch(
|
|||||||
getLocationInfo();
|
getLocationInfo();
|
||||||
} else {
|
} else {
|
||||||
tableData.value = [];
|
tableData.value = [];
|
||||||
filterForm.value.dateRange = getDefaultDateRange();
|
filterForm.value.dateRange = [];
|
||||||
filterForm.value.status = '';
|
filterForm.value.status = '';
|
||||||
filterForm.value.keyword = '';
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
|
|||||||
@@ -181,10 +181,9 @@ const hasMatchedFields = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/** 查询科室 */
|
/** 查询科室 */
|
||||||
const getLocationInfo = () => {
|
const getLocationInfo = async () => {
|
||||||
getOrgList().then((res) => {
|
const res = await getOrgList();
|
||||||
orgOptions.value = res.data.records;
|
orgOptions.value = res.data.records;
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const recursionFun = (targetDepartment) => {
|
const recursionFun = (targetDepartment) => {
|
||||||
@@ -205,7 +204,12 @@ const recursionFun = (targetDepartment) => {
|
|||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleViewDetail = (row) => {
|
const handleViewDetail = async (row) => {
|
||||||
|
// 确保科室数据已加载,以便将 ID 解析为名称
|
||||||
|
if (!orgOptions.value || orgOptions.value.length === 0) {
|
||||||
|
await getLocationInfo();
|
||||||
|
}
|
||||||
|
|
||||||
currentDetail.value = row;
|
currentDetail.value = row;
|
||||||
// 解析 descJson
|
// 解析 descJson
|
||||||
if (row.descJson) {
|
if (row.descJson) {
|
||||||
@@ -226,10 +230,9 @@ const handleViewDetail = (row) => {
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => patientInfo.value?.encounterId,
|
() => patientInfo.value?.encounterId,
|
||||||
(val) => {
|
async (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
fetchData();
|
await Promise.all([fetchData(), getLocationInfo()]);
|
||||||
getLocationInfo();
|
|
||||||
} else {
|
} else {
|
||||||
tableData.value = [];
|
tableData.value = [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,6 +47,15 @@
|
|||||||
<el-option label="已作废" value="5" />
|
<el-option label="已作废" value="5" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item label="关键字">
|
||||||
|
<el-input
|
||||||
|
v-model="filterForm.keyword"
|
||||||
|
placeholder="申请单号/检验项目"
|
||||||
|
clearable
|
||||||
|
style="width: 200px"
|
||||||
|
@keyup.enter="handleSearch"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="handleSearch" :loading="loading">
|
<el-button type="primary" @click="handleSearch" :loading="loading">
|
||||||
<el-icon><Search /></el-icon>
|
<el-icon><Search /></el-icon>
|
||||||
@@ -188,6 +197,7 @@ const orgOptions = ref([]);
|
|||||||
const filterForm = ref({
|
const filterForm = ref({
|
||||||
dateRange: [], // [startDate, endDate]
|
dateRange: [], // [startDate, endDate]
|
||||||
status: '', // 单据状态
|
status: '', // 单据状态
|
||||||
|
keyword: '', // 关键字搜索
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
@@ -211,7 +221,12 @@ const fetchData = async () => {
|
|||||||
if (filterForm.value.status !== '' && filterForm.value.status !== undefined) {
|
if (filterForm.value.status !== '' && filterForm.value.status !== undefined) {
|
||||||
params.status = filterForm.value.status;
|
params.status = filterForm.value.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加关键字搜索
|
||||||
|
if (filterForm.value.keyword && filterForm.value.keyword.trim()) {
|
||||||
|
params.keyword = filterForm.value.keyword.trim();
|
||||||
|
}
|
||||||
|
|
||||||
const res = await getInspection(params);
|
const res = await getInspection(params);
|
||||||
if (res.code === 200 && res.data) {
|
if (res.code === 200 && res.data) {
|
||||||
const raw = res.data?.records || res.data;
|
const raw = res.data?.records || res.data;
|
||||||
@@ -251,6 +266,7 @@ const handleReset = () => {
|
|||||||
// 重置筛选条件为默认值
|
// 重置筛选条件为默认值
|
||||||
filterForm.value.dateRange = [];
|
filterForm.value.dateRange = [];
|
||||||
filterForm.value.status = '';
|
filterForm.value.status = '';
|
||||||
|
filterForm.value.keyword = '';
|
||||||
// 重新加载数据
|
// 重新加载数据
|
||||||
fetchData();
|
fetchData();
|
||||||
};
|
};
|
||||||
@@ -331,10 +347,9 @@ const hasMatchedFields = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/** 查询科室 */
|
/** 查询科室 */
|
||||||
const getLocationInfo = () => {
|
const getLocationInfo = async () => {
|
||||||
getDepartmentList().then((res) => {
|
const res = await getDepartmentList();
|
||||||
orgOptions.value = res.data || [];
|
orgOptions.value = res.data || [];
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const recursionFun = (targetDepartment) => {
|
const recursionFun = (targetDepartment) => {
|
||||||
@@ -357,7 +372,12 @@ const recursionFun = (targetDepartment) => {
|
|||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleViewDetail = (row) => {
|
const handleViewDetail = async (row) => {
|
||||||
|
// 确保科室数据已加载,以便将 ID 解析为名称
|
||||||
|
if (!orgOptions.value || orgOptions.value.length === 0) {
|
||||||
|
await getLocationInfo();
|
||||||
|
}
|
||||||
|
|
||||||
currentDetail.value = row;
|
currentDetail.value = row;
|
||||||
// 解析 descJson
|
// 解析 descJson
|
||||||
if (row.descJson) {
|
if (row.descJson) {
|
||||||
@@ -378,13 +398,13 @@ const handleViewDetail = (row) => {
|
|||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => patientInfo.value?.encounterId,
|
() => patientInfo.value?.encounterId,
|
||||||
(val) => {
|
async (val) => {
|
||||||
if (val) {
|
if (val) {
|
||||||
// 设置默认日期范围为近7天
|
// 设置默认日期范围为近7天
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const sevenDaysAgo = new Date(today);
|
const sevenDaysAgo = new Date(today);
|
||||||
sevenDaysAgo.setDate(today.getDate() - 6); // 包含今天共7天
|
sevenDaysAgo.setDate(today.getDate() - 6); // 包含今天共7天
|
||||||
|
|
||||||
// 格式化为 YYYY-MM-DD
|
// 格式化为 YYYY-MM-DD
|
||||||
const formatDate = (date) => {
|
const formatDate = (date) => {
|
||||||
const year = date.getFullYear();
|
const year = date.getFullYear();
|
||||||
@@ -392,19 +412,19 @@ watch(
|
|||||||
const day = String(date.getDate()).padStart(2, '0');
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
return `${year}-${month}-${day}`;
|
return `${year}-${month}-${day}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
filterForm.value.dateRange = [
|
filterForm.value.dateRange = [
|
||||||
formatDate(sevenDaysAgo),
|
formatDate(sevenDaysAgo),
|
||||||
formatDate(today)
|
formatDate(today)
|
||||||
];
|
];
|
||||||
|
|
||||||
fetchData();
|
await Promise.all([fetchData(), getLocationInfo()]);
|
||||||
getLocationInfo();
|
|
||||||
} else {
|
} else {
|
||||||
tableData.value = [];
|
tableData.value = [];
|
||||||
// 重置筛选条件
|
// 重置筛选条件
|
||||||
filterForm.value.dateRange = [];
|
filterForm.value.dateRange = [];
|
||||||
filterForm.value.status = '';
|
filterForm.value.status = '';
|
||||||
|
filterForm.value.keyword = '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
|
|||||||
@@ -802,8 +802,10 @@ function clickRowDb(row, column, event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
row.showPopover = false;
|
row.showPopover = false;
|
||||||
// “待签发(已保存 requestId存在)”不允许再编辑;仅“待保存(无requestId)”允许编辑
|
// 允许所有 statusEnum==1 的医嘱进入编辑:
|
||||||
if (row.statusEnum == 1 && !row.requestId) {
|
// 1. 新医嘱(无 requestId):待保存
|
||||||
|
// 2. 护士退回医嘱(有 requestId):退回后状态重置为 DRAFT(1),需允许医生编辑修改后重新签发
|
||||||
|
if (row.statusEnum == 1) {
|
||||||
// 确保治疗类型为字符串,方便与单选框 label 对齐,默认为长期医嘱('1')
|
// 确保治疗类型为字符串,方便与单选框 label 对齐,默认为长期医嘱('1')
|
||||||
row.therapyEnum = String(row.therapyEnum ?? '1');
|
row.therapyEnum = String(row.therapyEnum ?? '1');
|
||||||
row.isEdit = true;
|
row.isEdit = true;
|
||||||
@@ -881,8 +883,9 @@ function handleFocus(row, index) {
|
|||||||
// 用 adviceType + categoryCode 组合查找匹配的选项
|
// 用 adviceType + categoryCode 组合查找匹配的选项
|
||||||
const selectValue = (adviceType == 1 && row.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
const selectValue = (adviceType == 1 && row.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||||
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
||||||
// 修复Bug #486:当行没有显式选择医嘱类型时,不传categoryCode,让搜索在全药库中进行
|
// 修复Bug #486:当行没有显式选择医嘱类型时(row.adviceType为undefined),
|
||||||
const categoryCode = selectedItem ? selectedItem.categoryCode : (row.adviceType !== undefined ? (adviceQueryParams.value.categoryCode || '') : '');
|
// 不传categoryCode,让搜索在全药库中进行;只有行已选择类型时才用对应categoryCode过滤
|
||||||
|
const categoryCode = row.adviceType !== undefined ? (selectedItem ? selectedItem.categoryCode : '') : '';
|
||||||
const searchKey = row.adviceName || '';
|
const searchKey = row.adviceName || '';
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
@@ -919,8 +922,9 @@ function handleChange(value) {
|
|||||||
// 用 adviceType + categoryCode 组合查找匹配的选项
|
// 用 adviceType + categoryCode 组合查找匹配的选项
|
||||||
const selectValue = (adviceType == 1 && row?.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
const selectValue = (adviceType == 1 && row?.categoryCode) ? '1-' + row.categoryCode : adviceType;
|
||||||
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
const selectedItem = adviceTypeList.value.find(item => item.value === selectValue) || adviceTypeList.value.find(item => item.adviceType === adviceType);
|
||||||
// 修复Bug #486:当行没有显式选择医嘱类型时,不传categoryCode,让搜索在全药库中进行
|
// 修复Bug #486:当行没有显式选择医嘱类型时(row?.adviceType为undefined),
|
||||||
const categoryCode = selectedItem ? selectedItem.categoryCode : (row?.adviceType !== undefined ? (adviceQueryParams.value.categoryCode || '') : '');
|
// 不传categoryCode,让搜索在全药库中进行;只有行已选择类型时才用对应categoryCode过滤
|
||||||
|
const categoryCode = row?.adviceType !== undefined ? (selectedItem ? selectedItem.categoryCode : '') : '';
|
||||||
tableRef.refresh(adviceType, categoryCode, value);
|
tableRef.refresh(adviceType, categoryCode, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,11 +17,13 @@
|
|||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<!-- <el-tab-pane label="医技报告" name="fourth">Task</el-tab-pane> -->
|
<!-- <el-tab-pane label="医技报告" name="fourth">Task</el-tab-pane> -->
|
||||||
<el-tab-pane label="检验申请" name="test">
|
<el-tab-pane label="检验申请" name="test">
|
||||||
<TestApplication ref="testApplicationRef" :show-status-column="false" />
|
<TestApplication ref="testApplicationRef" :show-status-column="true" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
```vue
|
||||||
<el-tab-pane label="检查申请" name="examine">
|
<el-tab-pane label="检查申请" name="examine">
|
||||||
<ExamineApplication ref="examineApplicationRef" />
|
<ExamineApplication ref="examineApplicationRef" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
```
|
||||||
<el-tab-pane label="汇总发药申请" name="summaryDrug">
|
<el-tab-pane label="汇总发药申请" name="summaryDrug">
|
||||||
<SummaryDrugApplication ref="summaryDrugApplicationRef" />
|
<SummaryDrugApplication ref="summaryDrugApplicationRef" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
@@ -44,11 +46,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, onBeforeMount, onMounted, provide, reactive, ref, watch } from 'vue';
|
import {computed, onBeforeMount, onMounted, provide, reactive, ref, watch,} from 'vue';
|
||||||
|
|
||||||
import Emr from './emr/index.vue';
|
import Emr from './emr/index.vue';
|
||||||
import inPatientBarDoctorFold from '@/components/patientBar/inPatientBarDoctorFold.vue';
|
import inPatientBarDoctorFold from '@/components/patientBar/inPatientBarDoctorFold.vue';
|
||||||
import SummaryDrugApplication from './components/applicationShow/summaryDrugApplication.vue';
|
|
||||||
import PatientList from '@/components/PatientList/patient-list.vue';
|
import PatientList from '@/components/PatientList/patient-list.vue';
|
||||||
import {localPatientInfo, updateLocalPatientInfo} from './store/localPatient';
|
import {localPatientInfo, updateLocalPatientInfo} from './store/localPatient';
|
||||||
import {patientInfo, updatePatientInfo} from './store/patient';
|
import {patientInfo, updatePatientInfo} from './store/patient';
|
||||||
@@ -83,7 +84,6 @@ const currentPatientInfo = ref({});
|
|||||||
const testApplicationRef = ref();
|
const testApplicationRef = ref();
|
||||||
const examineApplicationRef = ref();
|
const examineApplicationRef = ref();
|
||||||
const surgeryApplicationRef = ref();
|
const surgeryApplicationRef = ref();
|
||||||
const summaryDrugApplicationRef = ref();
|
|
||||||
const bloodTtransfusionAapplicationRef = ref();
|
const bloodTtransfusionAapplicationRef = ref();
|
||||||
|
|
||||||
// 患者列表相关逻辑
|
// 患者列表相关逻辑
|
||||||
|
|||||||
@@ -174,7 +174,6 @@ const activeNames = ref([]);
|
|||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const prescriptionList = ref([]);
|
const prescriptionList = ref([]);
|
||||||
const deadline = ref(formatDateStr(new Date(), 'YYYY-MM-DD') + ' 23:59:59');
|
const deadline = ref(formatDateStr(new Date(), 'YYYY-MM-DD') + ' 23:59:59');
|
||||||
const therapyEnum = ref(undefined);
|
|
||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const chooseAll = ref(false);
|
const chooseAll = ref(false);
|
||||||
@@ -190,6 +189,10 @@ const props = defineProps({
|
|||||||
deadline: {
|
deadline: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
|
therapyEnum: {
|
||||||
|
type: Number,
|
||||||
|
default: undefined,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleGetPrescription() {
|
function handleGetPrescription() {
|
||||||
@@ -200,7 +203,7 @@ function handleGetPrescription() {
|
|||||||
encounterIds: encounterIds,
|
encounterIds: encounterIds,
|
||||||
pageSize: 10000,
|
pageSize: 10000,
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
therapyEnum: therapyEnum.value,
|
therapyEnum: props.therapyEnum,
|
||||||
exeStatus: props.exeStatus,
|
exeStatus: props.exeStatus,
|
||||||
requestStatus: props.requestStatus,
|
requestStatus: props.requestStatus,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -58,7 +58,7 @@
|
|||||||
:clearable="false"
|
:clearable="false"
|
||||||
@change="handleGetPrescription"
|
@change="handleGetPrescription"
|
||||||
/>
|
/>
|
||||||
<el-radio-group v-model="therapyEnum" class="ml20" @change="handleRadioChange">
|
<el-radio-group v-model="therapyEnum" class="ml20" @change="handleTherapyChange">
|
||||||
<el-radio :value="undefined">全部</el-radio>
|
<el-radio :value="undefined">全部</el-radio>
|
||||||
<el-radio :value="1">长期</el-radio>
|
<el-radio :value="1">长期</el-radio>
|
||||||
<el-radio :value="2">临时</el-radio>
|
<el-radio :value="2">临时</el-radio>
|
||||||
@@ -79,6 +79,7 @@
|
|||||||
:exeStatus="exeStatus"
|
:exeStatus="exeStatus"
|
||||||
:requestStatus="requestStatus"
|
:requestStatus="requestStatus"
|
||||||
:deadline="deadline"
|
:deadline="deadline"
|
||||||
|
:therapyEnum="therapyEnum"
|
||||||
/>
|
/>
|
||||||
<SummaryMedicineList v-else />
|
<SummaryMedicineList v-else />
|
||||||
<!-- <el-tabs v-model="activeName" class="demo-tabs centered-tabs" @tab-change="handleClick">
|
<!-- <el-tabs v-model="activeName" class="demo-tabs centered-tabs" @tab-change="handleClick">
|
||||||
@@ -120,6 +121,7 @@ const requestStatus = ref(RequestStatus.COMPLETED);
|
|||||||
const chooseAll = ref(false);
|
const chooseAll = ref(false);
|
||||||
const drugType = ref('1');
|
const drugType = ref('1');
|
||||||
const isDetails = ref('1');
|
const isDetails = ref('1');
|
||||||
|
const therapyEnum = ref(undefined);
|
||||||
|
|
||||||
// 存储子组件引用的对象
|
// 存储子组件引用的对象
|
||||||
const prescriptionRefs = ref();
|
const prescriptionRefs = ref();
|
||||||
@@ -175,6 +177,10 @@ function handleRadioChange(value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleTherapyChange() {
|
||||||
|
handleGetPrescription();
|
||||||
|
}
|
||||||
|
|
||||||
function handleExecute() {
|
function handleExecute() {
|
||||||
proxy.$refs['prescriptionRefs'].handleMedicineSummary();
|
proxy.$refs['prescriptionRefs'].handleMedicineSummary();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -469,11 +469,19 @@ function handleExecute() {
|
|||||||
console.log(list, 'list');
|
console.log(list, 'list');
|
||||||
adviceExecute({ exeDate: exeDate.value, adviceExecuteDetailList: list }).then((res) => {
|
adviceExecute({ exeDate: exeDate.value, adviceExecuteDetailList: list }).then((res) => {
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
proxy.$modal.msgSuccess(res.msg || '医嘱执行成功');
|
|
||||||
handleGetPrescription();
|
handleGetPrescription();
|
||||||
lotNumberMatch({ encounterIdList: encounterIds }, { skipErrorMsg: true }).catch((error) => {
|
// 仅当选中医嘱中包含药品/耗材类医嘱时,才调用耗材批号匹配
|
||||||
console.warn('lotNumberMatch failed after adviceExecute:', error);
|
const hasMedOrDevice = list.some(
|
||||||
});
|
(item) =>
|
||||||
|
item.adviceTable === 'med_medication_request' ||
|
||||||
|
String(item.adviceTable || '').includes('device'),
|
||||||
|
);
|
||||||
|
if (hasMedOrDevice) {
|
||||||
|
lotNumberMatch({ encounterIdList: encounterIds }, { skipErrorMsg: true }).catch((error) => {
|
||||||
|
console.warn('lotNumberMatch failed after adviceExecute:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
proxy.$modal.msgSuccess(res.msg || '医嘱执行成功');
|
||||||
} else {
|
} else {
|
||||||
proxy.$modal.msgError(res.msg || '医嘱执行失败');
|
proxy.$modal.msgError(res.msg || '医嘱执行失败');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,53 +198,52 @@
|
|||||||
↓
|
↓
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="queue-actions-right">
|
|
||||||
<el-button
|
|
||||||
:type="showOnlyWaiting ? 'primary' : ''"
|
|
||||||
size="small"
|
|
||||||
@click="showOnlyWaiting = true"
|
|
||||||
>
|
|
||||||
只显示等待
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
:type="!showOnlyWaiting ? 'primary' : ''"
|
|
||||||
size="small"
|
|
||||||
@click="showOnlyWaiting = false"
|
|
||||||
>
|
|
||||||
显示全部状态
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 底部控制面板 -->
|
<!-- 底部控制面板 -->
|
||||||
<div class="footer-section">
|
<div class="footer-section">
|
||||||
<!-- 诊室快速过滤栏 -->
|
<!-- Bug #411:诊室快速过滤栏,筛选维度从科室改为诊室 -->
|
||||||
<div class="filter-section">
|
<div class="filter-section">
|
||||||
<div class="filter-label">
|
<div class="filter-left">
|
||||||
③ 诊室快速过滤栏
|
<div class="filter-label">
|
||||||
</div>
|
③ 诊室快速过滤栏
|
||||||
<div class="filter-select-wrapper">
|
</div>
|
||||||
<el-select
|
<div class="filter-button-wrapper">
|
||||||
v-model="selectedClinicRoom"
|
<el-button
|
||||||
placeholder="请选择诊室"
|
:type="selectedRoom === 'all' ? 'primary' : ''"
|
||||||
clearable
|
size="small"
|
||||||
filterable
|
@click="selectedRoom = 'all'"
|
||||||
style="width: 100%"
|
>
|
||||||
size="default"
|
全部
|
||||||
>
|
</el-button>
|
||||||
<el-option
|
<el-button
|
||||||
label="全部"
|
v-for="room in uniqueRooms"
|
||||||
value="all"
|
|
||||||
/>
|
|
||||||
<el-option
|
|
||||||
v-for="room in clinicRoomList"
|
|
||||||
:key="room"
|
:key="room"
|
||||||
:label="room"
|
:type="selectedRoom === room ? 'primary' : ''"
|
||||||
:value="room"
|
size="small"
|
||||||
/>
|
@click="selectedRoom = room"
|
||||||
</el-select>
|
>
|
||||||
|
{{ room }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="filter-right">
|
||||||
|
<el-button
|
||||||
|
:type="showOnlyWaiting ? 'primary' : ''"
|
||||||
|
size="small"
|
||||||
|
@click="showOnlyWaiting = true"
|
||||||
|
>
|
||||||
|
只显示等待
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
:type="!showOnlyWaiting ? 'primary' : ''"
|
||||||
|
size="small"
|
||||||
|
@click="showOnlyWaiting = false"
|
||||||
|
>
|
||||||
|
显示全部状态
|
||||||
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -680,10 +679,8 @@ const selectedCandidates = ref([])
|
|||||||
// 显示选项
|
// 显示选项
|
||||||
const showOnlyWaiting = ref(false)
|
const showOnlyWaiting = ref(false)
|
||||||
|
|
||||||
// 诊室过滤(按诊室维度筛选)
|
// Bug #411:诊室过滤,替代原来的科室下拉框(selectedDept/departmentList 已移除)
|
||||||
const selectedClinicRoom = ref('all')
|
const selectedRoom = ref('all')
|
||||||
// 诊室列表(从数据中动态提取)
|
|
||||||
const clinicRoomList = ref([])
|
|
||||||
|
|
||||||
// 修复【#397】:动态获取当前科室名称
|
// 修复【#397】:动态获取当前科室名称
|
||||||
const currentDeptName = computed(() => {
|
const currentDeptName = computed(() => {
|
||||||
@@ -906,11 +903,12 @@ const mapFrontendStatusToBackend = (status) => {
|
|||||||
// 从数据库加载队列
|
// 从数据库加载队列
|
||||||
const loadQueueFromDb = async () => {
|
const loadQueueFromDb = async () => {
|
||||||
try {
|
try {
|
||||||
// 使用当前登录人的科室
|
// Bug #411:不再按科室选筛加载,后端默认按当前登录人科室查询
|
||||||
|
const organizationId = undefined
|
||||||
|
// 只查询今天的患者
|
||||||
const today = new Date()
|
const today = new Date()
|
||||||
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`
|
const todayStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`
|
||||||
console.log('【心内科】loadQueueFromDb 开始:date=', todayStr)
|
const res = await getTriageQueueList({ organizationId, date: todayStr }).catch((err) => {
|
||||||
const res = await getTriageQueueList({ date: todayStr }).catch((err) => {
|
|
||||||
console.error('【心内科】loadQueueFromDb 请求异常:', err)
|
console.error('【心内科】loadQueueFromDb 请求异常:', err)
|
||||||
return { code: 500, msg: err?.message || '请求失败', data: null }
|
return { code: 500, msg: err?.message || '请求失败', data: null }
|
||||||
})
|
})
|
||||||
@@ -1138,8 +1136,6 @@ const loadDataFromApi = async () => {
|
|||||||
|
|
||||||
// 同步当前呼叫(队列从 DB 加载后已同步;这里再兜底一次)
|
// 同步当前呼叫(队列从 DB 加载后已同步;这里再兜底一次)
|
||||||
syncCurrentCallFromQueue()
|
syncCurrentCallFromQueue()
|
||||||
// 提取诊室列表供过滤栏使用
|
|
||||||
extractClinicRooms()
|
|
||||||
console.log('【心内科】数据加载完成:候选池', originalCandidatePoolList.value.length, '条,队列', originalQueueList.value.length, '条')
|
console.log('【心内科】数据加载完成:候选池', originalCandidatePoolList.value.length, '条,队列', originalQueueList.value.length, '条')
|
||||||
ElMessage.success('【心内科】已从门诊挂号接口加载数据')
|
ElMessage.success('【心内科】已从门诊挂号接口加载数据')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -1151,42 +1147,35 @@ const loadDataFromApi = async () => {
|
|||||||
totalSignedIn.value = originalCandidatePoolList.value.length
|
totalSignedIn.value = originalCandidatePoolList.value.length
|
||||||
totalInQueue.value = originalQueueList.value.length
|
totalInQueue.value = originalQueueList.value.length
|
||||||
syncCurrentCallFromQueue()
|
syncCurrentCallFromQueue()
|
||||||
extractClinicRooms()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 原始数据存储(用于过滤)
|
// 原始数据存储(用于过滤)
|
||||||
const originalCandidatePoolList = ref(getInitialCandidatePoolList())
|
const originalCandidatePoolList = ref(getInitialCandidatePoolList())
|
||||||
|
|
||||||
// 提取诊室列表(从队列和候选池数据中动态获取)
|
// 过滤后的智能候选池数据(按诊室过滤)
|
||||||
const extractClinicRooms = () => {
|
|
||||||
const roomSet = new Set()
|
|
||||||
// 从队列中提取
|
|
||||||
originalQueueList.value.forEach(item => {
|
|
||||||
if (item.room && item.room !== '-') {
|
|
||||||
roomSet.add(item.room)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// 从候选池中提取
|
|
||||||
originalCandidatePoolList.value.forEach(item => {
|
|
||||||
if (item.room && item.room !== '-') {
|
|
||||||
roomSet.add(item.room)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
clinicRoomList.value = Array.from(roomSet).sort()
|
|
||||||
}
|
|
||||||
|
|
||||||
// 过滤后的智能候选池数据
|
|
||||||
const filteredCandidatePoolList = computed(() => {
|
const filteredCandidatePoolList = computed(() => {
|
||||||
if (selectedClinicRoom.value === 'all') {
|
if (selectedRoom.value === 'all') {
|
||||||
return originalCandidatePoolList.value
|
return originalCandidatePoolList.value
|
||||||
}
|
}
|
||||||
return originalCandidatePoolList.value.filter(item => item.room === selectedClinicRoom.value)
|
return originalCandidatePoolList.value.filter(item => item.room === selectedRoom.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 原始队列数据存储(用于过滤)
|
// 原始队列数据存储(用于过滤)
|
||||||
const originalQueueList = ref(getInitialQueueList())
|
const originalQueueList = ref(getInitialQueueList())
|
||||||
|
|
||||||
|
// 动态计算已加载数据中的唯一诊室列表(依赖上方两个 ref,确保声明顺序正确)
|
||||||
|
const uniqueRooms = computed(() => {
|
||||||
|
const rooms = new Set()
|
||||||
|
originalCandidatePoolList.value.forEach(item => {
|
||||||
|
if (item.room && item.room !== '-') rooms.add(item.room)
|
||||||
|
})
|
||||||
|
originalQueueList.value.forEach(item => {
|
||||||
|
if (item.room && item.room !== '-') rooms.add(item.room)
|
||||||
|
})
|
||||||
|
return Array.from(rooms).sort()
|
||||||
|
})
|
||||||
|
|
||||||
const parseMmSsToSeconds = (mmss) => {
|
const parseMmSsToSeconds = (mmss) => {
|
||||||
if (!mmss || typeof mmss !== 'string') return 0
|
if (!mmss || typeof mmss !== 'string') return 0
|
||||||
const [mm, ss] = mmss.split(':')
|
const [mm, ss] = mmss.split(':')
|
||||||
@@ -1203,7 +1192,7 @@ const formatSecondsToMmSs = (totalSeconds) => {
|
|||||||
return `${mm}:${ss}`
|
return `${mm}:${ss}`
|
||||||
}
|
}
|
||||||
|
|
||||||
// 过滤后的智能队列数据(同时考虑诊室过滤和状态过滤)
|
// 过滤后的智能队列数据(Bug #411:诊室过滤 + 状态过滤)
|
||||||
const filteredQueueList = computed(() => {
|
const filteredQueueList = computed(() => {
|
||||||
let filtered = originalQueueList.value
|
let filtered = originalQueueList.value
|
||||||
|
|
||||||
@@ -1211,8 +1200,8 @@ const filteredQueueList = computed(() => {
|
|||||||
filtered = filtered.filter(item => item.status !== '已完成')
|
filtered = filtered.filter(item => item.status !== '已完成')
|
||||||
|
|
||||||
// 再按诊室过滤
|
// 再按诊室过滤
|
||||||
if (selectedClinicRoom.value !== 'all') {
|
if (selectedRoom.value !== 'all') {
|
||||||
filtered = filtered.filter(item => item.room === selectedClinicRoom.value)
|
filtered = filtered.filter(item => item.room === selectedRoom.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 再按状态过滤(只显示等待)
|
// 再按状态过滤(只显示等待)
|
||||||
@@ -1723,16 +1712,12 @@ const handleNextPatient = async () => {
|
|||||||
reqData.id = selectedQueueRow.value.id
|
reqData.id = selectedQueueRow.value.id
|
||||||
reqData.organizationId = selectedQueueRow.value.organizationId
|
reqData.organizationId = selectedQueueRow.value.organizationId
|
||||||
} else {
|
} else {
|
||||||
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
|
// Bug #411:已移除 selectedDept,改为从队列数据中动态获取科室
|
||||||
// 全科模式:优先用"当前叫号中/第一个等待"所在科室
|
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
|
||||||
let orgId = null
|
const waiting = originalQueueList.value.find((i) => i.status === '等待')
|
||||||
{
|
console.log('【心内科】handleNextPatient 查找:叫号中=', calling?.patientName, '等待=', waiting?.patientName)
|
||||||
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
|
const orgId = calling?.organizationId ?? waiting?.organizationId
|
||||||
const waiting = originalQueueList.value.find((i) => i.status === '等待')
|
console.log('【心内科】handleNextPatient 确定的 orgId=', orgId)
|
||||||
console.log('【心内科】handleNextPatient 查找:叫号中=', calling?.patientName, '等待=', waiting?.patientName)
|
|
||||||
orgId = calling?.organizationId ?? waiting?.organizationId
|
|
||||||
console.log('【心内科】handleNextPatient 确定的 orgId=', orgId)
|
|
||||||
}
|
|
||||||
if (orgId != null) {
|
if (orgId != null) {
|
||||||
reqData.organizationId = orgId
|
reqData.organizationId = orgId
|
||||||
}
|
}
|
||||||
@@ -1761,13 +1746,9 @@ const handleSkip = async () => {
|
|||||||
reqData.id = selectedQueueRow.value.id
|
reqData.id = selectedQueueRow.value.id
|
||||||
reqData.organizationId = selectedQueueRow.value.organizationId
|
reqData.organizationId = selectedQueueRow.value.organizationId
|
||||||
} else {
|
} else {
|
||||||
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
|
// 如果没有选中患者,使用当前叫号中的科室
|
||||||
// 全科模式:优先用”当前叫号中”所在科室
|
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
|
||||||
let orgId = null
|
const orgId = calling?.organizationId
|
||||||
{
|
|
||||||
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
|
|
||||||
orgId = calling?.organizationId
|
|
||||||
}
|
|
||||||
if (orgId != null) {
|
if (orgId != null) {
|
||||||
reqData.organizationId = orgId
|
reqData.organizationId = orgId
|
||||||
}
|
}
|
||||||
@@ -1795,13 +1776,9 @@ const handleComplete = async () => {
|
|||||||
reqData.id = selectedQueueRow.value.id
|
reqData.id = selectedQueueRow.value.id
|
||||||
reqData.organizationId = selectedQueueRow.value.organizationId
|
reqData.organizationId = selectedQueueRow.value.organizationId
|
||||||
} else {
|
} else {
|
||||||
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
|
// 如果没有选中患者,使用当前叫号中的科室
|
||||||
// 全科模式:优先用”当前叫号中”所在科室
|
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
|
||||||
let orgId = null
|
const orgId = calling?.organizationId
|
||||||
{
|
|
||||||
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
|
|
||||||
orgId = calling?.organizationId
|
|
||||||
}
|
|
||||||
if (orgId != null) {
|
if (orgId != null) {
|
||||||
reqData.organizationId = orgId
|
reqData.organizationId = orgId
|
||||||
}
|
}
|
||||||
@@ -1829,13 +1806,9 @@ const handleRequeue = async () => {
|
|||||||
reqData.id = selectedQueueRow.value.id
|
reqData.id = selectedQueueRow.value.id
|
||||||
reqData.organizationId = selectedQueueRow.value.organizationId
|
reqData.organizationId = selectedQueueRow.value.organizationId
|
||||||
} else {
|
} else {
|
||||||
// 如果没有选中患者,使用查询条件(兼容旧逻辑)
|
// 如果没有选中患者,使用当前叫号中的科室
|
||||||
// 全科模式:优先用”当前叫号中”所在科室
|
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
|
||||||
let orgId = null
|
const orgId = calling?.organizationId
|
||||||
{
|
|
||||||
const calling = originalQueueList.value.find((i) => i.status === '叫号中')
|
|
||||||
orgId = calling?.organizationId
|
|
||||||
}
|
|
||||||
if (orgId != null) {
|
if (orgId != null) {
|
||||||
reqData.organizationId = orgId
|
reqData.organizationId = orgId
|
||||||
}
|
}
|
||||||
@@ -2219,10 +2192,6 @@ onUnmounted(() => {
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.queue-actions-right {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.candidate-actions {
|
.candidate-actions {
|
||||||
@@ -2244,16 +2213,32 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.filter-section {
|
.filter-section {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
.filter-label {
|
.filter-left {
|
||||||
font-size: 14px;
|
flex: 1;
|
||||||
font-weight: bold;
|
|
||||||
color: #333;
|
.filter-label {
|
||||||
margin-bottom: 10px;
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-button-wrapper {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-select-wrapper {
|
.filter-right {
|
||||||
width: 100%;
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
align-self: flex-end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user