Fix Bug #503: AI修复

This commit is contained in:
2026-05-27 05:15:55 +08:00
parent 5558e90539
commit 97d94760f0
2 changed files with 150 additions and 0 deletions

View File

@@ -0,0 +1,120 @@
package com.openhis.application.service.impl;
import com.openhis.application.domain.entity.DispensingDetail;
import com.openhis.application.domain.entity.DispensingSummary;
import com.openhis.application.domain.entity.OrderDetail;
import com.openhis.application.mapper.DispensingDetailMapper;
import com.openhis.application.mapper.DispensingSummaryMapper;
import com.openhis.application.mapper.OrderDetailMapper;
import com.openhis.application.service.DispensingService;
import com.openhis.application.service.SysConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
/**
* 住院发退药业务实现
*
* 修复 Bug #503发药明细与发药汇总单数据触发时机不一致
* 核心逻辑:严格遵循《字典管理》中“病区护士执行提交药品模式”配置,
* 统一控制明细单与汇总单的生成时机,消除业务脱节风险。
*/
@Service
public class DispensingServiceImpl implements DispensingService {
private static final Logger log = LoggerFactory.getLogger(DispensingServiceImpl.class);
private final DispensingDetailMapper dispensingDetailMapper;
private final DispensingSummaryMapper dispensingSummaryMapper;
private final OrderDetailMapper orderDetailMapper;
private final SysConfigService sysConfigService;
// 字典配置键:病区护士执行提交药品模式 (1:需申请模式, 2:自动模式)
private static final String CONFIG_KEY_NURSE_SUBMIT_MODE = "NURSE_EXEC_SUBMIT_MODE";
public DispensingServiceImpl(DispensingDetailMapper dispensingDetailMapper,
DispensingSummaryMapper dispensingSummaryMapper,
OrderDetailMapper orderDetailMapper,
SysConfigService sysConfigService) {
this.dispensingDetailMapper = dispensingDetailMapper;
this.dispensingSummaryMapper = dispensingSummaryMapper;
this.orderDetailMapper = orderDetailMapper;
this.sysConfigService = sysConfigService;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void executeOrder(Long orderId) {
String mode = sysConfigService.getConfigValue(CONFIG_KEY_NURSE_SUBMIT_MODE, "1");
OrderDetail order = orderDetailMapper.selectById(orderId);
if (order == null) {
throw new IllegalArgumentException("医嘱不存在: " + orderId);
}
// 更新医嘱执行状态
order.setExecStatus(1); // 已执行
order.setExecTime(new Date());
orderDetailMapper.updateById(order);
// 核心修复:根据配置模式决定是否立即生成药房发药数据
if ("2".equals(mode)) {
// 自动模式:执行即申请,明细与汇总同步生成
createDispensingRecords(order);
log.info("自动模式:医嘱 {} 执行后已同步生成发药明细与汇总单", orderId);
} else {
// 需申请模式:仅更新医嘱状态,不生成药房单据,等待汇总申请
log.info("需申请模式:医嘱 {} 已执行,等待护士站汇总发药申请", orderId);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void applySummaryDispensing(List<Long> orderIds) {
String mode = sysConfigService.getConfigValue(CONFIG_KEY_NURSE_SUBMIT_MODE, "1");
// 核心修复:需申请模式下,汇总申请时才触发明细与汇总单生成
if ("1".equals(mode)) {
for (Long orderId : orderIds) {
OrderDetail order = orderDetailMapper.selectById(orderId);
if (order != null && order.getExecStatus() == 1 && order.getDispensingStatus() == 0) {
createDispensingRecords(order);
order.setDispensingStatus(1); // 已申请发药
orderDetailMapper.updateById(order);
}
}
log.info("需申请模式:批量汇总申请已触发,共生成 {} 条发药记录", orderIds.size());
} else {
log.warn("当前为自动模式,无需执行汇总发药申请操作");
}
}
/**
* 同步生成发药明细单与发药汇总单
*/
private void createDispensingRecords(OrderDetail order) {
// 1. 生成发药明细单
DispensingDetail detail = new DispensingDetail();
detail.setOrderId(order.getId());
detail.setPatientId(order.getPatientId());
detail.setDrugId(order.getCatalogItemId());
detail.setQuantity(order.getQuantity());
detail.setStatus(0); // 待发药
detail.setCreateTime(new Date());
dispensingDetailMapper.insert(detail);
// 2. 生成发药汇总单(按病区/药房/日期聚合,此处建立强关联)
DispensingSummary summary = new DispensingSummary();
summary.setOrderId(order.getId());
summary.setDetailId(detail.getId());
summary.setWardId(order.getWardId());
summary.setPharmacyId(order.getPharmacyId());
summary.setTotalQuantity(order.getQuantity());
summary.setStatus(0); // 待配药
summary.setCreateTime(new Date());
dispensingSummaryMapper.insert(summary);
}
}

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import { mount } from '@vue/test-utils'
// 注:实际项目可能使用 Cypress/Playwright此处以标准 E2E 断言结构演示,可根据实际测试框架替换底层 API
import ExamApply from '@/views/outpatient/exam/ExamApply.vue'
describe('门诊检查申请单交互回归测试', () => {
@@ -59,3 +60,32 @@ describe('Bug #506 Regression', { tags: ['@bug506', '@regression'] }, () => {
expect(orderMain.data.cancel_reason).toBe('诊前退号') // 原因字段修正
})
})
describe('Bug #503 Regression', { tags: ['@bug503', '@regression'] }, () => {
it('发药明细与发药汇总单数据触发时机应保持一致', async () => {
// 模拟系统参数:需申请模式 (mode=1)
const configMode = 1;
const orderId = 'ORD_503_001';
// 1. 护士执行医嘱
const execRes = await mockApi.post('/api/inpatient/order/execute', { orderId });
expect(execRes.status).toBe(200);
// 2. 验证需申请模式下,执行后药房明细单和汇总单均不应显示(状态同步拦截)
const detailRes = await mockApi.get('/api/pharmacy/dispensing/detail', { orderId });
const summaryRes = await mockApi.get('/api/pharmacy/dispensing/summary', { orderId });
expect(detailRes.data.length).toBe(0);
expect(summaryRes.data.length).toBe(0);
// 3. 护士执行汇总发药申请
const applyRes = await mockApi.post('/api/inpatient/dispensing/apply-summary', { orderIds: [orderId] });
expect(applyRes.status).toBe(200);
// 4. 验证申请后,明细单与汇总单同步出现且状态一致
const detailAfter = await mockApi.get('/api/pharmacy/dispensing/detail', { orderId });
const summaryAfter = await mockApi.get('/api/pharmacy/dispensing/summary', { orderId });
expect(detailAfter.data.length).toBeGreaterThan(0);
expect(summaryAfter.data.length).toBeGreaterThan(0);
expect(detailAfter.data[0].status).toBe(summaryAfter.data[0].status); // 状态同步
});
});