using DocumentFormat.OpenXml.EMMA; using FellowOakDicom; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Contracts.Dicom.DTO; using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.Service.ImageAndDoc.DTO; using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infrastructure; using MassTransit; using MassTransit.Initializers; using Medallion.Threading; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using System.Data; using System.IO.Compression; using System.Text; using System.Web; using ZiggyCreatures.Caching.Fusion; namespace IRaCIS.Core.Application.Service.ImageAndDoc { public interface IDownloadAndUploadService { Task PackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isDicom, bool isAnonymize = true); Task SubejctRandomReadingTaskNameDeal(Guid subjectId, Guid trialReadingCriterionId); } [ApiExplorerSettings(GroupName = "Trial")] public class DownloadAndUploadService(IRepository _systemAnonymizationRepository, IRepository _visitTaskRepository, IRepository _subjectVisitRepository, IOSSService _oSSService, IRepository _dictionaryRepository, IRepository _trialRepository, IRepository _studyMonitorRepository, IRepository _taskStudyRepository, IRepository _taskSeriesRepository, IRepository _taskInstanceRepository, IRepository _readingQuestionCriterionTrialRepository, IRepository _noneDicomStudyReposiotry, IRepository _noneDicomStudyFileReposiotry, IDistributedLockProvider _distributedLockProvider, IRepository _trialImageDownloadRepository, IRepository _subjectRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IDownloadAndUploadService { /// /// 受试者随机阅片,任务进行随机编号 /// 进入阅片任务前,随机挑选出该受试者的一个任务,然后给该任务一个编号,编号给的逻辑是:TimePoint Ran+ 已阅任务数量+1 /// 根据当前受试者该标准已阅任务数量(生效失效的任务都算,考虑重阅,最后编号不重复) 第一个就是TimePoint Ran1,后面依次随机挑选出来的阅片序号依次递增 /// /// /// /// public async Task SubejctRandomReadingTaskNameDeal(Guid subjectId, Guid trialReadingCriterionId) { //subject 随机阅片 或者无序 有上传 才处理任务编号 if (_visitTaskRepository.Any(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && (t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.SubjectRandom || (t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.Random && t.TrialReadingCriterion.ImageUploadEnum != ReadingImageUpload.None)))) { //找到 非一致性分析,未签名,状态正常的 并且任务名称是TimePoint的 任务 var needDealTaskList = await _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.UserRoleId && t.ReadingTaskState != ReadingTaskState.HaveSigned && t.TaskBlindName == "Timepoint" && t.ReadingCategory == ReadingCategory.Visit && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze), true).ToListAsync(); if (needDealTaskList.Count > 0) { //已完成的访视任务数量(包含重阅的) var haveFinishedTaskCount = await _visitTaskRepository.CountAsync(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.UserRoleId && t.ReadingTaskState == ReadingTaskState.HaveSigned && t.ReadingCategory == ReadingCategory.Visit); //已经处理过的任务名称的数量 var haveDealedTaskList = await _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.UserRoleId && t.ReadingTaskState != ReadingTaskState.HaveSigned && t.ReadingCategory == ReadingCategory.Visit && t.TaskBlindName != "Timepoint").Select(t => new { t.TaskBlindName, t.SourceSubjectVisitId, t.SouceReadModuleId }).ToListAsync(); //随机赋值编号 比如要处理5个任务,实例化一个包含1-5的数组,每次随机取出一个 List availableNumbers = Enumerable.Range(haveDealedTaskList.Count + haveFinishedTaskCount + 1, needDealTaskList.Count).ToList(); Random rng = new Random(); foreach (var visitTask in needDealTaskList) { int randomIndex = rng.Next(availableNumbers.Count); var findOldTask = haveDealedTaskList.Where(t => t.SourceSubjectVisitId == visitTask.SourceSubjectVisitId && t.SouceReadModuleId == visitTask.SouceReadModuleId).FirstOrDefault(); if (findOldTask != null) { visitTask.TaskBlindName = findOldTask.TaskBlindName; } else { visitTask.TaskBlindName = $"Timepoint Ran {availableNumbers[randomIndex]}"; } availableNumbers.RemoveAt(randomIndex); } await _visitTaskRepository.SaveChangesAsync(); } } return ResponseOutput.Ok(); } /// /// 获取该受试者任务上传列表(展示已上传情况) /// /// [HttpPost] public async Task>> GetSubjectImageUploadList(IRUploadStudyQuery inQuery) { //要根据标准阅片顺序,确定是否查询单个任务的,还是查询所有的 var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId) .Select(t => new { t.IsReadingTaskViewInOrder, t.Trial.Modalitys }).FirstNotNullAsync(); var subjectCode = string.Empty; var subjectId = inQuery.SubjectId; if (criterionInfo.IsReadingTaskViewInOrder == ReadingOrder.Random) { if (inQuery.VisitTaskId == null) { throw new Exception("无序阅片,前端参数传递错误"); } //考虑到一致性分析,必须要这个编号进行过滤 var taskInfo = _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId).Select(t => new { SubjectCode = t.IsAnalysisCreate ? t.BlindSubjectCode : t.Subject.Code, SubjectId = t.SubjectId, }).FirstOrDefault(); subjectId = taskInfo.SubjectId; subjectCode = taskInfo.SubjectCode; } else { if (inQuery.SubjectId == null || inQuery.SubjectCode == null) { throw new Exception("有序阅片,前端参数传递错误"); } //考虑到一致性分析,必须要这个编号进行过滤 subjectCode = inQuery.SubjectCode; } await SubejctRandomReadingTaskNameDeal((Guid)subjectId, inQuery.TrialReadingCriterionId); var query = _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SourceSubjectVisitId != null && t.DoctorUserId == _userInfo.UserRoleId && t.TaskState == TaskState.Effect) //满足 有序,或者随机只看到当前任务的dicom 非dicom检查 .WhereIf(criterionInfo.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId) .Select(u => new SubjectImageUploadDTO() { VisitTaskId = u.Id, SubejctId = u.SubjectId, TrialSiteId = u.Subject.TrialSiteId, IsImageFilter = u.TrialReadingCriterion.IsImageFilter, CriterionModalitys = u.TrialReadingCriterion.CriterionModalitys, SubjectCode = u.IsAnalysisCreate == true ? u.BlindSubjectCode : u.Subject.Code, TaskBlindName = u.TaskBlindName, TaskName = u.TaskName, ReadingTaskState = u.ReadingTaskState, SourceSubjectVisitId = u.SourceSubjectVisitId, OrginalStudyList = u.SourceSubjectVisit.StudyList .Where(t => u.TrialReadingCriterion.IsImageFilter ? ("|" + u.TrialReadingCriterion.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true) .Select(t => new StudyBasicInfo() { Id = t.Id, StudyInstanceUid = t.StudyInstanceUid, ModalityForEdit = t.ModalityForEdit, BodyPartExamined = t.BodyPartExamined, BodyPartForEdit = t.BodyPartForEdit, StudyCode = t.StudyCode, StudyTime = t.StudyTime, Description = t.Description, InstanceCount = t.InstanceCount, Modalities = t.Modalities, SeriesCount = t.SeriesCount, }).ToList(), UploadStudyList = u.TaskStudyList.Select(t => new StudyBasicInfo() { Id = t.Id, StudyInstanceUid = t.StudyInstanceUid, ModalityForEdit = t.ModalityForEdit, BodyPartExamined = t.BodyPartExamined, BodyPartForEdit = t.BodyPartForEdit, StudyCode = t.StudyCode, StudyTime = t.StudyTime, Description = t.Description, InstanceCount = t.InstanceCount, Modalities = t.Modalities, SeriesCount = t.SeriesCount, SopInstanceUidList = t.InstanceList.Select(t => t.SopInstanceUid).ToList(), }).ToList() }) ; //var test = await query.ToListAsync(); var list = await query.Where(t => t.SubjectCode == subjectCode).ToListAsync(); return ResponseOutput.Ok(list, new { TrialModality = criterionInfo.Modalitys }); } private void SpecialArchiveStudyDeal(TaskStudy 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 } [TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task PreArchiveDicomStudy(PriArchiveTaskStudyCommand preArchiveStudyCommand) { var studyMonitor = new StudyMonitor() { TrialId = preArchiveStudyCommand.TrialId, SubjectId = preArchiveStudyCommand.SubjectId, SubjectVisitId = preArchiveStudyCommand.SubjectVisitId, IsSuccess = false, UploadStartTime = DateTime.Now, IsDicom = true, IP = _userInfo.IP, FileCount = preArchiveStudyCommand.FileCount, }; var addEntity = await _studyMonitorRepository.AddAsync(studyMonitor, true); return ResponseOutput.Ok(addEntity.Id); } /// /// 在调用预归档前验证 这些检查是否可以全新上传还是已存在补充 目前前端允许 IsAllowUpload==true 全新、IsAllowReUpload==true 补充的study ,全部丢到后端,后端判断存在,就删除之前的检查,全新插入 /// /// /// /// public async Task> VerifyIRStudyAllowUpload(TaskStudyAchivePreConfirmCommand inCommand, [FromServices] IRepository _dicomStudyRepository) { var currentUploadSubjectVisitId = inCommand.VisitTaskId == null ? null : _visitTaskRepository.Where(t => t.Id == inCommand.VisitTaskId).Select(t => t.SourceSubjectVisitId).FirstOrDefault(); //重阅任务排除 var notAllowedUidList1 = _taskStudyRepository.Where(t => t.TrialId == inCommand.TrialId && t.VisitTask.TaskState == TaskState.Effect && inCommand.StudyInstanceUidList.Contains(t.StudyInstanceUid)).Select(t => new { t.StudyInstanceUid, t.SubjectId, SubjectVisitId = t.VisitTask.SourceSubjectVisitId, SubejectCode = t.VisitTask.IsAnalysisCreate ? t.VisitTask.BlindSubjectCode : t.Subject.Code, VisitTaskId = (Guid?)t.VisitTaskId }).ToList(); var notAllowedUidList2 = _dicomStudyRepository.Where(t => t.TrialId == inCommand.TrialId && inCommand.StudyInstanceUidList.Contains(t.StudyInstanceUid)).Select(t => new { t.StudyInstanceUid, t.SubjectId, SubjectVisitId = (Guid?)t.SubjectVisitId, SubejectCode = t.Subject.Code, VisitTaskId = (Guid?)null }).ToList(); var notAllowedUidList = notAllowedUidList1.Union(notAllowedUidList2); var result = new List(); foreach (var studyUid in inCommand.StudyInstanceUidList) { var findStudy = notAllowedUidList.Where(t => t.StudyInstanceUid == studyUid).FirstOrDefault(); if (findStudy != null) { //同一个subject 同一份影响 if (findStudy.SubejectCode == inCommand.SubjectCode && findStudy.SubjectId == inCommand.SubjectId) { //上传给后处理其他访视了 if (inCommand.VisitTaskId != null && findStudy.VisitTaskId != null && findStudy.VisitTaskId != inCommand.VisitTaskId && findStudy.SubjectVisitId != currentUploadSubjectVisitId) { result.Add(new TaskStudyArchiveConfirmResult() { StudyInstanceUid = studyUid, IsAllowReUpload = false, IsAllowUpload = false }); } //在原始crc 里面上传了,并且不是当前访视 else if (inCommand.VisitTaskId != null && findStudy.VisitTaskId == null && findStudy.SubjectVisitId != currentUploadSubjectVisitId) { result.Add(new TaskStudyArchiveConfirmResult() { StudyInstanceUid = studyUid, IsAllowReUpload = false, IsAllowUpload = false }); } else { result.Add(new TaskStudyArchiveConfirmResult() { StudyInstanceUid = studyUid, IsAllowReUpload = true }); } } else { result.Add(new TaskStudyArchiveConfirmResult() { StudyInstanceUid = studyUid, IsAllowReUpload = false, IsAllowUpload = false }); } } else { //说明没上传 不用管 result.Add(new TaskStudyArchiveConfirmResult() { StudyInstanceUid = studyUid, IsAllowUpload = true }); } } return result; } [TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task AddOrUpdateArchiveTaskStudy(TaskArchiveStudyCommand incommand) { #region 获取该subject 已生成任务的访视的检查 //var queryStudy = _visitTaskRepository.Where(t => t.SubjectId == incommand.SubjectId && t.SourceSubjectVisitId != null && t.DoctorUserId == _userInfo.Id).Select(u => new //{ // VisitTaskId = u.Id, // SourceSubjectVisitId = u.SourceSubjectVisitId, // OrginalStudyList = u.SourceSubjectVisit.StudyList.Select(t => new StudyBasicInfo() // { // Id = t.Id, // StudyInstanceUid = t.StudyInstanceUid // }).ToList(), //}); //var studyList = await queryStudy.ToListAsync(); //var findOriginStudy = studyList.FirstOrDefault(c => c.OrginalStudyList.Any(t => t.StudyInstanceUid == incommand.Study.StudyInstanceUid)); //if (findOriginStudy == null) //{ // return ResponseOutput.NotOk("该检查不属于该受试者,请核查"); //} #endregion //总数为0的检查不允许提交 if (incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Count() == 0) { return ResponseOutput.NotOk("Study_InstanceCountZero"); } var @uploadLock = _distributedLockProvider.CreateLock($"UploadTaskDicom"); using (await @uploadLock.AcquireAsync()) { if (_fusionCache.GetOrDefault(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid)) != Guid.Empty) { //---当前已有人正在上传和归档该检查! return ResponseOutput.NotOk(I18n.T("UploadDownLoad_ArchiveInProgress")); } else { //在事务未完成前 防止前端重复提交 await _fusionCache.SetAsync(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid), _userInfo.UserRoleId, TimeSpan.FromMinutes(1)); } } var visiTaskId = incommand.VisitTaskId; var modalitys = string.Empty; try { var trialId = incommand.TrialId; var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == incommand.StudyMonitorId); studyMonitor.UploadFinishedTime = DateTime.Now; studyMonitor.ArchiveFinishedTime = DateTime.Now; studyMonitor.FailedFileCount = incommand.FailedFileCount; studyMonitor.IsSuccess = incommand.FailedFileCount == 0; 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 findStudy = await _taskStudyRepository.FirstOrDefaultAsync(t => t.Id == studyId); studyMonitor.StudyId = studyId; studyMonitor.StudyCode = findStudy?.StudyCode ?? ""; studyMonitor.IsDicomReUpload = findStudy != null; //上传 if (studyMonitor.IsDicomReUpload == false) { var study = _mapper.Map(incommand.Study); var @lock = _distributedLockProvider.CreateLock($"StudyCode"); using (await @lock.AcquireAsync()) { //查询数据库获取最大的Code 没有记录则为0 var dbStudyCodeIntMax = _taskStudyRepository.Where(s => s.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max(); //获取缓存中的值 并发的时候,需要记录,已被占用的值 这样其他线程在此占用的最大的值上递增 var cacheMaxCodeInt = await _fusionCache.GetOrDefaultAsync(CacheKeys.TrialStudyMaxCode(trialId)); int currentNextCodeInt = cacheMaxCodeInt > dbStudyCodeIntMax ? cacheMaxCodeInt + 1 : dbStudyCodeIntMax + 1; study.Code = currentNextCodeInt; study.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(TaskStudy)); await _fusionCache.SetAsync(CacheKeys.TrialStudyMaxCode(trialId), study.Code, TimeSpan.FromMinutes(30)); } study.Id = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString(), visiTaskId.ToString()); study.TrialId = incommand.TrialId; study.SubjectId = incommand.SubjectId; study.VisitTaskId = visiTaskId; //study.SubjectVisitId = incommand.SubjectVisitId; //特殊处理逻辑 study.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Distinct()); SpecialArchiveStudyDeal(study); modalitys = study.Modalities; await _taskStudyRepository.AddAsync(study); studyMonitor.StudyCode = study.StudyCode; foreach (var seriesItem in incommand.Study.SeriesList) { var series = _mapper.Map(seriesItem); series.Id = IdentifierHelper.CreateGuid(seriesItem.StudyInstanceUid, seriesItem.SeriesInstanceUid, incommand.TrialId.ToString(), visiTaskId.ToString()); series.StudyId = study.Id; series.TrialId = incommand.TrialId; series.SubjectId = incommand.SubjectId; //series.SubjectVisitId = incommand.SubjectVisitId; series.VisitTaskId = visiTaskId; //前端传递的数量不准,上传的时候,把失败的也加进来了,以实际数组的数字为准 series.InstanceCount = seriesItem.InstanceList.Count; await _taskSeriesRepository.AddAsync(series); foreach (var instanceItem in seriesItem.InstanceList) { var isntance = _mapper.Map(instanceItem); Guid instanceId = IdentifierHelper.CreateGuid(study.StudyInstanceUid, series.SeriesInstanceUid, isntance.SopInstanceUid, study.TrialId.ToString(), visiTaskId.ToString()); isntance.Id = instanceId; isntance.StudyId = study.Id; isntance.SeriesId = series.Id; isntance.TrialId = incommand.TrialId; isntance.SubjectId = incommand.SubjectId; //isntance.SubjectVisitId = incommand.SubjectVisitId; isntance.VisitTaskId = visiTaskId; await _taskInstanceRepository.AddAsync(isntance); } } } else { //重传的时候也要赋值检查Id studyMonitor.StudyId = findStudy.Id; studyMonitor.StudyCode = findStudy.StudyCode; //特殊处理逻辑 findStudy.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Union(findStudy.Modalities.Split("、", StringSplitOptions.RemoveEmptyEntries)).Distinct()); SpecialArchiveStudyDeal(findStudy); modalitys = findStudy.Modalities; // 少了整个序列 //某个序列下少了instance foreach (var seriesItem in incommand.Study.SeriesList) { var seriesId = IdentifierHelper.CreateGuid(seriesItem.StudyInstanceUid, seriesItem.SeriesInstanceUid, trialId.ToString(), visiTaskId.ToString()); TaskSeries dicomSeries = await _taskSeriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId); //判断重复 if (dicomSeries == null) { var series = _mapper.Map(seriesItem); series.Id = seriesId; series.StudyId = findStudy.Id; series.TrialId = incommand.TrialId; series.SubjectId = incommand.SubjectId; series.VisitTaskId = visiTaskId; //series.SubjectVisitId = incommand.SubjectVisitId; dicomSeries = await _taskSeriesRepository.AddAsync(series); //新的序列 那么 检查的序列数量+1 findStudy.SeriesCount += 1; } else { //该序列掉了instance dicomSeries.InstanceCount += seriesItem.InstanceList.Count; } 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; await _taskInstanceRepository.AddAsync(insntance); } // 不管是新的序列 还是 该序列 掉了Instance 重传的时候 检查的instance 数量都会增加 findStudy.InstanceCount += seriesItem.InstanceList.Count; } } var @lock2 = _distributedLockProvider.CreateLock($"StudyCommit"); using (await @lock2.AcquireAsync()) { await _taskStudyRepository.SaveChangesAsync(); } } catch (Exception ex) { return ResponseOutput.NotOk(ex.Message); } finally { await _fusionCache.RemoveAsync(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid)); await _fusionCache.RemoveAsync(CacheKeys.TrialTaskStudyUidUploading(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid)); } return ResponseOutput.Ok(modalitys); } [HttpDelete] public async Task DeleteTaskStudy(Guid visitTaskId, bool isDicom, Guid? dicomStudyId, Guid? noneDicomStudyId) { if (isDicom) { if (dicomStudyId == null) { await _taskStudyRepository.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId); await _taskSeriesRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId); await _taskInstanceRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId); } else { await _taskStudyRepository.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId && t.Id == dicomStudyId); await _taskSeriesRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId && t.Id == dicomStudyId); await _taskInstanceRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId && t.Id == dicomStudyId); } } else { await _noneDicomStudyFileReposiotry.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId && t.OriginNoneDicomStudyId == noneDicomStudyId); } await _noneDicomStudyFileReposiotry.SaveChangesAsync(); return ResponseOutput.Ok(); } /// /// IR 上传任务 nonedicom 列表 后处理的数据UploadedFileCount不能排序 --new /// /// /// [HttpPost] public async Task> GetIRUploadTaskNoneDicomStudyList(IRUploadStudyQuery inQuery) { var subjectCode = inQuery.SubjectCode; var subjectId = inQuery.SubjectId; var doctorUserId = _userInfo.UserRoleId; if (inQuery.VisitTaskId != null) { //考虑到一致性分析,必须要这个编号进行过滤 //医学审核查看下载按钮,这个时候需要知道医生 var taskInfo = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId).Select(t => new { SubjectCode = t.IsAnalysisCreate ? t.BlindSubjectCode : t.Subject.Code, SubjectId = t.SubjectId, t.DoctorUserId, t.IsAnalysisCreate }).FirstNotNullAsync(); subjectId = taskInfo.SubjectId; subjectCode = taskInfo.SubjectCode; doctorUserId = (Guid)taskInfo.DoctorUserId!; } var info = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId) .Select(t => new { t.IsImageFilter, t.CriterionModalitys, t.IsReadingTaskViewInOrder }).FirstNotNullAsync(); var query = from u in _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SourceSubjectVisitId != null && t.DoctorUserId == doctorUserId && t.TaskState == TaskState.Effect) //满足 有序,或者随机只看到当前任务的dicom 非dicom检查 .WhereIf(info.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId) join ns in _noneDicomStudyReposiotry.Where(t => t.SubjectId == subjectId).WhereIf(info.IsImageFilter, t => ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|")) on u.SourceSubjectVisitId equals ns.SubjectVisitId select new TaskNoneDicomStudyDTO() { SubjectId = u.SubjectId, SubjectCode = u.IsSelfAnalysis == true ? u.BlindSubjectCode : u.Subject.Code, TaskBlindName = u.TaskBlindName, TaskName = u.TaskName, ReadingTaskState=u.ReadingTaskState, SourceSubjectVisitId = u.SourceSubjectVisitId, VisitTaskId = u.Id, Id = ns.Id, Description = ns.Description, ImageDate = ns.ImageDate, BodyPart = ns.BodyPart, FileCount = ns.FileCount, Modality = ns.Modality, StudyCode = ns.StudyCode, FileList = ns.NoneDicomFileList.Select(t => new NoneDicomFileInfo() { FileType = t.FileType, FileName = t.FileName, FileSize = t.FileSize, Path = t.Path }).ToList() }; var list = await query.Where(t => t.SubjectCode == subjectCode).SortToListAsync(inQuery); var noneDicomStudyTaskIdList = list.Select(t => t.VisitTaskId).ToList(); var taskNoneDicomStudyList = _visitTaskRepository.Where(t => noneDicomStudyTaskIdList.Contains(t.Id)) .SelectMany(t => t.TaskNoneDicomStudyFileList).Where(t => noneDicomStudyTaskIdList.Contains((Guid)t.VisitTaskId)) .Select(u => new NoneDicomFileInfo { OriginNoneDicomStudyId = u.OriginNoneDicomStudyId, FileType = u.FileType, FileName = u.FileName, FileSize = u.FileSize, Path = u.Path }) .ToList(); foreach (var item in list) { item.UploadedFileCount = taskNoneDicomStudyList.Where(t => t.OriginNoneDicomStudyId == item.Id).Count(); item.UploadedFileList = taskNoneDicomStudyList.Where(t => t.OriginNoneDicomStudyId == item.Id).ToList(); } return list; } /// /// IQC 获取CRC 上传到某一个访视的的检查信息 (原始影像信息 包含dicom 非dicom) /// /// /// [HttpPost] public async Task GetCRCUploadedStudyInfo(CRCUploadedStudyQuqry inQuery) { var isQueryDicom = inQuery.DicomStudyIdList.Count > 0; var isQueryNoneDicom = inQuery.NoneDicomStudyIdList.Count > 0; var imageType = (isQueryDicom && isQueryNoneDicom) ? ImageType.DicomAndNoneDicom : (isQueryDicom ? ImageType.Dicom : ImageType.NoneDicom); var query = from sv in _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId) select new { TrialId = sv.TrialId, SubjectId=sv.SubjectId, SubjectCode = sv.Subject.Code, TrialSiteCode=sv.TrialSite.TrialSiteCode, VisitName = sv.VisitName, StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false) .Select(u => new { u.PatientId, u.StudyTime, u.StudyCode, SeriesList = u.SeriesList.Select(z => new { z.Modality, InstanceList = z.DicomInstanceList.Select(k => new { k.Path, k.FileSize }) }) }).ToList(), NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false) .Select(nd => new { nd.Modality, nd.StudyCode, nd.ImageDate, FileList = nd.NoneDicomFileList.Select(file => new { file.FileName, file.Path, file.FileType, file.FileSize, }) }).ToList() }; var result = query.FirstOrDefault(); var preDownloadInfo = new TrialImageDownload() { Id = NewId.NextSequentialGuid(), TrialId = result.TrialId, SubjectId = result.SubjectId, SubjectCode = result.SubjectCode, TrialSiteCode = result.TrialSiteCode, IP = _userInfo.IP, DownloadStartTime = DateTime.Now, IsSuccess = false, ImageType = imageType, VisitName = string.Join(" | ", result.VisitName), NoneDicomStudyCount = result.NoneDicomStudyList.Count(), DicomStudyCount = result.StudyList.Count(), ImageCount = result.StudyList.Sum(s => s.SeriesList.Sum(s => s.InstanceList.Count())) + result.NoneDicomStudyList.Sum(s => s.FileList.Count()), ImageSize = result.StudyList.Sum(t => t.SeriesList.Sum(s => s.InstanceList.Sum(i => i.FileSize))) + result.NoneDicomStudyList.Sum(t => t.FileList.Sum(s => s.FileSize)) ?? 0 }; await _trialImageDownloadRepository.AddAsync(preDownloadInfo, true); return ResponseOutput.Ok(result, preDownloadInfo.Id); } /// /// IR 阅片页面 和IR 任务列表页面下载 勾选下载列表(后端要考虑到一致性分析 subjectCode的问题) /// /// /// [HttpPost] public async Task> GetSubjectImageDownloadSelectList(IRReadingDownloadQuery inQuery) { var doctorUserId = _userInfo.UserRoleId; var isAnalysisCreate = false; //要根据标准阅片顺序,确定是否查询单个任务的,还是查询所有的 var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId) .Select(t => new { t.IsReadingTaskViewInOrder }).FirstNotNullAsync(); var subjectCode = string.Empty; var subjectId = inQuery.SubjectId; if (criterionInfo.IsReadingTaskViewInOrder == ReadingOrder.Random) { if (inQuery.VisitTaskId == null) { throw new Exception("无序阅片,前端参数传递错误"); } } else { if (inQuery.SubjectId == null || inQuery.SubjectCode == null) { throw new Exception("有序阅片,前端参数传递错误"); } //考虑到一致性分析,必须要这个编号进行过滤 subjectCode = inQuery.SubjectCode; } if (inQuery.VisitTaskId != null) { //考虑到一致性分析,必须要这个编号进行过滤 //医学审核查看下载按钮,这个时候需要知道医生 var taskInfo = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId).Select(t => new { SubjectCode = t.IsAnalysisCreate ? t.BlindSubjectCode : t.Subject.Code, SubjectId = t.SubjectId, t.DoctorUserId, t.IsAnalysisCreate }).FirstNotNullAsync(); subjectId = taskInfo.SubjectId; subjectCode = taskInfo.SubjectCode; doctorUserId = (Guid)taskInfo.DoctorUserId!; isAnalysisCreate = taskInfo.IsAnalysisCreate; } var query = _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SourceSubjectVisitId != null && t.DoctorUserId == doctorUserId && t.TaskState == TaskState.Effect) //满足 有序,或者随机只看到当前任务的dicom 非dicom检查 .WhereIf(criterionInfo.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId) .ProjectTo(_mapper.ConfigurationProvider); //这里过滤是否是一致性分析的 var list = await query.Where(t => t.SubjectCode == subjectCode).ToListAsync(); foreach (var item in list) { if (item.IsImageFilter) { item.DicomStudyList = item.DicomStudyList.Where(t => ("|" + item.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|")).ToList(); item.NoneDicomStudyList = item.NoneDicomStudyList.Where(t => ("|" + item.CriterionModalitys + "|").Contains("|" + t.Modality + "|")).ToList(); } } #region 将任务级别转为检查级别 var result = new List(); var dicomStudyList = list.Where(item => item.DicomStudyList.Count > 0) .Select(item => new SubjectCRCImageUploadedStudyDto { VisitTaskId = item.VisitTaskId, SubjectId = item.SubjectId, SubjectCode = item.SubjectCode, TaskBlindName = item.TaskBlindName, TaskName = item.TaskName, IsImageFilter = item.IsImageFilter, CriterionModalitys = item.CriterionModalitys, SourceSubjectVisitId = item.SourceSubjectVisitId, //取dicom DicomStudyList = item.DicomStudyList, }).ToList(); var noneStudyList = list.Where(item => item.NoneDicomStudyList.Count > 0) .Select(item => new SubjectCRCImageUploadedStudyDto { VisitTaskId = item.VisitTaskId, SubjectId = item.SubjectId, SubjectCode = item.SubjectCode, TaskBlindName = item.TaskBlindName, TaskName = item.TaskName, IsImageFilter = item.IsImageFilter, CriterionModalitys = item.CriterionModalitys, SourceSubjectVisitId = item.SourceSubjectVisitId, //非dicom NoneDicomStudyList = item.NoneDicomStudyList, }).ToList(); result.AddRange(dicomStudyList); result.AddRange(noneStudyList); #endregion return result; } /// /// IR 阅片页面获取下载检查的信息 会根据标准进行过滤检查,(后端要考虑到一致性分析 subjectCode的问题) /// 检查在访视下面,所以需要传递下载的访视Id,另外下载访视下面那些检查,就把访视下的对应的检查Id 丢到数组里就好 /// /// /// [HttpPost] public async Task GetIRReadingDownloadStudyInfo(IRDownloadQuery inQuery) { var info = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId) .Select(t => new { t.IsImageFilter, t.CriterionModalitys, t.TrialId, t.IsReadingTaskViewInOrder }).FirstNotNullAsync(); var isQueryDicom = inQuery.DicomStudyIdList.Count > 0; var isQueryNoneDicom = inQuery.NoneDicomStudyIdList.Count > 0; var imageType = (isQueryDicom && isQueryNoneDicom) ? ImageType.DicomAndNoneDicom : (isQueryDicom ? ImageType.Dicom : ImageType.NoneDicom); var taskIdList = inQuery.SubjectVisitTaskList.Select(t => t.TaskId).ToList(); var subjectVisitIdList = inQuery.SubjectVisitTaskList.Select(t => t.SubjectVisitId).ToList(); var trialSiteCode = _visitTaskRepository.Where(t => t.Id == taskIdList.FirstOrDefault()).Select(t => t.IsAnalysisCreate ? t.BlindTrialSiteCode : t.Subject.TrialSite.TrialSiteCode).FirstOrDefault()??string.Empty; var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubjectId).SelectMany(t => t.SubjectVisitList.Where(t => subjectVisitIdList.Contains(t.Id))) //一致性分析,导致查询出来两条数据 join visitTask in _visitTaskRepository.Where(t => taskIdList.Contains(t.Id)) on sv.Id equals visitTask.SourceSubjectVisitId select new { SubjectCode = inQuery.SubjectCode, VisitName = sv.VisitName, TaskBlindName = visitTask.TaskBlindName, StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false) .Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true) .Select(u => new { u.PatientId, u.StudyTime, u.StudyCode, SeriesList = u.SeriesList.Select(z => new { z.Modality, InstancePathList = z.DicomInstanceList.Select(k => new { k.Path, k.FileSize }) }) }), NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false) .Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|") : true) .Select(nd => new { nd.Modality, nd.StudyCode, nd.ImageDate, FileList = nd.NoneDicomFileList.Select(file => new { file.FileName, file.Path, file.FileType, file.FileSize }) }) }; var result = await query.ToListAsync(); var preDownloadInfo = new TrialImageDownload() { Id = NewId.NextSequentialGuid(), TrialId = info.TrialId, SubjectId=inQuery.SubjectId, SubjectCode = inQuery.SubjectCode, TrialSiteCode= trialSiteCode, IP = _userInfo.IP, DownloadStartTime = DateTime.Now, IsSuccess = false, ImageType = imageType, VisitName = string.Join(" | ", result.Select(t => t.VisitName).OrderBy(t => t).ToList()), NoneDicomStudyCount = result.Sum(t => t.NoneDicomStudyList.Count()), DicomStudyCount = result.Sum(t => t.StudyList.Count()), ImageCount = result.Sum(t => t.StudyList.Sum(s => s.SeriesList.Sum(s => s.InstancePathList.Count())) + t.NoneDicomStudyList.Sum(s => s.FileList.Count())), ImageSize = result.Sum(t => t.StudyList.Sum(t => t.SeriesList.Sum(s => s.InstancePathList.Sum(i => i.FileSize))) + t.NoneDicomStudyList.Sum(t => t.FileList.Sum(s => s.FileSize)) ) ?? 0 }; await _trialImageDownloadRepository.AddAsync(preDownloadInfo, true); return ResponseOutput.Ok(result, new { PreDownloadId = preDownloadInfo.Id, info.IsReadingTaskViewInOrder }); } /// /// dicom 影像后处理预览接口 /// /// /// [HttpPost] public async Task GetTaskUploadedDicomStudyList(IRTaskUploadedDicomStudyQuery inQuery) { var info = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId) .Select(t => new { t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys }).FirstNotNullAsync(); var query = _taskStudyRepository.Where(t => t.VisitTaskId == inQuery.VisitTaskId) .Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true) .Select(t => new { StudyId = t.Id, t.Modalities, t.InstanceCount, t.SeriesCount, t.StudyCode, SeriesList = t.SeriesList.OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).Select(u => new { u.SeriesTime, u.InstanceCount, u.ImageResizePath, u.Modality, u.Description, u.SeriesInstanceUid, u.SeriesNumber, u.SliceThickness, u.StudyInstanceUid, IsExistMutiFrames = u.InstanceList.Any(t => t.NumberOfFrames > 1), InstanceInfoList = u.InstanceList.OrderBy(t => t.InstanceNumber).Select(k => new InstanceBasicInfo() { Id = k.Id, NumberOfFrames = k.NumberOfFrames, HtmlPath = k.HtmlPath, Path = k.Path, InstanceNumber = k.InstanceNumber, }).ToList() }) }); var list = await query.ToListAsync(); return ResponseOutput.Ok(list); } /// /// 影像下载成功回调 /// /// /// public async Task DownloadImageSuccess(Guid trialImageDownloadId) { await _trialImageDownloadRepository.UpdatePartialFromQueryAsync(t => t.Id == trialImageDownloadId, u => new TrialImageDownload() { DownloadEndTime = DateTime.Now, IsSuccess = true }, true); return ResponseOutput.Ok(); } /// /// 项目影像下载监控列表 /// /// /// [HttpPost] public async Task> GetTrialDownloadList(TrialIamgeDownQuery inQuery) { var query = _trialImageDownloadRepository.Where(t => t.TrialId == inQuery.TrialId) .WhereIf(inQuery.SubjectCode.IsNotNullOrEmpty(), t => t.SubjectCode.Contains(inQuery.SubjectCode)) .WhereIf(inQuery.IP.IsNotNullOrEmpty(), t => t.IP.Contains(inQuery.IP)) .WhereIf(inQuery.Name.IsNotNullOrEmpty(), t => t.CreateUserRole.UserName.Contains(inQuery.Name) || t.CreateUserRole.FullName.Contains(inQuery.Name)) .WhereIf(inQuery.ImageType != null, t => t.ImageType == inQuery.ImageType) .WhereIf(inQuery.UserType != null, t => t.CreateUserRole.UserTypeEnum == inQuery.UserType) .WhereIf(inQuery.IsSuccess != null, t => t.IsSuccess == inQuery.IsSuccess) .WhereIf(inQuery.DownloadStartTime != null, t => t.DownloadStartTime >= inQuery.DownloadStartTime) .WhereIf(inQuery.DownloadEndTime != null, t => t.DownloadEndTime <= inQuery.DownloadEndTime) .ProjectTo(_mapper.ConfigurationProvider); return await query.ToPagedListAsync(inQuery); } /// /// 更新后处理上传的检查modality /// /// /// /// [HttpPut] public async Task UpdateTaskStudyModality(Guid taskStudyId, string modality) { await _taskStudyRepository.UpdatePartialFromQueryAsync(t => t.Id == taskStudyId, u => new TaskStudy() { ModalityForEdit = modality }, true); return ResponseOutput.Ok(); } #region 之前后端下载废弃 /// /// 受试者级别所有的影像 /// 访视级别的影响 传递subjectVisitId /// 标准Id是可选的 不同标准有些检查可能有过滤 /// /// /// /// [Obsolete] public async Task GetSubejectOrVisitZipInfo([FromServices] IRepository _subjectRepository, SubejctZipInfoQuery inQuery) { var isImageFilter = false; var criterionModalitys = string.Empty; if (inQuery.TrialReadingCriterionId != null) { var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId).Select(t => new { t.IsImageFilter, t.CriterionModalitys }).FirstOrDefaultAsync(); if (criterionInfo != null) { isImageFilter = criterionInfo.IsImageFilter; criterionModalitys = criterionInfo.CriterionModalitys; } } if (inQuery.SubejectVisitId != null) { var query = from sv in _subjectVisitRepository.Where(t => t.Id == inQuery.SubejectVisitId) select new { SubjectCode = sv.Subject.Code, VisitName = sv.VisitName, StudyList = sv.StudyList.AsQueryable().WhereIf(isImageFilter, t => ("|" + criterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|")) .Select(u => new { u.PatientId, u.StudyTime, u.StudyCode, SeriesList = u.SeriesList.Select(z => new { z.Modality, InstancePathList = z.DicomInstanceList.Select(k => new { k.Path }) }) }), NoneDicomStudyList = sv.NoneDicomStudyList.AsQueryable().WhereIf(isImageFilter, t => ("|" + criterionModalitys + "|").Contains("|" + t.Modality + "|")) .Select(nd => new { nd.Modality, nd.StudyCode, nd.ImageDate, FileList = nd.NoneDicomFileList.Select(file => new { file.FileName, file.Path, file.FileType }) }) }; var result = query.ToList(); return ResponseOutput.Ok(result); } else if (inQuery.SubejctId != null) { var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubejctId).SelectMany(t => t.SubjectVisitList) select new { SubjectCode = sv.Subject.Code, VisitName = sv.VisitName, StudyList = sv.StudyList.AsQueryable().WhereIf(isImageFilter, t => ("|" + criterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|")) .Select(u => new { u.PatientId, u.StudyTime, u.StudyCode, SeriesList = u.SeriesList.Select(z => new { z.Modality, InstancePathList = z.DicomInstanceList.Select(k => new { k.Path }) }) }), NoneDicomStudyList = sv.NoneDicomStudyList.AsQueryable().WhereIf(isImageFilter, t => ("|" + criterionModalitys + "|").Contains("|" + t.Modality + "|")) .Select(nd => new { nd.Modality, nd.StudyCode, nd.ImageDate, FileList = nd.NoneDicomFileList.Select(file => new { file.FileName, file.Path, file.FileType }) }) }; var result = query.ToList(); return ResponseOutput.Ok(result); } else { return ResponseOutput.NotOk("不允许 subjectId SubejectVisitId 都不传递"); } } /// /// 后台任务调用,前端忽略该接口 /// /// /// /// /// /// [HttpPost] [Obsolete] public async Task PackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isDicom, bool isAnonymize = true) { var subjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId); try { var addOrUpdateFixedFieldList = new List(); var ircFieldList = new List(); if (isAnonymize) { var systemAnonymizationList = _systemAnonymizationRepository.Where(t => t.IsEnable).ToList(); addOrUpdateFixedFieldList = systemAnonymizationList.Where(t => t.IsFixed).ToList(); ircFieldList = systemAnonymizationList.Where(t => t.IsFixed == false).ToList(); } var subjectAndVisitInfo = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { SubjectCode = t.Subject.Code, t.Trial.TrialCode, t.VisitNum }).FirstOrDefault(); var query = from sv in _subjectVisitRepository.Where(t => t.Id == subjectVisitId) select new { 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, InstancePathList = z.DicomInstanceList.Select(k => new { k.Path }) }) }), NoneDicomStudyList = sv.NoneDicomStudyList.Select(nd => new { nd.Modality, nd.StudyCode, nd.ImageDate, FileList = nd.NoneDicomFileList.Select(file => new { file.FileName, file.Path, file.FileType }) }) }; var info = query.FirstOrDefault(); if (info != null) { // 创建一个临时文件夹来存放文件 string tempFolderPath = Path.Combine(Directory.GetCurrentDirectory(), $"DownloadTemp_{NewId.NextGuid()}"); Directory.CreateDirectory(tempFolderPath); //dicom 处理 if (isDicom) { // 遍历查询结果 foreach (var studyInfo in info.StudyList) { // 遍历 Series foreach (var seriesInfo in studyInfo.SeriesList) { string studyDicomFolderPath = Path.Combine(tempFolderPath, "Dicom",/* $"{info.SubjectCode}_{info.VisitName}",*/ $"{studyInfo.StudyCode}_{studyInfo.StudyTime?.ToString("yyyy-MM-dd")}_{seriesInfo.Modality}"); // 创建 影像 文件夹 Directory.CreateDirectory(studyDicomFolderPath); // 遍历 InstancePathList foreach (var instanceInfo in seriesInfo.InstancePathList) { // 复制文件到相应的文件夹 string destinationPath = Path.Combine(studyDicomFolderPath, Path.GetFileName(instanceInfo.Path)); //下载到当前目录 await _oSSService.DownLoadFromOSSAsync(instanceInfo.Path, destinationPath); #region 匿名化逻辑 if (isAnonymize) { //受试者随机阅片,需要匿名化检查时间 DicomFile dicomFile = await DicomFile.OpenAsync(destinationPath, Encoding.Default); DicomDataset dataset = dicomFile.Dataset; dataset.AddOrUpdate(DicomTag.StudyDate, string.Empty); dataset.AddOrUpdate(DicomTag.StudyTime, string.Empty); #region 前端已经匿名化,不需要做相关tag匿名化 //DicomFile dicomFile = await DicomFile.OpenAsync(destinationPath, Encoding.Default); //DicomDataset dataset = dicomFile.Dataset; //foreach (var item in addOrUpdateFixedFieldList) //{ // var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16)); // dataset.AddOrUpdate(dicomTag, item.ReplaceValue); //} //foreach (var item in ircFieldList) //{ // var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16)); // if (dicomTag == DicomTag.ClinicalTrialProtocolID) // { // dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.TrialCode); // } // if (dicomTag == DicomTag.ClinicalTrialSiteID) // { // //dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.TrialSiteCode); // } // if (dicomTag == DicomTag.ClinicalTrialSubjectID) // { // dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.SubjectCode); // } // if (dicomTag == DicomTag.ClinicalTrialTimePointID) // { // dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.VisitNum.ToString()); // } // if (dicomTag == DicomTag.PatientID) // { // dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.TrialCode + "_" + subjectAndVisitInfo.SubjectCode); // } //} #endregion } #endregion } } } var zipDicomPath = Path.Combine(Directory.GetCurrentDirectory(), $"{info.SubjectCode}_{info.VisitName}_ImageStudy_Dicom.zip"); ZipFile.CreateFromDirectory(Path.Combine(tempFolderPath, "Dicom"), zipDicomPath); //上传到Oss var relativeDicomPath = await _oSSService.UploadToOSSAsync(zipDicomPath, $"download_zip", false); //await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { PackState = PackState.Packed, VisitImageZipPath = relativeDicomPath }); File.Delete(zipDicomPath); } else { var relativeNoneDicomPath = string.Empty; if (info.NoneDicomStudyList.Count() == 1 && info.NoneDicomStudyList.SelectMany(t => t.FileList).Count() == 1) { relativeNoneDicomPath = info.NoneDicomStudyList.First().FileList.First().Path; } else { //非dicom 处理 foreach (var noneDicomStudy in info.NoneDicomStudyList) { string studyNoneDicomFolderPath = Path.Combine(tempFolderPath, "NoneDicom", /*$"{info.SubjectCode}_{info.VisitName}",*/ $"{noneDicomStudy.StudyCode}_{noneDicomStudy.ImageDate.ToString("yyyy-MM-dd")}_{noneDicomStudy.Modality}"); Directory.CreateDirectory(studyNoneDicomFolderPath); foreach (var file in noneDicomStudy.FileList) { string destinationPath = Path.Combine(studyNoneDicomFolderPath, Path.GetFileName(file.FileName)); //下载到当前目录 await _oSSService.DownLoadFromOSSAsync(HttpUtility.UrlDecode(file.Path), destinationPath); } } var zipNoneDicomPath = Path.Combine(Directory.GetCurrentDirectory(), $"{info.SubjectCode}_{info.VisitName}_ImageStudy_NoneDicom.zip"); ZipFile.CreateFromDirectory(Path.Combine(tempFolderPath, "NoneDicom"), zipNoneDicomPath); relativeNoneDicomPath = await _oSSService.UploadToOSSAsync(zipNoneDicomPath, $"download_zip", false); File.Delete(zipNoneDicomPath); } //await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { PackState = PackState.Packed, VisitNoDicomImageZipPath = relativeNoneDicomPath }); } //清理文件夹 Directory.Delete(tempFolderPath, true); } } catch (Exception ex) { //await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { PackState = PackState.WaitPack }); } } #endregion #region 按照任务为维度 展示上传的列表 废弃 /// /// IR 影像上传任务列表 --old 20240903 界面调整,现在先废弃 /// /// /// [HttpPost] [Obsolete] public async Task> GetIRUploadTaskList_Old(CRCUploadTaskQuery inQuery) { var query = _visitTaskRepository.Where(t => t.SubjectId == inQuery.SubjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SourceSubjectVisitId != null && t.DoctorUserId == _userInfo.UserRoleId && t.TaskState == TaskState.Effect) .ProjectTo(_mapper.ConfigurationProvider); var list = await query.Where(t => t.SubjectCode == inQuery.SubjectCode).ToListAsync(); return list; } /// /// IR 上传任务 dicom 列表 后处理的数据不能排序 --old 20240903 界面调整,现在先废弃 /// /// /// [HttpPost] [Obsolete] public async Task> GetIRUploadTaskDicomStudyList_Old(CRCUploadTaskStudyQuery inQuery) { var list = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId) .SelectMany(t => t.SourceSubjectVisit.StudyList) .ProjectTo(_mapper.ConfigurationProvider).SortToListAsync(inQuery); var taskDicomStudyList = _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId) .SelectMany(t => t.TaskStudyList) .Select(u => new { u.Id, u.SeriesCount, u.InstanceCount, SopInstanceList = u.InstanceList.Select(t => t.SopInstanceUid).ToList() }) .ToList(); foreach (var item in list) { var find = taskDicomStudyList.FirstOrDefault(t => t.Id == item.Id); if (find != null) { item.UploadedInstanceCount = find.InstanceCount; item.UploadedSopInstanceUidList = find.SopInstanceList; item.UploadedSeriesCount = find.SeriesCount; } } return list; } /// /// IR 上传任务 nonedicom 列表 后处理的数据不能排序 --old 20240903 界面调整,现在先废弃 /// /// /// [HttpPost] [Obsolete] public async Task> GetIRUploadTaskNoneDicomStudyList_Old(CRCUploadTaskStudyQuery inQuery) { var list = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId) .SelectMany(t => t.SourceSubjectVisit.StudyList) .ProjectTo(_mapper.ConfigurationProvider).SortToListAsync(inQuery); var taskNoneDicomStudyList = _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId) .SelectMany(t => t.TaskNoneDicomStudyFileList).Where(t => t.VisitTaskId == inQuery.VisitTaskId) .Select(u => new { u.OriginNoneDicomStudyId, }) .ToList(); foreach (var item in list) { item.UploadedFileCount = taskNoneDicomStudyList.Where(t => t.OriginNoneDicomStudyId == item.Id).Count(); } return list; } #endregion } }