Files
irc-netcore-api/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs
T
2026-08-17 13:43:06 +08:00

2968 lines
144 KiB
C#

using FellowOakDicom;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
using IRaCIS.Core.Infra.EFCore.Common;
using IRaCIS.Core.Infrastructure;
using MassTransit;
using MassTransit.Initializers;
using Medallion.Threading;
using Microsoft.AspNetCore.Mvc;
using System.Data;
using System.IO.Compression;
using System.Text;
using System.Web;
namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
public interface IDownloadAndUploadService
{
Task PackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isDicom, bool isAnonymize = true);
Task<IResponseOutput> SubejctRandomReadingTaskNameDeal(Guid subjectId, Guid trialReadingCriterionId);
}
[ApiExplorerSettings(GroupName = "Trial")]
public class DownloadAndUploadService(IRepository<SystemAnonymization> _systemAnonymizationRepository, IRepository<DicomStudy> _dicomStudyRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IOSSService _oSSService,
IRepository<FileUploadRecord> _fileUploadRecordRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<Trial> _trialRepository,
IRepository<StudyMonitor> _studyMonitorRepository,
IRepository<TaskStudy> _taskStudyRepository,
IRepository<TaskSeries> _taskSeriesRepository,
IRepository<TaskInstance> _taskInstanceRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<NoneDicomStudy> _noneDicomStudyReposiotry,
IRepository<NoneDicomStudyFile> _noneDicomStudyFileReposiotry,
IDistributedLockProvider _distributedLockProvider,
IRepository<TrialImageDownload> _trialImageDownloadRepository,
IRepository<Subject> _subjectRepository,
IRepository<DicomInstance> _instanceRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IDownloadAndUploadService
{
/// <summary>
/// 受试者随机阅片,任务进行随机编号
/// 进入阅片任务前,随机挑选出该受试者的一个任务,然后给该任务一个编号,编号给的逻辑是:TimePoint Ran+ 已阅任务数量+1
/// 根据当前受试者该标准已阅任务数量(生效失效的任务都算,考虑重阅,最后编号不重复) 第一个就是TimePoint Ran1,后面依次随机挑选出来的阅片序号依次递增
/// </summary>
/// <param name="subjectId"></param>
/// <param name="trialReadingCriterionId"></param>
/// <returns></returns>
public async Task<IResponseOutput> 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.ImageDownloadEnum != ReadingImageDownload.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<int> 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();
}
/// <summary>
/// 获取该受试者任务上传列表(展示已上传情况)
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetSubjectImageUploadList(IRUploadStudyQuery inQuery)
{
//要根据标准阅片顺序,确定是否查询单个任务的,还是查询所有的
var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId)
.Select(t => new { t.IsReadingTaskViewInOrder, t.Trial.Modalitys, t.IsImageFilter, t.CriterionModalitys }).FirstNotNullAsync();
var subjectCode = string.Empty;
var subjectId = inQuery.SubjectId;
bool? isIRImageDownloaded = null;
if (inQuery.VisitTaskId != null)
{
isIRImageDownloaded = _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId).Select(t => t.IsIRImageDownloaded).FirstOrDefault();
}
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;
}
if (inQuery.IsImageSegmentLabel == true)
{
var querySV = _subjectVisitRepository.Where(t => t.CheckState == CheckStateEnum.CVPassed)
.WhereIf(inQuery.SubjectVisitId != null, t => t.Id == inQuery.SubjectVisitId)
.WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
.Select(u => new SubjectVisitMarkUploadDto()
{
SubejctId = u.SubjectId,
TrialSiteId = u.TrialSiteId,
SubjectVisitId = u.Id,
SubjectCode = u.Subject.Code,
VisitName = u.VisitName,
OrginalStudyList = u.StudyList
.Select(t => new StudyBasicInfo()
{
Id = t.Id,
SubjectVisitId = t.SubjectVisitId,
StudyInstanceUid = t.StudyInstanceUid,
ModalityForEdit = t.ModalityForEdit,
BodyPartExamined = t.BodyPartExamined,
BodyPartForEdit = t.BodyPartForEdit,
BodyPartForEditOther = t.BodyPartForEditOther,
StudyCode = t.StudyCode,
StudyTime = t.StudyTime,
Description = t.Description,
InstanceCount = t.InstanceCount,
Modalities = t.Modalities,
SeriesCount = t.SeriesCount,
ReadingInstanceCount = t.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading).Count(),
ReadingSeriesCount = t.SeriesList.Where(t => t.IsReading).Count(),
}).ToList(),
UploadStudyList = u.TaskStudyList.Select(t => new StudyBasicInfo()
{
Id = t.Id,
SubjectVisitId = t.SubjectVisitId,
StudyInstanceUid = t.StudyInstanceUid,
ModalityForEdit = t.ModalityForEdit,
BodyPartExamined = t.BodyPartExamined,
BodyPartForEdit = t.BodyPartForEdit,
BodyPartForEditOther = t.BodyPartForEditOther,
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(),
ReadingInstanceCount = t.InstanceCount,
ReadingSeriesCount = t.SeriesCount,
}).ToList()
})
;
var SVlist = await querySV.ToListAsync();
return ResponseOutput.Ok(SVlist, new { TrialModality = criterionInfo.Modalitys, IsReadingTaskViewInOrder = criterionInfo.IsReadingTaskViewInOrder });
}
else
{
await SubejctRandomReadingTaskNameDeal((Guid)subjectId, inQuery.TrialReadingCriterionId);
var query = _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SourceSubjectVisit.CheckState == CheckStateEnum.CVPassed
&& 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)
.Where(t => inQuery.IsImageSegmentLabel == false ? t.ModalityForEdit == "XA" || t.ModalityForEdit == "DSA" || t.ModalityForEdit == "OCT" : true)
.Select(t => new StudyBasicInfo()
{
Id = t.Id,
StudyInstanceUid = t.StudyInstanceUid,
ModalityForEdit = t.ModalityForEdit,
BodyPartExamined = t.BodyPartExamined,
BodyPartForEdit = t.BodyPartForEdit,
BodyPartForEditOther = t.BodyPartForEditOther,
StudyCode = t.StudyCode,
StudyTime = t.StudyTime,
Description = t.Description,
InstanceCount = t.InstanceCount,
Modalities = t.Modalities,
SeriesCount = t.SeriesCount,
ReadingInstanceCount = t.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading).Count(),
ReadingSeriesCount = t.SeriesList.Where(t => t.IsReading).Count(),
}).ToList(),
OriginalTaskStudyList = inQuery.IsImageSegmentLabel == false ? u.SourceSubjectVisit.TaskStudyList.Select(t => new StudyBasicInfo()
{
Id = t.Id,
StudyInstanceUid = t.StudyInstanceUid,
ModalityForEdit = t.ModalityForEdit,
BodyPartExamined = t.BodyPartExamined,
BodyPartForEdit = t.BodyPartForEdit,
BodyPartForEditOther = t.BodyPartForEditOther,
StudyCode = t.StudyCode,
StudyTime = t.StudyTime,
Description = t.Description,
InstanceCount = t.InstanceCount,
Modalities = t.Modalities,
SeriesCount = t.SeriesCount,
ReadingInstanceCount = t.InstanceList.Count(),
ReadingSeriesCount = t.SeriesList.Count(),
}).ToList() : new List<StudyBasicInfo>(),
UploadStudyList = u.TaskStudyList.Select(t => new StudyBasicInfo()
{
Id = t.Id,
StudyInstanceUid = t.StudyInstanceUid,
ModalityForEdit = t.ModalityForEdit,
BodyPartExamined = t.BodyPartExamined,
BodyPartForEdit = t.BodyPartForEdit,
BodyPartForEditOther = t.BodyPartForEditOther,
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(),
ReadingInstanceCount = t.InstanceCount,
ReadingSeriesCount = t.SeriesCount,
}).ToList()
})
;
var list = await query.Where(t => t.SubjectCode == subjectCode).ToListAsync();
//靶段标注,阅片IR上传需要将原始DSA 和初次后处理的影像合并 作为原始检查影像
if (inQuery.IsImageSegmentLabel == false)
{
foreach (var item in list)
{
item.OrginalStudyList.AddRange(item.OriginalTaskStudyList.WhereIf(criterionInfo.IsImageFilter, t => ("|" + criterionInfo.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|")));
}
}
return ResponseOutput.Ok(list, new { TrialModality = criterionInfo.Modalitys, IsReadingTaskViewInOrder = criterionInfo.IsReadingTaskViewInOrder, IsIRImageDownloaded = isIRImageDownloaded });
}
}
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<IResponseOutput> 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);
}
/// <summary>
/// 在调用预归档前验证 这些检查是否可以全新上传还是已存在补充 目前前端允许 IsAllowUpload==true 全新、IsAllowReUpload==true 补充的study ,全部丢到后端,后端判断存在,就删除之前的检查,全新插入
/// </summary>
/// <param name="inCommand"></param>
/// <param name="_dicomStudyRepository"></param>
/// <returns></returns>
public async Task<List<TaskStudyArchiveConfirmResult>> VerifyIRStudyAllowUpload(TaskStudyAchivePreConfirmCommand inCommand, [FromServices] IRepository<DicomStudy> _dicomStudyRepository)
{
var result = new List<TaskStudyArchiveConfirmResult>();
if (inCommand.IsImageSegmentLabel == true)
{
var notAllowedUidList = _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();
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)
{
result.Add(new TaskStudyArchiveConfirmResult() { StudyInstanceUid = studyUid, IsAllowUpload = true, IsAllowReUpload = true });
}
else
{
result.Add(new TaskStudyArchiveConfirmResult() { StudyInstanceUid = studyUid, IsAllowReUpload = false, IsAllowUpload = false });
}
}
else
{
result.Add(new TaskStudyArchiveConfirmResult() { StudyInstanceUid = studyUid, IsAllowReUpload = false, IsAllowUpload = false });
}
}
}
else
{
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);
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<IResponseOutput> 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");
var visiTaskId = incommand.VisitTaskId ?? Guid.Empty;
using (await @uploadLock.AcquireAsync())
{
if (_fusionCache.GetOrDefault<Guid>(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, visiTaskId, incommand.Study.StudyInstanceUid)) != Guid.Empty)
{
//---当前已有人正在上传和归档该检查!
return ResponseOutput.NotOk(I18n.T("UploadDownLoad_ArchiveInProgress"));
}
else
{
//在事务未完成前 防止前端重复提交
await _fusionCache.SetAsync(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, visiTaskId, incommand.Study.StudyInstanceUid), _userInfo.UserRoleId, TimeSpan.FromMinutes(1));
}
}
Guid? svId = null;
if (incommand.IsImageSegmentLabel == true)
{
svId = _dicomStudyRepository.Where(t => t.TrialId == incommand.TrialId && t.StudyInstanceUid == incommand.Study.StudyInstanceUid).Select(t => t.SubjectVisitId).FirstOrDefault();
}
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(), visiTaskId.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<TaskStudy>(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<int>(CacheKeys.TrialStudyMaxCode(trialId));
int currentNextCodeInt = cacheMaxCodeInt > dbStudyCodeIntMax ? cacheMaxCodeInt + 1 : dbStudyCodeIntMax + 1;
study.Code = currentNextCodeInt;
study.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(TaskStudy));
await _fusionCache.SetAsync<int>(CacheKeys.TrialStudyMaxCode(trialId), study.Code, TimeSpan.FromMinutes(30));
}
study.Id = studyId;
study.TrialId = incommand.TrialId;
study.SubjectId = incommand.SubjectId;
study.VisitTaskId = visiTaskId;
study.SubjectVisitId = svId;
//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<TaskSeries>(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.SubjectVisitId = svId;
//前端传递的数量不准,上传的时候,把失败的也加进来了,以实际数组的数字为准
series.InstanceCount = seriesItem.InstanceList.Count;
await _taskSeriesRepository.AddAsync(series);
foreach (var instanceItem in seriesItem.InstanceList)
{
var isntance = _mapper.Map<TaskInstance>(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;
isntance.SubjectVisitId = svId;
await _taskInstanceRepository.AddAsync(isntance);
}
}
findStudy = study;
}
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);
var isNewSeries = false;
//判断重复
if (dicomSeries == null)
{
isNewSeries = true;
var series = _mapper.Map<TaskSeries>(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;
//}
//找到该序列已经存在的instanceId
var existInstanceIdList = _taskInstanceRepository.Where(t => t.SeriesId == dicomSeries.Id).Select(t => t.Id).ToList();
foreach (var instanceItem in seriesItem.InstanceList)
{
var insntance = _mapper.Map<TaskInstance>(instanceItem);
var instanceId = IdentifierHelper.CreateGuid(insntance.StudyInstanceUid, insntance.SeriesInstanceUid, insntance.SopInstanceUid, trialId.ToString(), visiTaskId.ToString());
if (!existInstanceIdList.Any(t => t == instanceId))
{
insntance.Id = instanceId;
insntance.StudyId = findStudy.Id;
insntance.SeriesId = dicomSeries.Id;
insntance.TrialId = incommand.TrialId;
insntance.SubjectId = incommand.SubjectId;
insntance.VisitTaskId = visiTaskId;
await _taskInstanceRepository.AddAsync(insntance);
if (isNewSeries == false)
{
dicomSeries.InstanceCount++;
}
findStudy.InstanceCount++;
}
}
// 不管是新的序列 还是 该序列 掉了Instance 重传的时候 检查的instance 数量都会增加
//findStudy.InstanceCount += seriesItem.InstanceList.Count;
}
}
#region 只配置单个部位自动赋值
var originStudy = _dicomStudyRepository.Where(t => t.TrialId == incommand.TrialId && t.StudyInstanceUid == findStudy.StudyInstanceUid).FirstOrDefault();
if (originStudy != null)
{
findStudy.BodyPartForEdit = originStudy.BodyPartForEdit;
findStudy.BodyPartForEditOther = originStudy.BodyPartForEditOther;
}
////项目配置的影像部位
//var trialBodyParts = _trialRepository.Where(t => t.Id == trialId).Select(t => t.BodyPartTypes).FirstOrDefault();
//var trialBodyPartList = trialBodyParts.Split('|', StringSplitOptions.RemoveEmptyEntries);
//if (trialBodyPartList.Count() == 1)
//{
// var first = trialBodyPartList.First();
// findStudy.BodyPartForEdit = first;
//}
#endregion
var @lock2 = _distributedLockProvider.CreateLock($"StudyCommit");
using (await @lock2.AcquireAsync())
{
await _taskStudyRepository.SaveChangesAsync();
}
await _fileUploadRecordRepository.BatchUpdateNoTrackingAsync(t => t.UploadBatchId == incommand.UploadBatchId, u => new FileUploadRecord() { StudyCode = findStudy.StudyCode });
}
catch (Exception ex)
{
return ResponseOutput.NotOk(ex.Message);
}
finally
{
await _fusionCache.RemoveAsync(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, visiTaskId, incommand.Study.StudyInstanceUid));
await _fusionCache.RemoveAsync(CacheKeys.TrialTaskStudyUidUploading(incommand.TrialId, visiTaskId, incommand.Study.StudyInstanceUid));
}
return ResponseOutput.Ok(modalitys);
}
[HttpDelete]
public async Task<IResponseOutput> DeleteTaskStudy(Guid visitTaskId, Guid? subjectVisitId, bool isDicom, Guid? dicomStudyId, Guid? noneDicomStudyId)
{
if (isDicom)
{
//靶段标注删除访视影像
if (visitTaskId == Guid.Empty && subjectVisitId != null && subjectVisitId != Guid.Empty)
{
var fisrtPath = await _taskInstanceRepository.Where(t => t.SubjectVisitId == subjectVisitId).Select(t => t.Path).FirstOrDefaultAsync();
var prefix = fisrtPath.Substring(1, fisrtPath.LastIndexOf('/') - 1);
await _oSSService.DeleteFromPrefix(prefix, true);
await _taskStudyRepository.DeleteFromQueryAsync(t => t.SubjectVisitId == subjectVisitId);
await _taskSeriesRepository.BatchDeleteNoTrackingAsync(t => t.SubjectVisitId == subjectVisitId);
await _taskInstanceRepository.BatchDeleteNoTrackingAsync(t => t.SubjectVisitId == subjectVisitId);
}
if (visitTaskId != Guid.Empty)
{
if (dicomStudyId == null)
{
var deleteStudyPathList = await _taskInstanceRepository.Where(t => t.VisitTaskId == visitTaskId).GroupBy(t => t.StudyId).Select(g => g.First().Path).ToListAsync();
foreach (var fisrtPath in deleteStudyPathList)
{
var prefix = fisrtPath.Substring(1, fisrtPath.LastIndexOf('/') - 1);
await _oSSService.DeleteFromPrefix(prefix, true);
}
await _taskStudyRepository.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId);
await _taskSeriesRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId);
await _taskInstanceRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId);
}
else
{
var fisrtPath = await _taskInstanceRepository.Where(t => t.VisitTaskId == visitTaskId && t.StudyId == dicomStudyId).Select(t => t.Path).FirstOrDefaultAsync();
var prefix = fisrtPath.Substring(1, fisrtPath.LastIndexOf('/') - 1);
await _oSSService.DeleteFromPrefix(prefix, true);
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
{
if (visitTaskId == Guid.Empty)
{
//删除靶段标注非dicom
await _noneDicomStudyFileReposiotry.DeleteFromQueryAsync(t => t.ImageLabelNoneDicomStudyId == noneDicomStudyId);
}
else
{
//删除后处理非dicom
await _noneDicomStudyFileReposiotry.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId && t.OriginNoneDicomStudyId == noneDicomStudyId);
}
}
await _noneDicomStudyFileReposiotry.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// IR 上传任务 nonedicom 列表 后处理的数据UploadedFileCount不能排序 --new
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<List<TaskNoneDicomStudyDTO>>> GetIRUploadTaskNoneDicomStudyList([FromServices] INoneDicomStudyService _noneDicomStudyService, IRUploadStudyQuery inQuery)
{
var subjectCode = inQuery.SubjectCode;
var subjectId = inQuery.SubjectId;
var doctorUserId = _userInfo.UserRoleId;
bool? isIRImageDownloaded = null;
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,
t.IsIRImageDownloaded,
}).FirstNotNullAsync();
subjectId = taskInfo.SubjectId;
subjectCode = taskInfo.SubjectCode;
doctorUserId = (Guid)taskInfo.DoctorUserId!;
isIRImageDownloaded = taskInfo.IsIRImageDownloaded;
}
var info = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId)
.Select(t => new { t.IsImageFilter, t.CriterionType, t.TrialId, t.CriterionModalitys, t.IsReadingTaskViewInOrder }).FirstNotNullAsync();
var config = await _subjectRepository.Where(t => t.Id == subjectId).Select(t => new { t.Trial.ImageFormatList, t.Trial.StudyNameList, t.Trial.IsShowStudyName, IsIRImageDownloaded = isIRImageDownloaded }).FirstOrDefaultAsync();
//靶段标注上传,查看访视级别,上传绑定访视级别
if (inQuery.IsImageSegmentLabel == true)
{
//存在ivus 和oct 这两种的项目
if (_readingQuestionCriterionTrialRepository.Where(t => t.TrialId == info.TrialId &&
((t.CriterionType == CriterionType.IVUS || t.CriterionType == CriterionType.OCT) && t.IsConfirm)).Distinct().Count() == 2
&& _noneDicomStudyReposiotry.Where(t => t.SubjectId == inQuery.SubjectId && t.Modality == "IVUS").Count() != _dicomStudyRepository.Where(t => t.SubjectId == inQuery.SubjectId).Select(t => t.SubjectVisitId).Distinct().Count()
)
{
#region ivus 自动创建非dicom检查
var addList = await _dicomStudyRepository.Where(t => t.SubjectId == inQuery.SubjectId)
.Select(t => new NoneDicomStudyAddOrEdit()
{
TrialId = t.TrialId,
SubjectId = t.SubjectId,
SubjectVisitId = t.SubjectVisitId,
ImageDate = (DateTime)t.StudyTime,
BodyPart = t.BodyPartForEdit,
BodyPartForEditOther = t.BodyPartForEditOther,
Modality = "IVUS"
}).ToListAsync();
var noneDicomStudyVisitIdList = _noneDicomStudyReposiotry.Where(t => t.SubjectId == inQuery.SubjectId && t.Modality == "IVUS").Select(t => t.SubjectVisitId).ToList();
var @lock = _distributedLockProvider.CreateLock($"NoneDicomCode");
using (await @lock.AcquireAsync())
{
var trialId = addList.FirstOrDefault().TrialId;
//默认会是0
var code = await _noneDicomStudyReposiotry.Where(t => t.TrialId == trialId).Select(x => x.Code).DefaultIfEmpty().MaxAsync();
foreach (var g in addList.Where(t => !noneDicomStudyVisitIdList.Contains(t.SubjectVisitId)).GroupBy(t => t.SubjectVisitId))
{
var addOrEditNoneDicomStudy = g.First();
var optEntity = await _noneDicomStudyReposiotry.InsertFromDTOAsync(addOrEditNoneDicomStudy);
optEntity.Code = code + 1;
optEntity.StudyCode = AppSettings.GetCodeStr(optEntity.Code, nameof(NoneDicomStudy));
code++;
}
await _noneDicomStudyReposiotry.SaveChangesAsync();
}
#endregion
}
var list = _noneDicomStudyReposiotry.Where(t => t.SubjectId == subjectId && t.SubjectVisit.CheckState == CheckStateEnum.CVPassed)
.WhereIf(inQuery.SubjectVisitId != null, t => t.SubjectVisitId == inQuery.SubjectVisitId)
//.WhereIf(info.IsImageFilter, t => ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|"))
.Select(u => new TaskNoneDicomStudyDTO()
{
SubjectId = u.SubjectId,
SubjectCode = u.Subject.Code,
VisitName = u.SubjectVisit.VisitName,
SourceSubjectVisitId = u.SubjectVisitId,
Id = u.Id,
Description = u.Description,
ImageDate = u.ImageDate,
BodyPart = u.BodyPart,
BodyPartForEditOther = u.BodyPartForEditOther,
FileCount = u.FileCount,
Modality = u.Modality,
StudyCode = u.StudyCode,
FileList = u.NoneDicomFileList.Select(t => new NoneDicomFileInfo()
{
FileType = t.FileType,
FileName = t.FileName,
FileSize = t.FileSize,
Path = t.Path
}).ToList(),
ReadingFileCount = u.NoneDicomFileList.Where(t => t.IsReading).Count(),
}).ToList();
var noneDicomStudyIdList = list.Select(t => t.Id).ToList();
var noneDicomStudyList = _noneDicomStudyFileReposiotry.Where(t => t.ImageLabelNoneDicomStudyId != null)
.Where(t => noneDicomStudyIdList.Contains((Guid)t.ImageLabelNoneDicomStudyId!))
.Select(u => new NoneDicomFileInfo
{
OriginNoneDicomStudyId = u.ImageLabelNoneDicomStudyId,
FileType = u.FileType,
FileName = u.FileName,
FileSize = u.FileSize,
Path = u.Path
})
.ToList();
foreach (var item in list)
{
item.UploadedFileCount = noneDicomStudyList.Where(t => t.OriginNoneDicomStudyId == item.Id).Count();
item.UploadedFileList = noneDicomStudyList.Where(t => t.OriginNoneDicomStudyId == item.Id).ToList();
}
return ResponseOutput.Ok(list, config);
}
else
{
var query = from u in _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId
&& t.SourceSubjectVisit.CheckState == CheckStateEnum.CVPassed && 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,
BodyPartForEditOther = ns.BodyPartForEditOther,
Modality = ns.Modality,
StudyCode = ns.StudyCode,
//靶段标注 阅片IR 上传时IsImageSegmentLabel == false ,正常后处理上传IsImageSegmentLabel 该字段为空
FileList = (inQuery.IsImageSegmentLabel == false ? ns.ImageLabelNoneDicomFileList : ns.NoneDicomFileList)
.Select(t => new NoneDicomFileInfo()
{
FileType = t.FileType,
FileName = t.FileName,
FileSize = t.FileSize,
Path = t.Path
}).ToList(),
FileCount = (inQuery.IsImageSegmentLabel == false ? ns.ImageLabelNoneDicomFileList : ns.NoneDicomFileList).Count(),
ReadingFileCount = (inQuery.IsImageSegmentLabel == false ? ns.ImageLabelNoneDicomFileList : ns.NoneDicomFileList).Where(t => t.IsReading).Count(),
};
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 ResponseOutput.Ok(list, config);
}
}
/// <summary>
/// IQC 获取CRC 上传到某一个访视的的检查信息 (原始影像信息 包含dicom 非dicom)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetCRCUploadedStudyInfo(CRCUploadedStudyQuqry inQuery)
{
var isQueryDicom = inQuery.DicomStudyIdList.Count > 0;
var isQueryNoneDicom = inQuery.NoneDicomStudyIdList.Count > 0;
var isExportReading = inQuery.IsExportReading == true;
var imageType = (isQueryDicom && isQueryNoneDicom) ? ImageType.DicomAndNoneDicom : (isQueryDicom ? ImageType.Dicom : ImageType.NoneDicom);
var dirDic = new Dictionary<string, string>();
#region DIR处理导出文件名,并将对应关系上传到OSS里面存储
var info = await _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId).Select(t => new { t.Trial.TrialCode }).FirstOrDefaultAsync();
//有传输语法值的导出 才生成DIR
//if (_subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId).SelectMany(t => t.StudyList.SelectMany(t => t.InstanceList)).All(c => c.TransferSytaxUID != string.Empty))
if (!_instanceRepository.Where(t => isExportReading ? (t.IsReading && t.DicomSerie.IsReading) : true)
.Where(t => inQuery.SubjectVisitId == t.SubjectVisitId).Any(c => c.TransferSytaxUID == string.Empty))
{
var list = _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId).SelectMany(t => t.StudyList)
.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
.SelectMany(t => t.InstanceList.Where(t => isExportReading ? (t.IsReading && t.DicomSerie.IsReading) : true))
.Select(t => new StudyDIRInfo()
{
DicomStudyId = t.DicomStudy.Id,
PatientId = info.TrialCode + "-" + t.DicomStudy.Subject.Code,
PatientName = t.DicomStudy.PatientName,
PatientBirthDate = t.DicomStudy.PatientBirthDate,
PatientSex = t.DicomStudy.PatientSex,
StudyInstanceUid = t.StudyInstanceUid,
StudyId = t.DicomStudy.StudyId,
DicomStudyDate = t.DicomStudy.DicomStudyDate,
DicomStudyTime = t.DicomStudy.DicomStudyTime,
AccessionNumber = t.DicomStudy.AccessionNumber,
StudyDescription = t.DicomStudy.Description,
SeriesInstanceUid = t.DicomSerie.SeriesInstanceUid,
Modality = t.DicomSerie.Modality,
DicomSeriesDate = t.DicomSerie.DicomSeriesDate,
DicomSeriesTime = t.DicomSerie.DicomSeriesTime,
SeriesNumber = t.DicomSerie.SeriesNumber,
SeriesDescription = t.DicomSerie.Description,
InstanceId = t.Id,
SopInstanceUid = t.SopInstanceUid,
SOPClassUID = t.SOPClassUID,
InstanceNumber = t.InstanceNumber,
MediaStorageSOPClassUID = t.MediaStorageSOPClassUID,
MediaStorageSOPInstanceUID = t.MediaStorageSOPInstanceUID,
TransferSytaxUID = t.TransferSytaxUID,
}).ToList();
var pathInfo = await _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId).Select(t => new { t.TrialId, t.SubjectId, VisitId = t.Id }).FirstNotNullAsync();
foreach (var item in list.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId }))
{
var studyUid = item.Key.StudyInstanceUid;
var ossFolder = $"{pathInfo.TrialId}/Image/{pathInfo.SubjectId}/{pathInfo.VisitId}/{item.Key.StudyInstanceUid}";
var isSucess = await SafeBussinessHelper.RunAsync(async () => await DicomDIRHelper.GenerateStudyDIRAndUploadAsync(item.ToList(), dirDic, ossFolder, _oSSService));
if (isSucess)
{
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic[$"{studyUid}_DICOMDIR"]}" });
}
}
}
#endregion
var query = from sv in _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId)
select new ImageDownloadDto()
{
TrialId = sv.TrialId,
SubjectId = sv.SubjectId,
SubjectCode = sv.Subject.Code,
TrialSiteCode = sv.TrialSite.TrialSiteCode,
VisitName = sv.VisitName,
VisitId = sv.Id,
StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
.Select(u => new DownloadDicomStudyDto()
{
PatientId = u.PatientId,
StudyTime = u.StudyTime,
StudyCode = u.StudyCode,
StudyInstanceUid = u.StudyInstanceUid,
StudyDIRPath = u.StudyDIRPath,
SeriesList = u.SeriesList.Where(t => isExportReading ? t.IsReading : true).Select(z => new DownloadDicomSeriesDto()
{
Modality = z.Modality,
InstanceList = z.DicomInstanceList.Where(t => isExportReading ? t.IsReading : true).Select(k => new DownloadDicomInstanceDto()
{
IsEncapsulated = k.IsEncapsulated,
InstanceId = k.Id,
FileName = string.Empty,
Path = k.Path,
FileSize = k.FileSize
}).ToList()
}).ToList()
}).ToList(),
NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isExportReading ? t.IsReading : true).Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)
.Select(nd => new DownloadNoneDicomStudyDto()
{
Modality = nd.Modality,
StudyCode = nd.StudyCode,
ImageDate = nd.ImageDate,
FileList = nd.NoneDicomFileList.Where(t => isExportReading ? t.IsReading : true).Select(file => new DownloadNoneDicomFileDto()
{
FileName = file.FileName,
Path = file.Path,
FileType = file.FileType,
FileSize = file.FileSize
}).ToList()
}).ToList()
};
var result = query.FirstOrDefault();
foreach (var item in result.StudyList.SelectMany(t => t.SeriesList).SelectMany(t => t.InstanceList))
{
var key = item.InstanceId.ToString();
if (dirDic.ContainsKey(key))
{
item.FileName = dirDic[key];
}
}
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);
}
/// <summary>
/// IR 阅片页面 和IR 任务列表页面下载 勾选下载列表(后端要考虑到一致性分析 subjectCode的问题)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> 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.IsImageSegmentLabel == true)
{
var list = await _subjectVisitRepository.Where(t => t.CheckState == CheckStateEnum.CVPassed)
.WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
.ProjectTo<SubjectVisitMarkStudyDto>(_mapper.ConfigurationProvider).ToListAsync();
#region 将任务级别转为检查级别
var result = new List<SubjectVisitMarkStudyDto>();
var dicomStudyList = list.Where(item => item.DicomStudyList.Count > 0)
.Select(item => new SubjectVisitMarkStudyDto
{
SourceSubjectVisitId = item.SourceSubjectVisitId,
VisitTaskId = item.VisitTaskId,
SubjectId = item.SubjectId,
SubjectCode = item.SubjectCode,
VisitName = item.VisitName,
//取dicom
DicomStudyList = item.DicomStudyList,
}).ToList();
var noneStudyList = list.Where(item => item.NoneDicomStudyList.Count > 0)
.Select(item => new SubjectVisitMarkStudyDto
{
SourceSubjectVisitId = item.SourceSubjectVisitId,
VisitTaskId = item.VisitTaskId,
SubjectId = item.SubjectId,
SubjectCode = item.SubjectCode,
VisitName = item.VisitName,
//非dicom
NoneDicomStudyList = item.NoneDicomStudyList,
}).ToList();
result.AddRange(dicomStudyList);
result.AddRange(noneStudyList);
#endregion
return ResponseOutput.Ok(result);
}
else
{
//下载这里查看也需要维护编号,维护的时候不会处理一致性分析任务
if (inQuery.SubjectId != null && inQuery.TrialReadingCriterionId != null)
{
await SubejctRandomReadingTaskNameDeal((Guid)subjectId, inQuery.TrialReadingCriterionId);
}
TaskState? taskState = null;
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,
t.TaskState
}).FirstNotNullAsync();
subjectId = taskInfo.SubjectId;
subjectCode = taskInfo.SubjectCode;
doctorUserId = (Guid)taskInfo.DoctorUserId!;
isAnalysisCreate = taskInfo.IsAnalysisCreate;
taskState = taskInfo.TaskState;
}
var query = _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId
&& t.SourceSubjectVisit.CheckState == CheckStateEnum.CVPassed && t.DoctorUserId == doctorUserId)
//满足 有序,或者随机只看到当前任务的dicom 非dicom检查
.WhereIf(inQuery.VisitTaskId == null, t => t.TaskState == TaskState.Effect)//从待阅列表进入,要筛选出有效的,任务可能重阅了,也要看到该任务的
.WhereIf(criterionInfo.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId)
.WhereIf(taskState == TaskState.Effect || taskState == TaskState.Freeze, t => t.TaskState == TaskState.Effect)//subject 随机可能当前阅片人有退回任务,此时传递了任务Id,但是要看整个subject得,要只留生效的
.WhereIf(taskState != null && taskState != TaskState.Effect && taskState != TaskState.Freeze, t => t.Id == inQuery.VisitTaskId) //非生效只查当前任务
.ProjectTo<SubjectCRCImageUploadedDto>(_mapper.ConfigurationProvider/*, new { IsImageSegmentLabel = inQuery.IsImageSegmentLabel }*/);
//这里过滤是否是一致性分析的
var list = await query.Where(t => t.SubjectCode == subjectCode).ToListAsync();
if (inQuery.IsImageSegmentLabel == false)
{
var subjectVisitIdList = list.Select(t => t.SourceSubjectVisitId).Distinct().ToList();
//var preDicomStudyList = _subjectVisitRepository.Where(t => subjectVisitIdList.Contains(t.Id)).SelectMany(t => t.TaskStudyList)
// .ProjectTo<DicomStudyBasicInfo>(_mapper.ConfigurationProvider).ToList();
var preNoneDicomStudyList = _subjectVisitRepository.Where(t => subjectVisitIdList.Contains(t.Id))
.SelectMany(t => t.NoneDicomStudyList)
.ProjectTo<ImageMarkNoneDicomStudyBasicInfo>(_mapper.ConfigurationProvider).ToList();
foreach (var item in list)
{
var dicomList = item.DicomStudyList.Where(t => inQuery.IsImageSegmentLabel == false ? t.ModalityForEdit == "XA" || t.ModalityForEdit == "DSA" || t.ModalityForEdit == "OCT" : true).ToList();
//dicomList.AddRange(preDicomStudyList.Where(t => t.SubjectVisitId == item.SourceSubjectVisitId).ToList());
item.DicomStudyList = dicomList;
item.NoneDicomStudyList = _mapper.Map<List<NoneDicomStudyBasicInfo>>(preNoneDicomStudyList.Where(t => t.SubjectVisitId == item.SourceSubjectVisitId).ToList());
}
}
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<SubjectCRCImageUploadedStudyDto>();
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 ResponseOutput.Ok(result);
}
}
/// <summary>
/// IR 阅片页面获取下载检查的信息 会根据标准进行过滤检查,(后端要考虑到一致性分析 subjectCode的问题)
/// 检查在访视下面,所以需要传递下载的访视Id,另外下载访视下面那些检查,就把访视下的对应的检查Id 丢到数组里就好
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetIRReadingDownloadStudyInfo(IRDownloadQuery inQuery)
{
var info = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId)
.Select(t => new { t.IsImageFilter, t.CriterionModalitys, t.TrialId, t.IsReadingTaskViewInOrder, t.Trial.TrialCode }).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).Distinct().ToList();
var subjectVisitIdList = inQuery.SubjectVisitTaskList.Select(t => t.SubjectVisitId).Distinct().ToList();
var trialSiteCode = _visitTaskRepository.Where(t => t.Id == taskIdList.FirstOrDefault()).Select(t => t.IsAnalysisCreate ? t.BlindTrialSiteCode : t.Subject.TrialSite.TrialSiteCode).FirstOrDefault() ?? string.Empty;
var dirDic = new Dictionary<string, string>();
#region 在下载前先处理DIR文件
//有传输语法值的导出 才生成DIR
if (_subjectVisitRepository.Where(t => t.SubjectId == inQuery.SubjectId && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.StudyList.SelectMany(t => t.InstanceList)).All(c => c.TransferSytaxUID != string.Empty))
{
var dirInfolist = _subjectRepository.Where(t => t.Id == inQuery.SubjectId).SelectMany(t => t.SubjectVisitList.Where(t => subjectVisitIdList.Contains(t.Id))).SelectMany(t => t.StudyList)
.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
.Where(t => info.IsImageFilter && inQuery.IsImageSegmentLabel == null ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
.Where(t => inQuery.IsImageSegmentLabel == false ? t.ModalityForEdit == "XA" || t.ModalityForEdit == "DSA" : true)
.SelectMany(t => t.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading))
.Select(t => new StudyDIRInfo()
{
SubjectVisitId = t.SubjectVisitId,
DicomStudyId = t.DicomStudy.Id,
PatientId = info.TrialCode + "-" + t.DicomStudy.PatientId,
PatientName = t.DicomStudy.PatientName,
PatientBirthDate = t.DicomStudy.PatientBirthDate,
PatientSex = t.DicomStudy.PatientSex,
StudyInstanceUid = t.StudyInstanceUid,
StudyId = t.DicomStudy.StudyId,
DicomStudyDate = t.DicomStudy.DicomStudyDate,
DicomStudyTime = t.DicomStudy.DicomStudyTime,
AccessionNumber = t.DicomStudy.AccessionNumber,
StudyDescription = t.DicomStudy.Description,
SeriesInstanceUid = t.DicomSerie.SeriesInstanceUid,
Modality = t.DicomSerie.Modality,
DicomSeriesDate = t.DicomSerie.DicomSeriesDate,
DicomSeriesTime = t.DicomSerie.DicomSeriesTime,
SeriesNumber = t.DicomSerie.SeriesNumber,
SeriesDescription = t.DicomSerie.Description,
InstanceId = t.Id,
SopInstanceUid = t.SopInstanceUid,
SOPClassUID = t.SOPClassUID,
InstanceNumber = t.InstanceNumber,
MediaStorageSOPClassUID = t.MediaStorageSOPClassUID,
MediaStorageSOPInstanceUID = t.MediaStorageSOPInstanceUID,
TransferSytaxUID = t.TransferSytaxUID,
}).ToList();
if (inQuery.IsImageSegmentLabel == false)
{
var taskDirInfolist = _taskInstanceRepository.Where(t => t.SubjectVisitId != null)
.Where(t => subjectVisitIdList.Contains((Guid)t.SubjectVisitId)).Select(t => new StudyDIRInfo()
{
IsTaskStudy = true,
SubjectVisitId = (Guid)t.SubjectVisitId,
DicomStudyId = t.TaskStudy.Id,
PatientId = info.TrialCode + "-" + t.TaskStudy.Subject.Code,
PatientName = t.TaskStudy.PatientName,
PatientBirthDate = t.TaskStudy.PatientBirthDate,
PatientSex = t.TaskStudy.PatientSex,
StudyInstanceUid = t.StudyInstanceUid,
StudyId = t.TaskStudy.StudyId,
DicomStudyDate = t.TaskStudy.DicomStudyDate,
DicomStudyTime = t.TaskStudy.DicomStudyTime,
AccessionNumber = t.TaskStudy.AccessionNumber,
StudyDescription = t.TaskStudy.Description,
SeriesInstanceUid = t.TaskSeries.SeriesInstanceUid,
Modality = t.TaskSeries.Modality,
DicomSeriesDate = t.TaskSeries.DicomSeriesDate,
DicomSeriesTime = t.TaskSeries.DicomSeriesTime,
SeriesNumber = t.TaskSeries.SeriesNumber,
SeriesDescription = t.TaskSeries.Description,
InstanceId = t.Id,
SopInstanceUid = t.SopInstanceUid,
SOPClassUID = t.SOPClassUID,
InstanceNumber = t.InstanceNumber,
MediaStorageSOPClassUID = t.MediaStorageSOPClassUID,
MediaStorageSOPInstanceUID = t.MediaStorageSOPInstanceUID,
TransferSytaxUID = t.TransferSytaxUID,
}).ToList();
dirInfolist.AddRange(taskDirInfolist);
}
var pathInfo = await _subjectRepository.Where(t => t.Id == inQuery.SubjectId).Select(t => new { t.TrialId, SubjectId = t.Id }).FirstNotNullAsync();
foreach (var item in dirInfolist.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId }))
{
var visitId = item.First().SubjectVisitId;
var isTaskStudy = item.First().IsTaskStudy;
var ossFolder = $"{pathInfo.TrialId}/Image/{pathInfo.SubjectId}/{visitId}/{item.Key.StudyInstanceUid}";
var studyUid = item.Key.StudyInstanceUid;
var isSucess = await SafeBussinessHelper.RunAsync(async () => await DicomDIRHelper.GenerateStudyDIRAndUploadAsync(item.ToList(), dirDic, ossFolder, _oSSService));
if (isSucess)
{
if (isTaskStudy)
{
await _taskStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new TaskStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic[$"{studyUid}_DICOMDIR"]}" });
}
else
{
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic[$"{studyUid}_DICOMDIR"]}" });
}
}
}
}
#endregion
var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubjectId).SelectMany(t => t.SubjectVisitList.Where(t => subjectVisitIdList.Contains(t.Id) && t.CheckState == CheckStateEnum.CVPassed))
//一致性分析,导致查询出来两条数据
join visitTask in _visitTaskRepository.Where(t => taskIdList.Contains(t.Id)) on sv.Id equals visitTask.SourceSubjectVisitId into cc
from leftVisitTask in cc.DefaultIfEmpty()
select new ImageDownloadDto()
{
TrialId = sv.TrialId,
SubjectId = sv.SubjectId,
TrialSiteCode = sv.TrialSite.TrialSiteCode,
VisitId = sv.Id,
SubjectCode = inQuery.SubjectCode,
VisitName = sv.VisitName,
TaskBlindName = leftVisitTask.TaskBlindName,
StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
.Where(t => info.IsImageFilter && inQuery.IsImageSegmentLabel == null ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
.Where(t => inQuery.IsImageSegmentLabel == false ? t.ModalityForEdit == "XA" || t.ModalityForEdit == "DSA" : true)
.Select(u => new DownloadDicomStudyDto()
{
PatientId = u.PatientId,
StudyTime = u.StudyTime,
StudyCode = u.StudyCode,
StudyInstanceUid = u.StudyInstanceUid,
StudyDIRPath = u.StudyDIRPath,
SeriesList = u.SeriesList.Where(t => t.IsReading).Select(z => new DownloadDicomSeriesDto()
{
Modality = z.Modality,
InstanceList = z.DicomInstanceList.Where(t => t.IsReading).Select(k => new DownloadDicomInstanceDto()
{
IsEncapsulated = k.IsEncapsulated,
InstanceId = k.Id,
FileName = string.Empty,
Path = k.Path,
FileSize = k.FileSize
}).ToList()
}).ToList()
}).ToList(),
//TaskStudyList =
//sv.TaskStudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
////.Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
//.Select(u => new DownloadDicomStudyDto()
//{
// PatientId = u.PatientId,
// StudyTime = u.StudyTime,
// StudyCode = u.StudyCode,
// StudyInstanceUid = u.StudyInstanceUid,
// StudyDIRPath = u.StudyDIRPath,
// SeriesList = u.SeriesList.Select(z => new DownloadDicomSeriesDto()
// {
// Modality = z.Modality,
// InstanceList = z.InstanceList.Select(k => new DownloadDicomInstanceDto()
// {
// IsEncapsulated = k.IsEncapsulated,
// InstanceId = k.Id,
// FileName = string.Empty,
// Path = k.Path,
// FileSize = k.FileSize
// }).ToList()
// }).ToList()
//}).ToList()
//,
NoneDicomStudyList = inQuery.IsImageSegmentLabel != false ? sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)
.Where(t => info.IsImageFilter && inQuery.IsImageSegmentLabel == null ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|") : true)
.Where(t => t.IsReading)
.Select(nd => new DownloadNoneDicomStudyDto()
{
Modality = nd.Modality,
StudyCode = nd.StudyCode,
ImageDate = nd.ImageDate,
FileList = nd.NoneDicomFileList.Where(t => t.IsReading).Select(file => new DownloadNoneDicomFileDto()
{
FileName = file.FileName,
Path = file.Path,
FileType = file.FileType,
FileSize = file.FileSize
}).ToList()
}).ToList() :
sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)
//.Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|") : true)
.Where(t => t.IsReading)
.Select(nd => new DownloadNoneDicomStudyDto()
{
Modality = nd.Modality,
StudyCode = nd.StudyCode,
ImageDate = nd.ImageDate,
FileList = nd.ImageLabelNoneDicomFileList.Where(t => t.IsReading).Select(file => new DownloadNoneDicomFileDto()
{
FileName = file.FileName,
Path = file.Path,
FileType = file.FileType,
FileSize = file.FileSize
}).ToList()
}).ToList()
};
var list = await query.ToListAsync();
foreach (var result in list)
{
//靶段标注处理
if (inQuery.IsImageSegmentLabel == false)
{
//result.StudyList.AddRange(result.TaskStudyList);
}
foreach (var item in result.StudyList.SelectMany(t => t.SeriesList).SelectMany(t => t.InstanceList))
{
var key = item.InstanceId.ToString();
if (dirDic.ContainsKey(key))
{
item.FileName = dirDic[key];
}
}
}
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(" | ", list.Select(t => t.VisitName).OrderBy(t => t).ToList()),
NoneDicomStudyCount = list.Sum(t => t.NoneDicomStudyList.Count()),
DicomStudyCount = list.Sum(t => t.StudyList.Count()),
ImageCount = list.Sum(t => t.StudyList.Sum(s => s.SeriesList.Sum(s => s.InstanceList.Count())) + t.NoneDicomStudyList.Sum(s => s.FileList.Count())),
ImageSize = list.Sum(t => t.StudyList.Sum(t => t.SeriesList.Sum(s => s.InstanceList.Sum(i => i.FileSize))) + t.NoneDicomStudyList.Sum(t => t.FileList.Sum(s => s.FileSize))
) ?? 0
};
await _trialImageDownloadRepository.AddAsync(preDownloadInfo, true);
return ResponseOutput.Ok(list, new { PreDownloadId = preDownloadInfo.Id, info.IsReadingTaskViewInOrder });
}
/// <summary>
/// dicom 影像后处理预览接口
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetTaskUploadedDicomStudyList(IRTaskUploadedDicomStudyQuery inQuery)
{
var info = await _visitTaskRepository
.WhereIf(inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId)//正常后处理
.Select(t => new { t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys }).FirstNotNullAsync();
var query = _taskStudyRepository
.WhereIf(inQuery.VisitTaskId != null, t => t.VisitTaskId == inQuery.VisitTaskId)//正常后处理
.WhereIf(inQuery.VisitTaskId == null && inQuery.SubjectVisitId != null, t => t.SubjectVisitId == inQuery.SubjectVisitId)//靶段标注处理的影像
.WhereIf(info.IsImageFilter && inQuery.VisitTaskId != null, t => ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|"))
.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,
FileSize = k.FileSize,
}).ToList()
})
});
var list = await query.ToListAsync();
return ResponseOutput.Ok(list);
}
/// <summary>
/// 更新后处理上传的检查modality
/// </summary>
/// <param name="taskStudyId"></param>
/// <param name="modality"></param>
/// <returns></returns>
[HttpPut]
public async Task<IResponseOutput> UpdateTaskStudyModality(Guid taskStudyId, string modality)
{
await _taskStudyRepository.UpdatePartialFromQueryAsync(t => t.Id == taskStudyId, u => new TaskStudy() { ModalityForEdit = modality }, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 影像下载成功回调
/// </summary>
/// <param name="trialImageDownloadId"></param>
/// <returns></returns>
public async Task<IResponseOutput> DownloadImageSuccess(Guid trialImageDownloadId, Guid? visitTaskId)
{
await _trialImageDownloadRepository.UpdatePartialFromQueryAsync(t => t.Id == trialImageDownloadId, u => new TrialImageDownload()
{ DownloadEndTime = DateTime.Now, IsSuccess = true }, true);
if (visitTaskId != null)
{
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => t.Id == visitTaskId.Value, u => new VisitTask() { IsIRImageDownloaded = true });
}
return ResponseOutput.Ok();
}
/// <summary>
/// 项目影像下载监控列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<TrialImageDownloadView>> 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.IdentityUser.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<TrialImageDownloadView>(_mapper.ConfigurationProvider);
return await query.ToPagedListAsync(inQuery);
}
#region 影像汇总页面
[HttpPost]
public async Task<IResponseOutput<PageOutput<TrialVisitImageStatView>>> GetTrialVisitImageStatList(TrialVisitImageQuery inQuery)
{
var query = _subjectVisitRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
.WhereIf(inQuery.SubjectCode.IsNotNullOrEmpty(), t => t.Subject.Code.Contains(inQuery.SubjectCode))
.WhereIf(inQuery.BeginScanDate != null, t => t.LatestScanDate >= inQuery.BeginScanDate)
.WhereIf(inQuery.EndScanDate != null, t => t.LatestScanDate == inQuery.EndScanDate)
.Select(t => new TrialVisitImageStatView()
{
TrialId = t.TrialId,
SubjectVisitId = t.Id,
SubjectCode = t.Subject.Code,
TrialSiteCode = t.TrialSite.TrialSiteCode,
TrialSiteId = t.TrialSiteId,
VisitName = t.VisitName,
VisitNum = t.VisitNum,
EarliestScanDate = t.EarliestScanDate,
LatestScanDate = t.LatestScanDate,
IsHaveDicom = t.StudyList.Any(),
IsHaveNoneDicom = t.NoneDicomStudyList.Any(),
TotalStudyCount = t.StudyList.Count() + t.NoneDicomStudyList.Count(),
TotalImageCount = t.StudyList.Sum(t => t.InstanceCount) + t.NoneDicomStudyList.Sum(t => t.FileCount),
TotalImageSize = t.StudyList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize) + t.NoneDicomStudyList.SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize),
TotalReadingImageSize = t.StudyList.SelectMany(t => t.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading)).Sum(t => t.FileSize)
+ t.NoneDicomStudyList.Where(t => t.IsReading).SelectMany(t => t.NoneDicomFileList.Where(t => t.IsReading)).Sum(t => t.FileSize),
//DicomStudyCount = t.StudyList.Count(),
//NoneDicomStudyCount = t.NoneDicomStudyList.Count(),
//DicomImageCount = t.StudyList.Sum(t => t.InstanceCount),
//NoneDicomImageCount = t.NoneDicomStudyList.Sum(t => t.FileCount),
//DicomImageSize = t.StudyList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize),
//NoneDicomImageSize = t.NoneDicomStudyList.SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize)
});
var defalutSortArray = new string[] { nameof(TrialVisitImageStatView.TrialSiteCode), nameof(QCCRCVisitViewModel.SubjectCode), nameof(QCCRCVisitViewModel.VisitNum) };
var pagelist = await query.Where(t => t.TotalImageCount > 0).ToPagedListAsync(inQuery, defalutSortArray);
return ResponseOutput.Ok(pagelist);
}
/// <summary>
/// 获取项目影像统计,有影像的subject 数量 访视数量
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
public async Task<IResponseOutput<TrialImageStatInfo>> GetTrialVisitImageStatInfo(Guid trialId)
{
var subjectImageList = _subjectVisitRepository.Where(t => t.TrialId == trialId)
.Where(t => t.StudyList.Sum(t => t.InstanceCount) > 0 || t.NoneDicomStudyList.Sum(t => t.FileCount) > 0)
.GroupBy(t => t.SubjectId)
.Select(g => new
{
SubjectId = g.Key,
VisitCount = g.Count(),
ReadingImageSize = g.SelectMany(t => t.NoneDicomStudyList.Where(t => t.IsReading)).SelectMany(t => t.NoneDicomFileList.Where(t => t.IsReading)).Sum(t => t.FileSize)
+ g.SelectMany(t => t.StudyList).SelectMany(t => t.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading)).Sum(t => t.FileSize),
ImageSize = g.SelectMany(t => t.NoneDicomStudyList).SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize)
+ g.SelectMany(t => t.StudyList).SelectMany(t => t.InstanceList).Sum(t => t.FileSize)
})
.ToList();
var subjectCount = subjectImageList.Count;
var subjectVisitCount = subjectImageList.Sum(t => t.VisitCount);
var totalImageSize = subjectImageList.Sum(t => t.ImageSize);
var totalReadingImageSize = subjectImageList.Sum(t => t.ReadingImageSize);
return ResponseOutput.Ok(new TrialImageStatInfo { SubjectCount = subjectCount, SubjectVisitCount = subjectVisitCount, TotalImageSize = totalImageSize, TotalReadingImageSize = totalReadingImageSize });
}
/// <summary>
/// 获取未阅片完成的访视,方便前端调用下载
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
public async Task<List<Guid?>> GetTrialUnreadVisitList(Guid trialId)
{
var subjectVisitList = await _visitTaskRepository.Where(t => t.TrialId == trialId && t.TaskState == TaskState.Effect && t.ReadingCategory == ReadingCategory.Visit && t.ReadingTaskState != ReadingTaskState.HaveSigned && t.SourceSubjectVisitId != null).Select(t => t.SourceSubjectVisitId)
.Distinct().ToListAsync();
return subjectVisitList;
}
/// <summary>
/// 批量勾选访视 进行下载
/// </summary>
/// <param name="inCommand"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetExportSubjectVisitImageList(TrialExportImageCommand inCommand)
{
var isExportReading = inCommand.IsExportReading == true;
var dirDic = new Dictionary<string, string>();
if (inCommand.IsKeyImage)
{
var downloadInfoList = _visitTaskRepository.Where(t => t.TrialId == inCommand.TrialId && (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global)
&& t.ReadingTaskState == ReadingTaskState.HaveSigned && t.IsAnalysisCreate == false && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze))
.Where(t => inCommand.SubjectVisitIdList.Contains((Guid)t.SourceSubjectVisitId))
.Select(t => new TrialKeyImageExportDTO()
{
ResearchProgramNo = t.Trial.ResearchProgramNo,
CriterionName = t.TrialReadingCriterion.CriterionName,
ArbitrationRule = t.TrialReadingCriterion.ArbitrationRule,
IsGlobalReading = t.TrialReadingCriterion.IsGlobalReading,
SubjectCriterionReadingPeriodVisitNumList = t.Subject.ReadModuleList
.Where(u => u.TrialReadingCriterionId == t.TrialReadingCriterionId && u.ReadingSetType == ReadingSetType.ImageReading).Select(c => c.SubjectVisit.VisitNum).ToList(),
TrialSiteCode = t.Subject.TrialSite.TrialSiteCode,
SubjectCode = t.Subject.Code,
ReadingCategory = t.ReadingCategory,
VisitName = t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.VisitName : "",
VisitTaskNum = t.VisitTaskNum,
ArmEnum = t.ArmEnum,
ReadingNoneDicomMarkPathList = t.ReadingNoneDicomMarkList.Select(c => new TrialKeyPicturePath { PicturePath = c.Path, OtherPicturePath = string.Empty }).ToList(),
QuestionMarkPictureList = t.ReadingTaskQuestionMarkList.Select(c => new TrialKeyPicturePath { PicturePath = c.PicturePath, OtherPicturePath = c.OtherPicturePath }).ToList(),
TableQuestionRowPictureList = t.LesionList.Select(c => new TrialKeyPicturePath { PicturePath = c.PicturePath, OtherPicturePath = c.OtherPicturePath }).ToList(),
SegmentationFileList = t.SegmentationList.Select(c => new TrialKeyPicturePath { PicturePath = c.SEGUrl, SegmentationName = c.SegmentationName, OtherPicturePath = string.Empty }).ToList(),
Id = t.Id,
//裁判选择结果
JudgeResultTaskId = t.JudgeVisitTask.JudgeResultTaskId,
//是否触发裁判
IsTrigerJudge = t.JudgeVisitTaskId != null,
IsJudgeSelect = null
}).ToList();
foreach (var subjectCriterionGroup in downloadInfoList.GroupBy(t => new { t.SubjectCode, t.CriterionName, t.ArbitrationRule, t.IsGlobalReading }))
{
var arbitrationRule = subjectCriterionGroup.Key.ArbitrationRule;
var isGlobalReading = subjectCriterionGroup.Key.IsGlobalReading;
foreach (var item in subjectCriterionGroup)
{
if (arbitrationRule == ArbitrationRule.Visit)
{
//是否产生裁判
if (item.IsTrigerJudge == true)
{
//裁判做完了
if (item.JudgeResultTaskId != null)
{
//裁判选择了自己,那么设置
if (item.JudgeResultTaskId == item.Id)
{
item.IsJudgeSelect = true;
}
else
{
item.IsJudgeSelect = false;
}
}
}
else
{
//没产生 且两个人做完了 默认R1
if (subjectCriterionGroup.Where(t => t.VisitTaskNum == item.VisitTaskNum && t.SubjectCode == item.SubjectCode).Select(t => t.ArmEnum).Distinct().Count() == 2)
{
if (item.ArmEnum == Arm.DoubleReadingArm1)
{
item.IsJudgeSelect = true;
}
else
{
item.IsJudgeSelect = false;
}
}
}
}
else if (arbitrationRule == ArbitrationRule.Reading)
{
//阅片期访视号
var subjectReadingPeriondVisitNumList = subjectCriterionGroup.FirstOrDefault()?.SubjectCriterionReadingPeriodVisitNumList;
//两个人完成最大得任务号(访视+全局)
var subjectMaxFinishedTaskNum = subjectCriterionGroup.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).DefaultIfEmpty().Max();
var addReadingPeriodNum = isGlobalReading ? ReadingCommon.TaskNumDic[ReadingCategory.Global] : 0;
//可能没有配置阅片期 ,或者配置了 没有完成
var finishedGlobalCount = 0;
var globalFinishedVisitTaskNumList = new List<decimal>();
//没有配置阅片期
if (subjectReadingPeriondVisitNumList == null)
{
finishedGlobalCount = 0;
}
{
globalFinishedVisitTaskNumList = subjectCriterionGroup.Where(t => subjectReadingPeriondVisitNumList.Any(c => (c + addReadingPeriodNum) == t.VisitTaskNum))
.Select(t => new { t.VisitTaskNum, t.ArmEnum }).Distinct()
.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).ToList();
finishedGlobalCount = globalFinishedVisitTaskNumList.Count();
}
if (finishedGlobalCount != 0)
{
//最大的完成的全局是否产生裁判
var maxFinishedGlobalNum = globalFinishedVisitTaskNumList.Max();
var globalMaxTask = subjectCriterionGroup.FirstOrDefault(t => t.VisitTaskNum == maxFinishedGlobalNum);
// 触发了裁判
if (globalMaxTask.IsTrigerJudge == true)
{
//最大裁判完成了
var maxJudgeVisitTaskNum = maxFinishedGlobalNum + ReadingCommon.TaskNumDic[ReadingCategory.Judge];
if (globalMaxTask.JudgeResultTaskId != null)
{
var maxJudgeArmEnum = subjectCriterionGroup.Where(t => t.Id == globalMaxTask.JudgeResultTaskId).FirstOrDefault().ArmEnum;
if (item.VisitTaskNum < maxJudgeVisitTaskNum)
{
//触发裁判
item.IsTrigerJudge = true;
if (item.ArmEnum == maxJudgeArmEnum)
{
item.IsJudgeSelect = true;
}
//裁判没选择的人设置为false
else
{
item.IsJudgeSelect = false;
}
}
}
else
{
//最大的裁判未完成
//找到当前未阅最大裁判之前的已完成的最大裁判任务
var finishedGlobalFinishedMaxJudge = subjectCriterionGroup.Where(t => globalFinishedVisitTaskNumList.Contains(t.VisitTaskNum) && t.IsTrigerJudge == true && t.JudgeResultTaskId != null).OrderByDescending(t => t.VisitTaskNum).FirstOrDefault();
//未完成裁判之前 没有已完成的全局裁判
if (finishedGlobalFinishedMaxJudge == null)
{
if (item.VisitTaskNum < maxJudgeVisitTaskNum)
{
item.IsTrigerJudge = true;
//item.IsJudgeSelect = null;
}
}
else
{
var maxFinishedJudgeVisitTaskNum = finishedGlobalFinishedMaxJudge.VisitTaskNum + +ReadingCommon.TaskNumDic[ReadingCategory.Judge];
var maxFinishedJudgeArmEnum = subjectCriterionGroup.Where(t => t.Id == finishedGlobalFinishedMaxJudge.JudgeResultTaskId).FirstOrDefault().ArmEnum;
if (item.VisitTaskNum < maxFinishedJudgeVisitTaskNum)
{
item.IsTrigerJudge = true;
if (item.ArmEnum == maxFinishedJudgeArmEnum)
{
item.IsJudgeSelect = true;
}
//裁判没选择的人设置为false
else
{
item.IsJudgeSelect = false;
}
}
else if (item.VisitTaskNum > maxFinishedJudgeVisitTaskNum && item.VisitTaskNum < maxJudgeVisitTaskNum)
{
//完成裁判 和未完成裁判之间的 裁判选择标记默认是null
item.IsTrigerJudge = true;
}
else
{
//在未完成全局裁判之后的访视 未知 都是null
item.IsTrigerJudge = null;
}
}
}
}
else
{
//最大的全局未产生裁判
if (item.VisitTaskNum <= maxFinishedGlobalNum)
{
item.IsTrigerJudge = false;
if (item.ArmEnum == Arm.DoubleReadingArm1)
{
item.IsJudgeSelect = true;
}
else
{
item.IsJudgeSelect = false;
}
}
}
}
}
}
}
downloadInfoList = downloadInfoList.Where(t => t.ReadingCategory == ReadingCategory.Visit).ToList();
return ResponseOutput.Ok(downloadInfoList);
}
else
{
#region 在下载前先处理DIR文件
//sql 超时
//_subjectVisitRepository.Where(t => inCommand.SubjectVisitIdList.Contains(t.Id))
// .SelectMany(t => t.StudyList.SelectMany(t => t.InstanceList.Where(t => isExportReading ? (t.IsReading && t.DicomSerie.IsReading) : true)))
// .All(c => c.TransferSytaxUID != string.Empty)
//有传输语法值的导出 才生成DIR
if (!_instanceRepository.Where(t => isExportReading ? (t.IsReading && t.DicomSerie.IsReading) : true)
.Where(t => inCommand.SubjectVisitIdList.Contains(t.SubjectVisitId)).Any(c => c.TransferSytaxUID == string.Empty))
{
var dirInfolist = _subjectVisitRepository.Where(t => inCommand.SubjectVisitIdList.Contains(t.Id)).SelectMany(t => t.StudyList)
.SelectMany(t => t.InstanceList.Where(t => isExportReading ? (t.IsReading && t.DicomSerie.IsReading) : true))
.Select(t => new StudyDIRInfo()
{
SubjectId = t.SubjectId,
SubjectVisitId = t.SubjectVisitId,
DicomStudyId = t.DicomStudy.Id,
PatientId = t.Trial.TrialCode + "-" + t.DicomStudy.Subject.Code,
PatientName = t.DicomStudy.PatientName,
PatientBirthDate = t.DicomStudy.PatientBirthDate,
PatientSex = t.DicomStudy.PatientSex,
StudyInstanceUid = t.StudyInstanceUid,
StudyId = t.DicomStudy.StudyId,
DicomStudyDate = t.DicomStudy.DicomStudyDate,
DicomStudyTime = t.DicomStudy.DicomStudyTime,
AccessionNumber = t.DicomStudy.AccessionNumber,
StudyDescription = t.DicomStudy.Description,
SeriesInstanceUid = t.DicomSerie.SeriesInstanceUid,
Modality = t.DicomSerie.Modality,
DicomSeriesDate = t.DicomSerie.DicomSeriesDate,
DicomSeriesTime = t.DicomSerie.DicomSeriesTime,
SeriesNumber = t.DicomSerie.SeriesNumber,
SeriesDescription = t.DicomSerie.Description,
InstanceId = t.Id,
SopInstanceUid = t.SopInstanceUid,
SOPClassUID = t.SOPClassUID,
InstanceNumber = t.InstanceNumber,
MediaStorageSOPClassUID = t.MediaStorageSOPClassUID,
MediaStorageSOPInstanceUID = t.MediaStorageSOPInstanceUID,
TransferSytaxUID = t.TransferSytaxUID,
}).ToList();
foreach (var item in dirInfolist.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId }))
{
var visitId = item.First().SubjectVisitId;
var subjectId = item.First().SubjectId;
var studyUid = item.Key.StudyInstanceUid;
var ossFolder = $"{inCommand.TrialId}/Image/{subjectId}/{visitId}/{item.Key.StudyInstanceUid}";
var isSucess = await SafeBussinessHelper.RunAsync(async () => await DicomDIRHelper.GenerateStudyDIRAndUploadAsync(item.ToList(), dirDic, ossFolder, _oSSService));
if (isSucess)
{
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/{dirDic[$"{studyUid}_DICOMDIR"]}" });
}
}
}
#endregion
var downloadInfo = _trialRepository.Where(t => t.Id == inCommand.TrialId).Select(t => new
{
t.ResearchProgramNo,
VisitList = t.SubjectVisitList.Where(t => inCommand.SubjectVisitIdList.Contains(t.Id)).Select(sv => new
{
TrialSiteCode = sv.TrialSite.TrialSiteCode,
SubjectCode = sv.Subject.Code,
VisitName = sv.VisitName,
StudyList = sv.StudyList.Select(u => new
{
u.PatientId,
u.StudyTime,
u.StudyCode,
StudyDIRPath = u.StudyDIRPath,
SeriesList = u.SeriesList.Where(t => isExportReading ? t.IsReading : true).Select(z => new
{
z.Modality,
InstanceList = z.DicomInstanceList.Where(t => isExportReading ? t.IsReading : true).Select(k => new DownloadDicomInstanceDto()
{
IsEncapsulated = k.IsEncapsulated,
InstanceId = k.Id,
FileName = string.Empty,
Path = k.Path,
FileSize = k.FileSize
})
})
}),
NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isExportReading ? t.IsReading : true).Select(nd => new
{
nd.Modality,
nd.StudyCode,
nd.ImageDate,
FileList = nd.NoneDicomFileList.Where(t => isExportReading ? t.IsReading : true).Select(file => new
{
file.FileName,
file.Path,
file.FileType
})
})
}).ToList()
}).FirstOrDefault();
foreach (var item in downloadInfo.VisitList.SelectMany(t => t.StudyList.SelectMany(t => t.SeriesList).SelectMany(t => t.InstanceList)))
{
var key = item.InstanceId.ToString();
if (dirDic.ContainsKey(key))
{
item.FileName = dirDic[key];
}
}
return ResponseOutput.Ok(downloadInfo);
}
}
#endregion
#region 第三人预处理影响上传下载
/// <summary>
/// 获取受试者级别 访视标注列表
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<SubjectVisitMarkDTO>>> GetTrialSubjectVisitMarkList(SubjectVisitMarkQuery inQuery)
{
var list = await _subjectRepository.Where(t => t.TrialId == inQuery.TrialId && t.SubjectDoctorList.Any())
.WhereIf(inQuery.SubjectCode.IsNotNullOrEmpty(), t => t.Code.Contains(inQuery.SubjectCode))
.WhereIf(inQuery.IsUrgent != null, t => t.IsUrgent == inQuery.IsUrgent)
.Select(t => new SubjectVisitMarkDTO()
{
TrialId = t.TrialId,
SubjectId = t.Id,
SubjectCode = t.Code,
IsUrgent = t.IsUrgent,
LatestDownloadTime = t.TrialImageDownloadList.Where(t => t.CreateUserRole.UserTypeEnum == UserTypeEnum.IndependentReviewer)
.OrderByDescending(t => t.CreateTime).Select(t => t.CreateTime).FirstOrDefault(),
LatestUploadTime = t.SubjectVisitList
.Where(v => v.SubmitState == SubmitStateEnum.Submitted && v.CheckState == CheckStateEnum.CVPassed)
.SelectMany(v => v.TaskStudyList)
.Select(s => s.CreateTime) // 假设字段名为 CreateTime,根据实际情况调整
.Union(
t.SubjectVisitList
.Where(v => v.SubmitState == SubmitStateEnum.Submitted && v.CheckState == CheckStateEnum.CVPassed)
.SelectMany(v => v.NoneDicomStudyList)
.Where(n => n.ImageLabelNoneDicomFileList.Any())
.Select(s => s.CreateTime) // 假设字段名为 CreateTime,根据实际情况调整
)
.OrderByDescending(time => time)
.FirstOrDefault(),
VisitCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).Count(),
MarkIVUSVisitCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).Count(t => t.NoneDicomStudyList.Where(t => t.Modality == "IVUS").SelectMany(c => c.ImageLabelNoneDicomFileList).Any()),
MarkOCTVisitCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).Count(t => t.NoneDicomStudyList.Where(t => t.Modality == "OCT").SelectMany(c => c.ImageLabelNoneDicomFileList).Any()),
DicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.StudyList).Count(),
MarkDicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.TaskStudyList).Count(),
NoneDicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.NoneDicomStudyList).Count(),
MarkNoneDicomStudyCount = t.SubjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted && t.CheckState == CheckStateEnum.CVPassed).SelectMany(t => t.NoneDicomStudyList).Where(t => t.ImageLabelNoneDicomFileList.Any()).Count(),
})
.WhereIf(inQuery.State == 0, t => t.LatestDownloadTime == null)//待处理
.WhereIf(inQuery.State == 1, t => t.LatestDownloadTime != null && (t.DicomStudyCount + t.NoneDicomStudyCount) != (t.MarkDicomStudyCount + t.MarkNoneDicomStudyCount))//处理中
.WhereIf(inQuery.State == 2, t => t.LatestDownloadTime != null && (t.DicomStudyCount + t.NoneDicomStudyCount) == (t.MarkDicomStudyCount + t.MarkNoneDicomStudyCount))//已完成
.ToPagedListAsync(inQuery);
return ResponseOutput.Ok(list);
}
#endregion
#region 之前后端下载废弃
/// <summary>
/// 受试者级别所有的影像
/// 访视级别的影响 传递subjectVisitId
/// 标准Id是可选的 不同标准有些检查可能有过滤
/// </summary>
/// <param name="_subjectRepository"></param>
/// <param name="inQuery"></param>
/// <returns></returns>
[Obsolete]
public async Task<IResponseOutput> GetSubejectOrVisitZipInfo([FromServices] IRepository<Subject> _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 都不传递");
}
}
/// <summary>
/// 后台任务调用,前端忽略该接口
/// </summary>
/// <param name="trialId"></param>
/// <param name="subjectVisitId"></param>
/// <param name="isDicom"></param>
/// <param name="isAnonymize"></param>
/// <returns></returns>
[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<SystemAnonymization>();
var ircFieldList = new List<SystemAnonymization>();
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 按照任务为维度 展示上传的列表 废弃
/// <summary>
/// IR 影像上传任务列表 --old 20240903 界面调整,现在先废弃
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
[Obsolete]
public async Task<List<SubjectUploadTaskInfo>> 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<SubjectUploadTaskInfo>(_mapper.ConfigurationProvider);
var list = await query.Where(t => t.SubjectCode == inQuery.SubjectCode).ToListAsync();
return list;
}
/// <summary>
/// IR 上传任务 dicom 列表 后处理的数据不能排序 --old 20240903 界面调整,现在先废弃
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
[Obsolete]
public async Task<List<IRUploadTaskDicomStudyDto>> GetIRUploadTaskDicomStudyList_Old(CRCUploadTaskStudyQuery inQuery)
{
var list = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId)
.SelectMany(t => t.SourceSubjectVisit.StudyList)
.ProjectTo<IRUploadTaskDicomStudyDto>(_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;
}
/// <summary>
/// IR 上传任务 nonedicom 列表 后处理的数据不能排序 --old 20240903 界面调整,现在先废弃
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
[Obsolete]
public async Task<List<IRUploadTaskNoneDicomStudyDto>> GetIRUploadTaskNoneDicomStudyList_Old(CRCUploadTaskStudyQuery inQuery)
{
var list = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId)
.SelectMany(t => t.SourceSubjectVisit.StudyList)
.ProjectTo<IRUploadTaskNoneDicomStudyDto>(_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
}
}