Compare commits

...

5 Commits

Author SHA1 Message Date
关羽
5e41614fd0 Fix Bug #521: [住院医生站-临床医嘱-检查申请] 手工选择执行科室后,保存仍提示"未找到项目执行的科室"
根因:medicalExaminations.vue submit() 中 positionId 使用 item.positionId(项目默认科室),
忽略了用户在前端手动选择的 form.targetDepartment(发往科室)。
修复:positionId: form.targetDepartment || item.positionId,与 laboratoryTests.vue 修复模式一致。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 21:11:45 +08:00
关羽
fc803173fa Fix Bug #519: 保存诊断时误删cli_condition导致传染病报卡关联断裂
根因:deleteEncounterDiagnosisInfos() 调用 conditionMapper.deleteByEncounterId() 删除了
cli_condition 记录,而 infectious_card.diag_id 指向的就是 cli_condition.id。
数据库验证:infectious_card 表中 10 条记录仅 1 条能 JOIN 到 cli_condition,
其余 9 条的 condition 已被级联删除,导致再次保存诊断时 hasInfectiousReport=0,
前端未过滤已报卡诊断,重复弹出报卡界面。

修复:移除 conditionMapper.deleteByEncounterId(encounterId),仅删除就诊诊断关联记录。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 21:07:52 +08:00
赵云
e1b85de8ea Fix Bug #498: 补充修复结果到分析报告
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 20:17:20 +08:00
赵云
3a928afbc7 Fix Bug #498: 看报告功能参数名不匹配(prescriptionNo→encounterId),修复后端接口无法获取正确参数导致报告查询返回空列表的问题
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 20:16:43 +08:00
赵云
0d9b2879ac Fix Bug #498: 根因+修复方案摘要 2026-05-16 20:10:38 +08:00
5 changed files with 184 additions and 4 deletions

103
docs/bug494_analysis.md Normal file
View File

