diff --git a/IRaCIS.Core.API/_PipelineExtensions/IRacisHostFile/IRacisHostFileStoreConfig.cs b/IRaCIS.Core.API/_PipelineExtensions/IRacisHostFile/IRacisHostFileStoreConfig.cs index 449c48da0..588165a42 100644 --- a/IRaCIS.Core.API/_PipelineExtensions/IRacisHostFile/IRacisHostFileStoreConfig.cs +++ b/IRaCIS.Core.API/_PipelineExtensions/IRacisHostFile/IRacisHostFileStoreConfig.cs @@ -12,8 +12,8 @@ namespace IRaCIS.Core.API public static void UseIRacisHostStaticFileStore(this IApplicationBuilder app, IWebHostEnvironment _hostEnvironment) { - - var iRaCISDataFolder = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment); + + var iRaCISDataFolder = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment); if (!Directory.Exists(iRaCISDataFolder)) { @@ -26,13 +26,7 @@ namespace IRaCIS.Core.API RequestPath = $"/{StaticData.Folder.IRaCISDataFolder}", ServeUnknownFileTypes = true, DefaultContentType = "application/octet-stream" - - // // Set up custom content types - associating file extension to MIME type - //var provider = new FileExtensionContentTypeProvider(); - // // Add new mappings - // provider.Mappings[".myapp"] = "application/x-msdownload"; - - }); + }); } } } diff --git a/IRaCIS.Core.API/_PipelineExtensions/IRacisHostFile/MultiDiskStaticFilesMiddleware.cs b/IRaCIS.Core.API/_PipelineExtensions/IRacisHostFile/MultiDiskStaticFilesMiddleware.cs index 25780b5c2..54b423784 100644 --- a/IRaCIS.Core.API/_PipelineExtensions/IRacisHostFile/MultiDiskStaticFilesMiddleware.cs +++ b/IRaCIS.Core.API/_PipelineExtensions/IRacisHostFile/MultiDiskStaticFilesMiddleware.cs @@ -1,10 +1,12 @@ -using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Domain.Share; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders.Physical; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting.Internal; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -24,12 +26,21 @@ namespace IRaCIS.Core.API private readonly StaticFileOptions _options; private readonly ILoggerFactory _loggerFactory; + private string iRaCISDefaultDataFolder = string.Empty; + public MultiDiskStaticFilesMiddleware(RequestDelegate next, IWebHostEnvironment hostingEnv, StaticFileOptions options, ILoggerFactory loggerFactory) { _next = next; _hostingEnv = hostingEnv; _options = options; _loggerFactory = loggerFactory; + + iRaCISDefaultDataFolder = FileStoreHelper.GetIRaCISRootDataFolder(_hostingEnv); + + if (!Directory.Exists(iRaCISDefaultDataFolder)) + { + Directory.CreateDirectory(iRaCISDefaultDataFolder); + } } public async Task Invoke(HttpContext context) @@ -39,52 +50,96 @@ namespace IRaCIS.Core.API var isDicomFile = path.Contains($"{StaticData.Folder.DicomFolder}"); - var isFind = false; + var defaultFileProvider = new PhysicalFileProvider(iRaCISDefaultDataFolder); + var staticFileOptions = new StaticFileOptions + { + FileProvider = defaultFileProvider, + RequestPath = $"/{StaticData.Folder.IRaCISDataFolder}", + ServeUnknownFileTypes = true, + DefaultContentType = "application/octet-stream" + }; + + var defaultRoot = Path.GetPathRoot(iRaCISDefaultDataFolder); + + //先从默认里面去找 if (isIRacisFile) { - + if (defaultFileProvider.GetFileInfo(context.Request.Path).Exists) + { + var staticFileMiddleware = new StaticFileMiddleware(_next, _hostingEnv, Options.Create(staticFileOptions), _loggerFactory); + await staticFileMiddleware.Invoke(context); + return; + } } + + //没找到 + //dicom影像,从多个文件夹尝试,因为会存在切换磁盘 if (isDicomFile) { + var disks = GetDisks().Where(t=>!t.Contains(defaultRoot)); + + foreach (var item in disks) + { + var otherFileStoreFolder = Path.Combine(item, _hostingEnv.EnvironmentName); + + var otherFileProvider= new PhysicalFileProvider(otherFileStoreFolder); + + var otherStaticFileOptions = new StaticFileOptions + { + FileProvider = otherFileProvider, + RequestPath = $"/{StaticData.Folder.IRaCISDataFolder}", + ServeUnknownFileTypes = true, + DefaultContentType = "application/octet-stream" + }; + + if (otherFileProvider.GetFileInfo(context.Request.Path).Exists) + { + var staticFileMiddleware = new StaticFileMiddleware(_next, _hostingEnv, Options.Create(staticFileOptions), _loggerFactory); + await staticFileMiddleware.Invoke(context); + return; + } + } } - - + // 如果所有磁盘都不存在所请求的文件,则将请求传递给下一个中间件组件。 await _next.Invoke(context); } - private async Task ServeFileAsync(HttpContext context, IFileInfo fileInfo) - { - var response = context.Response; - response.ContentType = GetContentType(fileInfo.PhysicalPath); - using (var fileStream = fileInfo.CreateReadStream()) - { - await fileStream.CopyToAsync(response.Body); - } - } private string[] GetDisks() { // 获取系统中所有可用的磁盘 return DriveInfo.GetDrives() - .Where(d => d.IsReady && d.DriveType == DriveType.Fixed) + .Where(d => d.IsReady && d.DriveType == DriveType.Fixed).Where(t => !t.Name.Contains("C") && !t.Name.Contains("c")) .Select(d => d.RootDirectory.FullName) .ToArray(); } - private static string GetContentType(string path) - { - var provider = new FileExtensionContentTypeProvider(); - if (!provider.TryGetContentType(path, out var contentType)) - { - contentType = "application/octet-stream"; - } - return contentType; - } + //private static string GetContentType(string path) + //{ + // var provider = new FileExtensionContentTypeProvider(); + // if (!provider.TryGetContentType(path, out var contentType)) + // { + // contentType = "application/octet-stream"; + // } + + // return contentType; + //} + + //private async Task ServeFileAsync(HttpContext context, IFileInfo fileInfo) + //{ + // var response = context.Response; + // response.ContentType = GetContentType(fileInfo.PhysicalPath); + + // using (var fileStream = fileInfo.CreateReadStream()) + // { + // await fileStream.CopyToAsync(response.Body); + // } + //} } diff --git a/IRaCIS.Core.Application/Service/Common/SystemMonitor.cs b/IRaCIS.Core.Application/Service/Common/SystemMonitor.cs index 429e4f4b7..caa897bd6 100644 --- a/IRaCIS.Core.Application/Service/Common/SystemMonitor.cs +++ b/IRaCIS.Core.Application/Service/Common/SystemMonitor.cs @@ -92,7 +92,7 @@ namespace IRaCIS.Core.Application.Service.Common } else { - bestStoreRootFolder = Path.Combine(drives.FirstOrDefault()?.Name, _hostEnvironment.EnvironmentName); + bestStoreRootFolder = Path.Combine(bestDrive?.RootDirectory.FullName, _hostEnvironment.EnvironmentName); } diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/DicomInstanceModel.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/DicomInstanceModel.cs index ba6b48896..b5fe095f1 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/DicomInstanceModel.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/DicomInstanceModel.cs @@ -45,11 +45,9 @@ namespace IRaCIS.Core.Application.Contracts public string ResearchProgramNo { get; set; } = string.Empty; public string TrialIndication { get; set; } = string.Empty; - public CheckStateEnum CheckState { get; set; } public decimal VisitNum { get; set; } - public string SVUPDES { get; set; } = string.Empty; public string VisitName { get; set; } = string.Empty; public string Sponsor { get; set; } = string.Empty; public Guid TrialId { get; set; } @@ -57,10 +55,15 @@ namespace IRaCIS.Core.Application.Contracts public Guid SubjectId { get; set; } public Guid SubjectVisitId { get; set; } - public SubmitStateEnum SubmitState { get; set; } - public AuditStateEnum AuditState { get; set; } - public ForwardStateEnum ForwardState { get; set; } + //public string SVUPDES { get; set; } = string.Empty; + + //public CheckStateEnum CheckState { get; set; } + + //public SubmitStateEnum SubmitState { get; set; } + + //public AuditStateEnum AuditState { get; set; } + //public ForwardStateEnum ForwardState { get; set; } //public string SubjectName => LastName + " / " + FirstName; //public string FirstName { get; set; } = string.Empty; diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/UnionStudyViewDodel.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/UnionStudyViewDodel.cs index 476951f05..9ae6ac8a3 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/UnionStudyViewDodel.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/UnionStudyViewDodel.cs @@ -34,7 +34,7 @@ namespace IRaCIS.Core.Application.Contracts public DateTime UploadTime { get; set; } - public string StudyCode { get; set; } + public string StudyCode { get; set; } //[JsonIgnore] @@ -69,7 +69,7 @@ namespace IRaCIS.Core.Application.Contracts } } - public string ArchiveIntervalStr + public string ArchiveIntervalStr { get { @@ -137,12 +137,12 @@ namespace IRaCIS.Core.Application.Contracts } - public class UnionStudyViewModel:UnionStudyBaseModel + public class UnionStudyViewModel : UnionStudyBaseModel { - + public Guid Id { get; set; } - + public int? Count { get; set; } @@ -153,12 +153,12 @@ namespace IRaCIS.Core.Application.Contracts public DateTime? StudyTime { get; set; } - + } - public class StudyQuery:PageInput + public class StudyQuery : PageInput { [NotDefault] public Guid TrialId { get; set; } @@ -174,4 +174,116 @@ namespace IRaCIS.Core.Application.Contracts public string[]? VisitPlanArray { get; set; } } + + + public class NewArchiveStudyCommand + { + [NotDefault] + public Guid TrialId { get; set; } + [NotDefault] + public Guid SiteId { get; set; } + [NotDefault] + public Guid SubjectId { get; set; } + [NotDefault] + public Guid SubjectVisitId { get; set; } + + public bool IsAdd { get; set; } + + public AddOrUpdateStudyDto Study { get; set; } + + public List SeriesList { get; set; } + + public List InstanceList { get; set; } + + } + + public class AddOrUpdateStudyDto + { + + public Guid? Id { get; set; } + + public string StudyId { get; set; } = string.Empty; + + + + //public int Code { get; set; } = 0; + + //public string StudyCode { get; set; } = string.Empty; + + + public string StudyInstanceUid { get; set; } = string.Empty; + public DateTime? StudyTime { get; set; } + public string Modalities { get; set; } = string.Empty; + + public string Description { get; set; } = string.Empty; + public int SeriesCount { get; set; } = 0; + public int InstanceCount { get; set; } = 0; + + public string InstitutionName { get; set; } = string.Empty; + public string PatientId { get; set; } = string.Empty; + public string PatientName { get; set; } = string.Empty; + public string PatientAge { get; set; } = string.Empty; + public string PatientSex { get; set; } = string.Empty; + + public string AccessionNumber { get; set; } = string.Empty; + public string PatientBirthDate { get; set; } = string.Empty; + public string AcquisitionTime { get; set; } = string.Empty; + public string AcquisitionNumber { get; set; } = string.Empty; + public string TriggerTime { get; set; } = string.Empty; + + public string BodyPartExamined { get; set; } = string.Empty; + + } + + public class AddOrUpdateSeriesDto + { + public Guid? Id { get; set; } + public string StudyInstanceUid { get; set; } + public string SeriesInstanceUid { get; set; } + public int SeriesNumber { get; set; } + public DateTime? SeriesTime { get; set; } + public string Modality { get; set; } + public string Description { get; set; } + public int InstanceCount { get; set; } + public string SliceThickness { get; set; } + + public string ImagePositionPatient { get; set; } + public string ImageOrientationPatient { get; set; } + public string BodyPartExamined { get; set; } + public string SequenceName { get; set; } + public string ProtocolName { get; set; } + public string ImagerPixelSpacing { get; set; } + + public string AcquisitionTime { get; set; } = string.Empty; + public string AcquisitionNumber { get; set; } = string.Empty; + public string TriggerTime { get; set; } = string.Empty; + + } + + + public class AddInstanceDto + { + public string StudyInstanceUid { get; set; } + public string SeriesInstanceUid { get; set; } + public string SopInstanceUid { get; set; } + public int InstanceNumber { get; set; } + public DateTime? InstanceTime { get; set; } + public bool CPIStatus { get; set; } + public int ImageRows { get; set; } + public int ImageColumns { get; set; } + public int SliceLocation { get; set; } + + + public string SliceThickness { get; set; } + public int NumberOfFrames { get; set; } + public string PixelSpacing { get; set; } + + public string ImagerPixelSpacing { get; set; } + public string FrameOfReferenceUID { get; set; } + public string WindowCenter { get; set; } + public string WindowWidth { get; set; } + + public bool Anonymize { get; set; } + public string Path { get; set; } + } } diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/Interface/IStudyService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/Interface/IStudyService.cs index 9d6da479d..d2e9efa5a 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/Interface/IStudyService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/Interface/IStudyService.cs @@ -12,6 +12,6 @@ namespace IRaCIS.Core.Application.Contracts DicomTrialSiteSubjectInfo GetSaveToDicomInfo(Guid subjectVisitId); IResponseOutput Item(Guid studyId); Task Preview(Guid studyId); - IResponseOutput> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo); + //IResponseOutput> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo); } } \ No newline at end of file diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs index 1f836f64c..9f5b4312c 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs @@ -7,12 +7,15 @@ using EasyCaching.Core; using System.Linq.Expressions; using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Infrastructure; +using DocumentFormat.OpenXml.Presentation; +using IRaCIS.Core.Domain.Models; namespace IRaCIS.Core.Application.Service.ImageAndDoc { [ApiExplorerSettings(GroupName = "Image")] public class StudyService : BaseService, IStudyService { + private static object lockCodeGenerate = new object(); private readonly IEasyCachingProvider _provider; @@ -20,16 +23,185 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc private readonly IRepository _subjectVisitRepository; private readonly IRepository _dicomInstanceRepository; private readonly IRepository _dicomSeriesRepository; + private readonly IRepository _dicomstudyRepository; + private readonly IRepository _dictionaryRepository; - public StudyService( IEasyCachingProvider provider + public StudyService(IEasyCachingProvider provider , IRepository subjectVisitRepository, IRepository dicomInstanceRepository, - IRepository dicomSeriesRepository) + IRepository dicomSeriesRepository, IRepository dicomstudyRepository, IRepository dictionaryRepository) { _provider = provider; _subjectVisitRepository = subjectVisitRepository; _dicomInstanceRepository = dicomInstanceRepository; _dicomSeriesRepository = dicomSeriesRepository; + _dicomstudyRepository = dicomstudyRepository; + _dictionaryRepository = dictionaryRepository; + } + + + private void SpecialArchiveStudyDeal(DicomStudy study) + { + #region 特殊逻辑 + + + if (study.PatientBirthDate.Length == 8) + { + study.PatientBirthDate = $"{study.PatientBirthDate[0]}{study.PatientBirthDate[1]}{study.PatientBirthDate[2]}{study.PatientBirthDate[3]}-{study.PatientBirthDate[4]}{study.PatientBirthDate[5]}-{study.PatientBirthDate[6]}{study.PatientBirthDate[7]}"; + } + + var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList(); + + + var modality = study.Modalities; + + 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"; + } + + study.ModalityForEdit = modalityForEdit; + #endregion + } + + public async Task AddOrUpdateArchiveStudy(NewArchiveStudyCommand incommand) + { + var trialId = incommand.TrialId; + if (incommand.IsAdd) + { + var study = _mapper.Map(incommand.Study); + + lock (lockCodeGenerate) + { + + //查询数据库获取最大的Code 没有记录则为0 + var dbStudyCodeIntMax = _dicomstudyRepository.Where(s => s.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max(); + + //获取缓存中的值 并发的时候,需要记录,已被占用的值 这样其他线程在此占用的最大的值上递增 + var cacheMaxCodeInt = _provider.Get($"{trialId}_{StaticData.CacheKey.StudyMaxCode}").Value; + + int currentNextCodeInt = cacheMaxCodeInt > dbStudyCodeIntMax ? cacheMaxCodeInt + 1 : dbStudyCodeIntMax + 1; + + study.Code = currentNextCodeInt; + + study.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(DicomStudy)); + + _provider.Set($"{trialId}_{StaticData.CacheKey.StudyMaxCode}", study.Code, TimeSpan.FromMinutes(30)); + + } + + + study.Id = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString()); + study.TrialId = incommand.TrialId; + study.SiteId = incommand.SiteId; + study.SubjectId = incommand.SubjectId; + study.SubjectVisitId = incommand.SubjectVisitId; + + + //特殊处理逻辑 + SpecialArchiveStudyDeal(study); + + + + await _dicomstudyRepository.AddAsync(study); + + + foreach (var seriesItem in incommand.SeriesList) + { + var series = _mapper.Map(seriesItem); + + series.Id = IdentifierHelper.CreateGuid(seriesItem.SeriesInstanceUid, incommand.TrialId.ToString()); + series.StudyId = study.Id; + + series.TrialId = incommand.TrialId; + series.SiteId = incommand.SiteId; + series.SubjectId = incommand.SubjectId; + series.SubjectVisitId = incommand.SubjectVisitId; + + await _dicomSeriesRepository.AddAsync(series); + + foreach (var instanceItem in incommand.InstanceList) + { + var isntance = _mapper.Map(instanceItem); + isntance.StudyId = study.Id; + isntance.SeriesId = series.Id; + + isntance.TrialId = incommand.TrialId; + isntance.SiteId = incommand.SiteId; + isntance.SubjectId = incommand.SubjectId; + isntance.SubjectVisitId = incommand.SubjectVisitId; + + await _dicomInstanceRepository.AddAsync(isntance); + } + } + + + + } + else + { + + var studyId = incommand.Study.Id; + + var study = await _dicomstudyRepository.FirstOrDefaultAsync(t => t.Id == studyId); + + _mapper.Map(incommand.Study, study); + + //特殊处理逻辑 + SpecialArchiveStudyDeal(study); + + await _dicomSeriesRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == incommand.Study.Id); + + + foreach (var seriesItem in incommand.SeriesList) + { + var series = _mapper.Map(seriesItem); + + series.Id = IdentifierHelper.CreateGuid(series.StudyInstanceUid, series.SeriesInstanceUid, trialId.ToString()); + series.StudyId = study.Id; + + series.TrialId = incommand.TrialId; + series.SiteId = incommand.SiteId; + series.SubjectId = incommand.SubjectId; + series.SubjectVisitId = incommand.SubjectVisitId; + + await _dicomSeriesRepository.AddAsync(series); + + foreach (var instanceItem in incommand.InstanceList) + { + var insntance = _mapper.Map(instanceItem); + insntance.Id= IdentifierHelper.CreateGuid(insntance.StudyInstanceUid, insntance.SeriesInstanceUid, insntance.SopInstanceUid, trialId.ToString()); + insntance.StudyId = study.Id; + insntance.SeriesId = series.Id; + + insntance.TrialId = incommand.TrialId; + insntance.SiteId = incommand.SiteId; + insntance.SubjectId = incommand.SubjectId; + insntance.SubjectVisitId = incommand.SubjectVisitId; + + await _dicomInstanceRepository.AddAsync(insntance); + } + } + + // 少了整个序列 + + //某个序列下少了instance + } + + await _dicomstudyRepository.SaveChangesAsync(); + + return ResponseOutput.Ok(); } @@ -151,7 +323,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc public async Task> GetDicomAndNoneDicomStudyMonitorList(StudyQuery studyQuery) { var svExpression = QCCommon.GetStudyMonitorSubjectVisitFilter(studyQuery.VisitPlanArray); - var StudyMonitorQuery = _repository.Where(t => t.TrialId == studyQuery.TrialId,ignoreQueryFilters:true) + var StudyMonitorQuery = _repository.Where(t => t.TrialId == studyQuery.TrialId, ignoreQueryFilters: true) .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id)) //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo)) .WhereIf(studyQuery.VisitPlanArray != null && studyQuery.VisitPlanArray?.Length > 0, svExpression) @@ -181,14 +353,14 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc UploadTime = t.CreateTime, - IsSuccess=t.IsSuccess, - Note=t.Note, + IsSuccess = t.IsSuccess, + Note = t.Note, IP = t.IP, FileCount = t.FileCount, FileSize = t.FileSize, UploadFinishedTime = t.UploadFinishedTime, UploadStartTime = t.UploadStartTime, - ArchiveFinishedTime=t.ArchiveFinishedTime, + ArchiveFinishedTime = t.ArchiveFinishedTime, @@ -403,7 +575,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc /// 批量验证 检查是否可以上传 并告知原因 /// [HttpPost] - public IResponseOutput> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo) + public (List, object?) VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo) { var trialInfo = _repository.Where().FirstOrDefault(t => t.Id == verifyInfo.TrialId).IfNullThrowException(); @@ -428,7 +600,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc result.Add(new VerifyStudyUploadResult() { ErrorMesseage = _localizer["Study_VisitBeforePrevError", waitUploadItem.StudyDate?.ToString("yyyy-MM-dd"), before?.ToString("yyyy-MM-dd")], StudyInstanceUid = waitUploadItem.StudyInstanceUid }); return; } - + //大于当前访视 最近的最早拍片日期 var after = visitList.Where(u => u.VisitNum > verifyInfo.VisitNum).Min(k => k.EarliestScanDate); @@ -445,7 +617,19 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc result.Add(temp); }); - return ResponseOutput.Ok(result); + + // 写入dicom 固定的信息,以及组织路径的信息 以及匿名化的信息 + var otherData = GetSaveToDicomInfo(verifyInfo.SubjectVisitId); + + var systemAnonymizationList = _repository.Where(t => t.IsEnable).ToList(); + + return (result, new + { + DicomStoreInfo = otherData, + AnonymizeFixedList = systemAnonymizationList.Where(t => t.IsFixed).ToList(), + AnonymizeNotFixedList = systemAnonymizationList.Where(t => t.IsFixed == false).ToList() + } + ); } @@ -498,6 +682,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc if (verifyStudyInfo.SubjectId == SubjectId && verifyStudyInfo.SubjectVisitId == currentSubjectVisitId) { result.AllowReUpload = true; + + result.UploadedSeriesList = _repository.Where(t => t.StudyId == verifyStudyInfo.Id).Select(t => new UploadedSeries() + { SeriesInstanceUid = t.SeriesInstanceUid, SOPInstanceUIDList = t.DicomInstanceList.Select(c => c.SopInstanceUid).ToList() }).ToList(); } //不是同一个受试者 else diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/_MapConfig.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/_MapConfig.cs index b42d581a3..9badbb824 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/_MapConfig.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/_MapConfig.cs @@ -12,6 +12,10 @@ namespace IRaCIS.Core.Application.Service { public ImageAndDocConfig() { + CreateMap(); + CreateMap(); + CreateMap(); + CreateMap(); CreateMap(); CreateMap(); @@ -31,7 +35,6 @@ namespace IRaCIS.Core.Application.Service .ForMember(d => d.SiteName, u => u.MapFrom(s => s.Site.SiteName)) .ForMember(d => d.UploaderFirstName, u => u.MapFrom(s => s.Uploader.FirstName)) .ForMember(d => d.UploaderLastName, u => u.MapFrom(s => s.Uploader.LastName)) - .ForMember(d => d.StudyStatus, u => u.MapFrom(s => s.Status)) .ForMember(d => d.UploadedTime, u => u.MapFrom(s => s.CreateTime)) .ForMember(d => d.DTFCount, u => u.MapFrom(s => s.StudyDTFList.Count())); diff --git a/IRaCIS.Core.Application/Service/Visit/DTO/VisitPointViewModel.cs b/IRaCIS.Core.Application/Service/Visit/DTO/VisitPointViewModel.cs index 084ed14f7..54d6cd175 100644 --- a/IRaCIS.Core.Application/Service/Visit/DTO/VisitPointViewModel.cs +++ b/IRaCIS.Core.Application/Service/Visit/DTO/VisitPointViewModel.cs @@ -317,6 +317,13 @@ namespace IRaCIS.Core.Application.Contracts + public class UploadedSeries + { + public string SeriesInstanceUid { get; set; } + + public List SOPInstanceUIDList { get; set; } + } + public class VerifyStudyUploadResult { @@ -330,6 +337,8 @@ namespace IRaCIS.Core.Application.Contracts public string ErrorMesseage { get; set; } = String.Empty; + public List UploadedSeriesList { get; set;} = new List(); + } public class VerifyUploadOrReupload diff --git a/IRaCIS.Core.Application/TestService.cs b/IRaCIS.Core.Application/TestService.cs index 3b9590c24..398e52540 100644 --- a/IRaCIS.Core.Application/TestService.cs +++ b/IRaCIS.Core.Application/TestService.cs @@ -8,6 +8,8 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; using Microsoft.Extensions.Options; using System.Linq.Expressions; +using System.Security.Cryptography; +using System.Text; using System.Text.RegularExpressions; @@ -45,14 +47,14 @@ namespace IRaCIS.Application.Services public async Task Get() { - Expression> visitTaskLambda = x => x.TrialId == Guid.Empty && x.SubjectId == Guid.Empty && x.TrialReadingCriterionId == Guid.Empty; + //Expression> visitTaskLambda = x => x.TrialId == Guid.Empty && x.SubjectId == Guid.Empty && x.TrialReadingCriterionId == Guid.Empty; - var visitTaskIdQueryable = _visitTaskRepositoryy.Where(visitTaskLambda).Where(t => t.Subject.SubjectVisitTaskList.AsQueryable().Where(visitTaskLambda).Any(c => c.IsNeedClinicalDataSign == true && c.IsClinicalDataSign == false && c.VisitTaskNum < t.VisitTaskNum)).Select(t => t.Id); + //var visitTaskIdQueryable = _visitTaskRepositoryy.Where(visitTaskLambda).Where(t => t.Subject.SubjectVisitTaskList.AsQueryable().Where(visitTaskLambda).Any(c => c.IsNeedClinicalDataSign == true && c.IsClinicalDataSign == false && c.VisitTaskNum < t.VisitTaskNum)).Select(t => t.Id); - await _visitTaskRepositoryy.BatchUpdateNoTrackingAsync(t => visitTaskIdQueryable.Contains(t.Id), u => new VisitTask() - { - IsFrontTaskNeedSignButNotSign = true - }); + //await _visitTaskRepositoryy.BatchUpdateNoTrackingAsync(t => visitTaskIdQueryable.Contains(t.Id), u => new VisitTask() + //{ + // IsFrontTaskNeedSignButNotSign = true + //}); //var a = ((Decimal)1.00).ToString().TrimEnd(new char[] { '.', '0' }); @@ -117,10 +119,10 @@ namespace IRaCIS.Application.Services //await _visitTaskRepositoryy.UpdatePartialFromQueryAsync( Guid.Parse("78360000-3E2C-0016-9B53-08DA6A002040"), c => new VisitTask() { UpdateTime = DateTime.Now.AddMinutes(1) }); - var a = _userInfo.IsTestUser; + //var a = _userInfo.IsTestUser; - var list1 = await _repository.Where().Select(t => t.TranslateValue(t.Value, t.ValueCN, true)).ToListAsync(); - var list2 = await _repository.Where().Select(t => t.TranslateValue(t.Value, t.ValueCN, false)).ToListAsync(); + //var list1 = await _repository.Where().Select(t => t.TranslateValue(t.Value, t.ValueCN, true)).ToListAsync(); + //var list2 = await _repository.Where().Select(t => t.TranslateValue(t.Value, t.ValueCN, false)).ToListAsync(); await _repository.SaveChangesAsync(); return _userInfo.LocalIp; @@ -156,7 +158,11 @@ namespace IRaCIS.Application.Services [AllowAnonymous] public async Task GetEnvironmentName([FromServices] IWebHostEnvironment env) { + var a = IdentifierHelper.CreateGuid("123456"); + var k = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes("123456")); + + var c = MD5Helper.Md5("123456"); //update DicomInstance set Path = '/IRaCISData/TrialData/' + cast(DicomInstance.TrialId as varchar) + '/' + DicomInstance.SiteId + '/' + DicomInstance.SubjectId + '/' + DicomInstance.SubjectVisitId + '/Dicom/' + DicomInstance.StudyId + '/' + DicomInstance.Id + '.dcm' diff --git a/IRaCIS.Core.Domain/Image/DicomInstance.cs b/IRaCIS.Core.Domain/Image/DicomInstance.cs index 20c45db39..a05f3bbf0 100644 --- a/IRaCIS.Core.Domain/Image/DicomInstance.cs +++ b/IRaCIS.Core.Domain/Image/DicomInstance.cs @@ -42,6 +42,7 @@ namespace IRaCIS.Core.Domain.Models public Guid SubjectId { get; set; } public Guid SubjectVisitId { get; set; } public bool Anonymize { get; set; } + public string Path { get; set; } public Guid CreateUserId { get; set; } public DateTime CreateTime { get; set; } = DateTime.Now; @@ -49,6 +50,5 @@ namespace IRaCIS.Core.Domain.Models public DateTime UpdateTime { get; set; } = DateTime.Now; - public string Path { get; set; } } } diff --git a/IRaCIS.Core.Domain/Image/DicomSeries.cs b/IRaCIS.Core.Domain/Image/DicomSeries.cs index e9a449b63..1e4be2b3c 100644 --- a/IRaCIS.Core.Domain/Image/DicomSeries.cs +++ b/IRaCIS.Core.Domain/Image/DicomSeries.cs @@ -31,9 +31,6 @@ namespace IRaCIS.Core.Domain.Models public int InstanceCount { get; set; } public string SliceThickness { get; set; } - - - public string ImagePositionPatient { get; set; } public string ImageOrientationPatient { get; set; } public string BodyPartExamined { get; set; } @@ -41,19 +38,18 @@ namespace IRaCIS.Core.Domain.Models public string ProtocolName { get; set; } public string ImagerPixelSpacing { get; set; } - public string AcquisitionTime { get; set; } = string.Empty; public string AcquisitionNumber { get; set; } = string.Empty; public string TriggerTime { get; set; } = string.Empty; - - - public Guid TrialId { get; set; } public Guid SiteId { get; set; } public Guid SubjectId { get; set; } public Guid SubjectVisitId { get; set; } + + public string BodyPartForEdit { get; set; } = string.Empty; + public Guid CreateUserId { get; set; } public DateTime CreateTime { get; set; } = DateTime.Now; public Guid UpdateUserId { get; set; } @@ -65,6 +61,5 @@ namespace IRaCIS.Core.Domain.Models public bool IsDeleted {get;set;} public bool IsReading { get; set; } = true; - public string BodyPartForEdit { get; set; } = string.Empty; } } diff --git a/IRaCIS.Core.Domain/Image/DicomStudy.cs b/IRaCIS.Core.Domain/Image/DicomStudy.cs index 700e13c91..861533503 100644 --- a/IRaCIS.Core.Domain/Image/DicomStudy.cs +++ b/IRaCIS.Core.Domain/Image/DicomStudy.cs @@ -37,8 +37,6 @@ namespace IRaCIS.Core.Domain.Models public string StudyCode { get; set; } = string.Empty; - public int Status { get; set; } = 1; - public string StudyInstanceUid { get; set; } = string.Empty; public DateTime? StudyTime { get; set; } public string Modalities { get; set; } = string.Empty; @@ -47,7 +45,6 @@ namespace IRaCIS.Core.Domain.Models public int SeriesCount { get; set; } = 0; public int InstanceCount { get; set; } = 0; - //public bool SoftDelete { get; set; } = false; public string InstitutionName { get; set; } = string.Empty; public string PatientId { get; set; } = string.Empty; @@ -62,13 +59,25 @@ namespace IRaCIS.Core.Domain.Models public string AcquisitionNumber { get; set; } = string.Empty; public string TriggerTime { get; set; } = string.Empty; + public string BodyPartExamined { get; set; } = string.Empty; + + public string BodyPartForEdit { get; set; } = string.Empty; + + public string ModalityForEdit { get; set; } = string.Empty; + + //0 未知 1 单重 2 双重 public bool IsDoubleReview { get; set; } - public string Comment { get; set; } = string.Empty;//上传的时候的 - - public string BodyPartExamined { get; set; } = string.Empty; + [JsonIgnore] + [ForeignKey("SubjectId")] + public Subject Subject { get; set; } + + [JsonIgnore] + [ForeignKey("SubjectVisitId")] + public SubjectVisit SubjectVisit { get; set; } + public Guid UpdateUserId { get; set; } public DateTime UpdateTime { get; set; } = DateTime.Now; public Guid CreateUserId { get; set; } @@ -78,34 +87,7 @@ namespace IRaCIS.Core.Domain.Models [ForeignKey("CreateUserId")] public User Uploader { get; set; } - //public DateTime? UploadedTime { get; set; } - //public string Uploader { get; set; } = string.Empty; - - - - - public DateTime? DeadlineTime { get; set; } - - public string QAComment { get; set; } = string.Empty; - - - public string BodyPartForEdit { get; set; } = string.Empty; - - public string ModalityForEdit { get; set; } = string.Empty; - - - public bool CheckPassed { get; set; } - - public string CheckResult { get; set; }=string.Empty; - - [JsonIgnore] - [ForeignKey("SubjectId")] - public Subject Subject { get; set; } - - [JsonIgnore] - [ForeignKey("SubjectVisitId")] - public SubjectVisit SubjectVisit { get; set; } //软删除 public bool IsDeleted { get; set; } diff --git a/IRaCIS.Core.Domain/Reading/ReadingCriterion/ReadingQuestionCriterionTrial.cs b/IRaCIS.Core.Domain/Reading/ReadingCriterion/ReadingQuestionCriterionTrial.cs index 4d5ad5f3a..e019facf1 100644 --- a/IRaCIS.Core.Domain/Reading/ReadingCriterion/ReadingQuestionCriterionTrial.cs +++ b/IRaCIS.Core.Domain/Reading/ReadingCriterion/ReadingQuestionCriterionTrial.cs @@ -239,7 +239,7 @@ namespace IRaCIS.Core.Domain.Models //自动 手动生成任务 - public bool IsAutoCreate { get; set; } + public bool IsAutoCreate { get; set; }=true; #endregion ///