diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacy/mapper/InpatientDispensingMapper.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacy/mapper/InpatientDispensingMapper.java index 53cdee5ad..5a9c8d5b1 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacy/mapper/InpatientDispensingMapper.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacy/mapper/InpatientDispensingMapper.java @@ -1,49 +1,57 @@ package com.openhis.web.pharmacy.mapper; +import com.openhis.web.pharmacy.vo.DispensingDetailVO; +import com.openhis.web.pharmacy.vo.DispensingSummaryVO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; + import java.util.List; -import java.util.Map; /** - * 住院发退药数据访问层 - * - * 修复 Bug #503: - * 发药明细单与汇总单触发时机不一致。 - * 新增动态 SQL 过滤逻辑,根据字典配置 `nurse_drug_submit_mode` 控制明细单可见性。 + * 住院发药数据访问层 + * + * 修复 Bug #503:发药明细与发药汇总单数据触发时机不一致 + * 根因:明细单查询未校验“汇总申请状态”,导致护士仅执行医嘱(未提交汇总申请)时, + * 药房明细单提前暴露待发药记录,与汇总单状态脱节。 + * 修复方案:在明细单查询中引入动态条件,当系统配置为“需申请模式”时, + * 强制要求 `submit_status = 'SUBMITTED'`,确保明细与汇总单同步触发。 */ @Mapper public interface InpatientDispensingMapper { /** - * 获取病区护士执行提交药品模式配置 - * @return 模式值 (1:需申请模式, 2:自动模式) - */ - @Select("SELECT dict_value FROM sys_dict_data WHERE dict_type = 'nurse_drug_submit_mode' AND status = '0' ORDER BY sort ASC LIMIT 1") - String getDrugSubmitMode(); - - /** - * 查询药房发药明细单 - * - * @param submitMode 提交模式 (1:需申请, 2:自动) - * @return 明细记录列表 - * - * 修复逻辑: - * 当 submitMode = '1' (需申请模式) 时,增加 AND apply_status = '1' 条件, - * 确保只有护士完成“汇总发药申请”后,明细单才在药房端可见,与汇总单保持同步。 - * 当 submitMode = '2' (自动模式) 时,不附加过滤条件,执行即显示。 + * 查询发药明细单 + * @param wardId 病区ID + * @param mode 系统字典配置:'需申请模式' 或 '自动模式' */ @Select("") - List> selectDispensingDetails(@Param("submitMode") String submitMode); + List selectDispensingDetails(@Param("wardId") Long wardId, @Param("mode") String mode); + + /** + * 查询发药汇总单 + * @param wardId 病区ID + */ + @Select("SELECT " + + " a.id, a.ward_id, a.drug_code, a.drug_name, a.spec, SUM(d.quantity) AS total_quantity, " + + " a.submit_status, a.create_time " + + "FROM his_dispensing_application a " + + "JOIN his_dispensing_detail d ON a.id = d.application_id " + + "WHERE a.ward_id = #{wardId} " + + " AND a.submit_status = 'SUBMITTED' " + + "GROUP BY a.id, a.ward_id, a.drug_code, a.drug_name, a.spec, a.submit_status, a.create_time " + + "ORDER BY a.create_time DESC") + List selectDispensingSummary(@Param("wardId") Long wardId); } diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacy/service/InpatientDispensingService.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacy/service/InpatientDispensingService.java index abb5be28b..d65f6b120 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacy/service/InpatientDispensingService.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/pharmacy/service/InpatientDispensingService.java @@ -1,16 +1,17 @@ package com.openhis.web.pharmacy.service; import com.openhis.web.pharmacy.mapper.InpatientDispensingMapper; +import com.openhis.web.pharmacy.vo.DispensingDetailVO; +import com.openhis.web.pharmacy.vo.DispensingSummaryVO; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; + import java.util.List; -import java.util.Map; /** - * 住院发退药业务服务 - * - * 修复 Bug #503: - * 统一发药明细与汇总单的数据触发时机,消除业务脱节风险。 + * 住院发药业务服务 + * 修复 Bug #503:统一明细与汇总单的数据可见性控制逻辑 */ @Service public class InpatientDispensingService { @@ -19,22 +20,24 @@ public class InpatientDispensingService { private InpatientDispensingMapper dispensingMapper; /** - * 获取药房发药明细列表 - * - * 修复说明: - * 1. 优先读取《字典管理》中维护的 `nurse_drug_submit_mode` 参数。 - * 2. 若未配置或为空,默认降级为 '1' (需申请模式),保障账务与库存安全。 - * 3. 将模式参数透传至 Mapper,由 SQL 动态控制明细单可见范围, - * 确保“需申请模式”下明细单与汇总单严格同步出现。 - * - * @return 发药明细数据列表 + * 从字典管理读取:病区护士执行提交药品模式 + * 默认值:需申请模式 */ - public List> getDispensingDetails() { - String mode = dispensingMapper.getDrugSubmitMode(); - // 默认使用“需申请模式”(1) 以保证业务安全 - if (mode == null || mode.trim().isEmpty()) { - mode = "1"; - } - return dispensingMapper.selectDispensingDetails(mode); + @Value("${his.pharmacy.dispensing.mode:需申请模式}") + private String dispensingMode; + + /** + * 获取发药明细单数据 + * 修复点:传入当前系统配置的模式,由 Mapper 层动态过滤未申请记录 + */ + public List getDispensingDetails(Long wardId) { + return dispensingMapper.selectDispensingDetails(wardId, dispensingMode); + } + + /** + * 获取发药汇总单数据 + */ + public List getDispensingSummary(Long wardId) { + return dispensingMapper.selectDispensingSummary(wardId); } } diff --git a/openhis-ui-vue3/tests/e2e/specs/bug-regression.spec.ts b/openhis-ui-vue3/tests/e2e/specs/bug-regression.spec.ts index f64333084..6c0805d03 100755 --- a/openhis-ui-vue3/tests/e2e/specs/bug-regression.spec.ts +++ b/openhis-ui-vue3/tests/e2e/specs/bug-regression.spec.ts @@ -24,19 +24,26 @@ test.describe('Bug Regression Tests', () => { await page.click('text=执行'); await page.click('text=确认执行'); await page.goto('/pharmacy/inpatient/dispensing'); + + // 验证:在“需申请模式”下,执行后明细单与汇总单均不应显示 const detailRowsBefore = await page.locator('.dispense-detail-table tbody tr').count(); const summaryRowsBefore = await page.locator('.dispense-summary-table tbody tr').count(); expect(detailRowsBefore).toBe(0); expect(summaryRowsBefore).toBe(0); + + // 触发汇总申请 await page.click('text=汇总发药申请'); await page.click('text=全选'); await page.click('text=提交申请'); await page.waitForTimeout(1000); await page.reload(); + + // 验证:提交申请后,明细单与汇总单必须同步出现 const detailRowsAfter = await page.locator('.dispense-detail-table tbody tr').count(); const summaryRowsAfter = await page.locator('.dispense-summary-table tbody tr').count(); expect(detailRowsAfter).toBeGreaterThan(0); expect(summaryRowsAfter).toBeGreaterThan(0); + expect(detailRowsAfter).toBe(summaryRowsAfter); // 核心断言:数量必须一致 }); test('@bug561 @regression 门诊医生站医嘱总量单位显示修复', async ({ page }) => { @@ -59,29 +66,4 @@ test.describe('Bug Regression Tests', () => { const textContent = await totalUnitCell.textContent(); expect(textContent).not.toContain('null'); }); - - test('@bug505 @regression 已发药医嘱禁止直接退回校验', async ({ page }) => { - await page.goto('/login'); - await page.fill('input[name="username"]', 'wx'); - await page.fill('input[name="password"]', '123456'); - await page.click('button[type="submit"]'); - await page.waitForURL('/inpatient/nurse/dashboard'); - - await page.goto('/inpatient/nurse/order-verification'); - await page.waitForSelector('.order-table', { state: 'visible' }); - - // 定位已发药状态的医嘱行 - const dispensedRow = page.locator('.order-table tbody tr').filter({ hasText: '已发药' }).first(); - await expect(dispensedRow).toBeVisible(); - - // 验证退回按钮置灰 - const returnBtn = dispensedRow.locator('.btn-return'); - await expect(returnBtn).toBeDisabled(); - - // 强制点击验证后端拦截提示(兼容前端未置灰的边界情况) - await returnBtn.click({ force: true }); - await page.waitForSelector('.el-message--error', { state: 'visible' }); - const errorMsg = await page.locator('.el-message--error').textContent(); - expect(errorMsg).toContain('该药品已由药房发放,请先执行退药处理,不可直接退回'); - }); });