|
@@ -283,32 +283,50 @@ public class DicomServiceImpl implements DicomService {
|
|
|
log.info("找到已存在的检查记录,将更新: studyId={}, studyInstanceUid={}",
|
|
log.info("找到已存在的检查记录,将更新: studyId={}, studyInstanceUid={}",
|
|
|
studyInfo.getStudyId(), studyInfo.getStudyInstanceUid());
|
|
studyInfo.getStudyId(), studyInfo.getStudyInstanceUid());
|
|
|
|
|
|
|
|
- // 更新上传时间和文件路径
|
|
|
|
|
- studyInfo.setUploadTime(LocalDateTime.now());
|
|
|
|
|
- studyInfo.setUpdateTime(LocalDateTime.now());
|
|
|
|
|
-
|
|
|
|
|
- // 重新统计序列和图像数
|
|
|
|
|
- java.util.Set<Integer> uniqueSeriesNumbers = new java.util.HashSet<>();
|
|
|
|
|
- for (File file : studyFiles) {
|
|
|
|
|
- try {
|
|
|
|
|
- DicomParser.DicomData dicomData = DicomParser.parse(file);
|
|
|
|
|
- if (dicomData.getSeriesNumber() != null) {
|
|
|
|
|
- uniqueSeriesNumbers.add(dicomData.getSeriesNumber());
|
|
|
|
|
|
|
+ // 保存新文件到目录(内部按SOPInstanceUID去重:不存在的新增,已存在的覆盖)
|
|
|
|
|
+ saveStudyFiles(studyInstanceUid, studyFiles, institutionId);
|
|
|
|
|
+
|
|
|
|
|
+ // 根据目录中实际文件重新统计序列和图像数
|
|
|
|
|
+ String studyDirPath = DICOM_ROOT_PATH + studyInfo.getDicomFilePath();
|
|
|
|
|
+ File studyDir = new File(studyDirPath);
|
|
|
|
|
+ File[] allDicomFiles = studyDir.listFiles((dir, name) ->
|
|
|
|
|
+ name.toLowerCase().endsWith(".dcm") || name.toLowerCase().endsWith(".dicom"));
|
|
|
|
|
+
|
|
|
|
|
+ java.util.Set<String> allSeriesUids = new java.util.HashSet<>();
|
|
|
|
|
+ int totalImageCount = 0;
|
|
|
|
|
+ if (allDicomFiles != null) {
|
|
|
|
|
+ totalImageCount = allDicomFiles.length;
|
|
|
|
|
+ for (File file : allDicomFiles) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ DicomParser.DicomData dicomData = DicomParser.parse(file);
|
|
|
|
|
+ String seriesUid = dicomData.getSeriesInstanceUID();
|
|
|
|
|
+ if (seriesUid != null && !seriesUid.isEmpty()) {
|
|
|
|
|
+ allSeriesUids.add(seriesUid);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("解析文件失败: {}", file.getName(), e);
|
|
|
}
|
|
}
|
|
|
- } catch (Exception e) {
|
|
|
|
|
- log.warn("解析文件失败: {}", file.getName(), e);
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 更新统计信息
|
|
|
|
|
- int seriesCount = uniqueSeriesNumbers.size() > 0 ? uniqueSeriesNumbers.size() : 1;
|
|
|
|
|
- studyInfo.setSeriesCount(studyInfo.getSeriesCount() + seriesCount);
|
|
|
|
|
- studyInfo.setImageCount(studyInfo.getImageCount() + studyFiles.size());
|
|
|
|
|
|
|
+ // 更新统计信息(使用实际值,而非累加)
|
|
|
|
|
+ studyInfo.setSeriesCount(allSeriesUids.size() > 0 ? allSeriesUids.size() : 1);
|
|
|
|
|
+ studyInfo.setImageCount(totalImageCount);
|
|
|
|
|
+ studyInfo.setUploadTime(LocalDateTime.now());
|
|
|
|
|
+ studyInfo.setUpdateTime(LocalDateTime.now());
|
|
|
|
|
|
|
|
studyInfoMapper.updateById(studyInfo);
|
|
studyInfoMapper.updateById(studyInfo);
|
|
|
- log.info("更新检查记录: studyId={}, 新的seriesCount={}, 新的imageCount={}",
|
|
|
|
|
|
|
+ log.info("更新检查记录: studyId={}, seriesCount={}, imageCount={}",
|
|
|
studyInfo.getStudyId(), studyInfo.getSeriesCount(), studyInfo.getImageCount());
|
|
studyInfo.getStudyId(), studyInfo.getSeriesCount(), studyInfo.getImageCount());
|
|
|
|
|
|
|
|
|
|
+ // 重新异步解析序列详细信息
|
|
|
|
|
+ try {
|
|
|
|
|
+ dicomAsyncService.parseStudySeriesAsync(studyInfo.getStudyId());
|
|
|
|
|
+ log.info("已启动异步重新解析序列任务: studyId={}", studyInfo.getStudyId());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.error("启动异步解析失败: studyId={}", studyInfo.getStudyId(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
} else {
|
|
} else {
|
|
|
// 不存在,创建新记录
|
|
// 不存在,创建新记录
|
|
|
studyInfo = new StudyInfo();
|
|
studyInfo = new StudyInfo();
|
|
@@ -580,15 +598,58 @@ public class DicomServiceImpl implements DicomService {
|
|
|
|
|
|
|
|
log.info("创建study目录: {}", targetDirPath);
|
|
log.info("创建study目录: {}", targetDirPath);
|
|
|
|
|
|
|
|
- // 复制所有文件到目标目录
|
|
|
|
|
- for (File sourceFile : sourceFiles) {
|
|
|
|
|
- String fileId = IdUtil.simpleUUID();
|
|
|
|
|
- String targetFileName = fileId + ".dcm";
|
|
|
|
|
- Path targetPath = targetDir.resolve(targetFileName);
|
|
|
|
|
|
|
+ // 1. 扫描目录中已有文件,建立 SOPInstanceUID -> 文件路径 的映射
|
|
|
|
|
+ java.util.Map<String, File> existingSopMap = new java.util.HashMap<>();
|
|
|
|
|
+ File[] existingFiles = targetDir.toFile().listFiles((dir, name) ->
|
|
|
|
|
+ name.toLowerCase().endsWith(".dcm") || name.toLowerCase().endsWith(".dicom"));
|
|
|
|
|
+ if (existingFiles != null) {
|
|
|
|
|
+ for (File existingFile : existingFiles) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ DicomParser.DicomData data = DicomParser.parse(existingFile);
|
|
|
|
|
+ String sopUid = data.getSopInstanceUID();
|
|
|
|
|
+ if (sopUid != null && !sopUid.isEmpty()) {
|
|
|
|
|
+ existingSopMap.put(sopUid, existingFile);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("解析已有DICOM文件失败: {}", existingFile.getName(), e);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ log.info("目录中已有 {} 个DICOM文件", existingSopMap.size());
|
|
|
|
|
|
|
|
- Files.copy(sourceFile.toPath(), targetPath, StandardCopyOption.REPLACE_EXISTING);
|
|
|
|
|
- log.debug("复制文件: {} -> {}", sourceFile.getName(), targetFileName);
|
|
|
|
|
|
|
+ // 2. 处理新上传的文件:已存在的覆盖更新,不存在的新增
|
|
|
|
|
+ int newCount = 0, updateCount = 0;
|
|
|
|
|
+ for (File sourceFile : sourceFiles) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ DicomParser.DicomData dicomData = DicomParser.parse(sourceFile);
|
|
|
|
|
+ String sopUid = dicomData.getSopInstanceUID();
|
|
|
|
|
+
|
|
|
|
|
+ if (sopUid != null && existingSopMap.containsKey(sopUid)) {
|
|
|
|
|
+ // 已存在,覆盖更新
|
|
|
|
|
+ File existingFile = existingSopMap.get(sopUid);
|
|
|
|
|
+ Files.copy(sourceFile.toPath(), existingFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
|
|
|
+ log.debug("更新已有文件: sopInstanceUid={}, file={}", sopUid, existingFile.getName());
|
|
|
|
|
+ updateCount++;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 不存在,新增
|
|
|
|
|
+ String fileId = IdUtil.simpleUUID();
|
|
|
|
|
+ String targetFileName = fileId + ".dcm";
|
|
|
|
|
+ Path targetPath = targetDir.resolve(targetFileName);
|
|
|
|
|
+ Files.copy(sourceFile.toPath(), targetPath, StandardCopyOption.REPLACE_EXISTING);
|
|
|
|
|
+ log.debug("新增文件: sopInstanceUid={}, file={}", sopUid, targetFileName);
|
|
|
|
|
+ newCount++;
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ // 解析失败的文件仍然保存
|
|
|
|
|
+ String fileId = IdUtil.simpleUUID();
|
|
|
|
|
+ String targetFileName = fileId + ".dcm";
|
|
|
|
|
+ Path targetPath = targetDir.resolve(targetFileName);
|
|
|
|
|
+ Files.copy(sourceFile.toPath(), targetPath, StandardCopyOption.REPLACE_EXISTING);
|
|
|
|
|
+ log.warn("解析失败,直接保存: {}", sourceFile.getName(), e);
|
|
|
|
|
+ newCount++;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ log.info("文件处理完成: 新增={}, 更新={}", newCount, updateCount);
|
|
|
|
|
|
|
|
return relativePath;
|
|
return relativePath;
|
|
|
}
|
|
}
|
|
@@ -1507,11 +1568,13 @@ public class DicomServiceImpl implements DicomService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 按实例号排序
|
|
|
|
|
- imageList.sort(Comparator.comparing(
|
|
|
|
|
- com.zskk.qcns.modules.dicom.vo.StudyImageVO::getInstanceNumber,
|
|
|
|
|
- Comparator.nullsLast(Integer::compareTo)
|
|
|
|
|
- ));
|
|
|
|
|
|
|
+ // 按序列号和实例号排序(先按序列分组,再按实例号排序)
|
|
|
|
|
+ imageList.sort(Comparator
|
|
|
|
|
+ .comparing(com.zskk.qcns.modules.dicom.vo.StudyImageVO::getSeriesNumber,
|
|
|
|
|
+ Comparator.nullsLast(Integer::compareTo))
|
|
|
|
|
+ .thenComparing(com.zskk.qcns.modules.dicom.vo.StudyImageVO::getInstanceNumber,
|
|
|
|
|
+ Comparator.nullsLast(Integer::compareTo))
|
|
|
|
|
+ );
|
|
|
|
|
|
|
|
log.info("获取检查图像成功: studyId={}, imageCount={}", studyId, imageList.size());
|
|
log.info("获取检查图像成功: studyId={}, imageCount={}", studyId, imageList.size());
|
|
|
return imageList;
|
|
return imageList;
|