# study_info 表 body_part 字段多部位拼接功能 ## 修改说明 ### 功能描述 修改了 `study_info` 表的 `body_part` 字段解析逻辑,支持多部位拼接。 - **单部位检查:** 保存单个部位,例如 `CHEST` - **多部位检查:** 使用 "+" 连接多个部位,例如 `CHEST+ABDOMEN` 或 `胸部+膝关节` --- ## 修改位置 ### 批量上传方法(主要修改) **文件:** `DicomServiceImpl.java:320-378` **修改内容:** #### 修改前(错误) ```java // 只使用第一个文件的部位 studyInfo.setBodyPart(firstDicomData.getBodyPartExamined()); ``` **问题:** 如果上传了胸部+腹部的片子,但第一个文件是胸部的,那么 `body_part` 字段就只会保存 `CHEST`,丢失了腹部信息。 #### 修改后(正确) ```java // 在循环中收集所有文件的部位 java.util.Set uniqueBodyParts = new java.util.LinkedHashSet<>(); for (File file : studyFiles) { DicomParser.DicomData dicomData = DicomParser.parse(file); // 收集所有部位 if (dicomData.getBodyPartExamined() != null && !dicomData.getBodyPartExamined().trim().isEmpty()) { uniqueBodyParts.add(dicomData.getBodyPartExamined().trim()); log.debug("文件 {} 解析到部位: {}", file.getName(), dicomData.getBodyPartExamined()); } } // 使用 "+" 连接多个部位 String bodyPart = null; if (!uniqueBodyParts.isEmpty()) { bodyPart = String.join("+", uniqueBodyParts); log.info("最终解析的检查部位: {} (来源: {} 个文件)", bodyPart, uniqueBodyParts.size()); } else { // 如果没有解析到部位,使用第一个文件的部位 bodyPart = firstDicomData.getBodyPartExamined(); log.warn("未能从文件中解析到部位,使用第一个文件的值: {}", bodyPart); } studyInfo.setBodyPart(bodyPart); ``` --- ## 实现细节 ### 1. 数据收集 使用 `LinkedHashSet` 收集所有文件的 `body_part_examined`: - **自动去重** - Set 自动去重,避免重复部位 - **保持顺序** - LinkedHashSet 保持插入顺序 ### 2. 拼接逻辑 ```java bodyPart = String.join("+", uniqueBodyParts); ``` **示例:** | 文件数 | 收集到的部位 | 最终保存的 body_part | |-------|-------------|---------------------| | 1 | `[CHEST]` | `CHEST` | | 2 | `[CHEST, ABDOMEN]` | `CHEST+ABDOMEN` | | 3 | `[CHEST, ABDOMEN, PELVIS]` | `CHEST+ABDOMEN+PELVIS` | | 5 | `[CHEST, CHEST, ABDOMEN, ABDOMEN, PELVIS]` | `CHEST+ABDOMEN+PELVIS` (去重后) | --- ## 数据对照表 ### study_info 表(检查级别) | 字段 | 说明 | 示例值 | |------|------|--------| | `exam_item_name` | 检查项目名称(拼接) | `胸部CT+腹部CT+盆部CT` | | `body_part` | **检查部位(拼接)** ⭐ | `CHEST+ABDOMEN+PELVIS` | ### series_info 表(片子级别) | 字段 | 说明 | 示例值 | |------|------|--------| | `exam_item_name` | 检查项目名称(单张片子) | `胸部CT` | | `body_part_examined` | **检查部位(单张片子)** | `CHEST` | **关系说明:** - `study_info` 是聚合信息(汇总整个检查) - `series_info` 是明细信息(每张片子) --- ## 多部位影像示例 ### 上传场景 上传3个文件: 1. `chest.dcm` - 部位:CHEST 2. `abdomen.dcm` - 部位:ABDOMEN 3. `pelvis.dcm` - 部位:PELVIS ### 保存结果 #### study_info 表(检查汇总) ``` study_id: STY001 exam_item_name: 胸部CT+腹部CT+盆部CT body_part: CHEST+ABDOMEN+PELVIS ✅ 拼接后的结果 ``` #### series_info 表(片子明细) ``` | sop_instance_uid | body_part_examined | exam_item_name | |------------------|-------------------|------------------| | uid_001 | CHEST | 胸部CT | | uid_002 | ABDOMEN | 腹部CT | | uid_003 | PELVIS | 盆部CT | ``` --- ## 日志输出 ### 单部位检查 ``` INFO - 文件 001.dcm 解析到部位: CHEST INFO - 最终解析的检查部位: CHEST (来源: 1 个文件) ``` ### 多部位检查 ``` DEBUG - 文件 chest.dcm 解析到部位: CHEST DEBUG - 文件 abdomen.dcm 解析到部位: ABDOMEN DEBUG - 文件 pelvis.dcm 解析到部位: PELVIS INFO - 最终解析的检查部位: CHEST+ABDOMEN+PELVIS (来源: 3 个文件) ``` ### 无法解析部位(降级处理) ``` WARN - 未能从文件中解析到部位,使用第一个文件的值: CHEST ``` --- ## 兼容性说明 ### 单文件上传 **文件:** `DicomServiceImpl.java:578` 单文件上传保持原有逻辑: ```java studyInfo.setBodyPart(dicomData.getBodyPartExamined()); ``` **原因:** 单文件上传只有一个文件,不需要拼接,直接使用该文件的部位即可。 ### 重复上传 重复上传不会影响 `body_part` 字段,只更新 `dicom_file_path`、`upload_time` 和 `update_time`。 --- ## 字段映射关系 | 数据来源 | study_info 字段 | series_info 字段 | |---------|-----------------|-------------------| | 文件1部位 | CHEST+ABDOMEN (拼接) | CHEST | | 文件2部位 | CHEST+ABDOMEN (拼接) | ABDOMEN | | 文件3部位 | CHEST+ABDOMEN (拼接) | PELVIS | --- ## 测试建议 ### 测试1:单部位检查 ```bash # 上传单部位文件(如胸部CT) # 预期结果:body_part = CHEST ``` ### 测试2:多部位检查 ```bash # 上传多部位文件(胸部+腹部+盆部) # 预期结果:body_part = CHEST+ABDOMEN+PELVIS ``` ### 测试3:验证数据 ```sql SELECT study_id, body_part, exam_item_name, image_count FROM study_info WHERE study_id = 'STY001'; SELECT instance_number, body_part_examined, exam_item_name FROM series_info WHERE study_id = 'STY001' ORDER BY instance_number; ``` **预期结果:** - `study_info.body_part` 应该是拼接后的值(如 `CHEST+ABDOMEN`) - `series_info.body_part_examined` 每条记录应该是单个部位(如 `CHEST` 或 `ABDOMEN`) --- ## 总结 ### 核心改进 1. ✅ 批量上传时收集所有文件的部位 2. ✅ 自动去重(使用 Set) 3. ✅ 使用 "+" 连接多个部位 4. ✅ 与 `exam_item_name` 字段的处理逻辑保持一致 5. ✅ 日志记录详细的解析过程 ### 数据一致性 - `study_info.body_part` - 聚合信息(所有部位拼接) - `series_info.body_part_examined` - 明细信息(单张片子的部位) ### 效果 现在多部位影像的 `body_part` 字段能正确显示为 `胸部+膝关节` 这样的格式,而不是只显示第一个部位的值! **重启应用后重新上传文件,即可看到正确的多部位信息!** 🎉