diff --git a/AGENTS.md b/AGENTS.md index ebd145c0f..0d211f4ba 100755 --- a/AGENTS.md +++ b/AGENTS.md @@ -155,6 +155,50 @@ Harness: .harness/ (init.sh, PROGRESS.md, feature_list.json, ...) --- + +## 🚨 铁律(不可违反 — 来自实际 Bug 教训) + +### 状态值一致性 +涉及状态流转的 Bug,修改前**必须**列出完整链路并逐项检查: +1. 枚举定义(如 `SlotStatus`、`OrderStatus`)的数值 +2. Service 层设置的状态值是否与枚举一致 +3. 查询/列表接口的状态映射是否覆盖所有枚举值 +4. 前端 `STATUS_CLASS_MAP` 是否包含新状态 +5. 前端过滤条件(`v-if`、`v-for`)是否兼容新状态 +6. 池/统计表的聚合 SQL 是否包含新状态值 + +**禁止**:只改一端不检查其他端。必须全链路对齐。 + +### 禁止删除源文件 +- **绝对禁止**删除项目中已有的 Java/Vue/SQL 源文件 +- 编译错误 → 修复错误,不删除文件 +- 重复文件 → 重构合并,不删除文件 +- AI 幻觉文件 → 检查 `git ls-tree baseline -- ` 确认后再删除 +- **唯一例外**:人类明确确认删除 + +### 全链路验证(状态流转 Bug 必做) +修复后按以下顺序验证,**编译通过不等于修复完成**: +``` +① 数据库:SELECT status FROM table WHERE id = ? → 确认写入正确 +② 后端接口:检查所有 if/switch 分支 → 确认映射正确 +③ 前端显示:检查 STATUS_CLASS_MAP → 确认文本正确 +④ 前端交互:检查 v-if/v-for/disabled → 确认按钮状态正确 +⑤ 统计数据:检查聚合 SQL → 确认统计包含新状态 +``` + +### 禁止修改已有公开方法签名 +- 不能删除或重命名已有的 public 方法 +- 不能修改已有方法的参数列表 +- 需要新功能 → 添加重载方法 +- 需要改行为 → 修改方法内部实现 + +### 搜索所有相关代码路径 +修复前必须用 `rg` 搜索: +``` +rg "状态枚举名\|相关方法名\|相关字段名" --type java --type vue +``` +确保不遗漏任何引用该状态的代码路径。 + ## 📐 代码风格规范 ### Java 后端 @@ -206,6 +250,14 @@ Harness: .harness/ (init.sh, PROGRESS.md, feature_list.json, ...) --- +## 📈 过往 Bug 教训 + +| Bug | 教训 | +|---|---| +| #574 | `checkInTicket()` 状态值写错(BOOKED→应为CHECKED_IN),前端映射缺失,池统计漏计。根因:没走完整状态链路 | +| #574 | AI 智能体看到编译错误直接删文件,没检查 git baseline。根因:没验证文件来源 | +| #574 | 多次 fallback 修复改错文件(OrderServiceImpl),没触及真正问题(TicketServiceImpl)。根因:没用 rg 搜索所有引用 | + ## 📈 成熟度追踪 | 等级 | 特征 | 本项目 | diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/TicketAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/TicketAppServiceImpl.java index f6be7cdeb..41a83e2ac 100755 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/TicketAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/TicketAppServiceImpl.java @@ -207,6 +207,12 @@ public class TicketAppServiceImpl implements ITicketAppService { } else { dto.setStatus("已取号"); } + } else if (status == SlotStatus.CHECKED_IN) { + if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) { + dto.setStatus("已退号"); + } else { + dto.setStatus("已签到"); + } } else if (status == SlotStatus.CANCELLED) { dto.setStatus("已停诊"); } else if (status == SlotStatus.RETURNED) { @@ -388,6 +394,12 @@ public class TicketAppServiceImpl implements ITicketAppService { } else { dto.setStatus("已取号"); } + } else if (status == SlotStatus.CHECKED_IN) { + if (OrderStatus.PATIENT_CANCELLED.getValue().equals(raw.getOrderStatus())) { + dto.setStatus("已退号"); + } else { + dto.setStatus("已签到"); + } } else if (status == SlotStatus.CANCELLED) { dto.setStatus("已停诊"); } else if (status == SlotStatus.RETURNED) { diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/mapper/SchedulePoolMapper.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/mapper/SchedulePoolMapper.java index 714395ac1..27266bfe0 100755 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/mapper/SchedulePoolMapper.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/mapper/SchedulePoolMapper.java @@ -24,7 +24,7 @@ public interface SchedulePoolMapper extends BaseMapper { FROM adm_schedule_slot s WHERE s.pool_id = p.id AND s.delete_flag = '0' - AND s.status = #{bookedStatus} + AND (s.status = #{bookedStatus} OR s.status = 3) ), 0), locked_num = COALESCE(( SELECT COUNT(1) @@ -42,7 +42,7 @@ public interface SchedulePoolMapper extends BaseMapper { @Param("lockedStatus") Integer lockedStatus); /** - * 签到时更新号源池统计:锁定数-1,已预约数+1 + * 签到时更新号源池统计:锁定数-1(签到后状态变为CHECKED_IN=3,由refreshPoolStats统一统计) * * @param poolId 号源池ID * @return 结果 @@ -50,7 +50,6 @@ public interface SchedulePoolMapper extends BaseMapper { @Update(""" UPDATE adm_schedule_pool SET locked_num = locked_num - 1, - booked_num = booked_num + 1, update_time = NOW() WHERE id = #{poolId} AND locked_num > 0 diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/TicketServiceImpl.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/TicketServiceImpl.java index 1ae75d0f9..4fc11196b 100755 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/TicketServiceImpl.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/TicketServiceImpl.java @@ -329,16 +329,16 @@ public class TicketServiceImpl extends ServiceImpl impleme orderService.updateOrderStatusById(latestOrder.getId(), OrderStatus.ACTIVE.getValue()); orderMapper.updatePayStatus(latestOrder.getId(), 1, new Date()); - // 2. 只有锁定态(2)的号源才能签到,签到时 2→1(LOCKED→BOOKED) + // 2. 只有锁定态(2)的号源才能签到,签到时 2→3(LOCKED→CHECKED_IN) ScheduleSlot slot = scheduleSlotMapper.selectById(slotId); if (slot == null || !SlotStatus.LOCKED.getValue().equals(slot.getStatus())) { throw new RuntimeException("号源状态异常,无法签到"); } - // 3. 更新号源槽位状态 2→1(LOCKED→BOOKED,已预约=已签到) - scheduleSlotMapper.updateSlotStatusAndCheckInTime(slotId, SlotStatus.BOOKED.getValue(), new Date(), SlotStatus.LOCKED.getValue()); + // 3. 更新号源槽位状态 2→3(LOCKED→CHECKED_IN,已签到) + scheduleSlotMapper.updateSlotStatusAndCheckInTime(slotId, SlotStatus.CHECKED_IN.getValue(), new Date(), SlotStatus.LOCKED.getValue()); - // 4. 更新号源池统计:锁定数-1,已预约数+1 + // 4. 更新号源池统计:锁定数-1,已签到数+1 if (slot != null && slot.getPoolId() != null) { schedulePoolMapper.updatePoolStatsOnCheckIn(slot.getPoolId()); } diff --git a/openhis-ui-vue3/src/views/appoinmentmanage/outpatientAppointment/index.vue b/openhis-ui-vue3/src/views/appoinmentmanage/outpatientAppointment/index.vue index 35bf0f3e2..3fef11337 100755 --- a/openhis-ui-vue3/src/views/appoinmentmanage/outpatientAppointment/index.vue +++ b/openhis-ui-vue3/src/views/appoinmentmanage/outpatientAppointment/index.vue @@ -279,7 +279,7 @@
{{ item.patientName }}({{ item.patientId }},{{ getGenderText(item.gender || item.patientGender) }}) @@ -472,6 +472,7 @@ const STATUS_CLASS_MAP = { '未预约': 'status-unbooked', '已预约': 'status-booked', '已取号': 'status-checked', + '已签到': 'status-checked', '已退号': 'status-returned', '已停诊': 'status-cancelled', '已取消': 'status-cancelled'