diff --git a/.analysis/bug403_analysis.md b/.analysis/bug403_analysis.md deleted file mode 100644 index cb4e8dba9..000000000 --- a/.analysis/bug403_analysis.md +++ /dev/null @@ -1,66 +0,0 @@ -# Bug #403 分析报告 - -## 根因分析 - -**Bug现象**:住院医生工作站应用医嘱组套后,药品明细字段(单次剂量、总量、总金额、药房/科室)丢失。 - -**数据流追踪**: - -1. **后端 `getGroupPackageForOrder`** (OrdersGroupPackageAppServiceImpl.java:168) - - 查询组套明细 SQL(OrdersGroupPackageAppMapper.xml:37-82)返回:`dose`, `quantity`, `doseQuantity`, `rateCode`, `methodCode`, `dispensePerDuration` 等字段 - - 通过 `getAdviceBaseInfo` 获取 `AdviceBaseDto` 赋值给 `detail.setOrderDetailInfos()`,包含:`doseUnitCode`, `doseUnitCode_dictText`, `positionId`, `inventoryList`, `priceList`, `partPercent` 等 - -2. **前端 `orderGroupDrawer.vue`** `handleUseOrderGroup` (line 568-694) - - 对每个组套明细项进行预处理,合并组套字段和医嘱库字段 - - 通过 `emit('useOrderGroup', processedDetailList)` 发送到父组件 - -3. **前端 `inpatientDoctor/home/components/order/index.vue`** `handleSaveGroup` (line 1546-1639) - - 接收 `orderGroupList`,对每个 item 调用 `setValue(mergedDetail)` 填充行数据 - - 然后用 `item` 的字段显式覆盖创建 `newRow` - -**根因定位**:`handleSaveGroup` 在构建 `newRow` 时(line 1594-1617),从 `item` 直接取值覆盖了 `setValue` 设置的值。问题在于: - -1. **`item.unitCodeName` 可能为 undefined**:组套明细 SQL 中 `unitCodeName` 来自字典关联 `sys_dict_data`,如果字典匹配不上则为 null。`newRow` 的 `unitCode_dictText` 直接使用 `item.unitCodeName || ''`,导致显示为空。 - -2. **`positionName` 未在 `orderGroupDrawer` 处理项中显式设置**:虽然 `setValue` 会通过库存查询设置 `positionName`,但 `orderGroupDrawer.vue` 的 `handleUseOrderGroup` 没有将 `positionName`(或至少 `orderDetail.positionName`)包含在 processed item 中,导致 `setValue` 的库存查找依赖 `inventoryList`,而 `inventoryList` 来自后端 `AdviceBaseDto`。 - -3. **`doseUnitCode_dictText` 依赖 `setValue` 的 `unitCodeList`**:`orderGroupDrawer` 的处理项中没有显式包含 `doseUnitCode_dictText`,完全依赖 `mergedDetail` 中 spread 的 `orderDetail` 字段。 - -## 影响范围 - -- 前端文件:`healthlink-his-ui/src/views/doctorstation/components/prescription/orderGroupDrawer.vue` -- 前端文件:`healthlink-his-ui/src/views/inpatientDoctor/home/components/order/index.vue` -- 影响场景:住院医生工作站和门诊医生工作站应用医嘱组套 - -## 修复方案 - -**修改 `orderGroupDrawer.vue` 的 `handleUseOrderGroup` 函数**(line 630-688): - -在 processed item 的 return 对象中显式添加缺失的字段: -- `doseUnitCode_dictText`:从 orderDetail 获取剂量单位显示文本 -- `positionName`:从 orderDetail 获取执行科室/药房名称 -- `injectFlag` / `injectFlag_enumText`:注射标识 -- `skinTestFlag` / `skinTestFlag_enumText`:皮试标识 -- `partPercent`、`partAttributeEnum`、`unitConversionRatio`:用于价格计算的关键字段 - -这些字段在 `orderDetail`(AdviceBaseDto)中都有,只是没有在 processed item 的顶层显式设置。`handleSaveGroup` 的 `newRow` 通过 `...prescriptionList.value[rowIndex.value]` spread 能获取到 `setValue` 设置的值,但显式在顶层包含可以确保数据流的完整性。 - -## 验证计划 - -1. 修改代码后,用 `node --check` 验证语法 -2. 在住院医生工作站测试:选择患者 → 点击组套 → 预览组套 → 应用到当前患者 -3. 验证表格中显示的字段:单次剂量、总量、总金额、药房/科室均有值 - ---- - -## 修复结果:✅ 成功,10行改动 - -**修改文件**:`healthlink-his-ui/src/views/doctorstation/components/prescription/orderGroupDrawer.vue` - -**改动说明**:在 `handleUseOrderGroup` 函数的 processed item 中显式添加了以下缺失字段: -- `doseUnitCode_dictText`:剂量单位显示文本(如"mg"),用于"单次剂量"列的后缀显示 -- `positionName`:药房/科室名称,用于"药房/科室"列显示 -- `injectFlag` / `injectFlag_enumText`:注射药品标识及文本 -- `skinTestFlag` / `skinTestFlag_enumText`:皮试标识及文本 - -**策略**:策略A(直接修复代码逻辑)—— 组套应用时数据预处理缺失部分关键字段,导致父组件 `handleSaveGroup` 构建行数据时无法获取完整信息。补充字段后,`setValue` 和 `newRow` 构造均能正确传递这些数据到表格。 diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100755 index d47443eb1..000000000 --- a/AGENTS.md +++ /dev/null @@ -1,318 +0,0 @@ -# HealthLink-HIS — Harness Engineering 开发指南 - -> **模型决定上限,Harness 决定底线。** -> 本文件是 HealthLink-HIS 项目的 Harness Engineering 落地。整合了 OpenAI/Anthropic Harness Engineering 方法论与 walkinglabs 实战模式。 - -> **🔴 铁律统一文件**: `/root/.codex/rules/IRON_LAWS.md` — 所有智能体必须遵守,运行时自动加载。 -> **📦 技能包安装**: https://github.com/paskaa/agentforge-harness-skill — 其他电脑一键安装所有铁律和技能。 - ---- - -## 📋 项目信息 - -HealthLink-HIS 医院管理系统 | Java 17 + Spring Boot + MyBatis Plus | Vue 3 + Element Plus | PostgreSQL - -### 构建和运行 - -```bash -cd /root/.openclaw/workspace/his-repo - -# 初始化(每次新会话先运行) -bash .harness/init.sh - -# 后端编译 -cd healthlink-his-server && mvn compile -pl healthlink-his-application -am - -# 后端打包 -mvn clean package -DskipTests - -# 后端运行 -cd healthlink-his-application && mvn spring-boot:run - -# 前端 -cd healthlink-his-ui && npm install && npm run dev -``` - -### 关键路径 - -``` -后端代码: healthlink-his-server/healthlink-his-application/src/main/java/com/ -后端配置: healthlink-his-server/healthlink-his-application/src/main/resources/ -Mapper XML: .../mapper/ (regdoctorstation/, doctorstation/, ...) -前端代码: healthlink-his-ui/src/ -Harness: .harness/ (init.sh, PROGRESS.md, feature_list.json, ...) -``` - ---- - -## 🔧 5 子系统模型(WalkingLabs) - -> 源自:[Learn Harness Engineering](https://walkinglabs.github.io/learn-harness-engineering/zh/) - -### 1. 指令子系统(Instruction) - -| 文件 | 用途 | -|---|---| -| **AGENTS.md**(本文件) | 项目规则、约束、工作流程 | -| `.harness/feature_list.json` | 机器可读的功能状态追踪 | -| `.harness/PROGRESS.md` | 会话进度和已验证状态 | -| `.harness/session-handoff.md` | 跨会话交接摘要 | - -### 2. 工具子系统(Tools) - -| 工具 | 用途 | -|---|---| -| `mvn compile` | 编译验证 | -| `git` | 版本控制 + 回滚 | -| `pwd` | 确认当前目录 | -| shell | 文件操作、命令执行 | - -### 3. 环境子系统(Environment) - -| 组件 | 状态 | -|---|---| -| Java 17 | ✅ `pom.xml` 锁定 | -| Maven | ✅ `mvn-wrapper` | -| PostgreSQL | ✅ 192.168.110.252:15432 | -| Node.js | ✅ `package.json` 锁定 | - -### 4. 状态子系统(State) - -| 机制 | 用途 | -|---|---| -| `update_plan` | 当前步骤检查点 | -| `.harness/PROGRESS.md` | 跨会话进度记录 | -| `.harness/feature_list.json` | 功能状态跟踪 | -| `git log` | 变更历史追溯 | - -### 5. 反馈子系统(Feedback) - -| 层级 | 命令 | 时间 | -|---|---|---| -| L1 编译 | `mvn compile -pl healthlink-his-application -am` | <30 秒 | -| L2 全链路 | 六环检查清单(见下文) | <5 分钟 | -| L3 审查 | 你人工审查 diff | 10-30 分钟 | - ---- - -## 📋 标准工作循环 - -``` -开始会话 - │ - ├→ 1. Init - │ ├── bash .harness/init.sh - │ ├── 读取 PROGRESS.md / feature_list.json - │ ├── git log --oneline -5 - │ └── 确认编译通过 - │ - ├→ 2. Plan - │ ├── update_plan / checklist_write 分解步骤 - │ ├── 评估复杂度/风险 - │ └── 设定检查点 - │ - ├→ 3. Implement - │ ├── 一次只做一个功能 - │ ├── 全链路检查清单核对 - │ └── 增量修改,只动必要文件 - │ - ├→ 4. Verify - │ ├── L1: mvn compile - │ ├── L2: 全链路数据流验证 - │ └── 生成变更摘要 - │ - └→ 5. Cleanup - ├── 运行 clean-state-checklist.md - ├── 更新 PROGRESS.md + feature_list.json - ├── git add + commit + push - └── init.sh 确认干净状态 -``` - ---- - -## 🔗 全链路修复原则 - -修 Bug 时,不得"就事论事",必须走通完整的**数据流全链路**: - -### 六环检查清单 - -``` -1. 录入 → 前端有无输入入口?(弹窗、行编辑、表单...) -2. 保存 → 前端 → API → Controller → Service → Entity → DB, - 每个保存入口都传了该字段吗? -3. 查询 → DB → Mapper XML(UNION ALL 子查询统一加)→ DTO → 前端展示 -4. 修改 → 编辑回显 → 修改保存 → 正确更新? -5. 删除 → 状态变更会丢失该字段吗? -6. 关联 → 上下游(护士站、计费、打印、报表)需要同步改吗? -``` - -### 常见陷阱 - -| 陷阱 | 解决 | -|---|---| -| 只修主入口,批量保存/签发保存漏了 | 检查所有 Service 实现类 | -| 前端加了后端没传 | 逐个入口确认 | -| UNION ALL 只改一半 | 所有子查询统一加 | -| DTO 继承链没检查 | 检查父类/子类字段一致性 | -| 只测新增没测编辑 | 新增和编辑都要测 | - ---- - - -## 🚨 铁律(不可违反 — 来自实际 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 → 确认统计包含新状态 -``` - -### 数据库变更必须通过 Flyway 迁移(铁律) -凡涉及**新建表、新增字段、修改字段、加索引**等 DDL 变更,**必须**通过 Flyway 框架实现: -1. 在 `healthlink-his-server/healthlink-his-application/src/main/resources/db/migration/` 创建 `V{n}__描述.sql` -2. 版本号递增(`V2`, `V3`, `V4`...),双下划线分隔 -3. **禁止**直接在数据库执行 DDL 而不创建迁移文件 -4. **禁止**修改已执行的迁移文件(Flyway 会校验 checksum) -5. 新表必须包含:`tenant_id`, `create_by`, `create_time`, `update_by`, `update_time`, `valid_flag` -6. 多租户表还需在 `MybatisPlusConfig.java` 的 `TENANT_TABLES` 中注册 -7. 详细使用指南见 `docs/FLYWAY_USAGE_GUIDE.md` - -### 禁止修改已有公开方法签名 -- 不能删除或重命名已有的 public 方法 -- 不能修改已有方法的参数列表 -- 需要新功能 → 添加重载方法 -- 需要改行为 → 修改方法内部实现 - -### 状态变更影响面分析(来自 Bug #574→575 教训) -改任何状态枚举值前,**必须**执行影响面分析: -1. `rg "原状态枚举名" --type java` 列出所有引用文件 -2. 逐个检查:设置值?查询过滤?显示映射?统计聚合? -3. 检查逆向流程:退号、取消、停诊是否兼容新状态 -4. 检查 XML mapper 中所有查询过滤条件 -5. 检查前端 STATUS_CLASS_MAP 和所有 v-if/v-for 条件 -**禁止**:只改正向流程不验逆向流程 - -### 逆向流程验证(来自 Bug #575 教训) -涉及状态流转的 Bug,验证时**必须**覆盖: -- 正向:预约→签到→就诊→完成 -- 逆向:退号、取消预约、停诊、退费 -- 边界:并发操作、重复操作、异常中断 -**禁止**:只测正向流程就标记"修复完成" - -### 搜索所有相关代码路径 -修复前必须用 `rg` 搜索: -``` -rg "状态枚举名\|相关方法名\|相关字段名" --type java --type vue -``` -确保不遗漏任何引用该状态的代码路径。 - -## 📐 代码风格规范 - -### Java 后端 - -| 项目 | 规范 | -|---|---| -| 包结构 | `com.healthlink.his`(业务)、`com.core`(核心) | -| 命名 | 类 PascalCase、方法 camelCase、常量 SCREAMING_SNAKE_CASE | -| 注解 | `@Slf4j`、`@Data`、`@Service/@Controller/@Repository` | -| 异常 | 统一异常处理,业务异常继承 `RuntimeException` | -| 缩进 | 4 空格,行 120 字符 | - -### Vue 前端 - -| 项目 | 规范 | -|---|---| -| 框架 | Vue 3 + Composition API + Element Plus + Pinia | -| 命名 | 组件 PascalCase、文件 kebab-case、变量 camelCase | -| 缩进 | 2 空格,单引号,行 100 字符 | - -### 导入顺序 - -**Java:** `java.*` → `javax.*` → 第三方 → `com.core.*` → `com.healthlink.his.*` -**Vue:** `vue` 相关 → 第三方 → `@/` 别名 → 相对路径 - ---- - -## 🏗️ 开发约定 - -| 领域 | 约定 | -|---|---| -| API | RESTful,统一响应格式,Swagger 文档 | -| 数据库 | snake_case 命名,主键 `id`,软删除 `valid_flag` | -| 安全 | 所有 API 需权限验证,SQL 注入/XSS 防护 | -| 性能 | Druid 连接池,路由懒加载,虚拟滚动 | - ---- - -## ⚙️ 关键配置 - -| 项目 | 值 | -|---|---| -| 后端端口 | 18080 | -| 前端端口 | 81 | -| API 前缀 | `/healthlink-his` | -| Swagger | `/healthlink-his/swagger-ui/index.html` | -| 后端配置 | `application.yml` / `application-{profile}.yml` | -| 前端配置 | `vite.config.js` / `.env.*` | - ---- - -## 📈 过往 Bug 教训 - -| Bug | 教训 | -|---|---| -| #574 | `checkInTicket()` 状态值写错(BOOKED→应为CHECKED_IN),前端映射缺失,池统计漏计。根因:没走完整状态链路 | -| #574 | AI 智能体看到编译错误直接删文件,没检查 git baseline。根因:没验证文件来源 | -| #574 | 多次 fallback 修复改错文件(OrderServiceImpl),没触及真正问题(TicketServiceImpl)。根因:没用 rg 搜索所有引用 | - -## 📈 成熟度追踪 - -| 等级 | 特征 | 本项目 | -|---|---|---| -| **L1 初始** | 零星使用 AI 工具 | ✅ 已超越 | -| **L2 管理** | 基础约束 + 反馈 + 控制 | ✅ **当前** | -| **L3 定义** | 标准化、可复用 | 🔄 walkinglabs 5 子系统整合 | -| **L4 量化** | 数据驱动优化 | ⏳ | -| **L5 优化** | AI 自主优化 Harness | ⏳ | - ---- - -## 📚 技能索引(Codex 内置) - -| 技能 | 用途 | -|---|---| -| `$harness-engineering` | 主方法论 — 约束 + 反馈 + 控制 + 持久 | -| `$walkinglabs-harness` | 实战模式 — 5 子系统 + 模板 + 会话持续 | -| `$durable-execution` | 检查点、幂等性、事件溯源 | -| `$closed-loop-testing` | 质量门禁、测试策略、反馈循环 | -| `$constraint-design` | DSL 设计、策略模式、约束编排 | -| `$review-audit` | 审查工作流、审计追踪、合规检查 | -| `$full-chain-fix` | 全链路数据流修复 | -| `$karpathy-guidelines` | 减少 LLM 编码常见错误 | - ---- - -> **总纲:** 你负责"做什么"和"为什么",Agent 负责"怎么做"和"做多好" -> **工作循环:** Init → Plan → Implement → Verify → Cleanup diff --git a/ANALYSIS.md b/ANALYSIS.md deleted file mode 100644 index eb880308c..000000000 --- a/ANALYSIS.md +++ /dev/null @@ -1,28 +0,0 @@ - -## Bug #426 修复报告 - -### 根因分析 -Element Plus `el-table` 的懒加载树形模式(`lazy` + `:load` + `tree-props="{ hasChildren: 'hasChildren' }"`)要求每一行数据必须包含 `hasChildren: true` 属性,才会在该行前渲染展开箭头(+ / -)。 - -代码中所有创建 `selectedItems` 行对象的路径(共7处)都正确设置了 `isPackage: true` 和 `packageId`,但**遗漏了 `hasChildren` 属性**,导致树形表格无法识别哪些行是可展开的套餐项。 - -### 影响范围 -- **文件**: `examinationApplication.vue`(前端) -- **涉及函数**: `handleItemSelect`、`handleMethodSelect`、`handleRowClick`、`onDetailMethodChange` -- **数据表**: 无数据库变更 - -### 修复方案 -在7处代码路径中,当 `packageId` 存在时同步设置 `hasChildren: true`: -1. `handleRowClick` 初始 item 创建: `hasChildren: false` -2. `handleRowClick` 回充时设置 `isPackage` 两处: `hasChildren: true` -3. `handleMethodSelect` 已存在项更新: `hasChildren: true` -4. `handleMethodSelect` 新项创建: `hasChildren: !!(method.packageId || targetItem.packageId)` -5. `handleItemSelect` 新行创建: `hasChildren: !!(item.packageId)` -6. `onDetailMethodChange` 方法切换: `hasChildren: true` - -### 验证计划 -- 在门诊医生站选择检查套餐后,"检查明细" tab 的树形表格应显示展开箭头 -- 点击展开箭头应懒加载套餐明细(项目名称、数量、单价) -- 回充已保存申请单时套餐项应正确显示展开箭头 - -修复结果:✅ 成功,13行改动 diff --git a/ANALYSIS_433.md b/ANALYSIS_433.md deleted file mode 100644 index fb49b3841..000000000 --- a/ANALYSIS_433.md +++ /dev/null @@ -1,54 +0,0 @@ -# Bug #433 分析报告 - -## 根因分析 - -### 问题1:麻醉方法回显为代码 - -**数据流**: -1. 数据库 `op_schedule.anes_method` 字段为 VARCHAR,存值为字典代码字符串如 `"2"` -2. 后端 `OpSchedule.anesMethod` 为 String 类型,通过 `getSurgeryScheduleDetail` 查询返回 -3. 前端 el-select 选项通过 `useDict('anesthesia_type')` 加载,选项值为 `Number(item.value)` 即数字类型 -4. `handleEdit` 中 `Object.assign(form, data)` 后 `form.anesMethod` 为字符串 `"2"` - -**根因**: `form.anesMethod` 为字符串 `"2"` 而 el-select 选项值为数字 `2`,类型不匹配导致 el-select 无法匹配到对应选项,直接显示原始值 "2"。 - -**现有代码的问题**: 代码中有两行转换逻辑: -```javascript -if (data.anesMethod != null) form.anesMethod = Number(data.anesMethod) // OK -if (data.anesthesiaTypeEnum != null) form.anesMethod = Number(data.anesthesiaTypeEnum) // 多余 -``` -第二行 `data.anesthesiaTypeEnum` 不是 `OpScheduleDto` 的字段,SQL 查询也不包含此字段,因此永远为 null。但如果某些情况下后端返回了此字段(例如值为 0),会错误覆盖第一行的正确赋值。 - -### 问题2:外请专家姓名未加载 - -**根因**: `OpScheduleDto` 继承自 `OpSchedule`,`externalExpertName` 字段在 `OpSchedule` 实体中已定义且数据库 `op_schedule` 表已有 `external_expert_name` 列。`getSurgeryScheduleDetail` 查询使用 `SELECT os.*`,会返回该字段。前端 `form` 中也已定义 `externalExpertName`。 - -经数据库查询验证,当前数据中 `external_expert_name` 字段确实为空(尚未有用户填写过此字段)。但需确保 `Object.assign` 正确映射,且 `isExternalExpert` 类型匹配 el-radio 的 `:value="1"` / `:value="0"`。 - -## 影响范围 - -- **前端**: `healthlink-his-ui/src/views/surgicalschedule/index.vue` — `handleEdit` 和 `handleView` 方法 -- **后端**: 无需修改(字段已存在且正常返回) -- **数据库**: 无需修改(字段已存在) - -## 修复方案 - -在 `handleEdit` 和 `handleView` 方法中: -1. 删除多余的 `anesthesiaTypeEnum` 转换行 -2. 使用 `$nextTick` 确保类型转换在 `Object.assign` 后在下一个 tick 执行,确保 Vue 响应式系统已处理完 `Object.assign` 的变更后再设置值 -3. 统一确保所有字典类型字段(`anesMethod`、`incisionType`、`isExternalExpert`、`isFirstSurgery`)类型正确 - -## 验证计划 - -1. 修改后用 `node --check` 验证 .vue 语法 -2. 确认 git diff 改动 ≥ 3 行 - -## 修复结果 - -✅ 成功,28行改动(handleEdit 和 handleView 各 7 行 × 2 函数) - -### 改动摘要 - -1. **删除错误行**: `if (data.anesthesiaTypeEnum != null) form.anesMethod = Number(data.anesthesiaTypeEnum)` — 此字段不在 OpScheduleDto 中,SQL 也不返回,若返回会错误覆盖 anesMethod -2. **使用 nextTick 包裹类型转换**: 确保 Object.assign 触发的 Vue 响应式更新完成后再设置字典字段值,避免 el-select 在 DOM 更新前无法匹配选项 -3. **同时修复 handleEdit 和 handleView**: 两处代码一致,均需要同步修复 diff --git a/ANALYSIS_434.md b/ANALYSIS_434.md deleted file mode 100644 index cf1a659ff..000000000 --- a/ANALYSIS_434.md +++ /dev/null @@ -1,50 +0,0 @@ -# Bug #434 分析报告 - -## 根因分析 - -### 问题:编辑弹窗中"切口类型"字段未正确回显数据 - -**数据流追踪**: -1. 用户点击"编辑"→ 前端调用 `getSurgeryScheduleDetail(row.scheduleId)` -2. 后端 SQL: `cs.incision_level AS incisionLevel` -3. PostgreSQL 返回列名: `incisionlevel` (全小写) -4. MyBatis 尝试将 `incisionlevel` 映射到 `OpScheduleDto.incisionLevel` -5. 映射失败!→ `data.incisionLevel` 为 null → `form.incisionType` 保持 undefined → el-select 显示空白 - -### 根因:PostgreSQL 小写化未加引号的列别名 - -PostgreSQL 会将未加双引号的列别名自动转为小写: -```sql --- SQL 写的别名 -cs.incision_level AS incisionLevel --- PostgreSQL 实际返回的列名 -incisionlevel ← 全小写! -``` - -MyBatis 收到列名 `incisionlevel`(全小写),尝试匹配 Java 属性 `incisionLevel`(驼峰)。由于 `mapUnderscoreToCamelCase` 只对含下划线的列生效(`incisionlevel` 无下划线),匹配失败。 - -**对比 `anes_method` 为什么能工作**: -- SQL: `os.anes_method`(无 AS 别名) -- PostgreSQL 返回: `anes_method`(保留下划线) -- MyBatis `mapUnderscoreToCamelCase`: `anes_method` → `anesMethod` ✅ - -**对比同 mapper 中的 `surgeryNo` 为什么能工作**: -- SQL: `os.oper_code AS surgeryNo` → PostgreSQL 返回 `surgeryno` -- 但 `OpSchedule` 实体中**没有** `surgeryNo` 字段,只有 `operCode` -- `os.oper_code` 列映射到 `operCode` 是通过 `mapUnderscoreToCamelCase` 正常工作的 -- `surgeryno` 找不到对应属性,被 MyBatis 忽略(不影响功能) - -### 修复方案 - -将 SQL 中的别名加双引号:`cs.incision_level AS "incisionLevel"` - -PostgreSQL 对加双引号的标识符保持大小写,返回列名 `incisionLevel`(驼峰),MyBatis 可直接匹配到 `OpScheduleDto.incisionLevel` 属性。 - -### 影响范围 -- **后端**: `SurgicalScheduleAppMapper.xml` — `getSurgeryScheduleDetail` 查询(第92行) -- **前端**: 无需修改(`handleEdit`/`handleView` 中的 nextTick 转换逻辑已正确) -- **数据库**: 无需修改(`cli_surgery.incision_level` 字段已存在且有数据) - -## 验证计划 -1. 修改 SQL 后,运行相同查询验证列名变为 `incisionLevel` -2. 确认前端 `node --check` 语法通过 diff --git a/BUG516_ANALYSIS.md b/BUG516_ANALYSIS.md deleted file mode 100644 index acf1ffac2..000000000 --- a/BUG516_ANALYSIS.md +++ /dev/null @@ -1,61 +0,0 @@ -# Bug #516 深度分析报告 - -## Bug 描述 -[住院医生站-临床医嘱-检验申请] 检验申请单手动填写的"发往科室"与生成的医嘱执行科室不一致 - -## 根因分析 - -### 前端 Bug(`laboratoryTests.vue`) - -`projectWithDepartment` 函数(第167行)声明了1个参数,但内部使用了未声明的变量 `type`: - -```javascript -const projectWithDepartment = (selectProjectIds) => { // 只有1个参数 - const manualDept = type === 2 ? form.targetDepartment : ''; // type 未声明! - ... - if (type === 2 && manualDept) { // type 未声明! -``` - -调用处传了第2个参数但函数不接收: -- 第221行(watch监听):`projectWithDepartment(newValue, 1)` -- 第228行(提交):`if (!projectWithDepartment(transferValue.value, 2))` - -**后果**: -1. `type` 始终为 `undefined`,`type === 2` 永远为 false -2. `manualDept` 永远为空字符串 -3. 用户手动选择的"发往科室"在提交时被清空 -4. 即使 `findItem` 未找到配置的科室,也无法用手动选择兜底 - -### 后端 Bug(`RequestFormManageAppServiceImpl.java`) - -第165-171行: - -```java -Long positionId = activityOrganizationConfig.stream() - .filter(dto -> activitySaveDto.getAdviceDefinitionId().equals(dto.getActivityDefinitionId())) - .map(ActivityOrganizationConfigDto::getOrganizationId).findFirst().orElse(null); -if (positionId == null) { - throw new ServiceException(activitySaveDto.getAdviceDefinitionName() + "未配置当前时间段的执行科室"); -} -serviceRequest.setOrgId(positionId); // 完全忽略前端传的 positionId! -``` - -后端从配置表 `adm_organization_location` 查找执行科室,完全无视前端传来的 `activitySaveDto.positionId`(即用户手动选择的"发往科室")。 - -### 数据流 - -1. 用户在前端选择检验项目 → 触发watch → `projectWithDepartment` 尝试自动设置科室 -2. 用户手动切换"发往科室"下拉框 → `form.targetDepartment` = 肝胆科ID -3. 用户点击提交 → `projectWithDepartment(transferValue.value, 2)` 调用 -4. 因 `type` 未声明,手动选择的科室被清空 → `form.targetDepartment` = '' -5. 前端构建提交参数:`positionId: item.positionId || form.targetDepartment` → 空值 -6. 后端收到请求,从配置表查默认科室(检验科) → `serviceRequest.setOrgId(检验科)` -7. 医嘱列表中"药房/科室"列显示检验科,而非用户选择的肝胆科 - -## 修复方案 - -### 前端修复(1行改动) -在 `projectWithDepartment` 函数签名中添加 `type` 参数。 - -### 后端修复(3行改动) -优先使用前端传来的 `positionId`,配置表作为兜底值。 diff --git a/BUG540_ANALYSIS.md b/BUG540_ANALYSIS.md deleted file mode 100644 index 9e9bf892e..000000000 --- a/BUG540_ANALYSIS.md +++ /dev/null @@ -1,79 +0,0 @@ -# Bug #540 分析报告 - -## Bug 描述 -【住院医生站-检查申请】详情页弹窗中"申请单描述"区域缺少临床必要信息显示 - -## 数据流分析 - -### 前端组件 -- 入口: `src/views/inpatientDoctor/home/index.vue` → "检查申请" tab → `ExamineApplication` -- 实际组件: `src/views/inpatientDoctor/home/components/applicationShow/examineApplication.vue` -- 编辑表单组件: `src/views/inpatientDoctor/home/components/order/applicationForm/medicalExaminations.vue` - -### 后端 API -- 查询: `GET /reg-doctorstation/request-form/get-check` → `typeCode = '23'` (ActivityDefCategory.TEST) -- 保存: `POST /reg-doctorstation/request-form/save-check` → `typeCode = '23'` -- SQL: `RequestFormManageAppMapper.xml` 的 `getRequestForm` 查询,SELECT `drf.desc_json` -- DTO: `RequestFormQueryDto` 有 `descJson` 字段 (String 类型) - -### 数据库 -- 表: `doc_request_form`,type_code = '23' 的记录 desc_json 均有数据 -- descJson 包含: targetDepartment, urgencyLevel, symptom, sign, clinicalDiagnosis, otherDiagnosis, relatedResult, attention, examinationPurpose, medicalHistorySummary, allergyHistory, expectedExaminationTime 等 - -## 根因定位 - -对比检验申请 (testApplication.vue) 和检查申请 (examineApplication.vue) 的详情弹窗中"申请单描述"区域的渲染逻辑: - -**testApplication.vue (检验申请) - 正确:** -```vue - -``` -- 遍历 `descJsonData` 的所有 key,只要 key 在 labelMap 中就显示 -- 空值显示为 '-' - -**examineApplication.vue (检查申请) - 问题:** -```vue - - {{ transformField(key, descJsonData[key]) || '-' }} - -``` -- 遍历固定的 `orderedDescFieldKeys` 数组,不遍历 descJsonData 的所有 key -- **关键问题**: `v-if="descJsonData[key] != null && descJsonData[key] !== ''"` 会过滤掉空值字段 - -但是,更关键的是外层条件: -```vue -
-``` - -`hasMatchedFields` 检查 `descJsonData` 的 key 是否在 `labelMap` 中。`labelMap` 包含所有需要显示的字段。 - -**实际根因**:通过对比 testApplication.vue 与 examineApplication.vue,发现两个组件在 "申请单描述" 区域的渲染方式不同。testApplication 遍历 descJsonData 的所有 key(只要有值就显示),而 examineApplication 只遍历 orderedDescFieldKeys 数组。 - -**最可能的根因**:当 descJsonData 中的字段值为空字符串时,examineApplication 的 `v-if` 条件 `descJsonData[key] !== ''` 会过滤掉该字段(整行不显示),而 testApplication 会显示该字段标签并填入 `-`。 - -对于 `targetDepartment` 字段,`recursionFun` 函数在科室列表中找不到对应 ID 时会返回空字符串 `''`,导致 `targetDepartment` 被过滤不显示。 - -**但核心问题是**:如果 descJsonData 存在但某些字段为空,这些字段会被完全隐藏而不是显示 `-`。用户期望看到的是字段标签+占位符 `-`,而不是整个字段不显示。 - -## 修复方案 - -将 examineApplication.vue 中"申请单描述"区域的渲染方式改为与 testApplication.vue 一致: -1. 遍历 `descJsonData` 的所有 key(而非固定 orderedDescFieldKeys) -2. 使用 `isFieldMatched(key)` 过滤需要显示的字段 -3. 空值显示为 `-`(而非完全隐藏) - -同时保留 `orderedDescFieldKeys` 用于打印功能(已有代码使用)。 - -## 变更文件 -- `healthlink-his-ui/src/views/inpatientDoctor/home/components/applicationShow/examineApplication.vue`(前端模板修改) - -修复结果:✅ 成功,5行改动(+5/-8) diff --git a/BUGFIX_ANALYSIS.md b/BUGFIX_ANALYSIS.md deleted file mode 100755 index b3a129968..000000000 --- a/BUGFIX_ANALYSIS.md +++ /dev/null @@ -1,91 +0,0 @@ -# Bug 根因分析与修复方案 - -## Bug 335 - 门诊医生站开立药品医嘱保存报错 - -### 问题分析 -根据代码分析,`DoctorStationAdviceAppServiceImpl.saveAdvice()` 方法处理药品医嘱保存时可能报错的原因: - -1. **patientId/encounterId 为 null** - 删除操作时前端可能未传 -2. **accountId 为 null** - 患者账户信息未正确获取 -3. **definitionId/definitionDetailId 为 null** - 定价信息缺失 -4. **库存校验失败** - 药品库存不足 - -### 修复方案 -✅ 已部分修复(见代码中的 BugFix 注释) -- 已添加 patientId/encounterId 自动补全逻辑 -- 已添加 accountId 自动创建逻辑 -- 需要进一步验证 definitionId 的处理 - ---- - -## Bug 336 - 门诊医生站开立诊疗项目保存报错 - -### 问题分析 -诊疗项目保存与药品类似,但有以下特殊点: - -1. **必须选择执行科室** - 代码中有校验 `throw new ServiceException("诊疗项目必须选择执行科室")` -2. **活动绑定设备处理** - 需要处理 `handService()` 中的设备绑定逻辑 -3. **库存校验** - 诊疗项目可能关联耗材 - -### 修复方案 -- 确保前端传递 executeDeptId(执行科室) -- 检查 handService() 方法中的异常处理 -- 添加更详细的错误日志 - ---- - -## Bug 338 - 门诊划价新增时未校验就诊记录及诊断记录 - -### 问题分析 -**这是患者安全问题!** 未接诊患者也可新增划价项目可能导致: -- 收费错误 -- 医疗纠纷 -- 数据不一致 - -当前代码问题: -- `OutpatientPricingAppServiceImpl.getAdviceBaseInfo()` 仅查询医嘱,未校验就诊状态 -- 前端划价保存接口未找到(可能在其他地方) - -### 修复方案 -1. 在划价查询时增加就诊状态校验 -2. 在划价保存时增加诊断记录校验 -3. 未接诊患者禁止划价 - ---- - -## Bug 339 - 药房筛选条件失效 - -### 问题分析 -查询结果中包含非选中药房的数据,可能原因: -- SQL WHERE 条件未正确应用 locationId -- 多表关联时过滤条件丢失 - -### 修复方案 -- 检查 `DoctorStationAdviceAppMapper.getAdviceBaseInfo()` 的 SQL -- 确保 locationId 条件正确应用 - ---- - -## 修复优先级 - -1. **Bug 338** - 患者安全问题,最高优先级 -2. **Bug 335/336** - 核心功能阻断,高优先级 -3. **Bug 339** - 数据准确性问题,中优先级 - ---- - -## 测试用例 - -### Bug 338 测试 -1. 选择未接诊患者,尝试划价 → 应禁止 -2. 选择已接诊但无诊断的患者,尝试划价 → 应提示补充诊断 -3. 选择正常接诊患者,划价 → 应成功 - -### Bug 335/336 测试 -1. 门诊医生站开立药品医嘱 → 应成功保存 -2. 门诊医生站开立诊疗项目 → 应成功保存 -3. 签发医嘱 → 应成功 - -### Bug 339 测试 -1. 选择"西药房"筛选 → 结果应仅包含西药房数据 -2. 选择"中药房"筛选 → 结果应仅包含中药房数据 diff --git a/BUGFIX_PLAN.md b/BUGFIX_PLAN.md deleted file mode 100755 index d5a97e663..000000000 --- a/BUGFIX_PLAN.md +++ /dev/null @@ -1,84 +0,0 @@ -# HIS 系统 Bug 修复计划 - -## 修复负责人 -华佗 (AI 团队) - -## 修复时间 -2026-04-05 开始 - ---- - -## Bug 清单与修复优先级 - -### 🔴 高优先级(核心业务阻断) - -#### Bug 335 - 门诊医生站开立药品医嘱保存报错 -- **模块**: 医生工作站 -- **文件**: `DoctorStationAdviceAppServiceImpl.java` -- **根因分析**: 待分析 -- **修复状态**: 🔄 分析中 - -#### Bug 336 - 门诊医生站开立诊疗项目保存报错 -- **模块**: 医生工作站 -- **文件**: `DoctorStationAdviceAppServiceImpl.java` -- **根因分析**: 待分析 -- **修复状态**: ⏳ 等待 335 修复后验证 - -#### Bug 338 - 门诊划价新增时未校验就诊记录及诊断记录 -- **模块**: 门诊收费 -- **问题**: 未接诊患者也可新增划价项目(患者安全问题) -- **修复方案**: 在划价保存前增加就诊状态和诊断记录校验 -- **修复状态**: ⏳ 待修复 - -### 🟡 中优先级(数据准确性/用户体验) - -#### Bug 339 - 药房筛选条件失效 -- **模块**: 药房药库报表管理 -- **问题**: 查询结果中包含非选中药房的数据 -- **修复状态**: ⏳ 待分析 - -#### Bug 333 - 耗材医嘱类型错误 -- **模块**: 医生工作站 -- **问题**: 类型误转为"中成药"且保存报错 -- **修复状态**: ⏳ 待分析 - -#### Bug 337 - 挂号时间显示异常 -- **模块**: 建档挂号管理 -- **问题**: 未显示当前实际挂号时间 -- **修复状态**: ⏳ 待分析 - -#### Bug 334 - 检验申请界面布局优化 -- **模块**: 门诊医生工作站 -- **问题**: 按钮布局需要调整 -- **修复状态**: ⏳ 待修复(前端) - -### 🟢 低优先级(历史遗留问题) - -#### Bug 249/253/280/300 - 3 月份遗留 bug -- **修复状态**: ⏳ 后续处理 - ---- - -## 修复流程 - -1. **分析根因** - 查看代码和日志,定位问题 -2. **编写修复** - 修改代码并添加必要校验 -3. **本地测试** - 确保修复有效且不引入新问题 -4. **提交代码** - commit 并推送到 gitea -5. **验证关闭** - 在禅道更新 Bug 状态 - ---- - -## 测试要求 - -- 修复后必须测试 -- 测试不通过继续修 -- 确保不影响其他功能 - ---- - -## 备注 - -- 所有修复基于 develop 分支 -- 修复完成后统一提交 -- 重要修复添加详细注释 diff --git a/BUG_355_ANALYSIS.md b/BUG_355_ANALYSIS.md deleted file mode 100755 index 03b088376..000000000 --- a/BUG_355_ANALYSIS.md +++ /dev/null @@ -1,163 +0,0 @@ -# Bug #355 - 性别字段回显不一致分析与修复 - -## 问题描述 -门诊挂号页面的预约签到弹窗中,患者"随自核"的性别显示为"未知",但挂号界面载入后显示为"男性",数据不一致。 - -## 根本原因 - -### 数据流程分析 - -1. **预约签到弹窗数据来源** (`TicketAppServiceImpl.listTicket()`) - - SQL 查询 (ScheduleSlotMapper.xml 第97行): - ```sql - COALESCE(CAST(o.gender AS VARCHAR), CAST(pinfo.gender_enum AS VARCHAR)) AS patientGender - ``` - - 后端逻辑 (TicketAppServiceImpl.java 第140-145行): - ```java - if (raw.getPatientGender() != null) { - String pg = raw.getPatientGender().trim(); - dto.setGender("1".equals(pg) ? "男" : ("2".equals(pg) ? "女" : "未知")); - } else { - dto.setGender("未知"); - } - ``` - -2. **挂号界面数据来源** (OutpatientRegistrationAppServiceImpl) - - 直接从 `adm_patient` 表查询患者最新信息 - - 性别字段: `pinfo.gender_enum` - - 翻译为文本: `EnumUtils.getInfoByValue(AdministrativeGender.class, genderEnum)` - -### 问题定位 - -**关键 SQL 逻辑问题:** -- `order_main.gender` 字段存储的是订单创建时的性别值(varchar 类型) -- `adm_patient.gender_enum` 字段存储的是患者最新性别(integer 类型) -- 当 `order_main.gender` 为 `NULL` 时,SQL 会回退到 `pinfo.gender_enum` - -**可能的场景:** -1. 订单创建时未保存性别字段 (`order_main.gender` = NULL) -2. 患者档案中的性别被修改过(但订单表未同步更新) -3. `pinfo.gender_enum` 值为 NULL 或者不合法 - -## 修复方案 - -### 方案1:修正 SQL 查询逻辑 (推荐) - -**问题:** 当 `order_main.gender` 为 NULL 时,SQL 正确回退到 `pinfo.gender_enum`,但 Java 代码中对 `patientGender` 的处理逻辑有问题。 - -**修复步骤:** - -1. 修改 SQL,直接从患者表获取性别,不依赖订单表的 gender 字段: - -```sql --- ScheduleSlotMapper.xml -LEFT JOIN adm_patient pinfo ON o.patient_id = pinfo.id --- 性别字段直接从患者表获取,避免订单表 gender 字段为空的情况 -pinfo.gender_enum AS genderEnum, -``` - -2. 修改 Java 代码,直接使用 `genderEnum` 字段: - -```java -// TicketAppServiceImpl.java -// 性别处理:直接使用患者表中的 gender_enum -Integer genderEnum = raw.getGenderEnum(); -if (genderEnum != null) { - if (Integer.valueOf(1).equals(genderEnum)) { - dto.setGender("男"); - } else if (Integer.valueOf(2).equals(genderEnum)) { - dto.setGender("女"); - } else { - dto.setGender("未知"); - } -} else { - dto.setGender("未知"); -} -``` - -### 方案2:确保订单表 gender 字段不为空 - -在订单创建时,确保将患者的性别同步到订单表的 `gender` 字段。 - -## 临时验证方案 - -在数据库中执行以下 SQL 检查患者"随自核"的数据: - -```sql --- 检查患者档案中的性别 -SELECT id, name, gender_enum, - CASE gender_enum - WHEN 1 THEN '男' - WHEN 2 THEN '女' - ELSE '未知' - END as gender_text -FROM adm_patient -WHERE name = '随自核'; - --- 检查订单表中的性别 -SELECT o.id, o.patient_id, o.patient_name, o.gender, p.gender_enum -FROM order_main o -LEFT JOIN adm_patient p ON o.patient_id = p.id -WHERE o.patient_name = '随自核'; - --- 检查号源数据 -SELECT s.id, s.pool_id, s.status as slot_status -FROM adm_schedule_slot s -WHERE EXISTS ( - SELECT 1 FROM order_main o WHERE o.slot_id = s.id - AND o.patient_name = '随自核' -); -``` - -## 修复代码 - -### 修改 ScheduleSlotMapper.xml - -在 `selectTicketSlotsPage` SQL 中,将患者性别字段改为直接从患者表获取: - -```xml - -COALESCE(CAST(o.gender AS VARCHAR), CAST(pinfo.gender_enum AS VARCHAR)) AS patientGender, - - -pinfo.gender_enum AS genderEnum, -``` - -### 修改 TicketAppServiceImpl.java - -在 `listTicket` 方法中修改性别处理逻辑: - -```java -// 原来的代码 (第140-145行) -// 性别处理:直接读取优先级最高的订单性别字段 (SQL 已处理优先级) -if (raw.getPatientGender() != null) { - String pg = raw.getPatientGender().trim(); - dto.setGender("1".equals(pg) ? "男" : ("2".equals(pg) ? "女" : "未知")); -} else { - dto.setGender("未知"); -} - -// 修改后的代码 -// 性别处理:直接使用患者表中的 gender_enum -Integer genderEnum = raw.getGenderEnum(); -if (genderEnum != null) { - if (Integer.valueOf(1).equals(genderEnum)) { - dto.setGender("男"); - } else if (Integer.valueOf(2).equals(genderEnum)) { - dto.setGender("女"); - } else { - dto.setGender("未知"); - } -} else { - dto.setGender("未知"); -} -``` - -## 验证步骤 - -1. 修复代码后,重新编译部署 -2. 打开预约签到弹窗,查找患者"随自核" -3. 确认性别字段显示为"男性" -4. 进行挂号操作 -5. 确认挂号界面显示的性别也是"男性" -6. 两者应该保持一致 diff --git a/BUG_355_FIX.md b/BUG_355_FIX.md deleted file mode 100755 index 774e9fc21..000000000 --- a/BUG_355_FIX.md +++ /dev/null @@ -1,117 +0,0 @@ -# Bug #355 修复代码 - -## 修改文件清单 - -| 序号 | 文件路径 | 修改类型 | 说明 | -|------|---------|---------|------| -| 1 | `his-source/healthlink-his-server/openhis-domain/src/main/resources/mapper/administration/ScheduleSlotMapper.xml` | SQL 查询修改 | 性别字段直接从患者表获取 | -| 2 | `his-source/healthlink-his-server/healthlink-his-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/TicketAppServiceImpl.java` | Java 代码修改 | 性别处理逻辑修改 | - ---- - -## 修复步骤 - -### 修改 1: ScheduleSlotMapper.xml - -**文件:** `his-source/healthlink-his-server/openhis-domain/src/main/resources/mapper/administration/ScheduleSlotMapper.xml` - -**修改位置:** 第97行 - -**修改前:** -```xml -COALESCE(CAST(o.gender AS VARCHAR), CAST(pinfo.gender_enum AS VARCHAR)) AS patientGender, -``` - -**修改后:** -```xml -pinfo.gender_enum AS genderEnum, -``` - -**说明:** 直接从患者表获取 `gender_enum` 字段,避免订单表 `gender` 字段为 NULL 导致的数据不一致。 - ---- - -### 修改 2: TicketAppServiceImpl.java - -**文件:** `his-source/healthlink-his-server/healthlink-his-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/TicketAppServiceImpl.java` - -**修改位置:** 第140-145行 - -**修改前:** -```java -// 性别处理:直接读取优先级最高的订单性别字段 (SQL 已处理优先级) -if (raw.getPatientGender() != null) { - String pg = raw.getPatientGender().trim(); - dto.setGender("1".equals(pg) ? "男" : ("2".equals(pg) ? "女" : "未知")); -} else { - dto.setGender("未知"); -} -``` - -**修改后:** -```java -// 性别处理:直接使用患者表中的 gender_enum -Integer genderEnum = raw.getGenderEnum(); -if (genderEnum != null) { - if (Integer.valueOf(1).equals(genderEnum)) { - dto.setGender("男"); - } else if (Integer.valueOf(2).equals(genderEnum)) { - dto.setGender("女"); - } else { - dto.setGender("未知"); - } -} else { - dto.setGender("未知"); -} -``` - -**说明:** 由于 SQL 查询已直接获取 `gender_enum` 字段,这里修改为直接使用该字段进行性别转换。 - ---- - -## 额外修改 (可选) - -如果需要同时修改 `selectTicketSlotsPage` 的其他字段,确保这些字段也被正确映射到 DTO: - -### 修改 TicketSlotDTO.java - -**文件:** `his-source/healthlink-his-server/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/TicketSlotDTO.java` - -**修改:** 添加 `genderEnum` 字段 - -```java -private Integer genderEnum; - -public Integer getGenderEnum() { - return genderEnum; -} - -public void setGenderEnum(Integer genderEnum) { - this.genderEnum = genderEnum; -} -``` - ---- - -## 编译部署 - -```bash -cd his-source/healthlink-his-server -mvn clean package -DskipTests -``` - ---- - -## 回归测试 - -| 测试项 | 预期结果 | 状态 | -|--------|---------|------| -| 预约签到弹窗性别显示 | 显示患者真实性别(男/女/未知) | 待测试 | -| 挂号界面性别显示 | 显示患者真实性别(男/女/未知) | 待测试 | -| 两者性别数据一致性 | 完全一致 | 待测试 | - ---- - -**修复人:** 关羽 -**修复日期:** 2026-04-08 -**BUG ID:** #355 diff --git a/BUG_355_FIX_NOTES.md b/BUG_355_FIX_NOTES.md deleted file mode 100755 index 10192c83e..000000000 --- a/BUG_355_FIX_NOTES.md +++ /dev/null @@ -1,65 +0,0 @@ -# BUG #355 - 修复备注 - -## 修复日期 -2026-04-08 - -## 修复人 -关羽 (guanyu) - -## 修复内容 - -### 问题描述 -门诊挂号页面的预约签到弹窗中,患者"随自核"的性别显示为"未知",但挂号界面载入后显示为"男性",数据不一致。 - -### 根本原因 -- 预约签到弹窗数据来自 `TicketAppServiceImpl.listTicket()` 方法 -- SQL 查询中使用了订单表的 `gender` 字段(可能为 NULL) -- 当订单表 `gender` 为 NULL 时,虽然 SQL 回退到患者表 `gender_enum`,但 Java 代码处理逻辑仍有问题 -- 导致性别显示不一致 - -### 修复方案 -修改 `TicketAppServiceImpl.java` 中的性别处理逻辑: -- 将 `raw.getPatientGender()` 改为 `raw.getGenderEnum()` -- 直接使用患者表中的 `gender_enum` 字段进行性别转换 -- 确保与挂号界面查询的数据来源一致 - -### 修改文件 -- `his-source/healthlink-his-server/healthlink-his-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/TicketAppServiceImpl.java` - -### 代码变更 -```java -// 修改前 -if (raw.getPatientGender() != null) { - String pg = raw.getPatientGender().trim(); - dto.setGender("1".equals(pg) ? "男" : ("2".equals(pg) ? "女" : "未知")); -} else { - dto.setGender("未知"); -} - -// 修改后 -Integer genderEnum = raw.getGenderEnum(); -if (genderEnum != null) { - if (Integer.valueOf(1).equals(genderEnum)) { - dto.setGender("男"); - } else if (Integer.valueOf(2).equals(genderEnum)) { - dto.setGender("女"); - } else { - dto.setGender("未知"); - } -} else { - dto.setGender("未知"); -} -``` - -### Git 提交 -- Commit: `7827e58a` -- 分支: `develop` - -### 测试建议 -1. 更新 Git 代码 -2. 编译部署后进行测试 -3. 验证预约签到弹窗和挂号界面的性别字段是否一致 - -### 状态 -✅ 代码修复完成,已提交到远程仓库 -⏳ 等待测试验证 diff --git a/BUG_362_ANALYSIS.md b/BUG_362_ANALYSIS.md deleted file mode 100755 index 0e4064cfe..000000000 --- a/BUG_362_ANALYSIS.md +++ /dev/null @@ -1,32 +0,0 @@ -# Bug 362 - 入科时间显示错误分析 - -## 问题描述 -双击查看详情时显示当前系统时间,而不是正确的入科时间。 - -## 当前分析状态 - -### 已确认 -1. **前端显示逻辑正确**: 患者详情对话框直接显示后端返回的 `admissionDate` 字段 -2. **后端数据来源正确**: 从 `adm_encounter.start_time` 获取入院时间 -3. **字段绑定正确**: 前端表格和详情都使用 `admissionDate` 字段 - -### 可能原因 -1. **数据库数据问题**: `adm_encounter.start_time` 字段本身存储的是当前系统时间 -2. **概念混淆**: 用户期望看到"入科时间",但系统显示的是"入院时间" -3. **前端缓存问题**: 某些情况下前端缓存了错误的时间值 - -### 调试措施 -1. **已添加调试日志**: 在患者详情对话框中添加 `console.log` 输出 `admissionDate` 值 -2. **需要验证**: 实际测试时查看浏览器控制台输出,确认具体值 - -### 下一步计划 -1. **等待测试结果**: 通过调试日志确认实际显示的值 -2. **根据结果修复**: - - 如果是数据问题:修复后端数据录入逻辑 - - 如果是概念问题:添加入科时间字段并修改显示 - - 如果是缓存问题:清理前端缓存逻辑 - -## 临时解决方案 -如果确认是数据问题,可以先在前端添加时间有效性检查,避免显示明显错误的时间。 - -正在自主分析中! \ No newline at end of file diff --git a/BUG_362_FIX_COMPLETE.md b/BUG_362_FIX_COMPLETE.md deleted file mode 100755 index 1349182e3..000000000 --- a/BUG_362_FIX_COMPLETE.md +++ /dev/null @@ -1,35 +0,0 @@ -# Bug 362 - 入科时间显示错误修复完成 - -## 问题根因 -用户期望看到 **入科时间**,但系统显示的是 **入院时间**。 - -- **入院时间**: `adm_encounter.start_time` (办理住院手续的时间) -- **入科时间**: `adm_encounter_location.start_time` (进入具体科室的时间) - -## 修复方案 - -### 后端修改 -1. **DTO类添加字段**: - - `NursingPageDto.wardAdmissionDate` - - `PatientHomeDto.wardAdmissionDate` -2. **SQL查询添加字段**: - - `NursingRecordAppMapper.xml`: 添加入科时间查询 - - `PatientHomeAppMapper.xml`: 添加入科时间子查询 - -### 前端修改 -1. **患者列表**: 将"入院日期"改为"入科日期",绑定到 `wardAdmissionDate` -2. **患者详情对话框**: 将"入院日期"改为"入科日期",绑定到 `wardAdmissionDate` -3. **患者卡片**: 将"入院"改为"入科",显示 `wardAdmissionDate` -4. **体温单界面**: 使用 `wardAdmissionDate` 作为入科时间 - -## 验证步骤 -1. 双击患者查看详情,确认显示的是入科时间而非入院时间 -2. 患者列表中"入科日期"列显示正确时间 -3. 患者卡片显示正确的入科时间 -4. 体温单界面使用正确的入科时间 - -## 修复状态 -✅ 已修复并提交到远程仓库 - ---- -赵云:Bug 362已修复! \ No newline at end of file diff --git a/BUG_364_362_ANALYSIS.md b/BUG_364_362_ANALYSIS.md deleted file mode 100755 index 865dc605f..000000000 --- a/BUG_364_362_ANALYSIS.md +++ /dev/null @@ -1,29 +0,0 @@ -# Bug 364/362 - 住院护士站任务分析 - -## Bug分配确认 - -### Bug #364 - 住院护士站三测单病历号检索失败 -**状态**: ⏳ 待分析 -**分析人**: 赵云 -**预计完成**: 今日内 - -### Bug #362 - 住院护士站入科时间显示错误 -**状态**: ⏳ 待分析 -**分析人**: 赵云 -**预计完成**: 今日内 - -### Bug #363 - 住院管理入院时间校验 -**状态**: ✅ 已分配给关羽 -**理由**: 此为后端业务逻辑问题,应由后端开发处理 - ---- - -## 当前进度(2026-04-08 23:17) - -赵云正在分析这两个前端Bug,已定位相关代码位置: -- 住院护士站主界面: `inpatientNurse/home/index.vue` -- 三测单相关: `action/nurseStation/temperatureSheet/` - -正在查找病历号检索和入科时间显示的具体实现。 - -子龙领命! \ No newline at end of file diff --git a/BUG_364_362_FIX.md b/BUG_364_362_FIX.md deleted file mode 100755 index 10258366a..000000000 --- a/BUG_364_362_FIX.md +++ /dev/null @@ -1,51 +0,0 @@ -# Bug 364/362 - 问题分析与修复方案 - -## Bug #364 - 住院护士站三测单病历号检索失败 ✅ 已修复 - -### 问题根因 -前端表格列定义错误,将"病历号"列绑定到了 `encounterId` (就诊ID) 而不是 `patientBusNo` (病历号)。 - -**前端问题** (`tprChart/index.vue`): -```vue - -``` -应该改为: -```vue - -``` - -### 解决方案 -修改前端表格列定义,将病历号列绑定到正确的字段。 - -**修复状态**: ✅ 已修复并提交 - ---- - -## Bug #362 - 住院护士站入科时间显示错误 ⏳ 分析中 - -### 问题根因 -在 `PatientHomeAppMapper.xml` 中,入院时间从 `adm_encounter.start_time` 获取: -```xml -T2.start_time AS admissionDate, -- 入院日期 -``` - -这个字段是正确的入院时间。Bug描述"双击查看详情时显示当前系统时间"可能是因为: -1. 某些情况下前端缓存了错误的日期 -2. 或者用户看到的是"住院天数"的计算基时间 - -### 解决方案 -确认前端显示的确实是 `admissionDate` 字段,而不是其他时间字段。 - ---- - -## 修复计划 - -### Bug 364 -1. ✅ 修改 `tprChart/index.vue` 中的病历号列绑定 -2. ⏳ 测试验证检索功能 - -### Bug 362 -1. ⏳ 检查前端显示逻辑 -2. ⏳ 确认数据来源正确 - -赵云:Bug 364已修复。Bug 362正在分析中。 \ No newline at end of file diff --git a/BUG_426_ANALYSIS.md b/BUG_426_ANALYSIS.md deleted file mode 100644 index f59de9837..000000000 --- a/BUG_426_ANALYSIS.md +++ /dev/null @@ -1,65 +0,0 @@ -# Bug #426 分析报告 - -**标题**: 门诊医生站-检查开立:已选择列表应支持树形展开,显示套餐明细(项目/数量/单价) - -## 根因分析 - -经过完整的代码追踪和数据库验证,定位到 **两个根因**: - -### 根因1:`loadPackageDetails` 响应判断条件错误(树形表格永远加载不到套餐明细) - -**涉及代码**: `examinationApplication.vue` 第576-605行 - -Axios 响应拦截器(`request.js` 第202行)对 `code === 200` 的响应返回 `Promise.resolve(res.data)`,即**解包后的 AjaxResult 对象**(如 `{data: [...]}`,不含 `code` 字段)。 - -但 `loadPackageDetails` 函数检查的是 `if (res.code === 200)` —— 这个条件 **永远为 false**(解包后的对象没有 `code` 字段),导致树形表格的懒加载 **永远返回空数组**。 - -``` -后端返回: {"code":200,"data":[{item_name:"xxx",quantity:1,...}]} -拦截器解包后: {data:[{item_name:"xxx",quantity:1,...}]} -loadPackageDetails 判断: res.code === 200 → undefined === 200 → FALSE -结果: resolve([]) → 树形展开后永远是空白 -``` - -**对比正常工作的 `loadPackageDetailsForItem`**: 该函数直接调用 `parsePackageDetailsPayload(res)` 解析数据,不检查 `res.code`,所以右侧卡片的套餐明细能正常加载。 - -### 根因2:`handleItemSelect` 中 `hasChildren` 未考虑 `packageName` 场景 - -**涉及代码**: `examinationApplication.vue` 第1492行 - -数据库 `check_part` 表只有 `package_name` 字段,没有 `package_id`。前端创建套餐项时: -- `isPackage` 正确判断了 `!!(item.packageId || item.packageName)` -- `hasChildren` 只判断了 `!!(item.packageId)` - -当项目有 `packageName` 但无 `packageId` 时,`hasChildren` 为 `false`,el-table 树形模式 **不显示展开箭头**,用户无法点击展开。 - -```javascript -// 当前代码 -hasChildren: !!(item.packageId) // item.packageId 为 null → false → 无展开箭头 - -// 修复后 -hasChildren: !!(item.packageId || item.packageName) // 有 packageName 也能展开 -``` - -## 修复方案 - -1. 修改 `loadPackageDetails` 函数:去掉 `res.code === 200` 检查,直接使用 `parsePackageDetailsPayload(res)` 解析数据(与 `loadPackageDetailsForItem` 保持一致) -2. 修改 `handleItemSelect` 中 `hasChildren` 赋值:增加 `|| item.packageName` 条件 - -## 验证数据 - -数据库确认: -- `check_part` 表有 `package_name` 字段(如 "彩色多普勒超声"),无 `package_id` -- `check_package` 表 id=29, package_name="彩色多普勒超声" -- `check_package_detail` 表有 7 条明细记录(ABO血型、肾功3项等) -- `check_method` 表有 `package_name` 字段,无 `package_id` - -## 修复结果:✅ 成功,16行改动 - -**Commit**: 24c90e9c → origin/develop -**修改**: 1 file changed, 11 insertions(+), 15 deletions(-) - -| 位置 | 修改 | -|------|------| -| loadPackageDetails (576-600行) | 去掉 res.code === 200 检查,直接 parsePackageDetailsPayload 解析 | -| handleItemSelect (1488行) | hasChildren 增加 \|\| item.packageName | diff --git a/BUG_428_ANALYSIS.md b/BUG_428_ANALYSIS.md deleted file mode 100644 index 566fca8ba..000000000 --- a/BUG_428_ANALYSIS.md +++ /dev/null @@ -1,93 +0,0 @@ -# Bug #428 分析报告与修复验证 - -**标题**: 门诊医生站-检查申请:未实现分类联动检查方法及套餐明细展示与勾选逻辑 -**类型**: codeerror | **严重度**: 3 | **优先级**: 3 -**提出人**: 陈显精(chenxj) - -## 需求描述 - -医生站在为患者新增检查申请时,需实现三个联动功能: -1. **动作一**:展开右侧项目分类(如:彩超)后,下方自动加载后台维护的"检查方法"列表 -2. **动作二**:勾选某个检查方法后,该项目自动填充到右侧顶部"已选择"列表 -3. **动作三**:在"已选择"列表中点击展开图标,展示该套餐包含的收费明细 - -## 根因分析 - -### 数据流追踪 - -``` -分类折叠列表(el-collapse) - └─ handleCollapseChange(activeName) ← 用户展开分类时触发 - └─ handleCategoryExpand(cat) ← 异步加载检查方法 - └─ searchCheckMethod({checkType: cat.typeName}) → GET /check/method/search - └─ cat.methods = [...] ← 响应式赋值,模板自动渲染 - -检查方法列表(cat.methods) - └─ handleMethodSelect(checked, method, cat) ← 用户勾选/取消方法时触发 - └─ checked=true: 创建 newItem → selectedItems.push(newItem) - └─ checked=false: 清空 selectedMethod - └─ 右侧"已选择"面板自动渲染 - -已选择列表(selectedItems) - └─ toggleItemExpand(item) ← 用户点击展开图标 - └─ loadPackageDetailsForItem(item) - └─ GET /system/check-type/package/{packageId}/details - └─ item.packageDetailsDisplay = [...] - └─ 套餐明细区域自动渲染 -``` - -### 涉及的三个核心函数 - -| 函数 | 文件行号 | 作用 | -|------|---------|------| -| `handleCollapseChange` | 925-937 | 监听折叠面板展开/收起,触发方法加载 | -| `handleCategoryExpand` | 889-923 | 调用 API 加载分类下的检查方法列表 | -| `handleMethodSelect` | 1345-1426 | 勾选方法时添加到 selectedItems,取消时清空 | -| `toggleItemExpand` | 1526-1536 | 展开/收起已选项目,加载套餐明细 | -| `loadPackageDetailsForItem` | 657-719 | 调用 API 加载套餐明细数据 | -| `isMethodSelected` | 1338-1342 | 判断方法是否已选中,控制 checkbox 状态 | - -### 涉及的后端 API - -| API | Controller | 作用 | -|-----|-----------|------| -| `GET /check/method/search?checkType=xxx` | CheckMethodController.java:33 | 按检查类型查询方法列表 | -| `GET /system/check-type/package/{id}/details` | CheckTypeController.java:226 | 查询套餐明细 | -| `GET /check/method/list` | CheckMethodController.java:24 | 获取全部检查方法 | - -### 关键修复点 - -1. **methods 数组初始化**(`loadCategoryList` 第1001行):每个分类初始化 `methods: []`,确保 Vue 响应式追踪 -2. **方法列表渲染**(模板 397-416行):使用 `v-show` 替代 `v-if`,避免 DOM 突然插入导致高度跳变(Bug #500) -3. **加载状态隔离**(第892/921行):使用 `categoryLoadingSet` 替代全局 `dictLoading`,避免切换分类时整个区域闪烁(Bug #500) -4. **过期请求忽略**(第899/918行):`currentActiveCategory` 守卫,快速切换时丢弃过期响应(Bug #500) -5. **套餐信息同步**(第1364/1398行):确保 `packageName`、`packageId` 从 method 正确传递到 newItem -6. **hasChildren 标记**(第1363/1399行):有 `packageId` 时同步设置 `hasChildren: true`,支持树形表格展开(Bug #426) -7. **套餐明细加载**(第657-719行):通过 `packageId` 或 `packageName` 查询后端,填充 `packageDetailsDisplay` - -## 修复方案 - -全部前端代码修复已在 `examinationApplication.vue` 中实现: - -| 修复项 | 位置 | 修改内容 | -|--------|------|---------| -| 分类联动加载方法 | 889-937行 | handleCollapseChange + handleCategoryExpand | -| 方法列表渲染 | 397-416行 | method-section 模板 | -| 方法勾选逻辑 | 1345-1426行 | handleMethodSelect | -| 已选择面板 | 422-477行 | selected-panel 模板 | -| 套餐明细加载 | 657-719行 | loadPackageDetailsForItem | -| 套餐明细展开 | 1526-1536行 | toggleItemExpand | -| 套餐明细展示 | 450-474行 | package-details-list 模板 | -| 方法选中状态 | 1338-1342行 | isMethodSelected | -| 防止加载闪烁 | 892/899/918/921行 | categoryLoadingSet + currentActiveCategory 守卫 | - -## 验证计划 - -1. 登录 doctor1,进入门诊医生站 -2. 点击"检查"tab,新增检查申请 -3. 展开右侧"彩超"分类 → 验证下方出现"检查方法"列表 -4. 勾选"心电1" → 验证右侧"已选择"出现该项目 -5. 点击"已选择"中项目的展开图标 → 验证出现"套餐明细"列表 -6. 取消勾选方法 → 验证"已选择"中该项目消失或方法清空 - -## 修复结果:✅ 代码已实现,42行核心逻辑 diff --git a/BUG_470_ANALYSIS.md b/BUG_470_ANALYSIS.md deleted file mode 100644 index 31b78e03e..000000000 --- a/BUG_470_ANALYSIS.md +++ /dev/null @@ -1,72 +0,0 @@ -# Bug #470 分析报告 - -## 根因分析 - -### 症状 -住院医生工作站-手术申请单加载手术项目耗时过长,影响医生开单效率。 - -### 根本原因 - -**后端 `getSurgeryPage` 接口缺少 Redis 缓存层。** - -与同模块的 `getAdviceBaseInfo`(已有24小时Redis缓存)不同,`getSurgeryPage` 每次调用都直接查询数据库。 - -**代码对比:** - -- `getAdviceBaseInfo`(DoctorStationAdviceAppServiceImpl.java:157-512): - - 使用 `ADVICE_BASE_INFO_CACHE_PREFIX` 前缀做 Redis 缓存 - - 24小时过期 - - 先查缓存,未命中才查 DB - -- `getSurgeryPage`(DoctorStationAdviceAppServiceImpl.java:2463-2472): - - **无任何缓存逻辑**,每次直接查数据库 - - 仅有日志记录耗时 - -**数据库查询性能验证:** -``` -Execution Time: 0.400 ms (10102条手术项目,已有 idx_wor_activity_def_surgery 索引) -Planning Time: 4.349 ms -``` -数据库查询本身很快(<1ms),但每次弹窗打开都重复执行查询 + 序列化 + 网络传输,累积延迟明显。 - -**辅助因素:** -1. `applicationFormBottomBtn.vue` 的对话框设置了 `destroy-on-close`,每次关闭都会销毁 Surgery 组件 -2. 前端虽有模块级内存缓存(`surgeryRecordsCache` / `surgeryMappedCache`),但首次加载仍需后端响应 -3. 前端 `getList()` 命中缓存时未清除 `loading.value`,导致 loading 动画可能卡住 - -### 影响范围 - -**涉及文件:** -- `healthlink-his-server/healthlink-his-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationAdviceAppServiceImpl.java` — 后端手术分页查询实现(需加缓存) -- `healthlink-his-ui/src/views/inpatientDoctor/home/components/order/applicationForm/surgery.vue` — 前端手术申请单组件(需修复 loading 状态) - -**涉及数据表:** -- `wor_activity_definition` — 活动定义表(手术项目源表),10,102条手术记录 -- `adm_charge_item_definition` — 收费项定义表(定价关联) - -## 修复方案 - -### 后端:给 `getSurgeryPage` 添加 Redis 缓存 - -**改动文件:** `DoctorStationAdviceAppServiceImpl.java` - -1. 新增缓存键常量:`SURGERY_PAGE_CACHE_PREFIX = "surgery:page:"` -2. 在无搜索关键字时,尝试从 Redis 读取缓存 -3. 缓存未命中时,查询数据库后写入 Redis(24小时过期) -4. 有搜索关键字时不缓存(避免缓存爆炸) - -**改动量:** 约 20 行 - -### 前端:修复 `getList()` 缓存命中时的 loading 状态 - -**改动文件:** `surgery.vue` - -1. 在 `getList()` 方法中,当命中内存缓存时,显式设置 `loading.value = false` - -**改动量:** 1 行 - -## 验证计划 - -1. 编译验证 Java 代码 -2. 语法验证 Vue 文件:`node --check surgery.vue` -3. 手动验证:登录医生工作站,打开手术申请单,观察加载速度(首次应有loading,二次打开应秒开) diff --git a/BUG_472_ANALYSIS.md b/BUG_472_ANALYSIS.md deleted file mode 100644 index a0c378da9..000000000 --- a/BUG_472_ANALYSIS.md +++ /dev/null @@ -1,65 +0,0 @@ -# Bug #472 深度分析报告 - -## 标题 -住院医生工作站-手术申请单:勾选手术项目无效,导致无法正常开立医嘱 - -## 根因分析 - -### 问题链路 -1. 当前分支将手术项目数据源从 `getApplicationList` 改为专用接口 `getSurgeryPage` -2. `getSurgeryPage` 的 SQL 查询使用 `LEFT JOIN adm_charge_item_definition t2` 关联价格表 -3. **关键问题**:SQL 中缺少 `DISTINCT ON (t1.ID)` 去重逻辑 -4. 如果某个手术项目在 `adm_charge_item_definition` 表中有**多条匹配的价格记录**(如不同状态、不同时间点),LEFT JOIN 会产生**多行重复记录**,具有相同的 `advice_definition_id` -5. 前端 `mapToTransferItem` 将这些重复记录映射为 el-transfer 数据项,所有重复项的 `key` 相同 -6. el-transfer 组件内部使用 key 进行 Vue 的列表渲染追踪。当多个 item 拥有相同的 key 时,Vue 的 diff 算法无法正确追踪哪些 item 被选中/取消选中,导致**点击复选框无响应** - -### 对比工作正常的代码 -旧版 `getAdviceBaseInfo` SQL(仍在工作)中明确使用了 `DISTINCT ON (T1.ID)` 去重: -```sql -SELECT DISTINCT ON (T1.ID) ... -``` - -新版 `getSurgeryPage` SQL 遗漏了这个去重逻辑。 - -## 影响范围 -- **前端**:`surgery.vue` — el-transfer 复选框交互异常 -- **后端 SQL**:`DoctorStationAdviceAppMapper.xml` — getSurgeryPage 查询缺少去重 -- **数据库表**:`wor_activity_definition`(手术项目定义)、`adm_charge_item_definition`(价格定义) -- **同类问题**:`getExaminationPage` 查询也存在相同缺陷 - -## 修复方案 - -### 1. 后端 SQL 修复(根因修复) -在 `DoctorStationAdviceAppMapper.xml` 的 `getSurgeryPage` 和 `getExaminationPage` 查询中添加 `DISTINCT ON (t1.ID)`: -- `DISTINCT ON (t1.ID)` 确保每个手术/检查项目只返回一行 -- PostgreSQL 的 DISTINCT ON 按 t1.ID 去重,保留每个组的第一行 - -### 2. 前端防御性修复(加固) -- `applicationList` 初始化为 `ref([])` 而非 `ref()`(避免 undefined) -- `mapToTransferItem` 添加 `adviceDefinitionId` 空值保护 - -## 验证计划 -1. 修改 SQL 后,进入住院医生工作站 → 手术申请单 -2. 确认"未选择"列表中每个手术项目只显示一次(无重复) -3. 点击复选框,项目应被正确选中并移入"已选择"列表 -4. 点击确认按钮,应成功开立手术申请 - ---- - -## 修复结果 - -**修复策略**:策略A(直接修复代码逻辑) - -**根因修复**: -- SQL `getSurgeryPage` 和 `getExaminationPage` 添加 `DISTINCT ON (t1.ID)` 去重 -- ORDER BY 调整为 `t1.ID, t1.name ASC, t2.ID ASC`(DISTINCT ON 要求 ORDER BY 首列必须与 DISTINCT ON 一致) - -**前端加固**: -- `applicationList` 初始化为 `ref([])` 而非 `ref()` -- 数据映射前过滤 `adviceDefinitionId != null` 的脏数据 - -**改动量**:2文件,8行增,6行删 -- `DoctorStationAdviceAppMapper.xml`:+4/-4(DISTINCT ON + ORDER BY 调整) -- `surgery.vue`:+4/-2(初始化空数组 + 空值过滤) - -**修复结果:✅ 成功,8行改动** diff --git a/BUG_497_ANALYSIS.md b/BUG_497_ANALYSIS.md deleted file mode 100644 index 203b744ae..000000000 --- a/BUG_497_ANALYSIS.md +++ /dev/null @@ -1,60 +0,0 @@ -# Bug #497 分析报告 - -## 标题 -【住院医生工作站-检查申请】检查申请列表缺失"申请单状态"列及全流程闭环状态流转逻辑 - -## 根因分析 - -### 问题描述 -检查申请列表的"申请单状态"列始终显示"待签发",无法正确反映护士校对、医技接单、报告生成等临床节点状态。 - -### 根因定位 -`doc_request_form.status` 列在数据库中存在(INTEGER, 默认值 0),但全链路没有任何代码更新它: - -1. **实体层**: `RequestForm` 领域实体(`RequestForm.java`)**没有 `status` 字段** → 保存时无法设置 -2. **服务层**: `saveRequestForm()` / `withdrawRequestForm()` 方法从未修改 `doc_request_form.status` -3. **查询层**: SQL 查询直接 SELECT `drf.status` → 始终返回默认值 0 -4. **前端层**: `parseStatus(0)` → 始终返回"待签发" - -实际业务状态由 `wor_service_request.status_enum` 管理(使用 `RequestStatus` 枚举:DRAFT=1, ACTIVE=2, COMPLETED=3, CANCELLED=5, COMPLETED_REPORT=8),但查询未利用这些数据。 - -### 修复方案 -1. **SQL 层**: 在 `getRequestForm` 查询中通过 LEFT JOIN `wor_service_request` 聚合其 `status_enum` 值,用 CASE 表达式动态计算申请单状态 -2. **实体层**: 给 `RequestForm.java` 添加 `status` 字段以完善领域模型 -3. **前端层**: 已有状态列、筛选器、操作按钮,无需修改 - -### 状态映射 -| ServiceRequest.status_enum | 前端显示状态 | 代码值 | -|---|---|---| -| DRAFT (1) | 待签发 | 0 | -| ACTIVE (2) | 已签发 | 1 | -| COMPLETED (3) | 已检查 | 5 | -| COMPLETED_REPORT (8) | 已出报告 | 6 | -| CANCELLED (5) | 已作废 | 7 | - -中间状态(已校对=2、待接收=3、已接收=4)由护理/医技等外部系统管理,本代码范围不涉及。 - -### 涉及文件 -- `healthlink-his-server/healthlink-his-application/src/main/resources/mapper/regdoctorstation/RequestFormManageAppMapper.xml` -- `healthlink-his-server/openhis-domain/src/main/java/com/openhis/document/domain/RequestForm.java` - -## 修复结果 - -**结果**: ✅ 成功 -**改动行数**: +86/-49 (2个文件) - -### 具体修改 - -#### 1. RequestFormManageAppMapper.xml -- 将原查询包裹在子查询中 -- 用 `CASE WHEN EXISTS` 动态计算状态,替代静态 `drf.status` 列 -- 状态筛选从外层作用于 `computed_status` -- 移除了不必要的 GROUP BY(子查询中无聚合) - -#### 2. RequestForm.java -- 添加 `status` 字段,补全领域模型 - -### 验证 -- ✅ Java 编译通过(mvn compile -pl healthlink-his-application -am -DskipTests) -- ✅ XML 格式正确(ElementTree 解析成功) -- ✅ 改动量 > 3 行(+86/-49) diff --git a/BUG_522_ANALYSIS.md b/BUG_522_ANALYSIS.md deleted file mode 100644 index 796867a6a..000000000 --- a/BUG_522_ANALYSIS.md +++ /dev/null @@ -1,32 +0,0 @@ -# Bug #522 分析报告 - -## Bug 描述 -[住院护士站-三测单] 体征录入点击保存后缺乏执行反馈且窗口异常自动关闭 - -## 涉及文件 -- 前端: `healthlink-his-ui/src/views/inpatientNurse/tprChart/components/addTprDialog.vue` -- API: `healthlink-his-ui/src/views/inpatientNurse/tprChart/components/api.js` -- 父组件: `healthlink-his-ui/src/views/inpatientNurse/tprChart/index.vue` - -## 根因分析 - -### 问题1:弹窗异常自动关闭 — 根因 - -在 `addTprDialog.vue` 模板中,保存按钮使用了 `:disabled="buttonDisabled"`(第50行和第108行),但 **`buttonDisabled` 变量在整个 script setup 中从未声明**。 - -在 Vue 3 `