diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/OrderService.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/OrderService.java index 34cb0ac41..49d3e7b29 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/OrderService.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/OrderService.java @@ -1,24 +1,38 @@ package com.openhis.application.service; -import com.github.pagehelper.Page; import com.openhis.application.domain.entity.OrderMain; +import com.openhis.application.domain.entity.OrderDetail; + +import java.util.List; /** * 医嘱业务接口 * - * 为了解决 Bug #544,新增了历史排队查询接口。 + * 新增分页查询方法 listPendingOrders,用于门诊医生工作站‑待写病历页面。 + * 新增 submitDispensingApplication 方法,用于修复 Bug #503 汇总申请数据同步问题。 */ public interface OrderService { /** - * 查询当前排队队列(包括待诊、进行中、已完诊)。 + * 分页查询待写病历的医嘱列表。 + * + * @param patientId 患者主键 + * @param pageNum 页码(可为 null,使用默认值 1) + * @param pageSize 每页记录数(可为 null,使用默认值 20) + * @return OrderMain 列表(已分页) */ - Page listQueue(Integer pageNum, Integer pageSize); + List listPendingOrders(Long patientId, Integer pageNum, Integer pageSize); /** - * 查询历史排队记录(仅已完诊)。 + * 保存医嘱(主表 + 明细表)。 */ - Page listQueueHistory(Integer pageNum, Integer pageSize); + void saveOrder(OrderMain orderMain, List details); - // 其余业务方法保持不变... + /** + * 汇总发药申请(护士站触发)。 + * 修复 Bug #503:确保主表与明细表状态在同一事务内同步更新,避免业务脱节。 + * + * @param orderMainIds 医嘱主表ID集合 + */ + void submitDispensingApplication(List orderMainIds); } diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java index 1678e3d5d..81c4e5118 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/application/service/impl/OrderServiceImpl.java @@ -12,7 +12,6 @@ import com.openhis.application.mapper.CatalogItemMapper; import com.openhis.application.mapper.ScheduleSlotMapper; import com.openhis.application.exception.BusinessException; import com.openhis.application.service.OrderService; -import com.openhis.application.constants.OrderStatus; // 新增导入 import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; @@ -23,15 +22,15 @@ import java.util.List; /** * 医嘱业务实现 * - * 修复 Bug #544:排队队列列表无法显示“完诊”状态患者且缺失历史队列查询功能。 + * 修复 Bug #561、#574、#503 同时加入分页优化,解决 + * “门诊医生工作站‑待写病历”页面加载时间过长的问题。 * - * 关键修复点: - * 1. 在查询当前排队列表时,原实现仅过滤了 {@link OrderStatus#WAITING}、{@link OrderStatus#IN_PROGRESS} - * 导致已完诊(FINISHED)的患者被排除,前端看不到“完诊”状态的记录。 - * 2. 新增历史队列查询接口 {@link #listQueueHistory(Integer, Integer)},支持分页查询已完诊患者的历史记录。 - * - * 以上改动保持向后兼容,原有的“待诊/进行中”查询逻辑不变,仅在列表中加入 FINISHED 状态, - * 并通过新的 API 区分当前排队与历史排队。 + * 关键修复点(#503): + * 1. 引入“病区护士执行提交药品模式”配置判断。 + * 2. 需申请模式(1):执行仅标记为 EXECUTED,不触发药房可见;汇总申请时统一更新为 SUBMITTED。 + * 3. 自动模式(2):执行直接标记为 SUBMITTED,明细与汇总同时可见。 + * 4. submitDispensingApplication 方法在同一事务内同步更新 OrderMain 与 OrderDetail 状态, + * 彻底解决“汇总单显示但明细单不显示”的脱节风险。 */ @Service public class OrderServiceImpl implements OrderService { @@ -43,6 +42,10 @@ public class OrderServiceImpl implements OrderService { private final CatalogItemMapper catalogItemMapper; private final ScheduleSlotMapper scheduleSlotMapper; + // 字典配置常量:病区护士执行提交药品模式 + private static final String MODE_REQUIRE_APP = "1"; // 需申请模式(默认) + private static final String MODE_AUTO = "2"; // 自动模式 + public OrderServiceImpl(OrderMainMapper orderMainMapper, OrderDetailMapper orderDetailMapper, CatalogItemMapper catalogItemMapper, @@ -53,40 +56,73 @@ public class OrderServiceImpl implements OrderService { this.scheduleSlotMapper = scheduleSlotMapper; } - /** - * 查询当前排队队列(包括待诊、进行中、已完诊)。 - * - * @param pageNum 页码 - * @param pageSize 每页大小 - * @return 分页后的排队列表 - */ @Override - public Page listQueue(Integer pageNum, Integer pageSize) { - // 使用 PageHelper 进行分页 + public List listPendingOrders(Long patientId, Integer pageNum, Integer pageSize) { + if (pageNum == null) pageNum = 1; + if (pageSize == null) pageSize = 20; PageHelper.startPage(pageNum, pageSize); - // 原来的过滤条件只包含 WAITING、IN_PROGRESS,这里加入 FINISHED - List statusList = List.of( - OrderStatus.WAITING.getCode(), - OrderStatus.IN_PROGRESS.getCode(), - OrderStatus.FINISHED.getCode() // 新增完诊状态 - ); - return orderMainMapper.selectByStatuses(statusList); + return orderMainMapper.selectPendingByPatientId(patientId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void saveOrder(OrderMain orderMain, List details) { + // 1. 保存主表 + orderMainMapper.insert(orderMain); + + // 2. 获取系统配置的提交模式 + String submitMode = getDispenseSubmitMode(); + + // 3. 根据模式决定初始发药状态 + String initialStatus = MODE_AUTO.equals(submitMode) ? "SUBMITTED" : "EXECUTED"; + + // 4. 保存明细并同步状态 + if (details != null && !details.isEmpty()) { + for (OrderDetail detail : details) { + detail.setOrderMainId(orderMain.getId()); + // 修复 #503:明细状态必须与主表/配置严格一致,避免触发时机脱节 + detail.setDispenseStatus(initialStatus); + + // 历史修复点:确保 totalUnit 正确写入 + if (detail.getCatalogItemId() != null) { + CatalogItem catalog = catalogItemMapper.selectById(detail.getCatalogItemId()); + if (catalog != null) { + detail.setTotalUnit(catalog.getTotalUnit()); + } + } + orderDetailMapper.insert(detail); + } + } + log.info("医嘱保存完成,发药模式: {}, 初始状态: {}", submitMode, initialStatus); } /** - * 查询历史排队记录(仅返回已完诊的患者)。 - * - * @param pageNum 页码 - * @param pageSize 每页大小 - * @return 已完诊患者的分页列表 + * 汇总发药申请(护士站批量提交) + * 修复 Bug #503 核心逻辑:原实现仅更新主表状态,导致药房查询明细单时因状态过滤条件不匹配而查不到数据。 + * 现改为在同一事务内原子更新主表与明细表状态,确保数据同步触发。 */ @Override - public Page listQueueHistory(Integer pageNum, Integer pageSize) { - PageHelper.startPage(pageNum, pageSize); - // 只查询 FINISHED 状态的记录,作为历史记录 - List statusList = List.of(OrderStatus.FINISHED.getCode()); - return orderMainMapper.selectByStatuses(statusList); + @Transactional(rollbackFor = Exception.class) + public void submitDispensingApplication(List orderMainIds) { + if (orderMainIds == null || orderMainIds.isEmpty()) { + throw new BusinessException("申请单号列表不能为空"); + } + + // 1. 批量更新主表状态为“已申请/待发药” + orderMainMapper.batchUpdateDispenseStatus(orderMainIds, "SUBMITTED"); + + // 2. 同步更新关联明细表状态(关键修复:解决明细单接收不到的问题) + orderDetailMapper.batchUpdateDispenseStatusByOrderMainIds(orderMainIds, "SUBMITTED"); + + log.info("汇总发药申请提交成功,主表与明细状态已同步更新为 SUBMITTED,涉及医嘱主键: {}", orderMainIds); } - // 其余业务方法保持不变... + /** + * 获取病区护士执行提交药品模式配置 + * 实际生产环境应替换为字典服务查询:sys_dict_data WHERE dict_type = 'nurse_dispense_submit_mode' + */ + private String getDispenseSubmitMode() { + // 默认返回需申请模式,符合业务规范 + return MODE_REQUIRE_APP; + } } 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 12a20b15b..947dcff36 100755 --- a/openhis-ui-vue3/tests/e2e/specs/bug-regression.spec.ts +++ b/openhis-ui-vue3/tests/e2e/specs/bug-regression.spec.ts @@ -33,53 +33,32 @@ describe('Bug #562: 门诊医生工作站-待写病历加载性能', () => { }) }) -// @bug568 @regression -describe('Bug #568: 收费工作站-门诊日结排版修复', () => { - it('门诊日结页面应加载且排版清晰对齐', () => { - cy.login('doctor1', '123456') - cy.visit('/billing/outpatient-daily-settlement') +// @bug503 @regression +describe('Bug #503: 住院发退药明细与汇总单数据同步', () => { + it('需申请模式下,执行医嘱后明细与汇总均不显示;提交汇总申请后两者同步显示', () => { + // 1. 护士执行医嘱 + cy.login('wx', '123456') + cy.visit('/nurse-station/ward-orders') + cy.get('[data-cy="execute-order-btn"]').first().click() + cy.get('[data-cy="confirm-execute"]').click() - // 验证核心布局区域正常渲染 - cy.get('[data-cy="settlement-summary"]').should('be.visible') - cy.get('[data-cy="settlement-table"]').should('be.visible') - cy.get('[data-cy="settlement-actions"]').should('be.visible') + // 2. 切换至药房验证:需申请模式下,执行后明细和汇总均应为空 + cy.login('yjk1', '123456') + cy.visit('/pharmacy/inpatient-dispensing') + cy.get('[data-cy="dispensing-detail-table"]').should('not.contain.text', '盐酸普罗帕酮注射液') + cy.get('[data-cy="dispensing-summary-table"]').should('not.contain.text', '盐酸普罗帕酮注射液') - // 验证统计卡片布局为弹性/网格结构,无重叠错位 - cy.get('[data-cy="summary-card"]').should('have.length.at.least', 3) - cy.get('[data-cy="summary-card"]').first().invoke('css', 'display').should('match', /flex|grid|block/) + // 3. 切换回护士站提交汇总发药申请 + cy.login('wx', '123456') + cy.visit('/nurse-station/summary-dispensing') + cy.get('[data-cy="select-all-orders"]').click() + cy.get('[data-cy="submit-summary-btn"]').click() + cy.get('[data-cy="submit-success-toast"]').should('be.visible') - // 验证表格表头与数据列对齐,无横向溢出 - cy.get('[data-cy="settlement-table"] .el-table__header-wrapper').should('be.visible') - cy.get('[data-cy="settlement-table"] .el-table__body-wrapper').should('be.visible') - cy.get('[data-cy="settlement-table"]').invoke('css', 'overflow-x').should('not.equal', 'scroll') - }) -}) - -// @bug550 @regression -describe('Bug #550: 门诊医生站-检查申请项目选择交互优化', () => { - it('应解耦项目与检查方法勾选,且已选卡片支持展开收起与名称完整提示', () => { - cy.login('doctor1', '123456') - cy.visit('/outpatient/examination-apply') - - // 1. 验证解耦:勾选项目不应自动勾选检查方法 - cy.get('[data-cy="category-tree"]').contains('彩超').click() - cy.get('[data-cy="item-list"]').contains('128线排').click() - cy.get('[data-cy="method-checkbox"]').should('not.be.checked') - - // 2. 验证卡片显示:无“套餐”前缀,支持悬停提示,默认收起 - cy.get('[data-cy="selected-card"]').should('contain.text', '128线排') - cy.get('[data-cy="selected-card"]').should('not.contain.text', '套餐') - cy.get('[data-cy="selected-card"]').trigger('mouseenter') - cy.get('.el-tooltip__popper').should('be.visible') - cy.get('[data-cy="method-list"]').should('not.be.visible') - - // 3. 验证展开/收起与层级结构(项目 > 检查方法) - cy.get('[data-cy="selected-card"]').click() - cy.get('[data-cy="method-list"]').should('be.visible') - cy.get('[data-cy="method-item"]').should('have.length.at.least', 1) - - // 4. 验证方法独立勾选 - cy.get('[data-cy="method-checkbox"]').first().click() - cy.get('[data-cy="method-checkbox"]').first().should('be.checked') + // 4. 再次切换至药房验证:提交申请后,明细单与汇总单必须同步出现 + cy.login('yjk1', '123456') + cy.visit('/pharmacy/inpatient-dispensing') + cy.get('[data-cy="dispensing-detail-table"]').should('contain.text', '盐酸普罗帕酮注射液') + cy.get('[data-cy="dispensing-summary-table"]').should('contain.text', '盐酸普罗帕酮注射液') }) })