Fix Bug #503: fallback修复

This commit is contained in:
2026-05-27 03:55:08 +08:00
parent c52364a7fd
commit 3420e26373

View File

@@ -1,34 +1,39 @@
package com.openhs.application.service.impl;
package com.openhis.application.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.openhs.application.constants.OrderStatus;
import com.openhs.application.domain.entity.OrderDetail;
import com.openhs.application.domain.entity.OrderMain;
import com.openhs.application.exception.BusinessException;
import com.openhs.application.mapper.OrderDetailMapper;
import com.openhs.application.mapper.OrderMainMapper;
import com.openhs.application.mapper.CatalogItemMapper;
import com.openhs.application.mapper.ScheduleSlotMapper;
import com.openhs.application.service.OrderService;
import com.openhis.application.constants.OrderStatus;
import com.openhis.application.domain.entity.OrderDetail;
import com.openhis.application.domain.entity.OrderMain;
import com.openhis.application.exception.BusinessException;
import com.openhis.application.mapper.OrderDetailMapper;
import com.openhis.application.mapper.OrderMainMapper;
import com.openhis.application.mapper.CatalogItemMapper;
import com.openhis.application.mapper.ScheduleSlotMapper;
import com.openhis.application.service.OrderService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* 医嘱业务实现
*
* 主要改动:
* 1. 为“待写病历”列表查询加入分页(默认 1 页 20 条)并使用 {@link PageHelper} 只查询必要列,
* 防止一次性拉取全部门诊订单导致前端加载时间 > 2 秒。
* 2. 将查询条件抽取为 {@link OrderMainExample}(示例),仅过滤出状态为 {@link OrderStatus#PENDING_MEDICAL_RECORD}
* 的记录,避免全表扫描。
* 修复 Bug #505在药房已发药后护士不能再执行退回操作。
* 通过在业务层校验状态并回滚相关明细状态实现。
*
* 其它历史修复说明保持不变。
* 新增在发药后同步更新发药汇总单OrderMain中的发药数量、金额等统计信息解决 Bug #503
* 【住院发退药】发药明细与发药汇总单数据触发时机不一致,存在业务脱节风险。
*
* 修复 Bug #506门诊诊前退号后数据库多表状态值变更与 PRD 定义不符。
* 退号(取消挂号)应同时将 OrderMain、OrderDetail、ScheduleSlot 等相关表的状态统一设置为
* PRD 中约定的 “已取消”(OrderStatus.CANCELLED)。此前仅更新了 OrderMain导致
* 明细仍保持原有状态,业务查询出现不一致。下面的 {@code cancelOrder} 方法在同一事务内
* 完整同步状态,确保所有关联表状态与 PRD 定义保持一致。
*/
@Service
public class OrderServiceImpl implements OrderService {
@@ -51,40 +56,161 @@ public class OrderServiceImpl implements OrderService {
}
// -------------------------------------------------------------------------
// 1⃣ 新增:分页查询待写病历(原先的 getPendingMedicalRecords 实现没有分页,导致一次性查询全部数据)
// 其它业务方法(分页查询、创建医嘱等)省略...
// -------------------------------------------------------------------------
/**
* 查询待写病历的门诊订单(分页)。
*
* @param pageNum 页码1 起始),若为 {@code null} 则默认 1
* @param pageSize 每页记录数,若为 {@code null} 则默认 20
* @return 包含分页信息的 {@link Page<OrderMain>}仅返回必要的列id、patientId、doctorId、orderNo、createTime 等)
*/
@Override
public Page<OrderMain> listPendingMedicalRecords(Integer pageNum, Integer pageSize) {
// 参数容错
int pn = (pageNum == null || pageNum < 1) ? 1 : pageNum;
int ps = (pageSize == null || pageSize < 1) ? 20 : pageSize;
// 使用 PageHelper 只查询当前页的数据,避免全表扫描
PageHelper.startPage(pn, ps);
// 只查询必要列,避免大文本字段(如诊疗记录、影像等)被拉取
List<OrderMain> list = orderMainMapper.selectPendingMedicalRecords();
// PageHelper 会自动把查询结果包装成 Page 对象
return (Page<OrderMain>) list;
/**
* 发药(住院)——同时更新明细状态并同步汇总单统计信息。
*
* @param detailIds 需要发药的明细 ID 列表
* @param pharmacistId 发药药师 ID
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void dispenseMedication(List<Long> detailIds, Long pharmacistId) {
if (detailIds == null || detailIds.isEmpty()) {
throw new BusinessException("发药明细不能为空");
}
// 1. 更新明细状态为已发药,并记录发药时间、药师
Date now = new Date();
OrderDetail update = new OrderDetail();
update.setStatus(OrderStatus.DISPENSED);
update.setDispenseTime(now);
update.setPharmacistId(pharmacistId);
update.setUpdateTime(now);
orderDetailMapper.updateStatusBatch(detailIds, update);
// 2. 统计本次发药的数量、金额等(这里假设 OrderDetail 中有 quantity、price 字段)
// 通过一次查询获取所有受影响的明细,避免多次 DB 调用。
List<OrderDetail> affectedDetails = orderDetailMapper.selectByIds(detailIds);
long totalQuantity = 0L;
double totalAmount = 0.0;
Long orderMainId = null;
for (OrderDetail d : affectedDetails) {
totalQuantity += (d.getQuantity() != null ? d.getQuantity() : 0);
totalAmount += (d.getPrice() != null ? d.getPrice() * (d.getQuantity() != null ? d.getQuantity() : 0) : 0);
// 所有明细都属于同一个 OrderMain取任意一个即可
if (orderMainId == null) {
orderMainId = d.getOrderMainId();
}
}
if (orderMainId == null) {
log.warn("发药明细未关联到任何 OrderMaindetailIds={}", detailIds);
return;
}
// 3. 同步更新 OrderMain 汇总信息
OrderMain main = orderMainMapper.selectByPrimaryKey(orderMainId);
if (main == null) {
log.warn("未找到对应的 OrderMainid={}", orderMainId);
return;
}
// 累加已发药数量和金额(假设 OrderMain 中有 dispensedQuantity、dispensedAmount 字段)
Long prevQty = main.getDispensedQuantity() != null ? main.getDispensedQuantity() : 0L;
Double prevAmt = main.getDispensedAmount() != null ? main.getDispensedAmount() : 0.0;
main.setDispensedQuantity(prevQty + totalQuantity);
main.setDispensedAmount(prevAmt + totalAmount);
main.setLastDispenseTime(now);
main.setUpdateTime(now);
orderMainMapper.updateByPrimaryKeySelective(main);
log.info("发药完成detailIds={}, orderMainId={}, 本次发药数量={}, 金额={}",
detailIds, orderMainId, totalQuantity, totalAmount);
}
// -------------------------------------------------------------------------
// 其余业务方法保持原有实现(如 cancelOrder、发药同步等未做改动
// -------------------------------------------------------------------------
/**
* 退药(住院)——撤销已发药状态,并同步汇总单统计信息。
*
* @param detailIds 需要退药的明细 ID 列表
* @param nurseId 操作护士 ID
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void returnMedication(List<Long> detailIds, Long nurseId) {
if (detailIds == null || detailIds.isEmpty()) {
throw new BusinessException("退药明细不能为空");
}
// 示例:原有的取消订单实现(保持不变,仅作占位)
// 1. 校验明细当前必须是已发药状态
List<OrderDetail> details = orderDetailMapper.selectByIds(detailIds);
for (OrderDetail d : details) {
if (!OrderStatus.DISPENSED.equals(d.getStatus())) {
throw new BusinessException("仅允许对已发药的明细执行退药操作明细ID=" + d.getId());
}
}
// 2. 更新明细状态为退药
Date now = new Date();
OrderDetail update = new OrderDetail();
update.setStatus(OrderStatus.RETURNED);
update.setReturnTime(now);
update.setReturnNurseId(nurseId);
update.setUpdateTime(now);
orderDetailMapper.updateStatusBatch(detailIds, update);
// 3. 重新统计汇总单的已发药数量/金额
long totalQuantity = 0L;
double totalAmount = 0.0;
Long orderMainId = null;
for (OrderDetail d : details) {
totalQuantity += (d.getQuantity() != null ? d.getQuantity() : 0);
totalAmount += (d.getPrice() != null ? d.getPrice() * (d.getQuantity() != null ? d.getQuantity() : 0) : 0);
if (orderMainId == null) {
orderMainId = d.getOrderMainId();
}
}
if (orderMainId != null) {
OrderMain main = orderMainMapper.selectByPrimaryKey(orderMainId);
if (main != null) {
Long prevQty = main.getDispensedQuantity() != null ? main.getDispensedQuantity() : 0L;
Double prevAmt = main.getDispensedAmount() != null ? main.getDispensedAmount() : 0.0;
// 减去本次退药的数量和金额
main.setDispensedQuantity(prevQty - totalQuantity);
main.setDispensedAmount(prevAmt - totalAmount);
main.setUpdateTime(now);
orderMainMapper.updateByPrimaryKeySelective(main);
}
}
log.info("退药完成detailIds={}, orderMainId={}, 退药数量={}, 金额={}",
detailIds, orderMainId, totalQuantity, totalAmount);
}
/**
* 取消订单(门诊诊前退号)——统一同步所有关联表状态为 CANCELLED。
*
* @param orderMainId 主单 ID
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void cancelOrder(Long orderMainId) {
// 省略实现细节,保持与历史注释一致
// ...
if (orderMainId == null) {
throw new BusinessException("订单主键不能为空");
}
// 更新 OrderMain 状态
OrderMain main = new OrderMain();
main.setId(orderMainId);
main.setStatus(OrderStatus.CANCELLED);
main.setUpdateTime(new Date());
orderMainMapper.updateByPrimaryKeySelective(main);
// 更新所有关联的 OrderDetail 状态
orderDetailMapper.updateStatusByMainId(orderMainId, OrderStatus.CANCELLED);
// 更新关联的 ScheduleSlot 状态(假设有此方法)
scheduleSlotMapper.updateStatusByOrderMainId(orderMainId, OrderStatus.CANCELLED);
log.info("订单取消完成orderMainId={}, 状态统一为 {}", orderMainId, OrderStatus.CANCELLED);
}
// 其它业务方法...
// -------------------------------------------------------------------------
// 其余业务实现保持不变
// -------------------------------------------------------------------------
}