From 1514694e37e5fea1cd80e7ba93abac40b898c38f Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Thu, 8 Jan 2026 15:18:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9irc=20=E5=8C=BF=E5=90=8D?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- IRC.Core.SCP/Service/CacheHelper.cs | 101 ++++++++++++++ IRC.Core.SCP/Service/DicomArchiveService.cs | 144 +++++++++++++------- 2 files changed, 197 insertions(+), 48 deletions(-) create mode 100644 IRC.Core.SCP/Service/CacheHelper.cs diff --git a/IRC.Core.SCP/Service/CacheHelper.cs b/IRC.Core.SCP/Service/CacheHelper.cs new file mode 100644 index 000000000..590cd6a20 --- /dev/null +++ b/IRC.Core.SCP/Service/CacheHelper.cs @@ -0,0 +1,101 @@ +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Infra.EFCore; +using Microsoft.EntityFrameworkCore; + +namespace IRaCIS.Core.SCP.Service; + + +public static class CacheKeys +{ + //项目缓存 + public static string Trial(string trialIdStr) => $"TrialId:{trialIdStr}"; + + //检查编号递增锁 + public static string TrialStudyMaxCode(Guid trialId) => $"TrialStudyMaxCode:{trialId}"; + + public static string TrialStudyUidUploading(Guid trialId, string studyUid) => $"TrialStudyUid:{trialId}_{studyUid}"; + //CRC上传影像提交锁key + public static string TrialStudyUidDBLock(Guid trialId, string studyUid) => $"TrialStudyUidDBLock:{trialId}_{studyUid}"; + + public static string TrialTaskStudyUidUploading(Guid trialId, Guid visiTaskId, string studyUid) => $"TrialStudyUid:{trialId}_{visiTaskId}_{studyUid}"; + //影像后处理上传提交锁key + public static string TrialTaskStudyUidDBLock(Guid trialId, Guid visiTaskId, string studyUid) => $"TrialTaskStudyUidDBLock:{trialId}_{visiTaskId}_{studyUid}"; + //系统匿名化 + public static string SystemAnonymization => $"SystemAnonymization"; + //前端国际化 + public static string FrontInternational => $"FrontInternationalList"; + + //登录挤账号 + public static string UserToken(Guid userId) => $"UserToken:{userId}"; + + //超时没请求接口自动退出 + public static string UserAutoLoginOut(Guid userId) => $"UserAutoLoginOut:{userId}"; + + + public static string UserDisable(Guid userId) => $"UserDisable:{userId}"; + + public static string UserRoleDisable(Guid userRoleId) => $"UserRoleDisable:{userRoleId}"; + + /// + /// 用户登录错误 限制登录 + /// + /// + /// + public static string UserLoginError(string userName) => $"login-failures:{userName}"; + + /// + /// 跳过阅片 + /// + /// + /// + public static string SkipReadingCacheKey(Guid userId) => $"{userId}SkipReadingCache"; + + + /// + /// 开始阅片时间 + /// + /// + /// + public static string StartReadingTimeKey(Guid userId) => $"{userId}StartReadingTime"; + + /// + /// 开始休息时间 + /// + /// + /// + public static string StartRestTime(Guid userId) => $"{userId}StartRestTime"; + + //每个用户 每个浏览器独立时间 + public static string UserMFAVerifyPass(Guid userId, string browserFingerprint) => $"UserMFAVerifyPass:{userId}:{browserFingerprint}"; + + public static string TrialSiteInfo(Guid trialSiteId) => $"{trialSiteId}TrialSiteInfo"; +} + +public static class CacheHelper +{ + public static async Task GetTrialStatusAsync(Guid trialId, IRepository _trialRepository) + { + var statusStr = await _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).Select(t => t.TrialStatusStr).FirstOrDefaultAsync(); + + return statusStr; + } + + public class TrialSiteInfoDTO + { + public string TrialSiteCode { get; set; } + public string TrialCode { get; set; } + } + public static async Task GetTrialSiteInfo(Guid trialSiteId, IRepository _trialSiteRepository) + { + var obj = await _trialSiteRepository.Where(t => t.Id == trialSiteId, ignoreQueryFilters: true).Select(t => new TrialSiteInfoDTO { TrialCode= t.Trial.TrialCode, TrialSiteCode= t.TrialSiteCode }).FirstOrDefaultAsync(); + + return obj??new TrialSiteInfoDTO(); + } + + public static async Task> GetSystemAnonymizationListAsync(IRepository _systemAnonymizationRepository) + { + var list = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync(); + + return list; + } +} diff --git a/IRC.Core.SCP/Service/DicomArchiveService.cs b/IRC.Core.SCP/Service/DicomArchiveService.cs index 5a032e611..1b03ac94e 100644 --- a/IRC.Core.SCP/Service/DicomArchiveService.cs +++ b/IRC.Core.SCP/Service/DicomArchiveService.cs @@ -1,49 +1,36 @@ -using IRaCIS.Core.Domain.Share; -using System.Text; -using Microsoft.AspNetCore.Hosting; -using IRaCIS.Core.Infrastructure; -using Medallion.Threading; -using FellowOakDicom; +using FellowOakDicom; using FellowOakDicom.Imaging.Codec; -using System.Data; -using IRaCIS.Core.Domain.Models; using FellowOakDicom.Network; -using IRaCIS.Core.SCP.Service; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore; -using MassTransit; -using System.Runtime.Intrinsics.X86; -using Serilog.Sinks.File; +using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Infrastructure.Extention; +using IRaCIS.Core.SCP.Service; +using MassTransit; +using Medallion.Threading; +using Microsoft.AspNetCore.Hosting; +using Serilog.Sinks.File; +using System.Data; +using System.Runtime.Intrinsics.X86; +using System.Text; +using ZiggyCreatures.Caching.Fusion; +using static IRaCIS.Core.SCP.Service.CacheHelper; namespace IRaCIS.Core.SCP.Service { - public class DicomArchiveService : BaseService, IDicomArchiveService + public class DicomArchiveService(IRepository _patientRepository, + IRepository _studyRepository, + IRepository _seriesRepository, + IRepository _instanceRepository, + IDistributedLockProvider _distributedLockProvider, + IRepository _systemAnonymizationRepository, + IRepository _trialSiteRepository, + IFusionCache _fusionCache + ) : BaseService, IDicomArchiveService { - private readonly IRepository _patientRepository; - private readonly IRepository _studyRepository; - private readonly IRepository _seriesRepository; - private readonly IRepository _instanceRepository; - private readonly IRepository _dictionaryRepository; - private readonly IDistributedLockProvider _distributedLockProvider; - private List _instanceIdList = new List(); - - public DicomArchiveService(IRepository patientRepository, IRepository studyRepository, - IRepository seriesRepository, - IRepository instanceRepository, - IRepository dictionaryRepository, - IDistributedLockProvider distributedLockProvider) - { - _distributedLockProvider = distributedLockProvider; - _studyRepository = studyRepository; - _patientRepository = patientRepository; - _seriesRepository = seriesRepository; - _instanceRepository = instanceRepository; - _dictionaryRepository = dictionaryRepository; - - } - @@ -53,18 +40,79 @@ namespace IRaCIS.Core.SCP.Service /// /// /// - public async Task ArchiveDicomFileAsync(DicomFile dicomFile, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE,long fileSize) + public async Task ArchiveDicomFileAsync(DicomFile dicomFile, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE, long fileSize) { + var dataset = dicomFile.Dataset; + #region 匿名化 + + var anonymizeList = await _fusionCache.GetOrSetAsync(CacheKeys.SystemAnonymization, _ => CacheHelper.GetSystemAnonymizationListAsync(_systemAnonymizationRepository), TimeSpan.FromDays(7)); + + var trialSiteInfo = await _fusionCache.GetOrSetAsync(CacheKeys.TrialSiteInfo(trialSiteId), _ => CacheHelper.GetTrialSiteInfo(trialSiteId, _trialSiteRepository), TimeSpan.FromMinutes(2)); + + var fixedFiledList = anonymizeList.Where(t => t.IsFixed).ToList(); + + var ircFiledList = anonymizeList.Where(t => t.IsFixed == false).ToList(); + + foreach (var item in fixedFiledList) + { + + var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16)); + + dataset.AddOrUpdate(dicomTag, item.ReplaceValue); + } + + foreach (var item in ircFiledList) + { + + var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16)); + + if (dicomTag == DicomTag.ClinicalTrialProtocolID) + { + dataset.AddOrUpdate(dicomTag, trialSiteInfo.TrialCode); + + } + if (dicomTag == DicomTag.ClinicalTrialSiteID) + { + dataset.AddOrUpdate(dicomTag, trialSiteInfo.TrialSiteCode); + + } + + if (dicomTag == DicomTag.ClinicalTrialSubjectID) + { + dataset.AddOrUpdate(dicomTag, ""); + + } + if (dicomTag == DicomTag.ClinicalTrialTimePointID) + { + dataset.AddOrUpdate(dicomTag, ""); + } + + if (dicomTag == DicomTag.PatientID) + { + var pid = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty); + + dataset.AddOrUpdate(dicomTag, trialSiteInfo.TrialCode + "_" + pid); + + } + + } + #endregion + + + + + + string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID); string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID); string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID); - string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID,string.Empty); + string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty); //Guid patientId= IdentifierHelper.CreateGuid(patientIdStr); - Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString()); + Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString()); Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString()); Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString()); @@ -77,9 +125,9 @@ namespace IRaCIS.Core.SCP.Service //using (@lock.Acquire()) { - var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId==trialSiteId ); - var findStudy = await _studyRepository.FirstOrDefaultAsync(t=>t.Id== studyId); - var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId); + var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr && t.TrialSiteId == trialSiteId); + 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); DateTime? 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); @@ -93,8 +141,8 @@ namespace IRaCIS.Core.SCP.Service findPatient = new SCPPatient() { Id = NewId.NextSequentialGuid(), - TrialId=trialId, - TrialSiteId=trialSiteId, + TrialId = trialId, + TrialSiteId = trialSiteId, PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty), PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty), PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty), @@ -122,7 +170,7 @@ namespace IRaCIS.Core.SCP.Service DateTime birthDate; - if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate,out birthDate)) + if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate, out birthDate)) { var patientAge = studyTime.Value.Year - birthDate.Year; // 如果生日还未到,年龄减去一岁 @@ -289,7 +337,7 @@ namespace IRaCIS.Core.SCP.Service RadiopharmaceuticalInformationSequence = dataset.GetSingleValueOrDefault(DicomTag.RadiopharmaceuticalInformationSequence, string.Empty), AcquisitionDate = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionDate, string.Empty), - + InstanceCount = 0 }; @@ -358,7 +406,7 @@ namespace IRaCIS.Core.SCP.Service Path = fileRelativePath, - FileSize= fileSize, + FileSize = fileSize, }; @@ -398,7 +446,7 @@ namespace IRaCIS.Core.SCP.Service } else { - await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath,FileSize=fileSize }); + await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath, FileSize = fileSize }); } await _studyRepository.SaveChangesAsync();