@@ -0,0 +1,103 @@
# Bug #494 分析报告
## Bug 描述
住院医生工作站-检查申请:"申请单名称"字段显示为通用名称"检查申请单",未展示具体检查项目名称。
## 代码分析
### 数据流
1. **保存时**medicalExaminations.vue → saveCheckd → RequestFormManageAppServiceImpl.saveRequestForm
- 前端传入 `name: selectedNames`(如 "B超常规检查"
- 后端保存到 `doc_request_form.name` 字段 ✅
2. **查询时**RequestFormManageAppMapper.xml → getRequestForm
- SQL 使用 COALESCE 子查询:优先从 `wor_service_request` 关联 `wor_activity_definition` 获取具体项目名称
- 如果子查询为空,回退到 `doc_request_form.name` 字段 ✅
3. **详情查询**RequestFormManageAppMapper.xml → getRequestFormDetail
-`wor_service_request` 关联 `wor_activity_definition` 获取 `advice_name`
4. **前端展示**examineApplication.vue → buildApplicationName
- 优先使用 `requestFormDetailList[0].adviceName`
- 回退到 `row.name`
- 最后回退到 `-`
### 数据库验证
对全部 21 条 type_code='23' 记录执行完整查询:
| 情况 | 记录数 | SQL 返回名称 | 前端展示 |
|------|--------|-------------|---------|
| 新数据 (JCZ开头)有服务请求name已填 | 2 | 正确(如"100单词听理解检查" | 正确 |
| 旧数据 (PAR开头)有服务请求name为"检查申请单" | 10 | 正确COALESCE 解析出实际名称) | 正确 |
| 旧数据有服务请求name为空 | 8 | 正确COALESCE 解析出实际名称) | 正确 |
| PAR00000009无服务请求name="检查申请单" | 1 | "检查申请单"(无服务请求可解析) | "检查申请单" |
### 根因
**仅 1 条记录PAR00000009存在问题**:该记录无任何关联的 `wor_service_request` 服务请求sr_count=0导致
- SQL COALESCE 子查询返回 NULL → 回退到 `drf.name` = "检查申请单"
- 详情查询返回空列表 → `buildApplicationName` 回退到 `row.name` = "检查申请单"
这条记录以 PAR 开头(非 JCZ是通过非标准路径创建的脏数据缺少关联的服务请求记录。
**其余 20 条记录95%)的 SQL COALESCE 已正确解析出具体项目名称**
### 修复方案
对于**无服务请求的孤儿申请单**,前端 `buildApplicationName` 函数已正确回退到 `row.name`。问题在于:
1. `row.name` 存储的是通用名称 "检查申请单"
2. 该记录没有关联的 service request无法从 activity_definition 解析具体名称
**修复方案:增强 SQL COALESCE 的容错性,对 desc_json 进行解析,提取申请单描述中的检查项目信息作为备选名称。**
但这不现实——desc_json 只包含表单字段(症状、体征等),不包含项目名称。
**更合理的修复:确保保存时 name 字段始终填入具体项目名称。**
检查 `medicalExaminations.vue` 的 submit 方法:
```js
const selectedNames = applicationListAllFilter.map(item => item.adviceName).join('+');
```
前端传入的 name 是用 `+` 拼接的多个项目名称。这个值被保存到 `doc_request_form.name`
SQL COALESCE 子查询使用 `STRING_AGG(DISTINCT wad.name, '、')`,用 `、` 分隔。
**问题确认:当 service request 存在但 activity_definition 已被删除时COALESCE 子查询返回 NULL回退到 drf.name。但 drf.name 可能为空或为"检查申请单"(旧数据)。**
对于这种 edge case**应该增强 SQL 容错**:当 `drf.name` 也为空或通用名称时,显示更友好的默认文本。
不过,**当前代码对绝大多数场景已经正确工作**。唯一显示"检查申请单"的是 PAR00000009 这条孤儿数据。
## 修复计划
增强前端 `buildApplicationName` 函数的容错性:
- 当 detailList 为空时,检查 `row.name` 是否为通用名称("检查申请单"
- 如果是,尝试从其他字段(如 desc_json提取有用信息
- 或者直接使用更明确的提示文本
但这只是对极端边缘情况的容错处理。根本问题是 PAR00000009 这条脏数据。
## 修复结果:✅ 已成功修复commit fd9309f1
### 修复内容3处改动30行
1. **后端 SQLRequestFormManageAppMapper.xml**
- 原:`drf.NAME` 直接取存储的名称
- 改:`COALESCE((SELECT STRING_AGG(DISTINCT wad.name, '、') FROM wor_service_request LEFT JOIN wor_activity_definition ...), drf.name)`
- 效果:优先从服务请求关联的诊疗定义中动态解析具体项目名称,回退到存储名称
2. **前端展示examineApplication.vue**
- 原:`<el-table-column prop="name" />` 直接显示 `name` 字段
- 改:使用 `buildApplicationName(scope.row)` 函数,优先使用 `requestFormDetailList[0].adviceName`
3. **前端提交medicalExaminations.vue**
- 增加 `adviceName: item.adviceName` 到提交数据中,确保后端能正确关联项目名称
### 数据库验证结果
全部 21 条 type_code='23' 记录中:
- 20 条95%SQL 正确返回具体项目名称(如 "B超常规检查"、"100单词听理解检查"
- 1 条PAR00000009无关联服务请求孤儿数据回退显示 "检查申请单"(符合预期)

78
docs/bug498_analysis.md Normal file
View File

@@ -0,0 +1,78 @@
# Bug #498 分析报告
## Bug 描述
【住院医生工作站-检查申请】检查申请列表操作项过于单一,缺失修改/作废/打印/看报告等核心临床操作
## 阶段1深度分析
### 当前代码状态
`examineApplication.vue` 的操作列lines 104-137已经实现了按状态动态展示按钮
- 待签发(0):详情 + 修改 + 删除
- 已签发(1):详情 + 撤回
- 已校对(2)/待接收(3):详情 + 打印
- 已接收(4)/已检查(5):详情 + 看报告
- 已出报告(6):详情 + 打印 + 看报告
- 已作废(7):详情
### 根因分析
**核心发现**前端按钮逻辑已完整实现但存在一个关键Bug导致"看报告"功能无法工作。
#### Bug`handleViewReport` 传递错误的参数
前端代码 (examineApplication.vue:920):
```js
const res = await getTestResult({ prescriptionNo: row.prescriptionNo });
```
后端接口 (DoctorStationAdviceController.java:190-192):
```java
@GetMapping(value = "/test-result")
public R<?> getTestResult(@RequestParam(value = "encounterId") Long encounterId) {
return iDoctorStationAdviceAppService.getTestResult(encounterId);
}
```
**问题**:前端传递 `prescriptionNo`,后端只接受 `encounterId`。Spring 忽略未知参数,`encounterId` 为 null后端直接返回空列表。
后端服务实现 (DoctorStationAdviceAppServiceImpl.java:2357-2376):
```java
public R<?> getTestResult(Long encounterId) {
if (encounterId == null) {
return R.ok(new ArrayList<>()); // encounterId为空时直接返回空列表
}
// ... 查询逻辑 ...
}
```
#### 数据流追踪
1. 前端 `handleViewReport(row)` → 获取 `row.prescriptionNo`
2. 调用 `getTestResult({ prescriptionNo: "JCZ26051600001" })`
3. 后端接收:`encounterId = null`(参数名不匹配,被忽略)
4. 后端返回空列表 → 前端显示"暂未生成报告"
### 修复方案
`handleViewReport` 中的参数从 `prescriptionNo` 改为 `encounterId`,使用 `row.encounterId``patientInfo.value.encounterId`
### 后端 API 完整性检查
| 操作 | 前端调用 | 后端接口 | 状态 |
|------|---------|---------|------|
| 修改 | saveCheckd → POST /save-check | saveRequestForm (支持编辑) | ✅ |
| 删除 | deleteRequestForm → POST /delete | deleteRequestForm (验证status=0) | ✅ |
| 撤回 | withdrawRequestForm → POST /withdraw | withdrawRequestForm (验证status=2) | ✅ |
| 打印 | 前端 window.open 打印 | 无后端依赖 | ✅ |
| 看报告 | getTestResult → GET /test-result | getTestResult(encounterId) | ❌ 参数名不匹配 |
## 修复结果:✅ 成功commit 3a928afb2行改动
### 修复内容
`examineApplication.vue:920` - 将 `handleViewReport` 中的请求参数从 `prescriptionNo` 改为 `encounterId`
```diff
- const res = await getTestResult({ prescriptionNo: row.prescriptionNo });
+ const res = await getTestResult({ encounterId: row.encounterId || patientInfo.value?.encounterId });
```
### 说明
- 操作列的动态按钮逻辑(修改/删除/撤回/打印/看报告)已在之前的提交中完整实现
- 本修复解决了"看报告"功能因参数名不匹配导致始终返回空数据的问题
- 其余操作(修改/删除/撤回/打印)的后端接口参数均正确匹配

View File

@@ -35,8 +35,7 @@ public class EncounterDiagnosisServiceImpl extends ServiceImpl<EncounterDiagnosi
*/ */
@Override @Override
public void deleteEncounterDiagnosisInfos(Long encounterId) { public void deleteEncounterDiagnosisInfos(Long encounterId) {
// 不删除中医 // 仅删除就诊诊断关联记录不删除cli_condition否则会导致传染病报卡diag_id失效
conditionMapper.deleteByEncounterId(encounterId);
baseMapper.deleteByEncounterId(encounterId); baseMapper.deleteByEncounterId(encounterId);
} }

View File

@@ -917,7 +917,7 @@ const handleViewReport = async (row) => {
reportLoading.value = true; reportLoading.value = true;
reportData.value = null; reportData.value = null;
try { try {
const res = await getTestResult({ prescriptionNo: row.prescriptionNo }); const res = await getTestResult({ encounterId: row.encounterId || patientInfo.value?.encounterId });
if (res.code === 200) { if (res.code === 200) {
if (res.data) { if (res.data) {
// 支持两种返回格式: // 支持两种返回格式:

View File

@@ -471,7 +471,7 @@ const submit = () => {
unitCode: item.unitCode || priceInfo.unitCode || '', unitCode: item.unitCode || priceInfo.unitCode || '',
unitPrice: item.price ?? priceInfo.price ?? 0, unitPrice: item.price ?? priceInfo.price ?? 0,
totalPrice: item.price ?? priceInfo.price ?? 0, totalPrice: item.price ?? priceInfo.price ?? 0,
positionId: item.positionId, positionId: form.targetDepartment || item.positionId, // 用户手动选择的发往科室优先于项目默认执行科室
ybClassEnum: item.ybClassEnum, ybClassEnum: item.ybClassEnum,
conditionId: item.conditionId, conditionId: item.conditionId,
encounterDiagnosisId: item.encounterDiagnosisId, encounterDiagnosisId: item.encounterDiagnosisId,