809 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			809 lines
		
	
	
		
			37 KiB
		
	
	
	
		
			C#
		
	
	
| using DocumentFormat.OpenXml.EMMA;
 | ||
| using IRaCIS.Core.Application.Contracts;
 | ||
| using IRaCIS.Core.Application.Contracts.Dicom.DTO;
 | ||
| using IRaCIS.Core.Application.Filter;
 | ||
| using IRaCIS.Core.Application.Interfaces;
 | ||
| using IRaCIS.Core.Application.Service.Reading.Dto;
 | ||
| using IRaCIS.Core.Domain.Share;
 | ||
| using IRaCIS.Core.Infrastructure;
 | ||
| using Microsoft.AspNetCore.Authorization;
 | ||
| using Microsoft.AspNetCore.Mvc;
 | ||
| using Microsoft.Extensions.DependencyInjection;
 | ||
| 
 | ||
| namespace IRaCIS.Core.Application.Services
 | ||
| {
 | ||
|     [ApiExplorerSettings(GroupName = "Trial")]
 | ||
|     public class SubjectVisitService(IRepository<SubjectVisit> _subjectVisitRepository,
 | ||
|         IRepository<Trial> _trialRepository,
 | ||
|         IRepository<DicomStudy> _dicomStudyRepository,
 | ||
|         IRepository<NoneDicomStudy> _noneDicomStudyRepository,
 | ||
|         IRepository<VisitTask> _visitTaskRepository,
 | ||
|         IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
 | ||
|         //IRepository<ReadingCustomTag> _readingCustomTagRepository,
 | ||
|          IRepository<ReadingTaskQuestionMark> _readingTaskQuestionMark,
 | ||
|         IRepository<NoneDicomStudyFile> _noneDicomStudyFileRepository,
 | ||
|         IRepository<Subject> _subjectRepository,
 | ||
|         IRepository<DicomInstance> _dicomInstanceRepository,
 | ||
|         IRepository<TaskStudy> _taskStudyRepository,
 | ||
|         IServiceProvider _serviceProvider,
 | ||
|         IRepository<DicomSeries> _dicomSeriesRepository,
 | ||
|         IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ISubjectVisitService
 | ||
|     {
 | ||
| 
 | ||
| 
 | ||
|         [HttpPost]
 | ||
|         [TrialGlobalLimit("AfterStopCannNotOpt")]
 | ||
|         [UnitOfWork]
 | ||
|         //[Authorize(Policy = IRaCISPolicy.CRC)]
 | ||
|         public async Task<IResponseOutput<string>> AddOrUpdateSV(SubjectVisitCommand svCommand)
 | ||
|         {
 | ||
| 
 | ||
|             var verifyExp1 = new EntityVerifyExp<SubjectVisit>()
 | ||
|             {
 | ||
|                 VerifyExp = t => t.VisitNum == svCommand.VisitNum && t.SubjectId == svCommand.SubjectId,
 | ||
|                 //---该受试者的访视计划中已经包含一个具有相同访视号的访视。
 | ||
|                 VerifyMsg = _localizer["Visit_DuplicateVisitNo"]
 | ||
|             };
 | ||
| 
 | ||
|             var verifyExp2 = new EntityVerifyExp<SubjectVisit>()
 | ||
|             {
 | ||
|                 VerifyExp = t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit,
 | ||
|                 //---该受试者已经有访视设置为末次访视,不允许将当前访视设置为末次访视。
 | ||
|                 VerifyMsg = _localizer["Visit_LastVisitNoChange"],
 | ||
|                 IsVerify = svCommand.IsFinalVisit
 | ||
|             };
 | ||
| 
 | ||
|             var verifyExp3 = new EntityVerifyExp<SubjectVisit>()
 | ||
|             {
 | ||
|                 VerifyExp = t => t.SubjectId == svCommand.SubjectId && t.VisitName == svCommand.VisitName,
 | ||
|                 //---该受试者的访视计划中已经包含一个具有相同访视名称的访视。
 | ||
|                 VerifyMsg = _localizer["Visit_DuplicateVisitName"]
 | ||
| 
 | ||
|             };
 | ||
| 
 | ||
|             svCommand.BlindName = "B" + ((int)(svCommand.VisitNum * 10)).ToString("D3");
 | ||
|             svCommand.VisitExecuted = svCommand.IsLostVisit ? VisitExecutedEnum.Executed : svCommand.VisitExecuted;
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             SubjectVisit? dbBeforeEntity = null;
 | ||
|             //Add
 | ||
|             if (svCommand.Id == null)
 | ||
|             {
 | ||
| 
 | ||
|                 //设置末次评估后,不允许添加计划外访视
 | ||
|                 if (svCommand.InPlan == false)
 | ||
|                 {
 | ||
|                     if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit))
 | ||
|                     {
 | ||
|                         //---设置末次评估后,不允许添加计划外访视。
 | ||
|                         throw new BusinessValidationFailedException(_localizer["Visit_NoExtraVisitAfterLast"]);
 | ||
|                     }
 | ||
| 
 | ||
|                     if (await _visitTaskRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.TaskState == TaskState.Effect && t.VisitTaskNum > svCommand.VisitNum && t.SignTime != null && t.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.InOrder))
 | ||
|                     {
 | ||
|                         //---该受试者后续访视已有任务完成阅片(有序阅片标准),不允许在此添加,如果确实需要,请回退
 | ||
|                         throw new BusinessValidationFailedException(_localizer["Visit_FinishedTasksNoAdd"]);
 | ||
|                     }
 | ||
| 
 | ||
|                 }
 | ||
| 
 | ||
|                 dbBeforeEntity = await _subjectVisitRepository.InsertFromDTOAsync(svCommand, false, verifyExp1, verifyExp2, verifyExp3);
 | ||
| 
 | ||
|                 //var cRCClinicalDataIds = await _clinicalDataTrialSetRepository.Where(x => x.TrialId == svCommand.TrialId && x.UploadRole == UploadRole.CRC && x.IsConfirm && x.ClinicalDataLevel == ClinicalLevel.SubjectVisit)
 | ||
| 
 | ||
|                 //.Select(x => x.Id).ToListAsync();
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|                 //List<ReadingClinicalData> readingClinicals = cRCClinicalDataIds.Select(x => new ReadingClinicalData()
 | ||
|                 //{
 | ||
|                 //    ClinicalDataTrialSetId = x,
 | ||
|                 //    IsVisit = true,
 | ||
|                 //    SubjectId = svCommand.SubjectId,
 | ||
|                 //    ReadingId = dbBeforeEntity.Id,
 | ||
|                 //    TrialId = svCommand.TrialId
 | ||
|                 //}).ToList();
 | ||
| 
 | ||
|                 //await _readingClinicalDataRepository.AddRangeAsync(readingClinicals);
 | ||
|             }
 | ||
| 
 | ||
|             else
 | ||
|             {
 | ||
|                 dbBeforeEntity = await _subjectVisitRepository.UpdateFromDTOAsync(svCommand, false, false, verifyExp1, verifyExp2, verifyExp3);
 | ||
| 
 | ||
| 
 | ||
|                 if (svCommand.PDState != dbBeforeEntity.PDState && dbBeforeEntity.SubmitState == SubmitStateEnum.Submitted)
 | ||
|                 {
 | ||
|                     //---当前访视影像提交后,不允许修改PD确认状态。
 | ||
|                     throw new BusinessValidationFailedException(_localizer["Visit_NoPDStatusChangeAfterSubmission"]);
 | ||
|                 }
 | ||
| 
 | ||
|                 if (svCommand.PDState != dbBeforeEntity.PDState && dbBeforeEntity.RequestBackState == RequestBackStateEnum.PM_AgressBack)
 | ||
|                 {
 | ||
|                     //---当前访视影像提交后,不允许修改PD确认状态。
 | ||
|                     throw new BusinessValidationFailedException(_localizer["Visit_NoPDStatusChangeAfterSubmission"]);
 | ||
|                 }
 | ||
| 
 | ||
|                 if (svCommand.IsLostVisit)
 | ||
|                 {
 | ||
|                     if (await _subjectVisitRepository.AnyAsync(t => t.Id == svCommand.Id && t.SubmitState == SubmitStateEnum.ToSubmit))
 | ||
|                     {
 | ||
|                         //---当前访视已经有影像上传,不允许设置为失访。
 | ||
|                         throw new BusinessValidationFailedException(_localizer["Visit_UploadedNoLost"]);
 | ||
|                     }
 | ||
|                 }
 | ||
| 
 | ||
|                 dbBeforeEntity = await _subjectVisitRepository.UpdateFromDTOAsync(svCommand, true, false, verifyExp1, verifyExp2, verifyExp3);
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             //更新受试者 访视基准日期 是否入组确认
 | ||
|             if (svCommand.SubjectFirstGiveMedicineTime != null && svCommand.IsBaseLine)
 | ||
|             {
 | ||
| 
 | ||
|                 await _subjectRepository.UpdatePartialFromQueryAsync(svCommand.SubjectId, t => new Subject()
 | ||
|                 {
 | ||
|                     FirstGiveMedicineTime = svCommand.SubjectFirstGiveMedicineTime
 | ||
|                 });
 | ||
| 
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             await _subjectVisitRepository.SaveChangesAsync();
 | ||
| 
 | ||
|             return ResponseOutput.Ok(dbBeforeEntity.Id.ToString());
 | ||
| 
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{isUrgent:bool}")]
 | ||
|         [TrialGlobalLimit("AfterStopCannNotOpt")]
 | ||
|         //[Authorize(Policy = IRaCISPolicy.PM_IQC)]
 | ||
|         public async Task<IResponseOutput> SetSubjectVisitUrgent(Guid subjectVisitId, bool isUrgent)
 | ||
|         {
 | ||
|             await _subjectVisitRepository.UpdatePartialFromQueryAsync(subjectVisitId, u => new SubjectVisit() { IsUrgent = isUrgent }, true);
 | ||
| 
 | ||
|             return ResponseOutput.Ok();
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         [HttpDelete, Route("{trialId:guid}/{id:guid}")]
 | ||
|         [TrialGlobalLimit("AfterStopCannNotOpt")]
 | ||
|         //[Authorize(Policy = IRaCISPolicy.CRC)]
 | ||
|         public async Task<IResponseOutput> DeleteSV(Guid id)
 | ||
|         {
 | ||
|             if (await _dicomStudyRepository.AnyAsync(t => t.SubjectVisitId == id))
 | ||
|             {
 | ||
|                 //---当前访视已经有影像上传,不允许删除。
 | ||
|                 return ResponseOutput.NotOk(_localizer["Visit_UploadedNoDelete"]);
 | ||
|             }
 | ||
|             if (await _subjectVisitRepository.AnyAsync(t => t.Id == id && t.InPlan))
 | ||
|             {
 | ||
|                 //---计划内的访视不允许删除。
 | ||
|                 return ResponseOutput.NotOk(_localizer["Visit_PlanVisitNoDelete"]);
 | ||
|             }
 | ||
|             if (await _subjectVisitRepository.AnyAsync(t => t.OutPlanPreviousVisitId == id))
 | ||
|             {
 | ||
|                 //---当前访视已经被设置为另一访视的上一访视,不允许删除。
 | ||
|                 return ResponseOutput.NotOk(_localizer["Visit_PreviousVisitNoDelete"]);
 | ||
|             }
 | ||
| 
 | ||
|             await _subjectVisitRepository.DeleteFromQueryAsync(s => s.Id == id, true);
 | ||
| 
 | ||
|             return ResponseOutput.Ok();
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取访视下的Dicom 检查信息   分所有的, 阅片的 不阅片   isReading : 0 查询所有 1 查询仅仅阅片的
 | ||
|         /// </summary>
 | ||
|         /// <param name="trialId"></param>
 | ||
|         /// <param name="sujectVisitId"></param>
 | ||
|         /// <param name="isReading"></param>
 | ||
|         /// <param name="visitTaskId"></param>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpGet, Route("{trialId:guid}/{sujectVisitId:guid}/{isReading}")]
 | ||
|         [AllowAnonymous]
 | ||
|         public async Task<List<VisitStudyDTO>> GetVisitStudyList(Guid trialId, Guid sujectVisitId, int isReading, [FromQuery] Guid? visitTaskId)
 | ||
|         {
 | ||
| 
 | ||
|             var qcAuditState = await _subjectVisitRepository.Where(s => s.Id == sujectVisitId).Select(t => t.AuditState).FirstOrDefaultAsync();
 | ||
| 
 | ||
|             //质控通过以后,过滤删除的   质控之前的不过滤
 | ||
|             var isQCFinished = qcAuditState == AuditStateEnum.QCPassed;
 | ||
| 
 | ||
| 
 | ||
|             var isImageFilter = false;
 | ||
|             var criterionModalitys = "";
 | ||
|             if (visitTaskId != null)
 | ||
|             {
 | ||
|                 var info = await _visitTaskRepository.Where(t => t.Id == visitTaskId)
 | ||
|                     .Select(t => new { t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys }).FirstNotNullAsync();
 | ||
|                 isImageFilter = info.IsImageFilter;
 | ||
|                 criterionModalitys = info.CriterionModalitys;
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             var studyList = await _dicomStudyRepository.Where(t => t.TrialId == trialId && t.SubjectVisitId == sujectVisitId).IgnoreQueryFilters()
 | ||
|             .Where(t => isImageFilter ? ("|" + criterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
 | ||
|             .WhereIf(isReading == 1 || isQCFinished, s => s.IsDeleted == false)
 | ||
|                 .Select(k => new VisitStudyDTO()
 | ||
|                 {
 | ||
|                     InstanceCount = k.InstanceCount,
 | ||
|                     Modalities = k.Modalities,
 | ||
|                     //SeriesCount = k.SeriesCount,
 | ||
|                     StudyCode = k.StudyCode,
 | ||
|                     StudyId = k.Id
 | ||
|                 }).ToListAsync();
 | ||
| 
 | ||
|             var studyIds = studyList.Select(t => t.StudyId).ToList();
 | ||
| 
 | ||
|             var instanceList = await _dicomInstanceRepository.Where(t => studyIds.Contains(t.StudyId)).IgnoreQueryFilters()
 | ||
|                    .WhereIf(isReading == 1, s => s.IsReading && s.IsDeleted == false)
 | ||
|                    .WhereIf(isQCFinished, t => t.IsDeleted == false)
 | ||
|                    .Select(t => new { t.SeriesId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.HtmlPath, t.IsReading, t.IsDeleted, t.FileSize }).ToListAsync();
 | ||
| 
 | ||
|             foreach (var t in studyList)
 | ||
|             {
 | ||
|                 t.SeriesList = await _dicomSeriesRepository.Where(s => s.StudyId == t.StudyId).IgnoreQueryFilters()
 | ||
|                .WhereIf(isReading == 1, s => s.IsReading && s.IsDeleted == false)
 | ||
|                 .WhereIf(isQCFinished, t => t.IsDeleted == false)
 | ||
|                .OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime)
 | ||
|                .ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
 | ||
| 
 | ||
| 
 | ||
|                 t.SeriesList.ForEach(series =>
 | ||
|                 {
 | ||
| 
 | ||
|                     series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k =>
 | ||
|                     new InstanceBasicInfo()
 | ||
|                     {
 | ||
|                         Id = k.Id,
 | ||
|                         NumberOfFrames = k.NumberOfFrames,
 | ||
|                         HtmlPath = k.HtmlPath,
 | ||
|                         Path = k.Path,
 | ||
|                         InstanceNumber = k.InstanceNumber,
 | ||
|                         IsReading = k.IsReading,
 | ||
|                         IsDeleted = k.IsDeleted,
 | ||
|                         FileSize = k.FileSize,
 | ||
|                     }).ToList();
 | ||
| 
 | ||
|                     series.InstanceCount = series.InstanceInfoList.Count();
 | ||
|                 }
 | ||
|                 );
 | ||
| 
 | ||
|                 //设置为阅片与否 不更改数据库检查  的instance数量 和 SeriesCount  所以这里要实时统计
 | ||
|                 //t.SeriesCount = t.SeriesList.Count;
 | ||
|                 t.InstanceCount = t.SeriesList.SelectMany(t => t.InstanceInfoList).Count();
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             return studyList.Where(x=>x.SeriesList.Count()>0).ToList();
 | ||
| 
 | ||
|             //return ResponseOutput.Ok(studyList.Where(t => t.SeriesList.Count > 0).ToList());
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取Series信息
 | ||
|         /// </summary>
 | ||
|         /// <param name="inDto"></param>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpPost]
 | ||
|         public async Task<DicomSeriesDTO> GetDicomSeriesInfo(GetDicomSeriesInfoInDto inDto)
 | ||
|         {
 | ||
|             DicomSeriesDTO series = await _dicomSeriesRepository.Where(s => s.Id == inDto.SeriesId).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).FirstNotNullAsync();
 | ||
| 
 | ||
|             var instanceList = await _dicomInstanceRepository.Where(t => t.SeriesId == inDto.SeriesId)
 | ||
|                .Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.SliceLocation, t.FileSize }).ToListAsync();
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).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();
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             //series.WindowWidth = instanceList.FirstOrDefault()!.WindowWidth;
 | ||
|             //series.WindowCenter = instanceList.FirstOrDefault()!.WindowCenter;
 | ||
| 
 | ||
|             return series;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取PTAndCtSeries
 | ||
|         /// </summary>
 | ||
|         /// <param name="inDto"></param>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpPost]
 | ||
|         public async Task<List<GetPTAndCtSeriesOutDto>> GetPTAndCtSeries(GetPTAndCtSeriesInDto inDto)
 | ||
|         {
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             var pastResultList = await _serviceProvider.GetService<IReadingImageTaskService>().GetReadingPastResultList(new GetReadingPastResultListInDto()
 | ||
|             {
 | ||
|                 VisitTaskId = inDto.VisitTaskId
 | ||
|             });
 | ||
| 
 | ||
|             var visitTaskIds = pastResultList.Select(x => x.VisitTaskId).ToList();
 | ||
|             var visitSeriesList = await _readingTableAnswerRowInfoRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId))
 | ||
|                    .Where(x => x.PTSeriesId != null && x.CTSeriesId != null)
 | ||
|                    .Select(x => new
 | ||
|                    {
 | ||
|                        x.PTSeriesId,
 | ||
|                        x.CTSeriesId,
 | ||
|                        x.VisitTaskId,
 | ||
|                        x.OtherStudyId,
 | ||
|                        x.VisitTask.SourceSubjectVisitId,
 | ||
|                        x.VisitTask.SourceSubjectVisit.IsBaseLine,
 | ||
|                        x.VisitTask.VisitTaskNum,
 | ||
|                        x.VisitTask.TaskBlindName,
 | ||
|                        x.UpdateTime,
 | ||
|                    }).ToListAsync();
 | ||
| 
 | ||
|             List<GetPTAndCtSeriesOutDto> result = new List<GetPTAndCtSeriesOutDto>();
 | ||
| 
 | ||
|             List<Guid> ctseriesIds = visitSeriesList.Select(x => x.CTSeriesId.Value).ToList();
 | ||
| 
 | ||
|             List<Guid> ptseriesIds = visitSeriesList.Select(x => x.PTSeriesId.Value).ToList();
 | ||
|             foreach (var item in visitTaskIds)
 | ||
|             {
 | ||
|                 var visitSeries = visitSeriesList.Where(x => x.VisitTaskId == item).OrderByDescending(x => x.UpdateTime).FirstOrDefault();
 | ||
|                 if (visitSeries != null)
 | ||
|                 {
 | ||
|                     result.Add(new GetPTAndCtSeriesOutDto()
 | ||
|                     {
 | ||
|                         PTSeriesId = visitSeries.PTSeriesId!.Value,
 | ||
|                         CTSeriesId = visitSeries.CTSeriesId!.Value,
 | ||
|                         TaskBlindName = visitSeries.TaskBlindName,
 | ||
|                         VisitTaskId = item,
 | ||
|                         SubjectVisitId = visitSeries.SourceSubjectVisitId!.Value,
 | ||
|                         IsBaseLineTask = visitSeries.IsBaseLine,
 | ||
|                     });
 | ||
| 
 | ||
| 
 | ||
|                 }
 | ||
| 
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             List<DicomSeriesDTO> ctseriesLists = await _dicomSeriesRepository.Where(s => ctseriesIds.Contains(s.Id)).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
 | ||
|             List<DicomSeriesDTO> ptseriesLists = await _dicomSeriesRepository.Where(s => ptseriesIds.Contains(s.Id)).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
 | ||
| 
 | ||
|             var seriesIds = ctseriesIds.Union(ptseriesIds).ToList();  //并集
 | ||
| 
 | ||
|             var instanceList = await _dicomInstanceRepository.Where(t => seriesIds.Contains(t.SeriesId))
 | ||
|               .Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.FileSize }).ToListAsync();
 | ||
| 
 | ||
|             var studyIds = instanceList.Select(x => x.StudyId).Distinct().ToList();
 | ||
| 
 | ||
|             var studyList = await _dicomStudyRepository.Where(t => studyIds.Contains(t.Id))
 | ||
|             .Select(k => new StudyInfo()
 | ||
|             {
 | ||
|                 InstanceCount = k.InstanceCount,
 | ||
|                 Modalities = k.Modalities,
 | ||
|                 SeriesCount = k.SeriesCount,
 | ||
|                 StudyCode = k.StudyCode,
 | ||
|                 StudyId = k.Id,
 | ||
|                 SubjectVisitId = k.SubjectVisitId,
 | ||
|             }).ToListAsync();
 | ||
|             AddinstanceList(ctseriesLists);
 | ||
|             AddinstanceList(ptseriesLists);
 | ||
| 
 | ||
|             void AddinstanceList(List<DicomSeriesDTO> list)
 | ||
|             {
 | ||
|                 list.ForEach(series =>
 | ||
|                 {
 | ||
| 
 | ||
| 
 | ||
|                     series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).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();
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|                     //series.WindowWidth = instanceList.FirstOrDefault()!.WindowWidth;
 | ||
|                     //series.WindowCenter = instanceList.FirstOrDefault()!.WindowCenter;
 | ||
|                 });
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             foreach (var item in result)
 | ||
|             {
 | ||
| 
 | ||
|                 item.StudyId = ptseriesLists.Where(x => x.Id == item.PTSeriesId).Select(x => x.StudyId).FirstOrDefault();
 | ||
| 
 | ||
|                 item.StudyInfoList = studyList.Where(x => x.SubjectVisitId == item.SubjectVisitId).ToList();
 | ||
| 
 | ||
|                 foreach (var study in item.StudyInfoList)
 | ||
|                 {
 | ||
|                     study.PTSeriesList = ptseriesLists.Where(x => x.SubjectVisitId == item.SubjectVisitId).ToList();
 | ||
|                     study.CTSeriesList = ctseriesLists.Where(x => x.SubjectVisitId == item.SubjectVisitId).ToList();
 | ||
|                 }
 | ||
| 
 | ||
|             }
 | ||
| 
 | ||
|             return result;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取访视下的Dicom 检查信息   分所有的, 阅片的 不阅片   isReading : 0 查询所有 1 查询仅仅阅片的
 | ||
|         /// </summary>
 | ||
|         /// <param name="indto"></param>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpPost]
 | ||
|         public async Task<List<VisitStudyDTO>> GetReadingVisitStudyList(GetReadingVisitStudyListIndto indto)
 | ||
|         {
 | ||
| 
 | ||
|             var studyList = new List<VisitStudyDTO>();
 | ||
| 
 | ||
|             var taskInfo = await _visitTaskRepository.Where(x => x.Id == indto.VisitTaskId).Select(t => new { t.TrialReadingCriterionId, t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys, t.ReadingTaskState, TaskStudyCount = t.TaskStudyList.Count }).FirstNotNullAsync();
 | ||
| 
 | ||
|             //影像后处理  上传了新的影像
 | ||
|             if (taskInfo.TaskStudyCount > 0)
 | ||
|             {
 | ||
| 
 | ||
|                 var taskStudyList = await _taskStudyRepository.Where(t => t.TrialId == indto.TrialId && t.VisitTaskId == indto.VisitTaskId)
 | ||
|                     .WhereIf(taskInfo.IsImageFilter == true, t => ("|" + taskInfo.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|"))
 | ||
|                     .ProjectTo<VisitStudyDTO>(_mapper.ConfigurationProvider).ToListAsync();
 | ||
| 
 | ||
|                 foreach (var study in taskStudyList)
 | ||
|                 {
 | ||
|                     study.SeriesList = study.SeriesList.OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ToList();
 | ||
| 
 | ||
|                     //foreach (var series in study.SeriesList)
 | ||
|                     //{
 | ||
|                     //    series.WindowCenter = series.InstanceInfoList.FirstOrDefault()!.WindowCenter;
 | ||
|                     //    series.WindowWidth = series.InstanceInfoList.FirstOrDefault()!.WindowWidth;
 | ||
|                     //}
 | ||
|                     //study.SeriesCount = study.SeriesList.Count;
 | ||
| 
 | ||
|                     study.InstanceCount = study.SeriesList.SelectMany(t => t.InstanceInfoList).Count();
 | ||
|                 }
 | ||
| 
 | ||
|                 studyList.AddRange(taskStudyList);
 | ||
| 
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 #region dicom 检查查询
 | ||
| 
 | ||
|                 //如果是手动生成的标准,需要过滤检查和序列数据
 | ||
| 
 | ||
|                 var isManualGenerate = await _trialReadingCriterionRepository.AnyAsync(t => t.Id == taskInfo.TrialReadingCriterionId && t.IsAutoCreate == false);
 | ||
| 
 | ||
|                 var dicomStudyList = await _dicomStudyRepository.Where(t => t.TrialId == indto.TrialId && t.SubjectVisitId == indto.SujectVisitId)
 | ||
|                     .WhereIf(taskInfo.IsImageFilter == true, t => ("|" + taskInfo.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|"))
 | ||
|                     .WhereIf(isManualGenerate, t => t.SubjectCriteriaEvaluationVisitStudyFilterList.Any(t => t.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && t.IsConfirmed && t.IsReading))
 | ||
|                     .Select(k => new VisitStudyDTO()
 | ||
|                     {
 | ||
|                         InstanceCount = k.InstanceCount,
 | ||
|                         StudyName = k.StudyName,
 | ||
|                         Modalities = k.Modalities,
 | ||
|                         //SeriesCount = k.SeriesCount,
 | ||
|                         StudyCode = k.StudyCode,
 | ||
|                         StudyId = k.Id,
 | ||
| 
 | ||
|                         BodyPartForEdit=k.BodyPartForEdit,
 | ||
|                         BodyPartForEditOther=k.BodyPartForEditOther
 | ||
| 
 | ||
| 
 | ||
|                     }).ToListAsync();
 | ||
|                 var studyIds = dicomStudyList.Select(t => t.StudyId).ToList();
 | ||
| 
 | ||
|                 var instanceList = await _dicomInstanceRepository.Where(t => studyIds.Contains(t.StudyId) && t.IsReading)
 | ||
|                        .Select(t => new { t.SeriesId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.IsReading, t.FileSize }).ToListAsync();
 | ||
| 
 | ||
|                 List<DicomSeriesDTO> seriesLists = await _dicomSeriesRepository.Where(s => studyIds.Contains(s.StudyId))
 | ||
|                      .WhereIf(isManualGenerate == false, t => t.IsReading)
 | ||
|                      .WhereIf(isManualGenerate, t => t.SubjectCriteriaEvaluationVisitStudyFilterList.Any(t => t.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && t.IsConfirmed && t.IsReading))
 | ||
|                     .OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
 | ||
| 
 | ||
|                 foreach (var t in dicomStudyList)
 | ||
|                 {
 | ||
|                     t.SeriesList = seriesLists.Where(s => s.StudyId == t.StudyId).OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ToList();
 | ||
| 
 | ||
|                     t.SeriesList.ForEach(series =>
 | ||
|                     {
 | ||
|                         series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).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();
 | ||
| 
 | ||
|                         // 设置阅片 不阅片,数字要要重新统计
 | ||
|                         series.InstanceCount = series.InstanceInfoList.Count;
 | ||
| 
 | ||
|                         //series.WindowWidth = instanceList.FirstOrDefault()!.WindowWidth;
 | ||
|                         //series.WindowCenter = instanceList.FirstOrDefault()!.WindowCenter;
 | ||
|                     });
 | ||
| 
 | ||
|                     //设置为阅片与否 不更改数据库检查  的instance数量 和 SeriesCount  所以这里要实时统计
 | ||
|                     //t.SeriesCount = t.SeriesList.Count;
 | ||
|                     t.InstanceCount = t.SeriesList.SelectMany(t => t.InstanceInfoList).Count();
 | ||
|                 }
 | ||
| 
 | ||
|                 studyList.AddRange(dicomStudyList);
 | ||
| 
 | ||
|                 #endregion
 | ||
| 
 | ||
|                 #region dicom 关键序列处理       
 | ||
| 
 | ||
|                 //已经签名的任务,加关键序列
 | ||
|                 if (taskInfo.ReadingTaskState == ReadingTaskState.HaveSigned)
 | ||
|                 {
 | ||
|                     var rowInfoList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == indto.VisitTaskId && x.StudyId != null).OrderBy(x => x.ReadingQuestionTrial.ShowOrder).ThenBy(x => x.RowIndex).Select(x => new StudyInstanceInfo()
 | ||
|                     {
 | ||
|                         ShowOrder = x.ReadingQuestionTrial.ShowOrder,
 | ||
|                         RowIndex = x.RowIndex,
 | ||
|                         SeriesId = x.SeriesId,
 | ||
|                         StudyId = x.StudyId,
 | ||
|                         InstanceId = x.InstanceId,
 | ||
|                         NumberOfFrames = x.NumberOfFrames,
 | ||
|                         CreateTime=x.CreateTime,
 | ||
|                       
 | ||
|                     }).ToListAsync();
 | ||
| 
 | ||
| 
 | ||
|                     // 这个表的数据已经移动到 _readingTaskQuestionMark 了
 | ||
|                     //var customoList = await _readingCustomTagRepository.Where(x => x.VisitTaskId == indto.VisitTaskId && x.StudyId != null).Select(x => new StudyInstanceInfo()
 | ||
|                     //{
 | ||
|                     //    ShowOrder = 0,
 | ||
|                     //    RowIndex = 0m,
 | ||
|                     //    SeriesId = x.SeriesId,
 | ||
|                     //    StudyId = x.StudyId,
 | ||
|                     //    InstanceId = x.InstanceId,
 | ||
|                     //    NumberOfFrames = x.NumberOfFrames,
 | ||
|                     //    CreateTime = x.CreateTime,
 | ||
|                     //}).ToListAsync();
 | ||
|                     //rowInfoList.AddRange(customoList);
 | ||
| 
 | ||
|                     var questionMarkList = await _readingTaskQuestionMark.Where(x => x.VisitTaskId == indto.VisitTaskId && x.StudyId != null).Select(x => new StudyInstanceInfo()
 | ||
|                     {
 | ||
|                         ShowOrder = x.ReadingQuestionTrial==null?0: x.ReadingQuestionTrial.ShowOrder,
 | ||
|                         RowIndex = 0m,
 | ||
|                         SeriesId = x.SeriesId,
 | ||
|                         StudyId = x.StudyId,
 | ||
|                         InstanceId = x.InstanceId,
 | ||
|                         NumberOfFrames = x.NumberOfFrames,
 | ||
|                         CreateTime = x.CreateTime,
 | ||
|                     }).ToListAsync();
 | ||
|                     rowInfoList.AddRange(questionMarkList);
 | ||
| 
 | ||
|                     var thisStudyIds = rowInfoList.OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).Select(x => x.StudyId).Distinct().ToList();
 | ||
|                     var thisSeriesIdIds = rowInfoList.Where(x => x.SeriesId != null).OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).Select(x => x.SeriesId).Distinct().ToList();
 | ||
|                     if (rowInfoList.Count > 0)
 | ||
|                     {
 | ||
|                         var thisVisitTaskStudy = await _dicomStudyRepository.Where(t => thisStudyIds.Contains(t.Id)).Select(k => new VisitStudyDTO()
 | ||
|                         {
 | ||
|                             InstanceCount = k.InstanceCount,
 | ||
| 
 | ||
|                             //SeriesCount = k.SeriesCount,
 | ||
| 
 | ||
|                             StudyId = k.Id,
 | ||
|                             IsCriticalSequence = true,
 | ||
| 
 | ||
|                         }).FirstOrDefaultAsync();
 | ||
| 
 | ||
|                         if (thisVisitTaskStudy != null)
 | ||
|                         {
 | ||
|                             thisVisitTaskStudy.StudyId = default(Guid);
 | ||
|                             var item = await _dicomSeriesRepository.Where(s => thisSeriesIdIds.Contains(s.Id)).OrderBy(s => s.SeriesNumber).
 | ||
|                                 ThenBy(s => s.SeriesTime)
 | ||
|                                 .ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
 | ||
| 
 | ||
|                             if (item != null)
 | ||
|                             {
 | ||
|                                 item.SeriesInstanceUid = string.Empty;
 | ||
| 
 | ||
|                                 var markInstanceIdList = rowInfoList.Where(y => y.InstanceId != null).OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).Select(y => y.InstanceId!.Value).Distinct().ToList();
 | ||
| 
 | ||
|                                 item.InstanceInfoList = await _dicomInstanceRepository.Where(t => markInstanceIdList.Contains(t.Id)).OrderBy(s => s.DicomSerie.SeriesNumber).ThenBy(s => s.DicomSerie.SeriesTime).ThenBy(x => x.InstanceTime).Select(k =>
 | ||
|                                   new InstanceBasicInfo()
 | ||
|                                   {
 | ||
|                                       Id = k.Id,
 | ||
|                                       NumberOfFrames = k.NumberOfFrames,
 | ||
|                                       HtmlPath = k.HtmlPath,
 | ||
|                                       Path = k.Path,
 | ||
|                                       InstanceNumber = k.InstanceNumber,
 | ||
|                                       StudyId = k.StudyId,
 | ||
|                                       SeriesId = k.SeriesId,
 | ||
|                                       FileSize = k.FileSize
 | ||
|                                   }).ToListAsync();
 | ||
| 
 | ||
|                                 item.InstanceInfoList.ForEach(x =>
 | ||
|                                 {
 | ||
|                                     x.RowDate = rowInfoList.FirstOrDefault(y => y.InstanceId == x.Id)?.CreateTime ?? DateTime.Now;
 | ||
|                                     var keyFramesList = rowInfoList.Where(y => y.InstanceId == x.Id && y.NumberOfFrames != 0 && y.NumberOfFrames != null).Select(y => y.NumberOfFrames).Distinct().ToList();
 | ||
| 
 | ||
|                                     if (keyFramesList.Count() > 0)
 | ||
|                                     {
 | ||
|                                         x.KeyFramesList = keyFramesList;
 | ||
|                                     }
 | ||
| 
 | ||
|                                     var item = rowInfoList.FirstOrDefault(y => y.InstanceId == x.Id);
 | ||
|                                     if (item != null)
 | ||
|                                     {
 | ||
|                                         x.ShowOrder = item.ShowOrder;
 | ||
|                                         x.RowIndex = item.RowIndex;
 | ||
|                                     }
 | ||
| 
 | ||
|                                 });
 | ||
| 
 | ||
|                                 item.InstanceInfoList = item.InstanceInfoList.OrderBy(x => x.ShowOrder).ThenBy(x=>x.RowIndex).ThenBy(x=>x.RowDate).ToList();
 | ||
| 
 | ||
| 
 | ||
|                                 item.InstanceCount = item.InstanceInfoList.Count;
 | ||
| 
 | ||
|                                 item.Description = "Key Series";
 | ||
| 
 | ||
|                                 var modalityList = await _dicomSeriesRepository.Where(s => thisSeriesIdIds.Contains(s.Id)).OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).Select(x => x.Modality).Distinct().ToListAsync(); ;
 | ||
|                                 item.Modality = string.Join(",", modalityList);
 | ||
|                                 thisVisitTaskStudy.SeriesList.Add(item);
 | ||
|                                 //thisVisitTaskStudy.SeriesCount = thisVisitTaskStudy.SeriesList.Count;
 | ||
|                             }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|                             studyList.Insert(0, thisVisitTaskStudy);
 | ||
| 
 | ||
|                         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|                     }
 | ||
| 
 | ||
|                     studyList.ForEach(x =>
 | ||
|                     {
 | ||
|                         x.SeriesList.ForEach(y =>
 | ||
|                         {
 | ||
|                             y.IsBeMark = rowInfoList.Any(z => z.SeriesId == y.Id);
 | ||
|                         });
 | ||
| 
 | ||
|                     });
 | ||
|                 }
 | ||
| 
 | ||
| 
 | ||
|                 #endregion
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             #region 非Dicom 检查查询
 | ||
| 
 | ||
|             var noDicomList = await _noneDicomStudyRepository.Where(x => x.TrialId == indto.TrialId && x.SubjectVisitId == indto.SujectVisitId && x.NoneDicomFileList.Any(t => !t.FileType.Contains(StaticData.FileType.Zip)))
 | ||
|                  .Where(t => t.IsReading)
 | ||
|                 .WhereIf(taskInfo.IsImageFilter == true, t => taskInfo.CriterionModalitys.Contains(t.Modality)).ToListAsync();
 | ||
| 
 | ||
| 
 | ||
|             List<VisitStudyDTO> noDicomStudyList = noDicomList.Select(x => new VisitStudyDTO()
 | ||
|             {
 | ||
|                 InstanceCount = x.FileCount,
 | ||
|                 StudyId = x.Id,
 | ||
|                 StudyName = x.StudyName,
 | ||
|                 Modalities = x.Modality,
 | ||
|                 //SeriesCount = 1,
 | ||
|                 StudyCode = x.StudyCode,
 | ||
|                 IsDicom = false,
 | ||
| 
 | ||
|                 BodyPartForEdit=x.BodyPart,
 | ||
|                 BodyPartForEditOther=x.BodyPartForEditOther
 | ||
| 
 | ||
|             }).ToList();
 | ||
| 
 | ||
|             var isExistTaskNoneDicomFile = _noneDicomStudyFileRepository.Any(t => t.VisitTaskId == indto.VisitTaskId);
 | ||
| 
 | ||
|             foreach (var item in noDicomStudyList)
 | ||
|             {
 | ||
|                 var nodicom = noDicomList.Where(x => x.Id == item.StudyId).First();
 | ||
| 
 | ||
|                 var instanceCount = await _noneDicomStudyFileRepository.Where(t => t.IsReading)
 | ||
|                     .WhereIf(isExistTaskNoneDicomFile, x => x.OriginNoneDicomStudyId == item.StudyId)
 | ||
|                     .WhereIf(isExistTaskNoneDicomFile == false, x => x.NoneDicomStudyId == item.StudyId).CountAsync();
 | ||
| 
 | ||
|                 if (instanceCount == 0)
 | ||
|                 {
 | ||
|                     item.SeriesList = new List<DicomSeriesDTO>();
 | ||
|                     //item.SeriesCount = 0;
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     item.SeriesList = new List<DicomSeriesDTO>()
 | ||
|                 {
 | ||
|                     new DicomSeriesDTO (){
 | ||
|                     IsDicom=false,
 | ||
|                     Id=item.StudyId,
 | ||
|                     InstanceCount=instanceCount,
 | ||
|                     Modality=item.Modalities,
 | ||
|                     StudyId=item.StudyId,
 | ||
|                     TrialId=nodicom.TrialId,
 | ||
|                     SubjectVisitId=nodicom.SubjectVisitId,
 | ||
|                     SubjectId=nodicom.SubjectId,
 | ||
|                     SeriesNumber=1,
 | ||
|                     NoneDicomFileFirstFile=await _noneDicomStudyFileRepository.WhereIf(isExistTaskNoneDicomFile,x=>x.OriginNoneDicomStudyId== item.StudyId)
 | ||
|                     .WhereIf(isExistTaskNoneDicomFile==false, x=>x.NoneDicomStudyId == item.StudyId)
 | ||
|                     .Where(x=> !x.FileType.Contains(StaticData.FileType.Zip)).Select(x=>x.Path).FirstOrDefaultAsync(),
 | ||
|                     }
 | ||
| 
 | ||
|                 };
 | ||
|                 }
 | ||
| 
 | ||
|             }
 | ||
| 
 | ||
|             studyList.AddRange(noDicomStudyList);
 | ||
| 
 | ||
|             #endregion
 | ||
| 
 | ||
| 
 | ||
|             #region 过滤空序列得检查 过滤空instance得序列
 | ||
| 
 | ||
|             foreach (var study in studyList)
 | ||
|             {
 | ||
|                 study.SeriesList = study.SeriesList.Where(t => t.InstanceCount > 0).ToList();
 | ||
|             }
 | ||
| 
 | ||
|             var result = studyList.Where(x => x.SeriesCount > 0).ToList();
 | ||
| 
 | ||
|             #endregion
 | ||
| 
 | ||
| 
 | ||
|             return result;
 | ||
| 
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 设置受试者访视已执行  也就是将studyUploaded状态置为true  为了那些没有影像 人工设置准备
 | ||
|         /// </summary>
 | ||
|         /// <param name="subjectVisitId"></param>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpPut("{trialId:guid}/{subjectVisitId:guid}")]
 | ||
|         [TrialGlobalLimit("AfterStopCannNotOpt")]
 | ||
|         [Obsolete]
 | ||
|         public async Task<IResponseOutput> SetSVExecuted(Guid subjectVisitId)
 | ||
|         {
 | ||
|             await _subjectVisitRepository.UpdatePartialFromQueryAsync(subjectVisitId, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Executed }, true);
 | ||
|             return ResponseOutput.Ok();
 | ||
|         }
 | ||
|     }
 | ||
| }
 |