From 6389919cfdde6f10f706c147ca68855dee397c58 Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Tue, 19 Mar 2024 08:58:45 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=BD=92=E6=A1=A3=E9=A2=84=E5=A4=84?= =?UTF-8?q?=E7=90=861?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IRaCIS.Core.Application.xml | 20 +- .../Service/ImageAndDoc/CStoreSCPService.cs | 35 ++++ .../ImageAndDoc/DicomArchiveService.cs | 197 ++++++++++++++++++ .../Interface/IDicomArchiveService.cs | 6 +- 4 files changed, 255 insertions(+), 3 deletions(-) diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index fd58e4f9d..942adfe18 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -847,6 +847,11 @@ + + + 后台托管服务的方式运行 + + 指定资源Id,渲染Dicom检查的Jpeg预览图像 Dicom检查的Id @@ -1836,7 +1841,7 @@ - 计算靶病灶状态 + 计算分裂靶病灶状态 @@ -5071,6 +5076,11 @@ 任务Id + + + 问题类型 + + 任务Id @@ -11500,6 +11510,14 @@ Financial---项目收入价格验证 + + + 单个文件接收 归档 + + + + + 指定资源Id,获取Dicom序列所属的实例信息列表 Dicom序列的Id diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/CStoreSCPService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/CStoreSCPService.cs index 53ea5547e..29933a52d 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/CStoreSCPService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/CStoreSCPService.cs @@ -8,9 +8,44 @@ using System.Threading.Tasks; using Microsoft.Extensions.Logging; using IRaCIS.Core.Application.Contracts.Dicom; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; namespace IRaCIS.Core.Application.Service.ImageAndDoc { + /// + /// 后台托管服务的方式运行 + /// + public class CStoreSCPHostedService : IHostedService + { + private readonly ILogger _logger; + private readonly IDicomServerFactory _dicomServerFactory; + private IDicomServer? _server; + + public CStoreSCPHostedService(ILogger logger, IDicomServerFactory dicomServerFactory) + { + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _dicomServerFactory = dicomServerFactory ?? throw new ArgumentNullException(nameof(dicomServerFactory)); + } + + public async Task StartAsync(CancellationToken cancellationToken) + { + _logger.LogInformation("Starting DICOM server"); + _server = _dicomServerFactory.Create(104); + _logger.LogInformation("DICOM server is running"); + } + + public Task StopAsync(CancellationToken cancellationToken) + { + if (_server != null) + { + _server.Stop(); + _server.Dispose(); + _server = null; + } + return Task.CompletedTask; + } + } + public class CStoreSCPService : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider { diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/DicomArchiveService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/DicomArchiveService.cs index 69929b1da..31991c2cd 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/DicomArchiveService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/DicomArchiveService.cs @@ -9,6 +9,9 @@ using IRaCIS.Core.Infrastructure; using Medallion.Threading; using FellowOakDicom; using FellowOakDicom.Imaging.Codec; +using System.Data; +using IRaCIS.Core.Domain.Models; +using FellowOakDicom.Network; namespace IRaCIS.Core.Application.Services { @@ -474,11 +477,205 @@ namespace IRaCIS.Core.Application.Services } + /// + /// 单个文件接收 归档 + /// + /// + /// + /// + public async Task ArchiveDicomFileAsync(DicomDataset dataset) + { + string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID); + string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID); + string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID); + + Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid); + Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid); + Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid); + + var isStudyNeedAdd = false; + var isSeriesNeedAdd = false; + var isInstanceNeedAdd = false; + + var @lock = _distributedLockProvider.CreateLock($"StudyInstanceUid"); + + using (@lock.Acquire()) + { + var findStudy = await _studyRepository.FirstOrDefaultAsync(t => t.Id == studyId); + var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId); + var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == instanceId); + + + if (findStudy == null) + { + isStudyNeedAdd = true; + findStudy = new DicomStudy + { + Id = studyId, + StudyInstanceUid = studyInstanceUid, + StudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue(DicomTag.StudyTime).TimeOfDay), + //Modalities = modality, + //ModalityForEdit = modalityForEdit, + Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty), + InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty), + PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty), + PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty), + PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty), + PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty), + BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty), + + StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty), + AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty), + + //需要特殊处理 + PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty), + + + AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty), + AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty), + TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty), + + + SiteId = Guid.Empty, + TrialId = Guid.Empty, + SubjectId = Guid.Empty, + SubjectVisitId = Guid.Empty, + //IsDoubleReview = addtionalInfo.IsDoubleReview, + SeriesCount = 0, + InstanceCount = 0 + }; + + //特殊逻辑 + + var modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty); + + var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList(); + + var modalityForEdit = dicModalityList.Contains(modality) ? modality : String.Empty; + + if (modality == "MR") + { + modalityForEdit = "MRI"; + } + + if (modality == "PT") + { + modalityForEdit = "PET"; + } + if (modality == "PT、CT") + { + modalityForEdit = "PET-CT"; + } + + findStudy.Modalities = modality; + findStudy.ModalityForEdit= modalityForEdit; + + if (findStudy.PatientBirthDate.Length == 8) + { + findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}"; + } + } + + + if (findSerice == null) + { + isSeriesNeedAdd = true; + + findSerice = new DicomSeries + { + Id = seriesId, + StudyId = findStudy.Id, + + StudyInstanceUid = findStudy.StudyInstanceUid, + SeriesInstanceUid = seriesInstanceUid, + SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1), + //SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay), + //SeriesTime = DateTime.TryParse(dataset.GetSingleValue(DicomTag.SeriesDate) + dataset.GetSingleValue(DicomTag.SeriesTime), out DateTime dt) ? dt : null, + SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue(DicomTag.SeriesTime).TimeOfDay), + Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty), + Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty), + SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty), + + ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty), + ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty), + BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty), + SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty), + ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty), + ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty), + + AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty), + AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty), + TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty), + + SiteId = Guid.Empty, + TrialId = Guid.Empty, + SubjectId = Guid.Empty, + SubjectVisitId = Guid.Empty, + + InstanceCount = 0 + }; + + ++findStudy.SeriesCount; + } + + + if (findInstance == null) + { + isInstanceNeedAdd = true; + findInstance = new DicomInstance + { + Id = instanceId, + StudyId = findStudy.Id, + SeriesId = findSerice.Id, + StudyInstanceUid = findStudy.StudyInstanceUid, + SeriesInstanceUid = findSerice.SeriesInstanceUid, + + SiteId = Guid.Empty, + TrialId = Guid.Empty, + SubjectId = Guid.Empty, + SubjectVisitId = Guid.Empty, + SopInstanceUid = sopInstanceUid, + InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1), + InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue(DicomTag.ContentTime).TimeOfDay), + //InstanceTime = DateTime.TryParse(dataset.GetSingleValue(DicomTag.ContentDate) + dataset.GetSingleValue(DicomTag.ContentTime), out DateTime dt) ? dt : null, + //InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate,(DateTime?)null)?.Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, TimeSpan.Zero)), + //dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime) + CPIStatus = false, + ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0), + ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0), + SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0), + SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty), + NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0), + PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty), + ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty), + FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty), + WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty), + WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty), + }; + ++findStudy.InstanceCount; + ++findSerice.InstanceCount; + } + if (isStudyNeedAdd) + { + await _studyRepository.AddAsync(findStudy); + } + if(isSeriesNeedAdd) + { + await _seriesRepository.AddAsync(findSerice); + } + if(isInstanceNeedAdd) + { + await _instanceRepository.AddAsync(findInstance); + } + await _studyRepository.SaveChangesAsync(); + } + + } } } diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/Interface/IDicomArchiveService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/Interface/IDicomArchiveService.cs index f78222dfc..92332cb06 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/Interface/IDicomArchiveService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/Interface/IDicomArchiveService.cs @@ -1,4 +1,6 @@ -namespace IRaCIS.Core.Application.Contracts.Dicom +using FellowOakDicom; + +namespace IRaCIS.Core.Application.Contracts.Dicom { public interface IDicomArchiveService { @@ -18,7 +20,7 @@ ////[EasyCachingAble(Expiration = 6000)] //string GetSeriesPreview(Guid seriesId); - + Task ArchiveDicomFileAsync(DicomDataset dicomDataset); } } From e22941d947657c109986bda6b16b7d62c6c221dd Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Tue, 19 Mar 2024 09:13:15 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=B3=A8=E9=87=8A=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IRaCIS.Core.Application.xml | 2 +- .../Service/ImageAndDoc/CStoreSCPService.cs | 54 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index 942adfe18..f23af1399 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -847,7 +847,7 @@ - + 后台托管服务的方式运行 diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/CStoreSCPService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/CStoreSCPService.cs index 29933a52d..79536d0b1 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/CStoreSCPService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/CStoreSCPService.cs @@ -15,36 +15,36 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc /// /// 后台托管服务的方式运行 /// - public class CStoreSCPHostedService : IHostedService - { - private readonly ILogger _logger; - private readonly IDicomServerFactory _dicomServerFactory; - private IDicomServer? _server; + //public class CStoreSCPHostedService : IHostedService + //{ + // private readonly ILogger _logger; + // private readonly IDicomServerFactory _dicomServerFactory; + // private IDicomServer? _server; - public CStoreSCPHostedService(ILogger logger, IDicomServerFactory dicomServerFactory) - { - _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _dicomServerFactory = dicomServerFactory ?? throw new ArgumentNullException(nameof(dicomServerFactory)); - } + // public CStoreSCPHostedService(ILogger logger, IDicomServerFactory dicomServerFactory) + // { + // _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + // _dicomServerFactory = dicomServerFactory ?? throw new ArgumentNullException(nameof(dicomServerFactory)); + // } - public async Task StartAsync(CancellationToken cancellationToken) - { - _logger.LogInformation("Starting DICOM server"); - _server = _dicomServerFactory.Create(104); - _logger.LogInformation("DICOM server is running"); - } + // public async Task StartAsync(CancellationToken cancellationToken) + // { + // _logger.LogInformation("Starting DICOM server"); + // _server = _dicomServerFactory.Create(104); + // _logger.LogInformation("DICOM server is running"); + // } - public Task StopAsync(CancellationToken cancellationToken) - { - if (_server != null) - { - _server.Stop(); - _server.Dispose(); - _server = null; - } - return Task.CompletedTask; - } - } + // public Task StopAsync(CancellationToken cancellationToken) + // { + // if (_server != null) + // { + // _server.Stop(); + // _server.Dispose(); + // _server = null; + // } + // return Task.CompletedTask; + // } + //} public class CStoreSCPService : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider