From 0f27e246a600faf0a7ffb52825b335aa88af927b Mon Sep 17 00:00:00 2001
From: hang <872297557@qq.com>
Date: Mon, 1 Sep 2025 16:39:10 +0800
Subject: [PATCH 1/9] =?UTF-8?q?=E5=8D=87=E7=BA=A7=E7=BC=BA=E9=99=B7?=
=?UTF-8?q?=E5=8C=85?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
IRaCIS.Core.Application/IRaCIS.Core.Application.csproj | 8 ++++----
.../Service/TrialSiteUser/TrialMaintenanceService.cs | 1 +
IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj | 6 +++---
IRaCIS.Core.Test/IRaCIS.Core.Test.csproj | 6 +++---
4 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj
index 2bdee0a79..bdb87f591 100644
--- a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj
+++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj
@@ -41,11 +41,11 @@
-
+
-
+
@@ -62,9 +62,9 @@
-
+
-
+
diff --git a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialMaintenanceService.cs b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialMaintenanceService.cs
index ed7b3aca8..25b4ed629 100644
--- a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialMaintenanceService.cs
+++ b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialMaintenanceService.cs
@@ -211,6 +211,7 @@ namespace IRaCIS.Core.Application.Service
//测试项目 可以加入 测试用户 或者内部正式用户
.WhereIf(trialType == TrialType.NoneOfficial, t => t.IdentityUser.IsTestUser == true || (t.IdentityUser.IsTestUser == false && t.IdentityUser.IsZhiZhun))
+ .Where(t => t.IdentityUser.Status == UserStateEnum.Enable && t.IsUserRoleDisabled == false)
.Where(t => userTypeEnums.Contains(t.UserTypeEnum))
.WhereIf(inQuery.UserTypeEnum != null, t => t.UserTypeEnum == inQuery.UserTypeEnum)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.UserRealName), t => t.IdentityUser.FullName.Contains(inQuery.UserRealName))
diff --git a/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj b/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj
index 12aa90fdc..d0b656afe 100644
--- a/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj
+++ b/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj
@@ -31,12 +31,12 @@
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj b/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj
index 01d324f8b..bb69e4176 100644
--- a/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj
+++ b/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj
@@ -50,10 +50,10 @@
-
-
+
+
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
From 9fa73705ba0fe950982a7d62b26c9d1f5c265cc8 Mon Sep 17 00:00:00 2001
From: he <109787524@qq.com>
Date: Wed, 3 Sep 2025 14:54:29 +0800
Subject: [PATCH 2/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Service/ReadingCalculate/MRECISTHCCCalculateService.cs | 2 ++
1 file changed, 2 insertions(+)
diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs
index 4a1c64ea1..b523e7948 100644
--- a/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs
+++ b/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs
@@ -823,6 +823,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
var tableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == taskinfo.TrialReadingCriterionId).ToListAsync();
foreach (var rowInfo in tableRowAnswers)
{
+ rowInfo.ReportMark = rowInfo.RowMark;
var question = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId && x.LesionType == rowInfo.LesionType).FirstOrDefaultAsync();
var organ = await _organInfoRepository.Where(x => x.Id == rowInfo.OrganInfoId).FirstOrDefaultAsync();
@@ -895,6 +896,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
// 添加 典型肝内病灶 默认值
tableRowAnswers.ForEach(x =>
{
+
var tableQuestion = tableQuestionList.Where(y => y.ReadingQuestionId == x.QuestionId && y.QuestionMark == QuestionMark.TypicalIntrahepaticLesion).FirstOrDefault();
if (tableQuestion != null)
{
From 25c5b32fa71bb4ff89bf7e3226fd4fb21ee4d937 Mon Sep 17 00:00:00 2001
From: he <109787524@qq.com>
Date: Wed, 3 Sep 2025 15:02:02 +0800
Subject: [PATCH 3/9] =?UTF-8?q?Revert=20"=E4=BF=AE=E6=94=B9"?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This reverts commit 9fa73705ba0fe950982a7d62b26c9d1f5c265cc8.
---
.../Service/ReadingCalculate/MRECISTHCCCalculateService.cs | 2 --
1 file changed, 2 deletions(-)
diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs
index b523e7948..4a1c64ea1 100644
--- a/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs
+++ b/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs
@@ -823,7 +823,6 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
var tableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == taskinfo.TrialReadingCriterionId).ToListAsync();
foreach (var rowInfo in tableRowAnswers)
{
- rowInfo.ReportMark = rowInfo.RowMark;
var question = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId && x.LesionType == rowInfo.LesionType).FirstOrDefaultAsync();
var organ = await _organInfoRepository.Where(x => x.Id == rowInfo.OrganInfoId).FirstOrDefaultAsync();
@@ -896,7 +895,6 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate
// 添加 典型肝内病灶 默认值
tableRowAnswers.ForEach(x =>
{
-
var tableQuestion = tableQuestionList.Where(y => y.ReadingQuestionId == x.QuestionId && y.QuestionMark == QuestionMark.TypicalIntrahepaticLesion).FirstOrDefault();
if (tableQuestion != null)
{
From fd5711a31d4733a0436f7d030dd7dfd63c764db3 Mon Sep 17 00:00:00 2001
From: hang <872297557@qq.com>
Date: Fri, 5 Sep 2025 10:51:41 +0800
Subject: [PATCH 4/9] =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E5=BD=B1=E5=83=8F?=
=?UTF-8?q?=E7=BB=B4=E6=8A=A4=E5=A4=84=E7=90=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
IRC.Core.SCP/IRC.Core.SCP.csproj | 2 +-
.../IRaCIS.Core.Application.csproj | 2 +-
.../IRaCIS.Core.Application.xml | 8 +
.../Common/TrialImageDownloadService.cs | 618 +++++++++++++++++-
4 files changed, 625 insertions(+), 5 deletions(-)
diff --git a/IRC.Core.SCP/IRC.Core.SCP.csproj b/IRC.Core.SCP/IRC.Core.SCP.csproj
index 084654c25..999a17361 100644
--- a/IRC.Core.SCP/IRC.Core.SCP.csproj
+++ b/IRC.Core.SCP/IRC.Core.SCP.csproj
@@ -19,7 +19,7 @@
-
+
true
diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj
index bdb87f591..790c4f8ed 100644
--- a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj
+++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj
@@ -53,7 +53,7 @@
-
+
diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
index 9bea1fdb8..66e61ea7a 100644
--- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
+++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
@@ -1118,6 +1118,14 @@
+
+
+
+ 下载已经删除的影像
+
+
+
+
医生文档关联关系维护
diff --git a/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs b/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs
index d06a9d8f3..ecb1b2a63 100644
--- a/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs
+++ b/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs
@@ -1,22 +1,30 @@
using DocumentFormat.OpenXml.EMMA;
+using DocumentFormat.OpenXml.Office2010.Excel;
+using DocumentFormat.OpenXml.Office2013.Drawing.ChartStyle;
using FellowOakDicom;
using FellowOakDicom.Imaging;
using FellowOakDicom.Imaging.Render;
using FellowOakDicom.IO.Buffer;
using IRaCIS.Core.Application.Helper;
+using IRaCIS.Core.Application.ViewModel;
+using IRaCIS.Core.Domain.Models;
using MassTransit;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
+using MiniExcelLibs;
using SharpCompress.Common;
using System;
using System.Collections.Generic;
+using System.Data;
+using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
using static IRaCIS.Core.Domain.Share.StaticData;
+using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
namespace IRaCIS.Core.Application.Service
{
@@ -243,11 +251,12 @@ namespace IRaCIS.Core.Application.Service
///
[HttpGet]
[AllowAnonymous]
- public async Task DownloadAndUploadTrialData(Guid trialId, [FromServices] IRepository _instanceRepository,
+ public async Task DownloadAndUploadTrialData(Guid trialId,
+ [FromServices] IRepository _instanceRepository,
[FromServices] IRepository _studyRepository,
[FromServices] IRepository _seriesRepository)
{
- var list = await _instanceRepository.Where(t => t.TrialId == trialId && t.SubjectVisitId == Guid.Parse("01000000-0a00-0242-bd20-08dcce543ded" ) && t.DicomStudy.ModalityForEdit == "IVUS")
+ var list = await _instanceRepository.Where(t => t.TrialId == trialId && t.SubjectVisitId == Guid.Parse("01000000-0a00-0242-bd20-08dcce543ded") && t.DicomStudy.ModalityForEdit == "IVUS")
.Select(t => new { t.SeriesId, t.StudyId, t.Id, t.Path }).ToListAsync();
int totalCount = list.Count;
@@ -288,7 +297,7 @@ namespace IRaCIS.Core.Application.Service
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Id,
u => new DicomInstance()
{
- IsEncapsulated= syntax.IsEncapsulated,
+ IsEncapsulated = syntax.IsEncapsulated,
TransferSytaxUID = dirInfo.TransferSytaxUID,
SOPClassUID = dirInfo.SOPClassUID,
MediaStorageSOPClassUID = dirInfo.MediaStorageSOPClassUID,
@@ -334,6 +343,609 @@ namespace IRaCIS.Core.Application.Service
return ResponseOutput.Ok();
}
+
+ ///
+ /// 维护dir 需求新增的字段
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task TrialImageAddExtralField(Guid trialId,
+ [FromServices] IRepository _instanceRepository,
+ [FromServices] IRepository _studyRepository,
+ [FromServices] IRepository _seriesRepository)
+ {
+ // UPDATE DicomStudy
+ //SET DicomStudyDate = CONVERT(char(8), StudyTime, 112), --yyyyMMdd
+ // DicomStudyTime = REPLACE(CONVERT(char(8), StudyTime, 108), ':', ''); --HHmmss
+ // where DicomStudyDate = ''
+
+
+ //instance 找到传输语法为空的,然后分组
+ var seriesList = _instanceRepository.Where(t => t.TrialId == trialId && t.TransferSytaxUID == "")
+ //按照序列 和 NumberOfFrames 分组
+ .GroupBy(t => new { t.NumberOfFrames, t.SeriesId })
+ // 每个分组 取数据最小的一条
+ .Select(g => new { g.Key.SeriesId, g.Key.NumberOfFrames, g.OrderBy(t => t.FileSize).First().Path }).ToList();
+
+ foreach (var item in seriesList)
+ {
+ var stream = await _oSSService.GetStreamFromOSSAsync(item.Path);
+
+ var dicomFile = DicomFile.Open(stream);
+
+ var pixelData = DicomPixelData.Create(dicomFile.Dataset);
+
+ //获取像素是否为封装形式
+ var syntax = dicomFile.Dataset.InternalTransferSyntax;
+
+ //读取需要维护的值
+ var transferSyntaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty);
+ var mediaStorageSOPClassUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty);
+ var mediaStorageSOPInstanceUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty);
+ var sOPClassUID = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty);
+
+ //维护序列层级四个字段 后再用sql 维护study series 时间拆分 和 MediaStorageSOPInstanceUID
+ await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.SeriesId == item.SeriesId, t => new DicomInstance()
+ {
+ IsEncapsulated = syntax.IsEncapsulated,
+ TransferSytaxUID = transferSyntaxUID,
+ MediaStorageSOPClassUID = mediaStorageSOPClassUID,
+ SOPClassUID = sOPClassUID,
+ });
+
+ }
+
+ return ResponseOutput.Ok();
+
+ }
+
+
+ ///
+ /// 下载已经删除的影像
+ ///
+ ///
+ ///
+ [HttpPost]
+ [AllowAnonymous]
+ public async Task DownloadDeleteTrialImage(Guid trialId)
+ {
+ trialId = Guid.Parse("01000000-ac13-0242-6397-08dcd2d2a091");
+
+ var downloadInfo = _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => new
+ {
+ t.ResearchProgramNo,
+
+ VisitList = t.SubjectVisitList
+ .Select(sv => new
+ {
+ TrialSiteCode = sv.TrialSite.TrialSiteCode,
+ SubjectCode = sv.Subject.Code,
+ VisitName = sv.VisitName,
+ StudyList = sv.StudyList.Select(u => new
+ {
+ u.PatientId,
+ u.StudyTime,
+ u.StudyCode,
+
+ SeriesList = u.SeriesList.Select(z => new
+ {
+ z.Modality,
+ z.SeriesNumber,
+
+ InstancePathList = z.DicomInstanceList.Where(t => t.IsDeleted == true || t.DicomSerie.IsDeleted == true || t.IsReading == false || t.DicomSerie.IsReading == false).Select(k => new
+ {
+ k.Path,
+ k.FileSize
+ }).ToList()
+ })
+
+ }).ToList()
+ }).ToList()
+
+ }).FirstOrDefault();
+
+
+ var filesizes = downloadInfo.VisitList.SelectMany(t => t.StudyList).SelectMany(t => t.SeriesList).SelectMany(t => t.InstancePathList).Sum(t => t.FileSize);
+ var count2 = downloadInfo.VisitList.SelectMany(t => t.StudyList).SelectMany(t => t.SeriesList).SelectMany(t => t.InstancePathList).Count();
+
+ Console.WriteLine($"下载总数量:{count2},总大小{filesizes}");
+
+ if (downloadInfo != null)
+ {
+ var downloadJobs = new List<(string Path, Func Job)>();
+
+ var rootFolder = @"E:\DownloadImage";
+
+ //var rootFolder = FileStoreHelper.GetDonwnloadImageFolder(_hostEnvironment);
+
+ // 获取无效字符(系统定义的)
+ string invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
+
+ // 用正则表达式替换所有非法字符为下划线或空字符
+ string pattern = $"[{Regex.Escape(invalidChars)}]";
+
+ var regexNo = Regex.Replace(downloadInfo.ResearchProgramNo, pattern, "_");
+
+ // 创建一个临时文件夹来存放文件
+ string trialFolderPath = Path.Combine(rootFolder, $"{regexNo}_{NewId.NextGuid()}");
+ Directory.CreateDirectory(trialFolderPath);
+
+ foreach (var visitItem in downloadInfo.VisitList)
+ {
+ if (visitItem.StudyList.Count() == 0)
+ {
+ continue;
+ }
+
+ #region 处理 中心,受试者dicom non-dicom 文件夹层级
+
+ //var siteFolderPath = Path.Combine(trialFolderPath, visitItem.TrialSiteCode);
+ //if (!Directory.Exists(siteFolderPath))
+ //{
+ // Directory.CreateDirectory(siteFolderPath);
+ //}
+
+ #endregion
+
+
+ foreach (var studyInfo in visitItem.StudyList)
+ {
+ // 遍历 Series
+ foreach (var seriesInfo in studyInfo.SeriesList)
+ {
+ string studyDicomFolderPath = Path.Combine(trialFolderPath, $"{visitItem.SubjectCode}_{visitItem.VisitName}", $"{studyInfo.StudyCode}_{studyInfo.StudyTime?.ToString("yyyy-MM-dd")}", $"{seriesInfo.SeriesNumber}");
+
+ // 创建 影像 文件夹
+ Directory.CreateDirectory(studyDicomFolderPath);
+
+ // 遍历 InstancePathList
+ foreach (var instanceInfo in seriesInfo.InstancePathList)
+ {
+ // 复制文件到相应的文件夹
+ string destinationPath = Path.Combine(studyDicomFolderPath, Path.GetFileName(instanceInfo.Path));
+
+
+ //加入到下载任务里
+ downloadJobs.Add((instanceInfo.Path, () => _oSSService.DownLoadFromOSSAsync(instanceInfo.Path, destinationPath)));
+
+ //下载到当前目录
+ //await _oSSService.DownLoadFromOSSAsync(instanceInfo.Path, destinationPath);
+ }
+ }
+
+
+ }
+ }
+
+ #region 异步方式处理
+
+ int totalCount = downloadJobs.Count;
+ int downloadedCount = 0;
+
+ // 在 trialFolderPath 下面放一个失败记录文件
+ string failedLogPath = Path.Combine(trialFolderPath, "failed_downloads.txt");
+
+ // 确保文件存在(如果之前有就清空)
+ File.WriteAllText(failedLogPath, "");
+
+ foreach (var job in downloadJobs)
+ {
+ try
+ {
+ await job.Job();
+ }
+ catch (Exception ex)
+ {
+
+
+ string errorMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 下载失败: {job.Path}, 错误: {ex.Message}\r\n";
+
+ Console.WriteLine(errorMessage);
+
+ await File.AppendAllTextAsync(failedLogPath, errorMessage);
+ }
+
+ downloadedCount++;
+
+ // 每处理50个,输出一次进度(或最后一个时也输出)
+ if (downloadedCount % 50 == 0 || downloadedCount == totalCount)
+ {
+ Console.WriteLine($"已下载 {downloadedCount} / {totalCount} 个文件,完成 {(downloadedCount * 100.0 / totalCount):F2}%");
+ }
+ }
+ #endregion
+
+ #region 多线程测试
+
+ //const int batchSize = 15;
+ //int totalCount = downloadJobs.Count;
+ //int downloadedCount = 0;
+
+ //for (int i = 0; i < downloadJobs.Count; i += batchSize)
+ //{
+ // var batch = downloadJobs.Skip(i).Take(batchSize).Select(job => job());
+
+ // await Task.WhenAll(batch);
+
+ // downloadedCount += batch.Count();
+
+ // Console.WriteLine($"已下载 {downloadedCount} / {totalCount} 个文件,完成 {(downloadedCount * 100.0 / totalCount):F2}%");
+ //}
+ #endregion
+
+ }
+
+ return ResponseOutput.Ok();
+
+
+ }
+
+
+ [AllowAnonymous]
+ public async Task ReadDicomDataWriteDB([FromServices] IRepository _instanceRepository)
+ {
+ var testPath = @"E:\WXT001";
+ var path = @"E:\WXT001";
+
+ var files = Directory.GetFiles(testPath, "*", SearchOption.AllDirectories)
+ // 只要没有后缀(Windows 显示类型是 .file)
+ .Where(f => string.IsNullOrEmpty(Path.GetExtension(f)))
+ .Where(f => Guid.TryParse(Path.GetFileNameWithoutExtension(f), out _))
+ .ToList();
+
+ Console.WriteLine($"找到 {files.Count} 个 DICOM 文件");
+
+ int total = files.Count;
+ int processed = 0;
+ double lastPercent = 0;
+
+ var options = new ParallelOptions { MaxDegreeOfParallelism = 12 };
+
+ // 输出文件路径
+ var outputFile = Path.Combine(@"D:\dicomWrite", $"{Guid.NewGuid()}_dicom_info.txt");
+
+ var outputErrorFile = Path.Combine(@"D:\dicomWrite", $"{Guid.NewGuid()}_dicom_info_error.txt");
+
+ // 用并发安全的写法(锁保护)
+ var fileLock = new object();
+
+ foreach (var file in files)
+ {
+ try
+ {
+ var id = Guid.Parse(Path.GetFileNameWithoutExtension(file));
+ var dicomFile = DicomFile.Open(file);
+
+ var dataset = dicomFile.Dataset;
+ var fileMeta = dicomFile.FileMetaInfo;
+ var syntax = dataset.InternalTransferSyntax;
+
+
+
+ //单位 设备 PatientId Visit 检查UId 帧数
+
+ var stationName = dataset.GetSingleValueOrDefault(DicomTag.StationName, string.Empty);
+
+ var institutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty);
+
+ var manufacturer = dataset.GetSingleValueOrDefault(DicomTag.Manufacturer, string.Empty);
+
+ //PatientID TrialCode_SubjectCode
+ //var patientID = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
+
+ //SubjectCode
+ var clinicalTrialSubjectID = dataset.GetSingleValueOrDefault(DicomTag.ClinicalTrialSubjectID, string.Empty);
+ //访视visitNum
+ var clinicalTrialTimePointID = dataset.GetSingleValueOrDefault(DicomTag.ClinicalTrialTimePointID, string.Empty);
+ var studyInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty);
+ var seriesInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty);
+ var sOPInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty);
+
+ var numberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 1);
+
+
+ // 传输语法
+ var transferSyntaxUID = fileMeta.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty);
+ var sOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty);
+ var mediaStorageSOPClassUID = fileMeta.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty);
+
+ var mediaStorageSOPInstanceUID = fileMeta.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty);
+
+
+ // 拼接一行 CSV 格式
+ var line = string.Join(",",
+ id,
+ stationName,
+ institutionName,
+ manufacturer,
+ clinicalTrialSubjectID,
+ clinicalTrialTimePointID,
+ studyInstanceUID,
+ seriesInstanceUID,
+ sOPInstanceUID,
+ numberOfFrames,
+ transferSyntaxUID,
+ sOPClassUID,
+ mediaStorageSOPClassUID,
+ mediaStorageSOPInstanceUID
+
+ );
+
+
+ await File.AppendAllTextAsync(outputFile, line + Environment.NewLine);
+
+ await _instanceRepository.BatchUpdateNoTrackingAsync(
+ t => t.Id == id,
+ t => new DicomInstance
+ {
+ IsEncapsulated = syntax.IsEncapsulated,
+ TransferSytaxUID = transferSyntaxUID,
+ MediaStorageSOPClassUID = mediaStorageSOPClassUID,
+ SOPClassUID = sOPClassUID,
+ MediaStorageSOPInstanceUID = mediaStorageSOPInstanceUID
+ }, false);
+ }
+ catch (Exception ex)
+ {
+ var errorMsg = $"{DateTime.Now}❌ {file} 解析失败: {ex.Message}";
+ Console.WriteLine(errorMsg);
+
+ await File.AppendAllTextAsync(outputErrorFile, errorMsg + Environment.NewLine);
+ }
+ finally
+ {
+ var done = Interlocked.Increment(ref processed);
+ double percent = done * 100.0 / total;
+
+ // 只在进度提升 >= 1% 时打印
+ if (percent - lastPercent >= 5.0 || done == total)
+ {
+ lastPercent = percent;
+ Console.WriteLine($"{DateTime.Now} 进度: {done}/{total} ({percent:F2}%)");
+ }
+ }
+
+ }
+
+
+
+
+
+
+ return ResponseOutput.Ok();
+ }
+
+ #region 维护已经下载本地的数据
+
+ [AllowAnonymous]
+ public async Task ReadExcelData([FromServices] IRepository _instanceRepository)
+ {
+ var rows = await MiniExcel.QueryAsync(@"C:\Users\hang\Desktop\维护数据读取.xlsx");
+
+ rows = rows.Where(t => !string.IsNullOrEmpty(t.InstanceId.ToString())).ToList();
+
+ var outputErrorFile = Path.Combine(@"D:\dicomWrite", $"{Guid.NewGuid()}_dicom_info_error.txt");
+
+ foreach (var item in rows)
+ {
+
+
+ try
+ {
+ await _instanceRepository.BatchUpdateNoTrackingAsync(
+ t => t.Id == item.InstanceId,
+ t => new DicomInstance
+ {
+ IsEncapsulated = item.IsEncapsulated,
+ TransferSytaxUID = item.TransferSyntaxUID,
+ MediaStorageSOPClassUID = item.MediaStorageSOPClassUID,
+ SOPClassUID = item.SOPClassUID,
+ MediaStorageSOPInstanceUID = item.MediaStorageSOPInstanceUID
+ }, false);
+ }
+ catch (Exception ex)
+ {
+
+ var errorMsg = $"{item.InstanceId} {DateTime.Now} 更新失败: {ex.Message}";
+ Console.WriteLine(errorMsg);
+
+ await File.AppendAllTextAsync(outputErrorFile, errorMsg + Environment.NewLine);
+ }
+
+
+ }
+
+
+
+
+ return ResponseOutput.Ok();
+ }
+
+ public class DicomSOPInfo
+ {
+ public Guid InstanceId { get; set; }
+
+
+ public string TransferSyntaxUID { get; set; }
+
+ public string SOPClassUID { get; set; }
+
+ public string MediaStorageSOPClassUID { get; set; }
+
+ public string MediaStorageSOPInstanceUID { get; set; }
+
+ public bool IsEncapsulated => DicomTransferSyntax.Lookup(DicomUID.Parse(TransferSyntaxUID)).IsEncapsulated;
+
+
+
+ }
+
+ #endregion
+
+
+ #region 通过Excel 读取未下载的,边下载边维护数据
+
+ [AllowAnonymous]
+ public async Task WriteNeedDealData([FromServices] IRepository _instanceRepository)
+ {
+
+ #region 获取差集数据
+ //var rows = await MiniExcel.QueryAsync(@"C:\Users\hang\Desktop\维护数据读取.xlsx");
+
+ //rows = rows.Where(t => !string.IsNullOrEmpty(t.InstanceId.ToString())).ToList();
+
+ //var allRows = await MiniExcel.QueryAsync(@"C:\Users\hang\Desktop\AllData.xlsx");
+
+ //allRows = allRows.Where(t => !string.IsNullOrEmpty(t.InstanceId.ToString())).ToList();
+
+ //var needDealRows = allRows.Where(t => !rows.Select(c => c.InstanceId).Contains(t.InstanceId)).ToList();
+
+ //var outputFile = Path.Combine(@"D:\dicomWrite", $"{Guid.NewGuid()}_dicom_info.txt");
+
+ //foreach (var item in needDealRows)
+ //{
+ // var line = string.Join(",", item.InstanceId, item.Path);
+
+ // await File.AppendAllTextAsync(outputFile, line + Environment.NewLine);
+ //}
+
+ #endregion
+
+ var folder = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment);
+
+ var needDealRows = await MiniExcel.QueryAsync(Path.Combine(folder, "needDownload.xlsx"));
+
+ needDealRows = needDealRows.Where(t => !string.IsNullOrEmpty(t.InstanceId.ToString())).ToList();
+
+
+
+ var outputFile = Path.Combine(folder, $"{Guid.NewGuid()}_dicom_info.txt");
+
+ var outputErrorFile = Path.Combine(folder, $"{Guid.NewGuid()}_dicom_info_error.txt");
+
+ int total = needDealRows.Count();
+
+ Console.WriteLine($"需要处理数量{total}");
+
+ int processed = 0;
+ double lastPercent = 0;
+
+ foreach (var item in needDealRows)
+ {
+
+ try
+ {
+ await using var stream = await _oSSService.GetStreamFromOSSAsync(item.Path);
+
+ var dicomFile = DicomFile.Open(stream);
+
+ var dataset = dicomFile.Dataset;
+ var fileMeta = dicomFile.FileMetaInfo;
+
+ var pixelData = DicomPixelData.Create(dicomFile.Dataset);
+
+ //获取像素是否为封装形式
+ var syntax = dicomFile.Dataset.InternalTransferSyntax;
+
+ var stationName = dataset.GetSingleValueOrDefault(DicomTag.StationName, string.Empty);
+
+ var institutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty);
+
+ var manufacturer = dataset.GetSingleValueOrDefault(DicomTag.Manufacturer, string.Empty);
+
+ //PatientID TrialCode_SubjectCode
+ //var patientID = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
+
+ //SubjectCode
+ var clinicalTrialSubjectID = dataset.GetSingleValueOrDefault(DicomTag.ClinicalTrialSubjectID, string.Empty);
+ //访视visitNum
+ var clinicalTrialTimePointID = dataset.GetSingleValueOrDefault(DicomTag.ClinicalTrialTimePointID, string.Empty);
+ var studyInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty);
+ var seriesInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty);
+ var sOPInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty);
+
+ var numberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 1);
+
+
+ // 传输语法
+ var transferSyntaxUID = fileMeta.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty);
+ var sOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty);
+ var mediaStorageSOPClassUID = fileMeta.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty);
+
+ var mediaStorageSOPInstanceUID = fileMeta.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty);
+
+
+ var line = string.Join(",",
+ item.InstanceId,
+ stationName,
+ institutionName,
+ manufacturer,
+ clinicalTrialSubjectID,
+ clinicalTrialTimePointID,
+ studyInstanceUID,
+ seriesInstanceUID,
+ sOPInstanceUID,
+ numberOfFrames,
+ transferSyntaxUID,
+ sOPClassUID,
+ mediaStorageSOPClassUID,
+ mediaStorageSOPInstanceUID
+
+ );
+
+
+ await File.AppendAllTextAsync(outputFile, line + Environment.NewLine);
+
+ //维护序列层级四个字段 后再用sql 维护study series 时间拆分 和 MediaStorageSOPInstanceUID
+ await _instanceRepository.BatchUpdateNoTrackingAsync(
+ t => t.Id == item.InstanceId,
+ t => new DicomInstance
+ {
+ IsEncapsulated = syntax.IsEncapsulated,
+ TransferSytaxUID = transferSyntaxUID,
+ MediaStorageSOPClassUID = mediaStorageSOPClassUID,
+ SOPClassUID = sOPClassUID,
+ MediaStorageSOPInstanceUID = mediaStorageSOPInstanceUID
+ }, false);
+ }
+ catch (Exception ex)
+ {
+
+ var errorMsg = $"{DateTime.Now}❌ 失败: {ex.Message}";
+ Console.WriteLine(errorMsg);
+
+ await File.AppendAllTextAsync(outputErrorFile, errorMsg + Environment.NewLine);
+ }
+ finally
+ {
+ processed++;
+ double percent = processed * 100.0 / total;
+
+ // 每提升 5% 或完成时输出
+ if (percent - lastPercent >= 5.0 || processed == total)
+ {
+ lastPercent = percent;
+ Console.WriteLine($"{DateTime.Now} 进度: {processed}/{total} ({percent:F2}%)");
+ }
+ }
+
+
+ }
+
+ return ResponseOutput.Ok();
+ }
+
+ public class NeedDealInstanceInfo
+ {
+ public Guid InstanceId { get; set; }
+
+ public string Path { get; set; }
+ }
+ #endregion
}
}
\ No newline at end of file
From 7f1232e2ff455fe4aab6d60d3dfa91004b0baa3e Mon Sep 17 00:00:00 2001
From: hang <872297557@qq.com>
Date: Fri, 5 Sep 2025 11:07:58 +0800
Subject: [PATCH 5/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=BE=93=E5=87=BA?=
=?UTF-8?q?=E6=97=A5=E5=BF=97=E5=B1=95=E7=A4=BA=E5=85=B7=E4=BD=93=E5=87=BA?=
=?UTF-8?q?=E9=97=AE=E9=A2=98=E7=9A=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Service/Common/TrialImageDownloadService.cs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs b/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs
index ecb1b2a63..07c6b41a6 100644
--- a/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs
+++ b/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs
@@ -915,7 +915,8 @@ namespace IRaCIS.Core.Application.Service
catch (Exception ex)
{
- var errorMsg = $"{DateTime.Now}❌ 失败: {ex.Message}";
+ var errorMsg = $"{DateTime.Now} ❌ 失败: {ex.Message} | InstanceId={item.InstanceId}, Path={item.Path}";
+
Console.WriteLine(errorMsg);
await File.AppendAllTextAsync(outputErrorFile, errorMsg + Environment.NewLine);
@@ -926,7 +927,7 @@ namespace IRaCIS.Core.Application.Service
double percent = processed * 100.0 / total;
// 每提升 5% 或完成时输出
- if (percent - lastPercent >= 5.0 || processed == total)
+ if (percent - lastPercent >= 2.0 || processed == total)
{
lastPercent = percent;
Console.WriteLine($"{DateTime.Now} 进度: {processed}/{total} ({percent:F2}%)");
From 0be5763ce39f5a13d17fc7419a777e05c34a3c82 Mon Sep 17 00:00:00 2001
From: hang <872297557@qq.com>
Date: Fri, 5 Sep 2025 15:14:36 +0800
Subject: [PATCH 6/9] =?UTF-8?q?IRC=E5=AF=BC=E5=87=BA=E6=94=AF=E6=8C=81?=
=?UTF-8?q?=E6=96=B0=E6=A0=87=E5=87=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Service/Common/ExcelExportService.cs | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/IRaCIS.Core.Application/Service/Common/ExcelExportService.cs b/IRaCIS.Core.Application/Service/Common/ExcelExportService.cs
index 34331fd2a..ece094738 100644
--- a/IRaCIS.Core.Application/Service/Common/ExcelExportService.cs
+++ b/IRaCIS.Core.Application/Service/Common/ExcelExportService.cs
@@ -135,7 +135,7 @@ namespace IRaCIS.Core.Application.Service.Common
QuestionAnswerList = g.Select(t => new QCQuestionAnswerExport() { Answer = t.Answer, QuestionName = t.QuesitonName, ShowOrder = t.ShowOrder, QuestionId = t.QuestionId }).OrderBy(t => t.ShowOrder).ToList()
- }).OrderBy(t => t.TrialSiteCode).ThenBy(t => t.SubjectCode).ThenBy(t => t.VisitNum).ThenBy(t=>t.CurrentQCEnum).ThenBy(t=>t.AuditTime).ToList();
+ }).OrderBy(t => t.TrialSiteCode).ThenBy(t => t.SubjectCode).ThenBy(t => t.VisitNum).ThenBy(t => t.CurrentQCEnum).ThenBy(t => t.AuditTime).ToList();
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
@@ -2898,7 +2898,8 @@ namespace IRaCIS.Core.Application.Service.Common
{
#region 外层问题处理
- if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB || criterion.CriterionType == CriterionType.IRECIST1Point1)
+ if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
+ || criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC)
{
fistLeveLNameList = trialConfigQuestionList.Select(t => new DynamicColumnConfig.ColumItem()
@@ -2941,7 +2942,8 @@ namespace IRaCIS.Core.Application.Service.Common
var extralNameList = new List();
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
- || criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
+ || criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC
+ || criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
{
//if(inQuery.ReadingExportType == ExportResult.DetailedTableOfLesions)
@@ -2982,7 +2984,8 @@ namespace IRaCIS.Core.Application.Service.Common
var addLessionInfoList = new List();
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
- || criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
+ || criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC
+ || criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
{
//病灶编号 和病灶类型没有配置,但是需要有的
addLessionInfoList.Add(new CommonQuesionInfo() { QuestionName = _userInfo.IsEn_Us ? "Lesion ID" : "病灶编号", QuestionValue = lession.LessionCode });
@@ -3022,7 +3025,8 @@ namespace IRaCIS.Core.Application.Service.Common
#endregion
#region 不管是list 还是taskList 最终处理的数据都是list 处理好数据后合并
- if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB || criterion.CriterionType == CriterionType.IRECIST1Point1)
+ if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
+ || criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC)
{
//针对1.1 整体肿瘤评估 有的两列要合并一列
foreach (var item in list)
From 2e3c209de24c58c40c655dfba8bc9dc455105bf4 Mon Sep 17 00:00:00 2001
From: hang <872297557@qq.com>
Date: Mon, 8 Sep 2025 10:40:54 +0800
Subject: [PATCH 7/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=8E=E5=A4=84?=
=?UTF-8?q?=E7=90=86=E4=B8=8A=E4=BC=A0=E6=A3=80=E6=9F=A5bug?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../IRaCIS.Core.Application.xml | 10 -
.../Service/Common/ExcelExportService.cs | 255 ------------------
.../ImageAndDoc/DownloadAndUploadService.cs | 2 +-
3 files changed, 1 insertion(+), 266 deletions(-)
diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
index 66e61ea7a..f6eb43710 100644
--- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
+++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
@@ -957,16 +957,6 @@
-
-
- 一致性分析结果导出 7 8 分别是自身 和组件一致性
-
-
-
-
-
-
-
获取阅片标准可以导出的列表
diff --git a/IRaCIS.Core.Application/Service/Common/ExcelExportService.cs b/IRaCIS.Core.Application/Service/Common/ExcelExportService.cs
index ece094738..614c90328 100644
--- a/IRaCIS.Core.Application/Service/Common/ExcelExportService.cs
+++ b/IRaCIS.Core.Application/Service/Common/ExcelExportService.cs
@@ -2311,263 +2311,8 @@ namespace IRaCIS.Core.Application.Service.Common
#region 通用阅片结果导出
- ///
- /// 一致性分析结果导出 7 8 分别是自身 和组件一致性
- ///
- ///
- ///
- ///
- ///
- ///
- [HttpPost]
- public async Task GetAnalysisTaskList_Export(VisitTaskQuery inQuery,
- [FromServices] IRepository _commonDocumentRepository,
- [FromServices] IDictionaryService _dictionaryService,
- [FromServices] IRepository _trialRepository)
- {
- //每次查询必须是单标准的
- var criterion = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId).Select(t => new { t.CriterionType, t.CriterionName, t.ArbitrationRule }).FirstNotNullAsync();
- var query = _visitTaskRepository.Where(t => t.TrialId == inQuery.TrialId && t.TaskAllocationState == TaskAllocationState.Allocated && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze))
-
- //一致性分析
- .WhereIf(inQuery.ReadingExportType == ExportResult.DetailedTableOfIntraReaderAnalysisResults, t => t.IsSelfAnalysis == true || t.IsSelfAnalysis == null)
- .WhereIf(inQuery.ReadingExportType == ExportResult.DetailedTableOfIntraReaderAnalysisResults, t => t.IsSelfAnalysis == null ? t.Subject.SubjectVisitTaskList.Any(u => u.IsSelfAnalysis == true && u.VisitTaskNum == t.VisitTaskNum && u.DoctorUserId == t.DoctorUserId && u.TrialReadingCriterionId == t.TrialReadingCriterionId) : true)
- .WhereIf(inQuery.ReadingExportType == ExportResult.DetailedTableOfInterReaderAnalysisResults, t => t.IsSelfAnalysis == false || t.IsSelfAnalysis == null)
-
- //访视和全局查询已签名完成的,裁判可以是未签名,未完成的
- .Where(t => (t.ReadingTaskState == ReadingTaskState.HaveSigned && (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global)) || t.ReadingCategory == ReadingCategory.Judge)
- .WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
- .WhereIf(inQuery.TrialSiteId != null, t => t.Subject.TrialSiteId == inQuery.TrialSiteId)
-
- .WhereIf(inQuery.IsUrgent != null, t => t.IsUrgent == inQuery.IsUrgent)
- .WhereIf(inQuery.DoctorUserId != null, t => t.DoctorUserId == inQuery.DoctorUserId)
- .WhereIf(inQuery.ReadingCategory != null, t => t.ReadingCategory == inQuery.ReadingCategory)
- //.WhereIf(inQuery.ReadingTaskState != null, t => t.ReadingTaskState == inQuery.ReadingTaskState)
- .WhereIf(inQuery.TaskAllocationState != null, t => t.TaskAllocationState == inQuery.TaskAllocationState)
- .WhereIf(inQuery.ArmEnum != null, t => t.ArmEnum == inQuery.ArmEnum)
- .WhereIf(!string.IsNullOrEmpty(inQuery.TrialSiteCode), t => (t.BlindTrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate) || (t.Subject.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode!) && t.IsAnalysisCreate == false))
- .WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.TaskName.Contains(inQuery.TaskName) || t.TaskBlindName.Contains(inQuery.TaskName))
- .WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => t.Subject.Code.Contains(inQuery.SubjectCode))
- .WhereIf(inQuery.BeginAllocateDate != null, t => t.AllocateTime > inQuery.BeginAllocateDate)
- .WhereIf(inQuery.EndAllocateDate != null, t => t.AllocateTime < inQuery.EndAllocateDate);
-
- var list = await query.ProjectTo(_mapper.ConfigurationProvider,
- new
- {
- readingExportType = inQuery.ReadingExportType,
- criterionType = criterion.CriterionType,
- trialReadingCriterionId = inQuery.TrialReadingCriterionId,
- isEn_Us = _userInfo.IsEn_Us
- }).ToListAsync();
-
- list = list.OrderBy(t => t.SubjectCode).ThenBy(t => t.ArmEnum).ThenBy(t => t.VisitTaskNum).ToList();
-
-
- var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
- exportInfo.CriterionName = criterion.CriterionName;
-
- #region 处理系统标准存在疾病和整体肿瘤合并
-
- //如果是以合并后的找翻译字典,会少,所以必须放在前面
- var translateDicNameList = list.SelectMany(t => t.QuestionAnswerList).Where(t => t.TranslateDicName.IsNotNullOrEmpty()).Select(t => t.TranslateDicName).Distinct().ToList();
-
- //针对1.1 整体肿瘤评估 有的两列要合并一列
- if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB || criterion.CriterionType == CriterionType.IRECIST1Point1)
- {
- foreach (var item in list)
- {
- //处理合并表头
-
- var questionType = item.IsBaseline == true ? QuestionType.ExistDisease : QuestionType.Tumor;
-
- var findItem = item.QuestionAnswerList.Where(t => t.QuestionType == questionType).FirstOrDefault();
-
- if (findItem != null)
- {
- findItem.QuestionName = _userInfo.IsEn_Us ? "Overall Response" : "整体肿瘤评估";
- }
-
-
- if (item.IsBaseline == true)
- {
- item.QuestionAnswerList = item.QuestionAnswerList.Where(t => t.QuestionType != QuestionType.Tumor).ToList();
- }
- else
- {
- item.QuestionAnswerList = item.QuestionAnswerList.Where(t => t.QuestionType != QuestionType.ExistDisease).ToList();
- }
- }
- }
- else if (criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
- {
-
- foreach (var item in list)
- {
- //处理合并表头
-
- var questionType = item.IsBaseline == true ? QuestionType.ExistDisease : QuestionType.ImgOncology;
-
- var findItem = item.QuestionAnswerList.Where(t => t.QuestionType == questionType).FirstOrDefault();
-
- if (findItem != null)
- {
- findItem.QuestionName = _userInfo.IsEn_Us ? "Overall Response" : "整体肿瘤评估";
- }
-
- if (item.IsBaseline == true)
- {
- item.QuestionAnswerList = item.QuestionAnswerList.Where(t => t.QuestionType != QuestionType.ImgOncology).ToList();
- }
- else
- {
- item.QuestionAnswerList = item.QuestionAnswerList.Where(t => t.QuestionType != QuestionType.ExistDisease).ToList();
- }
- }
- }
- else if (criterion.CriterionType == CriterionType.PCWG3)
- {
-
- }
- else if (criterion.CriterionType == CriterionType.SelfDefine)
- {
- //自定义的又问题名称重复 所以统一加上组名
-
- //有重复的就加,没有重复的就不加
- if (list.Any(t => t.QuestionAnswerList.Select(t => t.QuestionName).Count() != t.QuestionAnswerList.Select(t => t.QuestionName).Distinct().Count()))
- {
- foreach (var item in list)
- {
- foreach (var qs in item.QuestionAnswerList)
- {
- qs.QuestionName = qs.Group + "_" + qs.QuestionName;
- }
- }
- }
-
-
- }
-
- #endregion
-
- var export_Template = StaticData.Export.TrialSelfAnalysisList_Export;
-
- #region 自身一致性分析和组间一致性分析
-
- if (inQuery.ReadingExportType == ExportResult.DetailedTableOfIntraReaderAnalysisResults)
- {
- //找到非一致性分析的任务
- var selfExportList = list.Where(t => t.IsSelfAnalysis == null).ToList();
-
- //处理一致性分析结果是否和原始阅片是否一致
- foreach (var item in selfExportList)
- {
- //找到一致性分析的结果
- var selfAnalysisTask = list.Where(t => t.IsSelfAnalysis == true && t.SubjectCode == item.SubjectCode && t.VisitTaskNum == item.VisitTaskNum && t.TaskName == t.TaskName && t.UserName == item.UserName).FirstOrDefault();
-
- //将自身一致性分析的字段 赋值到访视任务这个字段
- item.IsAnalysisDiffToOriginalData = selfAnalysisTask?.IsAnalysisDiffToOriginalData;
-
- //处理再次阅片人的结果
- if (selfAnalysisTask != null)
- {
- var cloneQuestionAnswerList = selfAnalysisTask.QuestionAnswerList.Clone();
-
- foreach (var qItem in cloneQuestionAnswerList)
- {
- qItem.QuestionName = qItem.QuestionName + $"{(_userInfo.IsEn_Us ? "(Again)" : "(再次)")}";
- }
-
- item.QuestionAnswerList = item.QuestionAnswerList.Union(cloneQuestionAnswerList).ToList();
- }
- }
-
- list = selfExportList;
- }
- else
- {
- export_Template = StaticData.Export.TrialGroupAnalysisList_Export;
-
- var newList = new List();
-
- foreach (var group in list.GroupBy(t => new { t.SubjectCode, t.VisitTaskNum, t.TaskName }).OrderBy(g => g.Key.SubjectCode).ThenBy(g => g.Key.VisitTaskNum))
- {
- var subjectVisitGroupList = group.ToList();
-
-
- //找到当前访视组间一致性分析的任务结果
-
- var groupOtherTaskList = subjectVisitGroupList.Where(t => t.IsSelfAnalysis == false).ToList();
-
- foreach (var subjectVisitTaskArm in subjectVisitGroupList.Where(t => t.IsSelfAnalysis == null).OrderBy(t => t.ArmEnum))
- {
- foreach (var otherTask in groupOtherTaskList)
- {
- //非一致性分析任务
- var cloneObj = subjectVisitTaskArm.Clone();
-
- var otherTaskQuestionAnserList = otherTask.QuestionAnswerList.Clone();
-
- foreach (var qItem in otherTaskQuestionAnserList)
- {
- qItem.QuestionName = qItem.QuestionName + $"{(_userInfo.IsEn_Us ? "(Again)" : "(再次)")}";
- }
-
- //处理 再次阅片人,再次阅片人角色 两列
- var addQuestionList = new List();
-
- addQuestionList.Add(new CommonQuesionInfo() { QuestionName = _userInfo.IsEn_Us ? "Reviwer(Again)" : "阅片人(再次)", QuestionValue = otherTask.UserName });
- addQuestionList.Add(new CommonQuesionInfo() { QuestionName = _userInfo.IsEn_Us ? "Reviwer Role(Again)" : "阅片人角色(再次)", QuestionValue = ((int)otherTask.ArmEnum).ToString(), TranslateDicName = "ArmEnum" });
-
-
- cloneObj.QuestionAnswerList = cloneObj.QuestionAnswerList.Union(addQuestionList).Union(otherTaskQuestionAnserList).ToList();
-
-
- cloneObj.IsGroupAnalysisDiffToOriginalData = cloneObj.ArmEnum == Arm.DoubleReadingArm1 ? otherTask.IsGroupDiffArm1 : otherTask.IsGroupDiffArm2;
-
- newList.Add(cloneObj);
- }
- }
- }
- translateDicNameList.Add("ArmEnum");
-
- list = newList;
-
- }
-
- #endregion
-
- var columNameList = list.SelectMany(t => t.QuestionAnswerList).Where(t => t.QuestionName.IsNotNullOrEmpty()).Select(t => t.QuestionName).Distinct().ToList();
-
- exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list.Where(t => t.ReadingCategory != ReadingCategory.Global).ToList(), _userInfo.TimeZoneId);
- exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
-
- var dynamicColumnConfig = new DynamicColumnConfig()
- {
- //可读的列表名行索引,不是{{}} 模板行索引
- AutoColumnTitleRowIndex = 2,
- AutoColumnStartIndex = 5,
- TempalteLastColumnIndex = 4,
- DynamicItemDicName = "TranslateDicName",
- DynamicItemValueName = "QuestionValue",
- DynamicItemTitleName = "QuestionName",
- DynamicListName = "QuestionAnswerList",
- RemoveColunmIndexList = new List() { },
- ColumnIdNameList = columNameList.Select(t => new DynamicColumnConfig.ColumItem() { Id = Guid.Empty, Name = t }).ToList(),
- TranslateDicNameList = translateDicNameList ?? new List()
- };
-
-
- var (memoryStream, fileName) = await ExcelExportHelper.DataExport_NpoiTestAsync(export_Template, exportInfo, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(AnalysisDynamicCommonExport), criterion.CriterionType, dynamicColumnConfig);
-
- return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
- {
- FileDownloadName = $"{exportInfo.ResearchProgramNo}_{exportInfo.CriterionName}_{fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
- };
-
- }
-
///
/// 获取阅片标准可以导出的列表
diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs
index 21c9dd018..7be3b0487 100644
--- a/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs
+++ b/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs
@@ -435,7 +435,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
studyMonitor.RecordPath = incommand.RecordPath;
studyMonitor.FileSize = incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize);
- var studyId = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString());
+ var studyId = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString(), visiTaskId.ToString());
var findStudy = await _taskStudyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
From 270941431d40c6beb70424a48f292a5246d30b5c Mon Sep 17 00:00:00 2001
From: hang <872297557@qq.com>
Date: Tue, 9 Sep 2025 09:04:43 +0800
Subject: [PATCH 8/9] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=8E=E5=A4=84?=
=?UTF-8?q?=E7=90=86=E4=B8=8A=E4=BC=A0=E7=BB=9F=E8=AE=A1instance=E6=95=B0?=
=?UTF-8?q?=E9=87=8F=20=E5=92=8Cseries=E6=95=B0=E9=87=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ImageAndDoc/DownloadAndUploadService.cs | 44 ++++++++++++-------
1 file changed, 28 insertions(+), 16 deletions(-)
diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs
index 7be3b0487..7e185716c 100644
--- a/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs
+++ b/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs
@@ -471,7 +471,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
}
- study.Id = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString(), visiTaskId.ToString());
+ study.Id = studyId;
study.TrialId = incommand.TrialId;
study.SubjectId = incommand.SubjectId;
study.VisitTaskId = visiTaskId;
@@ -568,29 +568,41 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
//新的序列 那么 检查的序列数量+1
findStudy.SeriesCount += 1;
}
- else
- {
- //该序列掉了instance
- dicomSeries.InstanceCount += seriesItem.InstanceList.Count;
- }
+ //else
+ //{
+ // //该序列掉了instance
+ // dicomSeries.InstanceCount += seriesItem.InstanceList.Count;
+ //}
+
+ //找到该序列已经存在的instanceId
+ var existInstanceIdList = _taskInstanceRepository.Where(t => t.SeriesId == dicomSeries.Id).Select(t => t.Id).ToList();
foreach (var instanceItem in seriesItem.InstanceList)
{
var insntance = _mapper.Map(instanceItem);
- insntance.Id = IdentifierHelper.CreateGuid(insntance.StudyInstanceUid, insntance.SeriesInstanceUid, insntance.SopInstanceUid, trialId.ToString(), visiTaskId.ToString());
- insntance.StudyId = findStudy.Id;
- insntance.SeriesId = dicomSeries.Id;
- insntance.TrialId = incommand.TrialId;
- insntance.SubjectId = incommand.SubjectId;
- insntance.VisitTaskId = visiTaskId;
+ var instanceId = IdentifierHelper.CreateGuid(insntance.StudyInstanceUid, insntance.SeriesInstanceUid, insntance.SopInstanceUid, trialId.ToString(), visiTaskId.ToString());
+
+
+ if (!existInstanceIdList.Any(t => t == instanceId))
+ {
+ insntance.Id = instanceId;
+ insntance.StudyId = findStudy.Id;
+ insntance.SeriesId = dicomSeries.Id;
+
+ insntance.TrialId = incommand.TrialId;
+ insntance.SubjectId = incommand.SubjectId;
+ insntance.VisitTaskId = visiTaskId;
+
+ await _taskInstanceRepository.AddAsync(insntance);
+
+ dicomSeries.InstanceCount++;
+ findStudy.InstanceCount++;
+ }
- await _taskInstanceRepository.AddAsync(insntance);
}
-
-
// 不管是新的序列 还是 该序列 掉了Instance 重传的时候 检查的instance 数量都会增加
- findStudy.InstanceCount += seriesItem.InstanceList.Count;
+ //findStudy.InstanceCount += seriesItem.InstanceList.Count;
}
From 49a36b8214e4fcbf20b0dfaf69ad7b14d5e7afb6 Mon Sep 17 00:00:00 2001
From: hang <872297557@qq.com>
Date: Wed, 10 Sep 2025 15:43:04 +0800
Subject: [PATCH 9/9] =?UTF-8?q?=E7=BB=B4=E6=8A=A4=E6=95=B0=E6=8D=AE?=
=?UTF-8?q?=E7=BB=93=E6=9D=9F=E6=8F=90=E4=BA=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Common/TrialImageDownloadService.cs | 105 ++++++++++++++++++
1 file changed, 105 insertions(+)
diff --git a/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs b/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs
index 07c6b41a6..5b4d1ef88 100644
--- a/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs
+++ b/IRaCIS.Core.Application/Service/Common/TrialImageDownloadService.cs
@@ -728,6 +728,10 @@ namespace IRaCIS.Core.Application.Service
rows = rows.Where(t => !string.IsNullOrEmpty(t.InstanceId.ToString())).ToList();
+ int total = rows.Count();
+ int processed = 0;
+ double lastPercent = 0;
+
var outputErrorFile = Path.Combine(@"D:\dicomWrite", $"{Guid.NewGuid()}_dicom_info_error.txt");
foreach (var item in rows)
@@ -740,6 +744,7 @@ namespace IRaCIS.Core.Application.Service
t => t.Id == item.InstanceId,
t => new DicomInstance
{
+
IsEncapsulated = item.IsEncapsulated,
TransferSytaxUID = item.TransferSyntaxUID,
MediaStorageSOPClassUID = item.MediaStorageSOPClassUID,
@@ -755,7 +760,18 @@ namespace IRaCIS.Core.Application.Service
await File.AppendAllTextAsync(outputErrorFile, errorMsg + Environment.NewLine);
}
+ finally
+ {
+ processed++;
+ double percent = processed * 100.0 / total;
+ // 每提升 5% 或完成时输出
+ if (percent - lastPercent >= 2.0 || processed == total)
+ {
+ lastPercent = percent;
+ Console.WriteLine($"{DateTime.Now} 进度: {processed}/{total} ({percent:F2}%)");
+ }
+ }
}
@@ -782,6 +798,95 @@ namespace IRaCIS.Core.Application.Service
+ }
+
+
+ [AllowAnonymous]
+ public async Task ReadExcelImageDataInstanceIsReading([FromServices] IRepository _instanceRepository,
+ [FromServices] IRepository _seriesRepository,
+ [FromServices] IRepository _studyRepository)
+ {
+
+ var trialId = Guid.Parse("01000000-ac13-0242-6397-08dcd2d2a091");
+
+ var rows = await MiniExcel.QueryAsync(@"C:\Users\hang\Desktop\instanceReading.xlsx");
+
+ rows = rows.Where(t => !string.IsNullOrEmpty(t.SopInstanceUid) && t.SopInstanceUid.Length > 15).ToList();
+
+ var outputErrorFile = Path.Combine(@"D:\dicomWrite", $"{Guid.NewGuid()}_dicom_info_error.txt");
+
+
+ //foreach (var batch in rows.Chunk(20))
+ //{
+ // var sopUids = batch.Select(x => x.SopInstanceUid).ToList();
+
+ // try
+ // {
+ // await _instanceRepository.BatchUpdateNoTrackingAsync(
+ // t => sopUids.Contains(t.SopInstanceUid) && t.TrialId == trialId,
+ // t => new DicomInstance
+ // {
+ // IsReading = true,
+ // IsDeleted = false
+ // }, false);
+
+
+ // await _seriesRepository.BatchUpdateNoTrackingAsync(
+ // t => t.DicomInstanceList.Any(t => sopUids.Contains(t.SopInstanceUid)) && t.TrialId == trialId,
+ // t => new DicomSeries
+ // {
+ // IsReading = true,
+ // IsDeleted = false
+ // }, false);
+ // }
+ // catch (Exception ex)
+ // {
+ // var errorMsg = $"{string.Join(",", sopUids)} {DateTime.Now} 批量更新失败: {ex.Message}";
+ // Console.WriteLine(errorMsg);
+ // await File.AppendAllTextAsync(outputErrorFile, errorMsg + Environment.NewLine);
+ // }
+ //}
+
+ //找到该项目的检查,实时统计数量,并且回更数据库
+
+ var studyList = _studyRepository.Where(t => t.TrialId == trialId && (t.SeriesCount != t.SeriesList.Count() || t.InstanceCount != t.InstanceList.Count()))
+ .Select(t => new
+ {
+ t.Id,
+ t.StudyCode,
+ DBSeriesCount = t.SeriesCount,
+ DBInstanceCount = t.InstanceCount,
+
+ ActrualSeriesCount = t.SeriesList.Count(),
+
+ ActrualInstanceCount = t.InstanceList.Count(),
+
+ }).ToList();
+
+
+ var seriesList = _seriesRepository.Where(t => t.TrialId == trialId && t.InstanceCount != t.DicomInstanceList.Count())
+ .Select(t => new
+ {
+ SeriesId = t.Id,
+ t.DicomStudy.StudyCode,
+ DBInstanceCount = t.InstanceCount,
+ ActrualInstanceCount = t.DicomInstanceList.Count(),
+
+ }).ToList();
+
+
+ await File.AppendAllTextAsync(outputErrorFile, studyList.ToJsonStr() + Environment.NewLine);
+
+ await File.AppendAllTextAsync(outputErrorFile, seriesList.ToJsonStr() + Environment.NewLine);
+
+ return ResponseOutput.Ok();
+ }
+
+ public class DicomSOPInstanceInfo
+ {
+ public string SopInstanceUid { get; set; }
+
+
}
#endregion