using IRaCIS.Core.Domain.Share; using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Application.Service.Reading.Dto; using MassTransit; using IRaCIS.Core.Infra.EFCore.Common; using System.Linq.Dynamic.Core; using IRaCIS.Core.Application.Service; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Domain.Models; namespace IRaCIS.Application.Services { /// /// 生成的阅片模块(在大列表上展示的) 阅片期 /// [ApiExplorerSettings(GroupName = "Reading")] public class ReadModuleService( IRepository _subjectVisitRepository, IRepository _subjectRepository, IRepository _userRepository, IRepository _trialRepository, IVisitTaskHelpeService _visitTaskHelpeService, IRepository _visitTaskRepository, IRepository _clinicalDataTrialSetRepository, IRepository _readModuleViewRepository, IRepository _readingQuestionCriterionTrialRepository, IRepository _dicomInstanceRepository, IRepository _noneDicomStudyFileRepository, IRepository _readingClinicalDataRepository, IRepository _readingPeriodSetRepository, IRepository _readModuleRepository) : BaseService { #region 获取修改时可选择的阅片期截止访视 /// /// 获取修改截止访视下拉 /// /// /// [HttpPost] public async Task> GetCanChangeReadVisitList(GetCanChangeReadVisitListInDto inDto) { //增加标准 var mixReadVisitNum = await _visitTaskRepository.Where(x => x.TrialReadingCriterionId == inDto.TrialReadingCriterionId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.ReadingCategory == ReadingCategory.Visit && x.SubjectId == inDto.SubjectId && x.TaskState == TaskState.Effect).OrderByDescending(x => x.VisitTaskNum).Select(x=> x.VisitTaskNum).FirstOrDefaultAsync(); var visitQuery = _subjectVisitRepository.Where(x => x.SubjectId == inDto.SubjectId && x.LatestScanDate != null && !x.IsLostVisit); var finalVisitNum = await visitQuery.Where(x => x.IsFinalVisit).Select(x => x.VisitNum).FirstOrDefaultAsync(); //增加标准 var readModulequery = _readModuleRepository.AsQueryable().Where(x => x.TrialReadingCriterionId == inDto.TrialReadingCriterionId); var resultlist = await visitQuery.WhereIf(finalVisitNum != null && finalVisitNum != 0, x => x.VisitNum <= finalVisitNum) .Where(x => x.VisitNum > mixReadVisitNum) .Where(x => !x.IsBaseLine) // 排除基线 .WhereIf(inDto.ReadingSetType == ReadingSetType.TumorReading, x => readModulequery.Where(y => y.SubjectVisitId == x.Id && y.TrialReadingCriterionId == inDto.TrialReadingCriterionId && y.ReadingSetType == ReadingSetType.ImageReading).Count() > 0) .WhereIf(inDto.ReadingSetType == ReadingSetType.ImageReading, x => readModulequery.Where(y => y.Id != inDto.Id && y.SubjectVisitId == x.Id && y.TrialReadingCriterionId == inDto.TrialReadingCriterionId && y.ReadingSetType == ReadingSetType.ImageReading).Count() == 0) .Select(x => new GetSubjectReadVisitsOutDto() { SubjectVisitId = x.Id, VisitName = x.VisitName, VisitNum = x.VisitNum, }).OrderBy(x => x.VisitNum).ToListAsync(); return resultlist; } #endregion /// /// 修改全局阅片截止访视 /// /// /// [HttpPost] public async Task ChangeCutOffVisit(ChangeCutOffVisitInDto inDto) { if (await _readModuleRepository.AnyAsync(x => x.Id == inDto.Id && x.IsCRCConfirm)) { //---CRC已经确认临床数据 不允许编辑 throw new BusinessValidationFailedException(_localizer["ReadModule_CRCConfirmCanNtoEdit"]); } await _readModuleRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.Id, x => new ReadModule() { SubjectVisitId=inDto.SubjectVisitIdId, ModuleName=inDto.Name, }); return await _readModuleRepository.SaveChangesAsync(); } /// /// 获取读片模块 //加了标准参数 /// [HttpPost] public async Task<(PageOutput,object)> GetReadModuleList(GetReadModuleDto dto) { #region MyRegion if (dto.SortField.IsNullOrEmpty()) { dto.SortField = nameof(ReadModuleView.SubjectCode); dto.Asc = true; } dto.SortField = dto.Asc ? dto.SortField : dto.SortField + " desc"; var subjectQuery = _readModuleViewRepository.Where(x => x.TrialReadingCriterionId == dto.TrialReadingCriterionId) .WhereIf(dto.TrialId != null, x => x.TrialId == dto.TrialId) .WhereIf(dto.SubjectId != null, x => x.SubjectId == dto.SubjectId) .WhereIf(dto.TrialSiteCode != null && dto.TrialSiteCode != string.Empty, x => x.TrialSiteCode.Contains(dto.TrialSiteCode)) .WhereIf(dto.SubjectCode != null && dto.SubjectCode != string.Empty, x => x.SubjectCode.Contains(dto.SubjectCode)) .WhereIf(dto.ModuleType != null, x => x.ModuleType == dto.ModuleType) .WhereIf(dto.CompleteClinicalData == CompleteClinicalDataEnum.NA, x => x.NeedSignClinicalDataCount == 0) .WhereIf(dto.CompleteClinicalData == CompleteClinicalDataEnum.NotComplete, x => x.NeedSignClinicalDataCount != x.SignClinicalDataCount) .WhereIf(dto.CompleteClinicalData == CompleteClinicalDataEnum.Complete, x => x.NeedSignClinicalDataCount != 0 && x.NeedSignClinicalDataCount == x.SignClinicalDataCount) .WhereIf(dto.ReadingStatus != null, x => x.ReadingStatus == dto.ReadingStatus); //.WhereIf(dto.Name != null, x => x.Name.Contains(dto.Name!)).OrderBy(x => x.SiteCode); var subjectIds = await subjectQuery.OrderBy(dto.SortField).Select(x => x.SubjectId).Distinct().Skip((dto.PageIndex - 1) * dto.PageSize).Take(dto.PageSize).ToListAsync(); List ReadModuleViewList = await subjectQuery.Where(x => subjectIds.Contains(x.SubjectId)).OrderBy(dto.SortField).ToListAsync(); List getReadList = ReadModuleViewList.GroupBy(x => new { x.SubjectId, x.TrialSiteId, x.TrialSiteCode, x.SubjectCode }) .Select(x => new GetReadModuleDtoOut() { TrialSiteCode = x.Key.TrialSiteCode, TrialSiteId = x.Key.TrialSiteId, SubjectCode = x.Key.SubjectCode, SubjectId = x.Key.SubjectId, Data = x.OrderBy(x=>x.ModuleType).ThenBy(x=>x.VisitNum).ToList(), }).ToList(); PageOutput pageOutput = new PageOutput() { PageSize = dto.PageSize, CurrentPageData = getReadList, PageIndex = dto.PageIndex, TotalCount = await subjectQuery.Select(x => x.SubjectId).Distinct().CountAsync(), }; var maxcount = 0; pageOutput.CurrentPageData.ForEach(x => { maxcount = maxcount < x.Data.Count ? x.Data.Count : maxcount; }); var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == dto.TrialReadingCriterionId).Select(x => new { x.IsReadingTaskViewInOrder, x.IsOncologyReading, x.IsGlobalReading, x.IsReadingPeriod, x.ReadingInfoSignTime, }).FirstNotNullAsync(); return (pageOutput, new { MaxLength = maxcount, IsReadingTaskViewInOrder= criterionInfo.IsReadingTaskViewInOrder, IsClinicalReading = criterionInfo.IsOncologyReading, // OnlyExistsMedicalHistory = !(await _clinicalDataTrialSetRepository.AnyAsync(x => x.TrialId == dto.TrialId && x.ClinicalDataSetName != "既往局部治疗史" && x.IsConfirm)), IsExistsSubjectClinicalData= await _clinicalDataTrialSetRepository.AnyAsync(x => x.TrialId == dto.TrialId&&x.ClinicalDataLevel== ClinicalLevel.Subject && x.IsConfirm&&x.TrialClinicalDataSetCriteriaList.Any(y=>y.TrialReadingCriterionId== dto.TrialReadingCriterionId)), IsExistsVisitClinicalData = await _clinicalDataTrialSetRepository.AnyAsync(x => x.TrialId == dto.TrialId && x.ClinicalDataLevel == ClinicalLevel.SubjectVisit && x.IsConfirm && x.TrialClinicalDataSetCriteriaList.Any(y => y.TrialReadingCriterionId == dto.TrialReadingCriterionId)), IsExistsStudyClinicalData = await _clinicalDataTrialSetRepository.AnyAsync(x => x.TrialId == dto.TrialId && x.ClinicalDataLevel == ClinicalLevel.Study && x.IsConfirm && x.TrialClinicalDataSetCriteriaList.Any(y => y.TrialReadingCriterionId == dto.TrialReadingCriterionId)), IsExistsReadingClinicalData = await _clinicalDataTrialSetRepository.AnyAsync(x => x.TrialId == dto.TrialId && x.ClinicalDataLevel == ClinicalLevel.ImageRead && x.IsConfirm && x.TrialClinicalDataSetCriteriaList.Any(y => y.TrialReadingCriterionId == dto.TrialReadingCriterionId)), IsExistsOncologyReadClinicalData = await _clinicalDataTrialSetRepository.AnyAsync(x => x.TrialId == dto.TrialId && x.ClinicalDataLevel == ClinicalLevel.OncologyRead && x.IsConfirm && x.TrialClinicalDataSetCriteriaList.Any(y => y.TrialReadingCriterionId == dto.TrialReadingCriterionId)), IsGlobalReading = criterionInfo.IsGlobalReading, IsReadingPeriod=criterionInfo.IsReadingPeriod, ReadingInfoSignTime=criterionInfo.ReadingInfoSignTime, ExistClinicalData=await _clinicalDataTrialSetRepository.AnyAsync(x => x.IsConfirm && x.TrialClinicalDataSetCriteriaList.Any(y => y.TrialReadingCriterionId == dto.TrialReadingCriterionId)), }) ; #endregion } /// /// 获取单条详情信息 /// /// /// [HttpPost] public async Task GetReadModule(GetReadModuleSingleIndto dto) { var data = await GetReadModuleList(new GetReadModuleDto() { SubjectId = dto.SubjectId, TrialId=dto.TrialId, TrialReadingCriterionId=dto.TrialReadingCriterionId, }); GetReadModuleSingleOutdto? readModule = data.Item1.CurrentPageData.FirstOrDefault().Data.Where(x => x.Id == dto.Id).Select(x => new GetReadModuleSingleOutdto() { Id = x.Id, ModuleType = x.ModuleType, SubjectVisitId = x.SubjectVisitId, SubjectVisitName = x.SubjectVisitName, Status = x.ReadingStatus, }).FirstOrDefault(); var stakeholderIds = new List(); var subjectVisit =await _subjectVisitRepository.FirstOrDefaultAsync(x => x.Id == readModule.SubjectVisitId); switch (readModule.Status) { case ReadingStatusEnum.ImageNotSubmit: stakeholderIds.AddRange(await _dicomInstanceRepository.Where(x => x.SubjectVisitId == readModule.SubjectVisitId).Select(x => x.CreateUserId).Distinct().ToListAsync()); stakeholderIds.AddRange(await _noneDicomStudyFileRepository.Where(x => x.NoneDicomStudy.SubjectVisitId == readModule.SubjectVisitId).Select(x => x.CreateUserId).Distinct().ToListAsync()); break; case ReadingStatusEnum.ImageQuality: if (subjectVisit.PreliminaryAuditUserId != null) { stakeholderIds.Add(subjectVisit.PreliminaryAuditUserId.Value); } if (subjectVisit.ReviewAuditUserId != null) { stakeholderIds.Add(subjectVisit.ReviewAuditUserId.Value); } break; case ReadingStatusEnum.TaskAllocate: if (subjectVisit.CheckUserId != null) { stakeholderIds.Add(subjectVisit.CheckUserId.Value); } break; case ReadingStatusEnum.ImageReading: case ReadingStatusEnum.ReadCompleted: var doctorUserId = await _visitTaskRepository.Where(x => (x.SouceReadModuleId == dto.Id || x.SourceSubjectVisitId == dto.Id)&&x.TaskState==TaskState.Effect) .Where(x => x.DoctorUserId != null).Select(x => x.DoctorUserId.Value).ToListAsync(); stakeholderIds.AddRange(doctorUserId); break; }; readModule.StakeholderIds = stakeholderIds.Distinct().ToList(); readModule.StakeholderNames = await _userRepository.Where(x => readModule.StakeholderIds.Contains(x.Id)).Select(x => x.FirstName + "/" + x.LastName).ToListAsync(); return readModule; } /// /// 添加阅片的时候 获取访视 //标准参数必传 /// /// /// public async Task> GetSubjectReadVisitList(GetSubjectReadVisitsInDto inDto) { //增加标准 var maxReadVisit = await _readModuleRepository.Where(x => x.SubjectId == inDto.SubjectId && x.ReadingSetType==inDto.ReadingSetType && x.TrialReadingCriterionId==inDto.TrialReadingCriterionId).Include(x=>x.SubjectVisit).OrderByDescending(x=>x.SubjectVisit.VisitNum).FirstOrDefaultAsync(); var maxReadVisitNum= maxReadVisit==null?-1:maxReadVisit.SubjectVisit.VisitNum; var visitQuery = _subjectVisitRepository.Where(x => x.SubjectId == inDto.SubjectId && x.LatestScanDate != null && !x.IsLostVisit); var finalVisitNum = await visitQuery.Where(x => x.IsFinalVisit).Select(x => x.VisitNum).FirstOrDefaultAsync(); //增加标准 var readModulequery = _readModuleRepository.AsQueryable().Where(x=>x.TrialReadingCriterionId == inDto.TrialReadingCriterionId); var resultlist= await visitQuery.WhereIf(finalVisitNum!=0, x => x.VisitNum <= finalVisitNum) .WhereIf(inDto.ReadingSetType== ReadingSetType.TumorReading, x => readModulequery.Where(y => y.SubjectVisitId == x.Id&&y.TrialReadingCriterionId== inDto.TrialReadingCriterionId && y.ReadingSetType == ReadingSetType.ImageReading).Count() > 0) .Where(x=>x.VisitNum> maxReadVisitNum) .Where(x=>!x.IsBaseLine) // 排除基线 .Where(x => readModulequery.Where(y => y.SubjectVisitId == x.Id&& y.TrialReadingCriterionId == inDto.TrialReadingCriterionId && y.ReadingSetType == inDto.ReadingSetType).Count() == 0).OrderBy(x => finalVisitNum) .Select(x => new GetSubjectReadVisitsOutDto() { SubjectVisitId = x.Id, VisitName = x.VisitName, VisitNum = x.VisitNum, }).OrderBy(x=>x.VisitNum).ToListAsync(); return resultlist; } /// /// 添加阅片期 /// /// /// [HttpPost] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task AddReadModule(ReadModuleAddDto dto) { var visitQuery = _subjectVisitRepository.Where(x => x.SubjectId == dto.SubjectId); visitQuery = visitQuery //.WhereIf(dto.ExpirationDate != null, x => x.LatestScanDate <= dto.ExpirationDate.Value) .WhereIf(dto.ExpirationVisitNum != null, x => x.VisitNum == dto.ExpirationVisitNum!); var visit = visitQuery.OrderByDescending(x => x.VisitNum).FirstOrDefault(); var moduleType = dto.ReadingSetType == ReadingSetType.ImageReading ? ModuleTypeEnum.Global : ModuleTypeEnum.Oncology; if (visit != null) { if (await _readModuleRepository.AnyAsync(x => x.SubjectVisitId == visit.Id&&x.ModuleType== moduleType && x.TrialReadingCriterionId == dto.TrialReadingCriterionId)) { //---当前访视已经添加过阅片期 throw new BusinessValidationFailedException(_localizer["ReadModule_AlreadyAdded"]); } var readModuleData = new ReadModule() { Id = NewId.NextGuid(), SubjectId = dto.SubjectId, ModuleType = moduleType, IsUrgent = visit.IsUrgent, ModuleName = dto.Name, SubjectVisitId = visit.Id, ReadingSetType = dto.ReadingSetType, TrialId = dto.TrialId, ReadingStatus = ReadingStatusEnum.TaskAllocate, //增加标准 TrialReadingCriterionId = dto.TrialReadingCriterionId, }; await _readModuleRepository.AddAsync(readModuleData); // 判断是否要添加肿瘤学或者全局阅片任务 switch (readModuleData.ModuleType) { case ModuleTypeEnum.Global: //增加标准 var taskListInfo = await _visitTaskRepository.Where(x => x.SourceSubjectVisitId == readModuleData.SubjectVisitId&&x.TaskState==TaskState.Effect && x.ReadingTaskState == ReadingTaskState.HaveSigned &&!x.IsAnalysisCreate && x.TrialReadingCriterionId==dto.TrialReadingCriterionId ).ToListAsync(); foreach (var taskInfo in taskListInfo) { await _visitTaskHelpeService.AddTaskAsync(new GenerateTaskCommand() { OriginalVisitId = taskInfo.Id, ReadingCategory = GenerateTaskCategory.Global, TrialId = dto.TrialId, ReadingGenerataTaskList = new List() { new ReadingGenerataTaskDTO() { IsUrgent = readModuleData.IsUrgent ?? false, SubjectId = readModuleData.SubjectId, ReadingName = readModuleData.ModuleName, ReadModuleId =readModuleData.Id, ReadingCategory = ReadingCategory.Global, } } }); } break; case ModuleTypeEnum.Oncology: var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == dto.TrialReadingCriterionId).Select(x => new { x.ReadingType, }).FirstNotNullAsync(); //增加标准 var globalModule = await _readModuleRepository.Where(x => x.SubjectId == readModuleData.SubjectId && x.SubjectVisitId == readModuleData.SubjectVisitId&& x.ModuleType == ModuleTypeEnum.Global && x.TrialReadingCriterionId == dto.TrialReadingCriterionId).FirstOrDefaultAsync(); if (globalModule != null) { var globalTaskInfoList = await _visitTaskRepository.Where(x => x.SouceReadModuleId == globalModule.Id && x.TrialReadingCriterionId == dto.TrialReadingCriterionId && x.TaskState == TaskState.Effect && x.ReadingTaskState == ReadingTaskState.HaveSigned&&!x.IsAnalysisCreate).ToListAsync(); if (globalTaskInfoList.Count() > 0 && globalTaskInfoList.Count == (int)criterionInfo.ReadingType) { var isAdd = false; if (globalTaskInfoList[0].JudgeVisitTaskId == null) { isAdd = true; } else { isAdd = await _visitTaskRepository.AnyAsync(x => x.Id == globalTaskInfoList[0].JudgeVisitTaskId && x.ReadingTaskState == ReadingTaskState.HaveSigned); } if (isAdd) { await _visitTaskHelpeService.AddTaskAsync(new GenerateTaskCommand() { OriginalVisitId = globalTaskInfoList[0].Id, ReadingCategory = GenerateTaskCategory.Oncology, TrialId = dto.TrialId, ReadingGenerataTaskList = new List() { new ReadingGenerataTaskDTO() { IsUrgent = readModuleData.IsUrgent ?? false, SubjectId = readModuleData.SubjectId, VisitNum=visit.VisitNum, ReadingName = readModuleData.ModuleName, ReadModuleId =readModuleData.Id, ReadingCategory = ReadingCategory.Oncology, } } }); } } } else { //---请先添加全局阅片 return ResponseOutput.NotOk(_localizer["ReadModule_AddGlobalFirst"]); } break; } var res = await _readModuleRepository.SaveChangesAsync(); return ResponseOutput.Ok(res); } else { //---未找到符合要求的访视 return ResponseOutput.NotOk(_localizer["ReadModule_VisitNotFound"]); } } /// /// 删除 /// /// /// [HttpDelete("{readModuleId:guid}")] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task DeleteReadModule(Guid readModuleId) { var readModule = await _readModuleRepository.Where(x => x.Id == readModuleId).FirstNotNullAsync(); if(await _readingClinicalDataRepository.Where(t => t.ReadingId == readModuleId).AnyAsync(t => t.ReadingClinicalDataState == ReadingClinicalDataStatus.HaveSigned)) { //---临床资料已签名,不允许删除 return ResponseOutput.NotOk(_localizer["ReadModule_SignedDataCannotDelete"]); } if (await _readModuleRepository.AnyAsync(x => x.Id == readModuleId&&x.IsCRCConfirm)) { //---CRC已经确认临床数据 不允许删除 return ResponseOutput.NotOk(_localizer["ReadModule_CRCConfirmClinicalData"]); } //增加标准 if (readModule.ModuleType==ModuleTypeEnum.Global&&(await _readModuleRepository.AnyAsync(x=>x.ModuleType==ModuleTypeEnum.Oncology&&x.SubjectVisitId== readModule.SubjectVisitId && x.TrialReadingCriterionId==readModule.TrialReadingCriterionId))) { //---当前访视存在肿瘤学阅片,请先删除肿瘤学阅片 throw new BusinessValidationFailedException(_localizer["ReadModule_TumorExists"]); } if (await _visitTaskRepository.AnyAsync(x => readModuleId==x.SouceReadModuleId)) { //---当前阅片已生成任务,操作失败。 throw new BusinessValidationFailedException(_localizer["ReadModule_TaskGenerated"]); } await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => readModuleId==x.SouceReadModuleId, x => new VisitTask() { TaskState = TaskState.Adbandon }); await _readModuleRepository.UpdatePartialFromQueryAsync(t => t.Id == readModuleId, x => new ReadModule() { IsDeleted = true }); await _readModuleRepository.SaveChangesAsync(); return ResponseOutput.Result(true); } } }