777 lines
34 KiB
C#
777 lines
34 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<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)
|
||
.Where(t => isImageFilter ? ("|" + criterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
|
||
.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 }).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,
|
||
}).ToList();
|
||
|
||
series.InstanceCount = series.InstanceInfoList.Count();
|
||
}
|
||
);
|
||
|
||
//设置为阅片与否 不更改数据库检查 的instance数量 和 SeriesCount 所以这里要实时统计
|
||
//t.SeriesCount = t.SeriesList.Count;
|
||
t.InstanceCount = t.SeriesList.SelectMany(t => t.InstanceInfoList).Count();
|
||
}
|
||
|
||
|
||
|
||
|
||
return studyList;
|
||
|
||
//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 }).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,
|
||
|
||
}).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 }).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,
|
||
|
||
}).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,
|
||
Modalities = k.Modalities,
|
||
//SeriesCount = k.SeriesCount,
|
||
StudyCode = k.StudyCode,
|
||
StudyId = k.Id,
|
||
|
||
}).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 }).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,
|
||
|
||
}).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,
|
||
}).ToListAsync();
|
||
|
||
|
||
|
||
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,
|
||
}).ToListAsync();
|
||
|
||
rowInfoList.AddRange(customoList);
|
||
|
||
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)).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,
|
||
}).ToListAsync();
|
||
|
||
item.InstanceInfoList.ForEach(x =>
|
||
{
|
||
|
||
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.OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).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)))
|
||
.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,
|
||
Modalities = x.Modality,
|
||
//SeriesCount = 1,
|
||
StudyCode = x.StudyCode,
|
||
IsDicom = false,
|
||
|
||
}).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.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();
|
||
}
|
||
}
|
||
}
|