irc-netcore-api/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs

1623 lines
75 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using DocumentFormat.OpenXml.EMMA;
using FellowOakDicom;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using MassTransit;
using MassTransit.Initializers;
using Medallion.Threading;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System.Data;
using System.IO.Compression;
using System.Text;
using System.Web;
using ZiggyCreatures.Caching.Fusion;
namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
public interface IDownloadAndUploadService
{
Task PackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isDicom, bool isAnonymize = true);
Task<IResponseOutput> SubejctRandomReadingTaskNameDeal(Guid subjectId, Guid trialReadingCriterionId);
}
[ApiExplorerSettings(GroupName = "Trial")]
public class DownloadAndUploadService(IRepository<SystemAnonymization> _systemAnonymizationRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IOSSService _oSSService,
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,
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.ImageUploadEnum != ReadingImageUpload.None))))
{
//找到 非一致性分析,未签名,状态正常的 并且任务名称是TimePoint的 任务
var needDealTaskList = await _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.UserRoleId
&& t.ReadingTaskState != ReadingTaskState.HaveSigned && t.TaskBlindName == "Timepoint" && t.ReadingCategory == ReadingCategory.Visit
&& (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze), true).ToListAsync();
if (needDealTaskList.Count > 0)
{
//已完成的访视任务数量(包含重阅的)
var haveFinishedTaskCount = await _visitTaskRepository.CountAsync(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.UserRoleId
&& t.ReadingTaskState == ReadingTaskState.HaveSigned && t.ReadingCategory == ReadingCategory.Visit);
//已经处理过的任务名称的数量
var haveDealedTaskList = await _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.DoctorUserId == _userInfo.UserRoleId
&& t.ReadingTaskState != ReadingTaskState.HaveSigned && t.ReadingCategory == ReadingCategory.Visit && t.TaskBlindName != "Timepoint").Select(t => new { t.TaskBlindName, t.SourceSubjectVisitId, t.SouceReadModuleId }).ToListAsync();
//随机赋值编号 比如要处理5个任务实例化一个包含1-5的数组每次随机取出一个
List<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<List<SubjectImageUploadDTO>>> GetSubjectImageUploadList(IRUploadStudyQuery inQuery)
{
//要根据标准阅片顺序,确定是否查询单个任务的,还是查询所有的
var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId)
.Select(t => new { t.IsReadingTaskViewInOrder, t.Trial.Modalitys }).FirstNotNullAsync();
var subjectCode = string.Empty;
var subjectId = inQuery.SubjectId;
if (criterionInfo.IsReadingTaskViewInOrder == ReadingOrder.Random)
{
if (inQuery.VisitTaskId == null)
{
throw new Exception("无序阅片,前端参数传递错误");
}
//考虑到一致性分析,必须要这个编号进行过滤
var taskInfo = _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId).Select(t => new
{
SubjectCode = t.IsAnalysisCreate ? t.BlindSubjectCode : t.Subject.Code,
SubjectId = t.SubjectId,
}).FirstOrDefault();
subjectId = taskInfo.SubjectId;
subjectCode = taskInfo.SubjectCode;
}
else
{
if (inQuery.SubjectId == null || inQuery.SubjectCode == null)
{
throw new Exception("有序阅片,前端参数传递错误");
}
//考虑到一致性分析,必须要这个编号进行过滤
subjectCode = inQuery.SubjectCode;
}
await SubejctRandomReadingTaskNameDeal((Guid)subjectId, inQuery.TrialReadingCriterionId);
var query = _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SourceSubjectVisitId != null
&& t.DoctorUserId == _userInfo.UserRoleId && t.TaskState == TaskState.Effect)
//满足 有序或者随机只看到当前任务的dicom 非dicom检查
.WhereIf(criterionInfo.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId)
.Select(u => new SubjectImageUploadDTO()
{
VisitTaskId = u.Id,
SubejctId = u.SubjectId,
TrialSiteId = u.Subject.TrialSiteId,
IsImageFilter = u.TrialReadingCriterion.IsImageFilter,
CriterionModalitys = u.TrialReadingCriterion.CriterionModalitys,
SubjectCode = u.IsAnalysisCreate == true ? u.BlindSubjectCode : u.Subject.Code,
TaskBlindName = u.TaskBlindName,
TaskName = u.TaskName,
ReadingTaskState = u.ReadingTaskState,
SourceSubjectVisitId = u.SourceSubjectVisitId,
OrginalStudyList = u.SourceSubjectVisit.StudyList
.Where(t => u.TrialReadingCriterion.IsImageFilter ? ("|" + u.TrialReadingCriterion.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
.Select(t => new StudyBasicInfo()
{
Id = t.Id,
StudyInstanceUid = t.StudyInstanceUid,
ModalityForEdit = t.ModalityForEdit,
BodyPartExamined = t.BodyPartExamined,
BodyPartForEdit = t.BodyPartForEdit,
StudyCode = t.StudyCode,
StudyTime = t.StudyTime,
Description = t.Description,
InstanceCount = t.InstanceCount,
Modalities = t.Modalities,
SeriesCount = t.SeriesCount,
}).ToList(),
UploadStudyList = u.TaskStudyList.Select(t => new StudyBasicInfo()
{
Id = t.Id,
StudyInstanceUid = t.StudyInstanceUid,
ModalityForEdit = t.ModalityForEdit,
BodyPartExamined = t.BodyPartExamined,
BodyPartForEdit = t.BodyPartForEdit,
StudyCode = t.StudyCode,
StudyTime = t.StudyTime,
Description = t.Description,
InstanceCount = t.InstanceCount,
Modalities = t.Modalities,
SeriesCount = t.SeriesCount,
SopInstanceUidList = t.InstanceList.Select(t => t.SopInstanceUid).ToList(),
}).ToList()
})
;
//var test = await query.ToListAsync();
var list = await query.Where(t => t.SubjectCode == subjectCode).ToListAsync();
return ResponseOutput.Ok(list, new { TrialModality = criterionInfo.Modalitys });
}
private void SpecialArchiveStudyDeal(TaskStudy study)
{
#region 特殊逻辑
if (study.PatientBirthDate.Length == 8)
{
study.PatientBirthDate = $"{study.PatientBirthDate[0]}{study.PatientBirthDate[1]}{study.PatientBirthDate[2]}{study.PatientBirthDate[3]}-{study.PatientBirthDate[4]}{study.PatientBirthDate[5]}-{study.PatientBirthDate[6]}{study.PatientBirthDate[7]}";
}
var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList();
var modality = study.Modalities;
var modalityForEdit = dicModalityList.Contains(modality) ? modality : String.Empty;
if (modality == "MR")
{
modalityForEdit = "MRI";
}
if (modality == "PT")
{
modalityForEdit = "PET";
}
if (modality == "PT、CT")
{
modalityForEdit = "PET-CT";
}
study.ModalityForEdit = modalityForEdit;
#endregion
}
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
public async Task<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 currentUploadSubjectVisitId = inCommand.VisitTaskId == null ? null : _visitTaskRepository.Where(t => t.Id == inCommand.VisitTaskId).Select(t => t.SourceSubjectVisitId).FirstOrDefault();
//重阅任务排除
var notAllowedUidList1 = _taskStudyRepository.Where(t => t.TrialId == inCommand.TrialId && t.VisitTask.TaskState == TaskState.Effect && inCommand.StudyInstanceUidList.Contains(t.StudyInstanceUid)).Select(t => new
{
t.StudyInstanceUid,
t.SubjectId,
SubjectVisitId = t.VisitTask.SourceSubjectVisitId,
SubejectCode = t.VisitTask.IsAnalysisCreate ? t.VisitTask.BlindSubjectCode : t.Subject.Code,
VisitTaskId = (Guid?)t.VisitTaskId
}).ToList();
var notAllowedUidList2 = _dicomStudyRepository.Where(t => t.TrialId == inCommand.TrialId && inCommand.StudyInstanceUidList.Contains(t.StudyInstanceUid)).Select(t => new
{
t.StudyInstanceUid,
t.SubjectId,
SubjectVisitId = (Guid?)t.SubjectVisitId,
SubejectCode = t.Subject.Code,
VisitTaskId = (Guid?)null
}).ToList();
var notAllowedUidList = notAllowedUidList1.Union(notAllowedUidList2);
var result = new List<TaskStudyArchiveConfirmResult>();
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");
using (await @uploadLock.AcquireAsync())
{
if (_fusionCache.GetOrDefault<Guid>(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid)) != Guid.Empty)
{
//---当前已有人正在上传和归档该检查!
return ResponseOutput.NotOk(I18n.T("UploadDownLoad_ArchiveInProgress"));
}
else
{
//在事务未完成前 防止前端重复提交
await _fusionCache.SetAsync(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid), _userInfo.UserRoleId, TimeSpan.FromMinutes(1));
}
}
var visiTaskId = incommand.VisitTaskId;
var modalitys = string.Empty;
try
{
var trialId = incommand.TrialId;
var studyMonitor = await _studyMonitorRepository.FirstOrDefaultAsync(t => t.Id == incommand.StudyMonitorId);
studyMonitor.UploadFinishedTime = DateTime.Now;
studyMonitor.ArchiveFinishedTime = DateTime.Now;
studyMonitor.FailedFileCount = incommand.FailedFileCount;
studyMonitor.IsSuccess = incommand.FailedFileCount == 0;
studyMonitor.RecordPath = incommand.RecordPath;
studyMonitor.FileSize = incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize);
var studyId = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString());
var findStudy = await _taskStudyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
studyMonitor.StudyId = studyId;
studyMonitor.StudyCode = findStudy?.StudyCode ?? "";
studyMonitor.IsDicomReUpload = findStudy != null;
//上传
if (studyMonitor.IsDicomReUpload == false)
{
var study = _mapper.Map<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 = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString(), visiTaskId.ToString());
study.TrialId = incommand.TrialId;
study.SubjectId = incommand.SubjectId;
study.VisitTaskId = visiTaskId;
//study.SubjectVisitId = incommand.SubjectVisitId;
//特殊处理逻辑
study.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Distinct());
SpecialArchiveStudyDeal(study);
modalitys = study.Modalities;
await _taskStudyRepository.AddAsync(study);
studyMonitor.StudyCode = study.StudyCode;
foreach (var seriesItem in incommand.Study.SeriesList)
{
var series = _mapper.Map<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.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;
await _taskInstanceRepository.AddAsync(isntance);
}
}
}
else
{
//重传的时候也要赋值检查Id
studyMonitor.StudyId = findStudy.Id;
studyMonitor.StudyCode = findStudy.StudyCode;
//特殊处理逻辑
findStudy.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Union(findStudy.Modalities.Split("、", StringSplitOptions.RemoveEmptyEntries)).Distinct());
SpecialArchiveStudyDeal(findStudy);
modalitys = findStudy.Modalities;
// 少了整个序列
//某个序列下少了instance
foreach (var seriesItem in incommand.Study.SeriesList)
{
var seriesId = IdentifierHelper.CreateGuid(seriesItem.StudyInstanceUid, seriesItem.SeriesInstanceUid, trialId.ToString(), visiTaskId.ToString());
TaskSeries dicomSeries = await _taskSeriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
//判断重复
if (dicomSeries == null)
{
var series = _mapper.Map<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;
}
foreach (var instanceItem in seriesItem.InstanceList)
{
var insntance = _mapper.Map<TaskInstance>(instanceItem);
insntance.Id = IdentifierHelper.CreateGuid(insntance.StudyInstanceUid, insntance.SeriesInstanceUid, insntance.SopInstanceUid, trialId.ToString(), visiTaskId.ToString());
insntance.StudyId = findStudy.Id;
insntance.SeriesId = dicomSeries.Id;
insntance.TrialId = incommand.TrialId;
insntance.SubjectId = incommand.SubjectId;
insntance.VisitTaskId = visiTaskId;
await _taskInstanceRepository.AddAsync(insntance);
}
// 不管是新的序列 还是 该序列 掉了Instance 重传的时候 检查的instance 数量都会增加
findStudy.InstanceCount += seriesItem.InstanceList.Count;
}
}
var @lock2 = _distributedLockProvider.CreateLock($"StudyCommit");
using (await @lock2.AcquireAsync())
{
await _taskStudyRepository.SaveChangesAsync();
}
}
catch (Exception ex)
{
return ResponseOutput.NotOk(ex.Message);
}
finally
{
await _fusionCache.RemoveAsync(CacheKeys.TrialTaskStudyUidDBLock(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid));
await _fusionCache.RemoveAsync(CacheKeys.TrialTaskStudyUidUploading(incommand.TrialId, incommand.VisitTaskId, incommand.Study.StudyInstanceUid));
}
return ResponseOutput.Ok(modalitys);
}
[HttpDelete]
public async Task<IResponseOutput> DeleteTaskStudy(Guid visitTaskId, bool isDicom, Guid? dicomStudyId, Guid? noneDicomStudyId)
{
if (isDicom)
{
if (dicomStudyId == null)
{
await _taskStudyRepository.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId);
await _taskSeriesRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId);
await _taskInstanceRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId);
}
else
{
await _taskStudyRepository.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId && t.Id == dicomStudyId);
await _taskSeriesRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId && t.Id == dicomStudyId);
await _taskInstanceRepository.BatchDeleteNoTrackingAsync(t => t.VisitTaskId == visitTaskId && t.Id == dicomStudyId);
}
}
else
{
await _noneDicomStudyFileReposiotry.DeleteFromQueryAsync(t => t.VisitTaskId == visitTaskId && t.OriginNoneDicomStudyId == noneDicomStudyId);
}
await _noneDicomStudyFileReposiotry.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// IR 上传任务 nonedicom 列表 后处理的数据UploadedFileCount不能排序 --new
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<TaskNoneDicomStudyDTO>> GetIRUploadTaskNoneDicomStudyList(IRUploadStudyQuery inQuery)
{
var subjectCode = inQuery.SubjectCode;
var subjectId = inQuery.SubjectId;
var doctorUserId = _userInfo.UserRoleId;
if (inQuery.VisitTaskId != null)
{
//考虑到一致性分析,必须要这个编号进行过滤
//医学审核查看下载按钮,这个时候需要知道医生
var taskInfo = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId).Select(t => new
{
SubjectCode = t.IsAnalysisCreate ? t.BlindSubjectCode : t.Subject.Code,
SubjectId = t.SubjectId,
t.DoctorUserId,
t.IsAnalysisCreate
}).FirstNotNullAsync();
subjectId = taskInfo.SubjectId;
subjectCode = taskInfo.SubjectCode;
doctorUserId = (Guid)taskInfo.DoctorUserId!;
}
var info = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId)
.Select(t => new { t.IsImageFilter, t.CriterionModalitys, t.IsReadingTaskViewInOrder }).FirstNotNullAsync();
var query = from u in _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId
&& t.SourceSubjectVisitId != null && t.DoctorUserId == doctorUserId && t.TaskState == TaskState.Effect)
//满足 有序或者随机只看到当前任务的dicom 非dicom检查
.WhereIf(info.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId)
join ns in _noneDicomStudyReposiotry.Where(t => t.SubjectId == subjectId).WhereIf(info.IsImageFilter, t => ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|"))
on u.SourceSubjectVisitId equals ns.SubjectVisitId
select new TaskNoneDicomStudyDTO()
{
SubjectId = u.SubjectId,
SubjectCode = u.IsSelfAnalysis == true ? u.BlindSubjectCode : u.Subject.Code,
TaskBlindName = u.TaskBlindName,
TaskName = u.TaskName,
ReadingTaskState=u.ReadingTaskState,
SourceSubjectVisitId = u.SourceSubjectVisitId,
VisitTaskId = u.Id,
Id = ns.Id,
Description = ns.Description,
ImageDate = ns.ImageDate,
BodyPart = ns.BodyPart,
FileCount = ns.FileCount,
Modality = ns.Modality,
StudyCode = ns.StudyCode,
FileList = ns.NoneDicomFileList.Select(t => new NoneDicomFileInfo()
{
FileType = t.FileType,
FileName = t.FileName,
FileSize = t.FileSize,
Path = t.Path
}).ToList()
};
var list = await query.Where(t => t.SubjectCode == subjectCode).SortToListAsync(inQuery);
var noneDicomStudyTaskIdList = list.Select(t => t.VisitTaskId).ToList();
var taskNoneDicomStudyList = _visitTaskRepository.Where(t => noneDicomStudyTaskIdList.Contains(t.Id))
.SelectMany(t => t.TaskNoneDicomStudyFileList).Where(t => noneDicomStudyTaskIdList.Contains((Guid)t.VisitTaskId))
.Select(u => new NoneDicomFileInfo
{
OriginNoneDicomStudyId = u.OriginNoneDicomStudyId,
FileType = u.FileType,
FileName = u.FileName,
FileSize = u.FileSize,
Path = u.Path
})
.ToList();
foreach (var item in list)
{
item.UploadedFileCount = taskNoneDicomStudyList.Where(t => t.OriginNoneDicomStudyId == item.Id).Count();
item.UploadedFileList = taskNoneDicomStudyList.Where(t => t.OriginNoneDicomStudyId == item.Id).ToList();
}
return list;
}
/// <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 imageType = (isQueryDicom && isQueryNoneDicom) ? ImageType.DicomAndNoneDicom : (isQueryDicom ? ImageType.Dicom : ImageType.NoneDicom);
var query = from sv in _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId)
select new
{
TrialId = sv.TrialId,
SubjectId=sv.SubjectId,
SubjectCode = sv.Subject.Code,
TrialSiteCode=sv.TrialSite.TrialSiteCode,
VisitName = sv.VisitName,
StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
.Select(u => new
{
u.PatientId,
u.StudyTime,
u.StudyCode,
SeriesList = u.SeriesList.Select(z => new
{
z.Modality,
InstanceList = z.DicomInstanceList.Select(k => new
{
k.Path,
k.FileSize
})
})
}).ToList(),
NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)
.Select(nd => new
{
nd.Modality,
nd.StudyCode,
nd.ImageDate,
FileList = nd.NoneDicomFileList.Select(file => new
{
file.FileName,
file.Path,
file.FileType,
file.FileSize,
})
}).ToList()
};
var result = query.FirstOrDefault();
var preDownloadInfo = new TrialImageDownload()
{
Id = NewId.NextSequentialGuid(),
TrialId = result.TrialId,
SubjectId = result.SubjectId,
SubjectCode = result.SubjectCode,
TrialSiteCode = result.TrialSiteCode,
IP = _userInfo.IP,
DownloadStartTime = DateTime.Now,
IsSuccess = false,
ImageType = imageType,
VisitName = string.Join(" | ", result.VisitName),
NoneDicomStudyCount = result.NoneDicomStudyList.Count(),
DicomStudyCount = result.StudyList.Count(),
ImageCount = result.StudyList.Sum(s => s.SeriesList.Sum(s => s.InstanceList.Count())) + result.NoneDicomStudyList.Sum(s => s.FileList.Count()),
ImageSize = result.StudyList.Sum(t => t.SeriesList.Sum(s => s.InstanceList.Sum(i => i.FileSize))) + result.NoneDicomStudyList.Sum(t => t.FileList.Sum(s => s.FileSize))
?? 0
};
await _trialImageDownloadRepository.AddAsync(preDownloadInfo, true);
return ResponseOutput.Ok(result, preDownloadInfo.Id);
}
/// <summary>
/// IR 阅片页面 和IR 任务列表页面下载 勾选下载列表(后端要考虑到一致性分析 subjectCode的问题
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<SubjectCRCImageUploadedStudyDto>> GetSubjectImageDownloadSelectList(IRReadingDownloadQuery inQuery)
{
var doctorUserId = _userInfo.UserRoleId;
var isAnalysisCreate = false;
//要根据标准阅片顺序,确定是否查询单个任务的,还是查询所有的
var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == inQuery.TrialReadingCriterionId)
.Select(t => new { t.IsReadingTaskViewInOrder }).FirstNotNullAsync();
var subjectCode = string.Empty;
var subjectId = inQuery.SubjectId;
if (criterionInfo.IsReadingTaskViewInOrder == ReadingOrder.Random)
{
if (inQuery.VisitTaskId == null)
{
throw new Exception("无序阅片,前端参数传递错误");
}
}
else
{
if (inQuery.SubjectId == null || inQuery.SubjectCode == null)
{
throw new Exception("有序阅片,前端参数传递错误");
}
//考虑到一致性分析,必须要这个编号进行过滤
subjectCode = inQuery.SubjectCode;
}
if (inQuery.VisitTaskId != null)
{
//考虑到一致性分析,必须要这个编号进行过滤
//医学审核查看下载按钮,这个时候需要知道医生
var taskInfo = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId).Select(t => new
{
SubjectCode = t.IsAnalysisCreate ? t.BlindSubjectCode : t.Subject.Code,
SubjectId = t.SubjectId,
t.DoctorUserId,
t.IsAnalysisCreate
}).FirstNotNullAsync();
subjectId = taskInfo.SubjectId;
subjectCode = taskInfo.SubjectCode;
doctorUserId = (Guid)taskInfo.DoctorUserId!;
isAnalysisCreate = taskInfo.IsAnalysisCreate;
}
var query = _visitTaskRepository.Where(t => t.SubjectId == subjectId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId
&& t.SourceSubjectVisitId != null && t.DoctorUserId == doctorUserId && t.TaskState == TaskState.Effect)
//满足 有序或者随机只看到当前任务的dicom 非dicom检查
.WhereIf(criterionInfo.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom && inQuery.VisitTaskId != null, t => t.Id == inQuery.VisitTaskId)
.ProjectTo<SubjectCRCImageUploadedDto>(_mapper.ConfigurationProvider);
//这里过滤是否是一致性分析的
var list = await query.Where(t => t.SubjectCode == subjectCode).ToListAsync();
foreach (var item in list)
{
if (item.IsImageFilter)
{
item.DicomStudyList = item.DicomStudyList.Where(t => ("|" + item.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|")).ToList();
item.NoneDicomStudyList = item.NoneDicomStudyList.Where(t => ("|" + item.CriterionModalitys + "|").Contains("|" + t.Modality + "|")).ToList();
}
}
#region 将任务级别转为检查级别
var result = new List<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 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 }).FirstNotNullAsync();
var isQueryDicom = inQuery.DicomStudyIdList.Count > 0;
var isQueryNoneDicom = inQuery.NoneDicomStudyIdList.Count > 0;
var imageType = (isQueryDicom && isQueryNoneDicom) ? ImageType.DicomAndNoneDicom : (isQueryDicom ? ImageType.Dicom : ImageType.NoneDicom);
var taskIdList = inQuery.SubjectVisitTaskList.Select(t => t.TaskId).ToList();
var subjectVisitIdList = inQuery.SubjectVisitTaskList.Select(t => t.SubjectVisitId).ToList();
var trialSiteCode = _visitTaskRepository.Where(t => t.Id == taskIdList.FirstOrDefault()).Select(t => t.IsAnalysisCreate ? t.BlindTrialSiteCode : t.Subject.TrialSite.TrialSiteCode).FirstOrDefault()??string.Empty;
var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubjectId).SelectMany(t => t.SubjectVisitList.Where(t => subjectVisitIdList.Contains(t.Id)))
//一致性分析,导致查询出来两条数据
join visitTask in _visitTaskRepository.Where(t => taskIdList.Contains(t.Id))
on sv.Id equals visitTask.SourceSubjectVisitId
select new
{
SubjectCode = inQuery.SubjectCode,
VisitName = sv.VisitName,
TaskBlindName = visitTask.TaskBlindName,
StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
.Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
.Select(u => new
{
u.PatientId,
u.StudyTime,
u.StudyCode,
SeriesList = u.SeriesList.Select(z => new
{
z.Modality,
InstancePathList = z.DicomInstanceList.Select(k => new
{
k.Path,
k.FileSize
})
})
}),
NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)
.Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|") : true)
.Select(nd => new
{
nd.Modality,
nd.StudyCode,
nd.ImageDate,
FileList = nd.NoneDicomFileList.Select(file => new
{
file.FileName,
file.Path,
file.FileType,
file.FileSize
})
})
};
var result = await query.ToListAsync();
var preDownloadInfo = new TrialImageDownload()
{
Id = NewId.NextSequentialGuid(),
TrialId = info.TrialId,
SubjectId=inQuery.SubjectId,
SubjectCode = inQuery.SubjectCode,
TrialSiteCode= trialSiteCode,
IP = _userInfo.IP,
DownloadStartTime = DateTime.Now,
IsSuccess = false,
ImageType = imageType,
VisitName = string.Join(" | ", result.Select(t => t.VisitName).OrderBy(t => t).ToList()),
NoneDicomStudyCount = result.Sum(t => t.NoneDicomStudyList.Count()),
DicomStudyCount = result.Sum(t => t.StudyList.Count()),
ImageCount = result.Sum(t => t.StudyList.Sum(s => s.SeriesList.Sum(s => s.InstancePathList.Count())) + t.NoneDicomStudyList.Sum(s => s.FileList.Count())),
ImageSize = result.Sum(t => t.StudyList.Sum(t => t.SeriesList.Sum(s => s.InstancePathList.Sum(i => i.FileSize))) + t.NoneDicomStudyList.Sum(t => t.FileList.Sum(s => s.FileSize))
) ?? 0
};
await _trialImageDownloadRepository.AddAsync(preDownloadInfo, true);
return ResponseOutput.Ok(result, new { PreDownloadId = preDownloadInfo.Id, info.IsReadingTaskViewInOrder });
}
/// <summary>
/// dicom 影像后处理预览接口
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetTaskUploadedDicomStudyList(IRTaskUploadedDicomStudyQuery inQuery)
{
var info = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId)
.Select(t => new { t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys }).FirstNotNullAsync();
var query = _taskStudyRepository.Where(t => t.VisitTaskId == inQuery.VisitTaskId)
.Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
.Select(t => new
{
StudyId = t.Id,
t.Modalities,
t.InstanceCount,
t.SeriesCount,
t.StudyCode,
SeriesList = t.SeriesList.OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).Select(u => new
{
u.SeriesTime,
u.InstanceCount,
u.ImageResizePath,
u.Modality,
u.Description,
u.SeriesInstanceUid,
u.SeriesNumber,
u.SliceThickness,
u.StudyInstanceUid,
IsExistMutiFrames = u.InstanceList.Any(t => t.NumberOfFrames > 1),
InstanceInfoList = u.InstanceList.OrderBy(t => t.InstanceNumber).Select(k =>
new InstanceBasicInfo()
{
Id = k.Id,
NumberOfFrames = k.NumberOfFrames,
HtmlPath = k.HtmlPath,
Path = k.Path,
InstanceNumber = k.InstanceNumber,
}).ToList()
})
});
var list = await query.ToListAsync();
return ResponseOutput.Ok(list);
}
/// <summary>
/// 影像下载成功回调
/// </summary>
/// <param name="trialImageDownloadId"></param>
/// <returns></returns>
public async Task<IResponseOutput> DownloadImageSuccess(Guid trialImageDownloadId)
{
await _trialImageDownloadRepository.UpdatePartialFromQueryAsync(t => t.Id == trialImageDownloadId, u => new TrialImageDownload()
{ DownloadEndTime = DateTime.Now, IsSuccess = true }, 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.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);
}
/// <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();
}
#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
}
}