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();