using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infrastructure; using MassTransit; using Microsoft.AspNetCore.Mvc; namespace IRaCIS.Core.Application.Service { /// /// 阅片期配置 /// [ApiExplorerSettings(GroupName = "Reading")] public class ReadingPeriodSetService(IRepository _subjectVisitRepository, IRepository _readingPeriodSetRepository, IRepository _readModuleRepository, IRepository _visitStageRepository, IRepository _trialRepository, IReadingImageTaskService _readingImageTaskService, IRepository _visitTaskRepository, IRepository _readingQuestionCriterionTrialRepository, IVisitTaskHelpeService _visitTaskHelpeService, IRepository _readingPeriodPlanRepository, IRepository _siteSetRepository, IRepository _subjectRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService { #region 阅片期配置 基本信息维护 以及生效 /// /// 新增或者修改 (增加标准搜索,已修改) /// /// /// [HttpPost] [TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task AddOrUpdateReadingPeriodSet(ReadingPeriodSetAddOrEdit addOrEditReadingPeriodSet) { if (await _readingPeriodSetRepository.AnyAsync(x => x.Id != addOrEditReadingPeriodSet.Id && x.IsTakeEffect != ReadingPeriodStatus.Revocation && x.TrialId == addOrEditReadingPeriodSet.TrialId && x.ReadingPeriodName == addOrEditReadingPeriodSet.ReadingPeriodName && x.TrialReadingCriterionId == addOrEditReadingPeriodSet.TrialReadingCriterionId)) { //---阅片期名称重复,操作失败 return ResponseOutput.NotOk(_localizer["ReadingPeriodSet_NameDup"]); } if (addOrEditReadingPeriodSet.ReadingPeriodName == "Global") { //---阅片期名称不能为Global return ResponseOutput.NotOk(_localizer["ReadingPeriodSet_Global"]); } if (addOrEditReadingPeriodSet.Id == null) { var entity = _mapper.Map(addOrEditReadingPeriodSet); entity.ReadingPeriodSites = addOrEditReadingPeriodSet.SiteIds.Select(x => new ReadingPeriodSite() { ReadingPeriodSetId = entity.Id, TrialId = entity.TrialId, TrialSiteId = x, }).ToList(); entity.ReadingPeriodPlanList = addOrEditReadingPeriodSet.SubjectVisitIds.Select(x => new ReadingPeriodPlan { ReadingPeriodSetId = entity.Id, SubjectVisitId = x, }).ToList(); await _readingPeriodSetRepository.AddAsync(entity, true); return ResponseOutput.Ok(entity.Id); } else { var entity = (await _readingPeriodSetRepository.Where(t => t.Id == addOrEditReadingPeriodSet.Id, true).Include(t => t.ReadingPeriodSites).Include(x => x.ReadingPeriodPlanList).FirstOrDefaultAsync()).IfNullThrowException(); _mapper.Map(addOrEditReadingPeriodSet, entity); entity.ReadingPeriodSites = addOrEditReadingPeriodSet.SiteIds.Select(x => new ReadingPeriodSite() { ReadingPeriodSetId = entity.Id, TrialId = entity.TrialId, TrialSiteId = x, }).ToList(); entity.ReadingPeriodPlanList = addOrEditReadingPeriodSet.SubjectVisitIds.Select(x => new ReadingPeriodPlan { ReadingPeriodSetId = entity.Id, SubjectVisitId = x, }).ToList(); var success = await _readingPeriodSetRepository.SaveChangesAsync(); return ResponseOutput.Ok(entity.Id); } } /// /// 删除 /// /// /// [HttpDelete("{readingPeriodSetId:guid}")] [TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task DeleteReadingPeriodSet(Guid readingPeriodSetId) { await _readingPeriodSetRepository.UpdatePartialFromQueryAsync(t => t.Id == readingPeriodSetId, x => new ReadingPeriodSet() { IsDeleted = true }); await _readingPeriodPlanRepository.UpdatePartialFromQueryAsync(t => t.ReadingPeriodSetId == readingPeriodSetId, x => new ReadingPeriodPlan() { IsDeleted = true }); await _readingPeriodPlanRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } /// /// 设置阅片期配置是否生效 (增加标准搜索,已修改) /// /// /// [HttpPut] [TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task SetReadingPeriodSetEffect(SetReadingPeriodSetEffect indto) { var readingPeriodSet = await _readingPeriodSetRepository.Where(x => x.Id == indto.Id).FirstNotNullAsync(); if (indto.IsTakeEffect == ReadingPeriodStatus.TakeEffect) { var plans = _readingPeriodPlanRepository.Where(x => x.ReadingPeriodSetId == indto.Id).Include(x => x.SubjectVisit) .Include(x => x.ReadingPeriodSet).Include(x => x.SubjectVisit).ToList(); var needAddVisitIds = plans.Select(x => x.SubjectVisitId).ToList(); var repeatVisitIds = _readModuleRepository.Where(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && x.ReadingSetType == readingPeriodSet.ReadingSetType && needAddVisitIds.Contains(x.SubjectVisitId)).Select(x => x.SubjectVisitId).ToList(); plans = plans.Where(x => !repeatVisitIds.Contains(x.SubjectVisitId)).ToList(); List readModules = new List(); foreach (var item in plans) { readModules.Add(new ReadModule() { Id = NewId.NextGuid(), SubjectId = item.SubjectVisit.SubjectId, ModuleType = item.ReadingPeriodSet.ReadingSetType == ReadingSetType.ImageReading ? ModuleTypeEnum.Global : ModuleTypeEnum.Oncology, IsUrgent = item.SubjectVisit.IsUrgent, ModuleName = item.ReadingPeriodSet.ReadingPeriodName, SubjectVisitId = item.SubjectVisitId, ReadingSetType = item.ReadingPeriodSet.ReadingSetType, ReadingPeriodSetId = item.ReadingPeriodSet.Id, ReadingStatus = ReadingStatusEnum.TaskAllocate, TrialId = readingPeriodSet.TrialId, //VisitNum = item.SubjectVisit.VisitNum, //增加标准 TrialReadingCriterionId = readingPeriodSet.TrialReadingCriterionId }); }; await _readModuleRepository.AddRangeAsync(readModules); await _readModuleRepository.SaveChangesAsync(); // 判断是否要添加肿瘤学或者全局阅片任务 var subjectVisitIds = readModules.Select(x => x.SubjectVisitId).ToList(); switch (readingPeriodSet.ReadingSetType) { case ReadingSetType.ImageReading: //增加标准 var taskInfoList = await _visitTaskRepository.Where(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && subjectVisitIds.Contains(x.SourceSubjectVisitId ?? default(Guid)) && x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && x.TaskState == TaskState.Effect && x.ReadingTaskState == ReadingTaskState.HaveSigned && !x.IsAnalysisCreate).ToListAsync(); foreach (var item in taskInfoList) { var readModule = readModules.Where(x => x.SubjectVisitId == item.SourceSubjectVisitId).FirstOrDefault(); if (readModule != null) { await _visitTaskHelpeService.AddTaskAsync(new GenerateTaskCommand() { OriginalVisitId = item.Id, ReadingCategory = GenerateTaskCategory.Global, TrialId = item.TrialId, ReadingGenerataTaskList = new List() { new ReadingGenerataTaskDTO() { IsUrgent = readModule.IsUrgent??false, SubjectId = readModule.SubjectId, ReadingName = readModule.ModuleName, ReadModuleId =readModule.Id, ReadingCategory = ReadingCategory.Global, } } }); } } // 根据SourceSubjectVisitId 分组 var visitTaskid = taskInfoList.GroupBy(x => x.SourceSubjectVisitId).Select(x => x.Max(y => y.Id)).ToList(); // 生成裁判任务 是否需要生成函数里面有逻辑判断 foreach (var item in visitTaskid) { await _readingImageTaskService.TriggerJudgeQuestion(item); } break; case ReadingSetType.TumorReading: var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == readingPeriodSet.TrialReadingCriterionId).Select(x => new { x.ReadingType, }).FirstNotNullAsync(); //增加标准 var globalModuleIds = await _readModuleRepository.Where(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && subjectVisitIds.Contains(x.SubjectVisitId) && x.ModuleType == ModuleTypeEnum.Global).Select(x => x.Id).ToListAsync(); //增加标准 var globalTaskInfo = await _visitTaskRepository.Where(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && globalModuleIds.Contains(x.SouceReadModuleId ?? default(Guid)) && x.TaskState == TaskState.Effect && x.ReadingTaskState == ReadingTaskState.HaveSigned && !x.IsAnalysisCreate).GroupBy(x => new { x.SouceReadModuleId }).Select(x => new { SouceReadModuleId = x.Key.SouceReadModuleId, Count = x.ToList().Count, TaskId = x.Select(x => x.Id).FirstOrDefault(), ReadModuleId = x.Select(x => x.SouceReadModuleId).FirstOrDefault(), JudgeTaskId = x.Select(x => x.JudgeVisitTaskId).FirstOrDefault(), JudgeTaskResultId = x.Select(x => x.JudgeVisitTask.JudgeResultTaskId).FirstOrDefault(), }).ToListAsync(); foreach (var item in globalTaskInfo) { if (item.Count == (int)criterionInfo.ReadingType) { //没有裁判 或者有裁判,并且裁判任务做完了 if (item.JudgeTaskId == null || item.JudgeTaskResultId != null) { var readModule = readModules.Where(x => x.Id == item.ReadModuleId).FirstOrDefault(); await _visitTaskHelpeService.AddTaskAsync(new GenerateTaskCommand() { OriginalVisitId = item.TaskId, ReadingCategory = GenerateTaskCategory.Oncology, TrialId = readingPeriodSet.TrialId, ReadingGenerataTaskList = new List() { new ReadingGenerataTaskDTO() { IsUrgent = readModule.IsUrgent ?? false, SubjectId = readModule.SubjectId, ReadingName = readModule.ModuleName, ReadModuleId =readModule.Id, ReadingCategory = ReadingCategory.Oncology, } } }); } } } break; } } else { List readModuleIds = await _readModuleRepository.Where(x => x.ReadingPeriodSetId == indto.Id).Select(x => x.Id).ToListAsync(); if (await _visitTaskRepository.AnyAsync(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && readModuleIds.Contains(x.SouceReadModuleId ?? default(Guid)) && x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.TaskState == TaskState.Effect)) { //---当前标准阅片已生成任务并且阅片完成,撤销失败。 throw new BusinessValidationFailedException(_localizer["ReadingPeriodSet_TaskCompletedCannotRevoke"]); } await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.TrialReadingCriterionId == readingPeriodSet.TrialReadingCriterionId && readModuleIds.Contains(x.SouceReadModuleId ?? default(Guid)), x => new VisitTask() { TaskState = TaskState.Adbandon }); await _readModuleRepository.UpdatePartialFromQueryAsync(x => x.ReadingPeriodSetId == indto.Id, x => new ReadModule() { IsDeleted = true }); } var readQuery = await _readingPeriodSetRepository.UpdatePartialFromQueryAsync(indto.Id, x => new ReadingPeriodSet() { IsTakeEffect = indto.IsTakeEffect, EffectOfTime = indto.IsTakeEffect == ReadingPeriodStatus.TakeEffect ? DateTime.Now : null, }); var result = await _readingPeriodSetRepository.SaveChangesAsync(); return ResponseOutput.Result(result); } #endregion #region 阅片计划 相关 /// /// 获取选中的计划 (增加标准不影响 因为阅片期设置关联了标准) /// /// /// [HttpPost] public async Task> GetPreviewTheReadingPlanList(PreviewTheReadingListDto inDto) { var plans = _readingPeriodPlanRepository.Where(x => x.ReadingPeriodSetId == inDto.ReadingPeriodSetId).Include(x => x.SubjectVisit).Include(x => x.SubjectVisit.TrialSite).Include(x => x.SubjectVisit.Subject) .Include(x => x.ReadingPeriodSet).Select(x => new PreviewTheReadingListOutDto { Id = x.Id, ExpirationDate = x.ReadingPeriodSet.ExpirationDate, SubjectVisitId = x.SubjectVisitId, TrialSiteCode = x.SubjectVisit.TrialSite.TrialSiteCode, LatestScanDate = x.SubjectVisit.LatestScanDate, ReadingPeriodName = x.ReadingPeriodSet.ReadingPeriodName, ReadingPeriodSetId = x.ReadingPeriodSetId, SubjectCode = x.SubjectVisit.Subject.Code, SubjectId = x.SubjectVisit.SubjectId, SubjectVisitName = x.SubjectVisit.VisitName, EffectOfTime = x.ReadingPeriodSet.EffectOfTime, }); return await plans.ToPagedListAsync(inDto, nameof(PreviewTheReadingListOutDto.SubjectId)); } /// /// 添加对应的阅片计划 (后续生效将计划变为模块) (增加标准不影响 因为阅片期设置关联了标准) /// /// /// [TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task GenerateReadingTask(ReadingToGenerateInDto inDto) { List plans = new List(); inDto.SubjectVisitIds.ForEach(x => { plans.Add(new ReadingPeriodPlan() { SubjectVisitId = x, ReadingPeriodSetId = inDto.ReadingPeriodSetId }); }); await _readingPeriodPlanRepository.UpdatePartialFromQueryAsync(x => x.ReadingPeriodSetId == inDto.ReadingPeriodSetId, x => new ReadingPeriodPlan() { IsDeleted = true }); await _readingPeriodPlanRepository.SaveChangesAsync(); await _readingPeriodPlanRepository.AddRangeAsync(plans); var result = await _readingPeriodPlanRepository.SaveChangesAsync(); return ResponseOutput.Result(result); } #endregion #region 阅片期相关查询 /// /// 分页获取 (增加标准搜索,已修改) /// /// /// [HttpPost] public async Task> GetReadingPeriodSetList(ReadingPeriodSetQuery query) { var readQuery = _readingPeriodSetRepository.Where(t => t.TrialId == query.TrialId).Include(x => x.ReadingPeriodSites) .WhereIf(query.ReadingPeriodName != null, x => x.ReadingPeriodName.Contains(query.ReadingPeriodName!)) .WhereIf(query.TrialReadingCriterionId != null, x => x.TrialReadingCriterionId == query.TrialReadingCriterionId) .ProjectTo(_mapper.ConfigurationProvider); var pageList = await readQuery.ToPagedListAsync(query, nameof(ReadingPeriodSetView.CreateTime)); pageList.CurrentPageData.ForEach(x => { //---末次访视 x.SubjectVisitName = x.IsGlobal ? _localizer["ReadingPeriodSet_LastVisit"] : x.SubjectVisitName; }); return pageList; } /// /// 获取单条 /// /// /// [HttpPost("{id:guid}")] public async Task GetReadingPeriodSet(Guid id) { return await _readingPeriodSetRepository.AsQueryable().Include(x => x.ReadingPeriodSites).Where(x => x.Id == id).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync(); } /// /// 获取阅片期配置的截至访视的下拉框 (增加标准搜索,已修改) /// /// /// [HttpPost] public async Task> GetReadingVisitList(GetReadingVisitListInDto inDto) { var maxVisitNum = await _readingPeriodSetRepository .WhereIf(inDto.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inDto.TrialReadingCriterionId) .Where(x => x.TrialId == inDto.TrialId && x.ReadingSetType == inDto.ReadingSetType && x.IsTakeEffect == ReadingPeriodStatus.TakeEffect) .MaxAsync(x => x.ExpirationVisitNum) ?? 0; var thisVisitNum = await _readingPeriodSetRepository.Where(x => x.Id == inDto.ReadingPeriodSetId).Select(x => x.ExpirationVisitNum).FirstOrDefaultAsync() ?? -1; var globalVisitNum = new List(); if (inDto.ReadingSetType == ReadingSetType.TumorReading) { globalVisitNum = await _readModuleRepository .WhereIf(inDto.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inDto.TrialReadingCriterionId) .Where(x => x.ReadingSetType == ReadingSetType.ImageReading && x.TrialId == inDto.TrialId).Select(x => x.SubjectVisit.VisitNum).Distinct().ToListAsync(); } List result = await _visitStageRepository.Where(x => x.TrialId == inDto.TrialId) .WhereIf(inDto.ReadingSetType == ReadingSetType.TumorReading, x => globalVisitNum.Contains(x.VisitNum)) //.Where(x => x.VisitNum > 0)// 不能是基线 .Where(x => x.VisitNum == thisVisitNum || x.VisitNum >= maxVisitNum).Select(x => new GetReadingVisitListOutDto() { VisitName = x.VisitName, VisitNum = x.VisitNum, VisitStageId = x.Id, }).OrderBy(x=>x.VisitNum).ToListAsync(); return result; } /// /// 获取影像阅片的预览 // 需要清除之前已经选中的 (增加标准搜索,已修改) /// /// [HttpPost] public async Task> GetPreviewTheReadingList(PreviewTheReadingListInDto inDto) { var readModulequery = _readModuleRepository.AsQueryable(); // 当前项目 最晚拍片日期不为null 中心筛选 var visitQuery = _subjectVisitRepository.Where(x => x.TrialId == inDto.TrialId && x.LatestScanDate != null && !x.IsLostVisit) .WhereIf(inDto.ReadingScope == ReadingScopeEnum.Site, x => inDto.SiteIds.Contains(x.TrialSiteId)) .Where(x => !x.IsBaseLine);// 排除基线 // 已经存在的访视 需要排除 var existsBubjectVisitsQuery = _readModuleRepository.Where(y => y.ReadingSetType == inDto.ReadingSetType && y.TrialId == inDto.TrialId && y.TrialReadingCriterionId == inDto.TrialReadingCriterionId).Select(x => x.SubjectVisitId); visitQuery = visitQuery.Where(x => !existsBubjectVisitsQuery.Contains(x.Id)) .WhereIf(inDto.ExpirationDate != null, x => x.LatestScanDate < inDto.ExpirationDate.Value.AddDays(1)) .WhereIf(inDto.ExpirationVisitNum != null, x => x.VisitNum == inDto.ExpirationVisitNum) .WhereIf(inDto.ReadingSetType == ReadingSetType.TumorReading, x => readModulequery.Where(y => y.SubjectVisitId == x.Id && y.ReadingSetType == ReadingSetType.ImageReading).Count() > 0); var subjectIdlist = await visitQuery.OrderBy(x => x.SubjectId).Select(x => x.SubjectId).Distinct().Skip((inDto.PageIndex - 1) * inDto.PageSize).Take(inDto.PageSize).ToListAsync(); var totalCount = visitQuery.Select(x => x.SubjectId).Distinct().Count(); var visitlist = await visitQuery.Include(x => x.Subject).Include(x => x.TrialSite).Where(x => subjectIdlist.Contains(x.SubjectId)).ToListAsync(); var subjectVisits = visitlist.GroupBy(x => x.SubjectId).Select(x => new { SubjectId = x.Key, Visits = x.ToList() }); List visits = new List(); subjectVisits.ForEach(x => { var visit = x.Visits.OrderByDescending(x => x.VisitNum).FirstOrDefault(); if (visit != null) { visits.Add(visit); } }); PageOutput result = new PageOutput() { CurrentPageData = visits .Select(x => new PreviewTheReadingListOutDto { ExpirationDate = inDto.ExpirationDate, SubjectVisitId = x.Id, TrialSiteCode = x.TrialSite.TrialSiteCode, LatestScanDate = x.LatestScanDate, ReadingPeriodName = inDto.ReadingPeriodName, SubjectCode = x.Subject.Code, SubjectId = x.SubjectId, SubjectVisitName = x.VisitName, }).ToList(), PageSize = inDto.PageSize, PageIndex = inDto.PageIndex, TotalCount = totalCount, }; return result; } #endregion } }