using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Office2019.Excel.ThreadedComments; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.Interfaces; using IRaCIS.Core.Application.Service.ImageAndDoc; using IRaCIS.Core.Application.Service.OAuth; using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.Service.ReadingCalculate.Interface; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; using IRaCIS.Core.Infrastructure; using MassTransit; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Newtonsoft.Json.Serialization; using NPOI.POIFS.Properties; using NPOI.SS.Formula.Functions; using Panda.DynamicWebApi.Attributes; using ZiggyCreatures.Caching.Fusion; namespace IRaCIS.Core.Application.Service { /// /// IR影像阅片 /// [ApiExplorerSettings(GroupName = "Reading")] public partial class ReadingImageTaskService( IRepository _noneDicomStudyRepository, IRepository _visitTaskRepository, IRepository _trialRepository, IRepository _noneDicomStudyFileRepository, IRepository _readingNoneDicomMarkRepository, IRepository _userLogRepository, IRepository _readingTableQuestionAnswerRepository, IRepository _readingOncologyTaskInfoRepository, IVisitTaskHelpeService _visitTaskHelpeService, IVisitTaskService _visitTaskService, IReadingClinicalDataService _readingClinicalDataService, IReadingCalculateService _readingCalculateService, IRepository _subjectVisitRepository, IRepository _subjectRepository, IRepository _userFeedBackRepository, IOptionsMonitor _verifyConfig, IRepository _readingGlobalTaskInfoRepository, IRepository _readingCriterionPageRepository, IRepository _readingTaskRelationRepository, IRepository _readingJudgeInfoRepository, IRepository _readModuleRepository, IRepository _dicomInstanceRepository, IRepository _organInfoRepository, IRepository _organTrialInfoRepository, IRepository _trialDocumentRepository, ILuganoCalculateService _luganoCalculateService, IRepository _readingCustomTagRepository, IRepository _readingTaskQuestionMarkRepository, IRepository _readingTrialCriterionDictionaryRepository, IRepository _readingTableAnswerRowInfoRepository, IRepository _readingTableQuestionSystemRepository, IRepository _readingTableQuestionTrialRepository, IRepository _readingTaskQuestionAnswerRepository, IRepository _readingQuestionCriterionTrialRepository, IRepository _readingQuestionSystem, IRepository _noneDicomStudyFileSystem, IGeneralCalculateService _generalCalculateService, IRepository _readingQuestionTrialRepository, IRepository _taskStudyRepository, IDownloadAndUploadService _downloadAndUploadService, ITrialEmailNoticeConfigService _trialEmailNoticeConfigService, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, IReadingImageTaskService { #region 计算 /// /// 获取阅片的计算数据 /// /// /// [HttpPost] public async Task GetReadingCalculationData(GetReadingCalculationDataInDto inDto) { return await _readingCalculateService.GetReadingCalculationData(inDto); } #endregion /// /// 删除单个表格问题标记 /// /// /// /// [HttpPost] [Route("/DeleteSingleTableQuestionMark/{param}")] public async Task DeleteSingleTableQuestionMark(DeleteSingleTableQuestionMarkInDto inDto, string param) { var mark = await _readingTaskQuestionMarkRepository.Where(x => x.Id == inDto.Id).FirstNotNullAsync(); var taskid = mark.VisitTaskId; await _readingTableQuestionAnswerRepository.DeleteFromQueryAsync(x => x.RowId == mark.RowId && x.TableQuestionId == mark.TableQuestionId); await _readingTaskQuestionMarkRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.Id, x => new ReadingTaskQuestionMark() { InstanceId = null, SeriesId = null, StudyId = null, MarkTool = string.Empty, // PicturePath = string.Empty, 稽查需要显示截图 NumberOfFrames = null, MeasureData = string.Empty, OrderMarkName = string.Empty, OtherInstanceId = null, OtherSeriesId = null, OtherStudyId = null, OtherMarkTool = string.Empty, OtherPicturePath = string.Empty, OtherNumberOfFrames = null, OtherMeasureData = string.Empty, }); var result = await _readingTaskQuestionMarkRepository.SaveChangesAsync(); await _readingCalculateService.CalculateTask(new CalculateTaskInDto() { IsChangeOtherTask = false, VisitTaskId = taskid, ComputationTrigger = (ComputationTrigger)int.Parse(param), }); return result; } /// /// 删除表格问题标记 /// /// /// /// [HttpPost] [Route("/DeleteTableQuestionMark/{param}")] public async Task DeleteTableQuestionMark(DeleteTableQuestionMarkInDto inDto, string param) { await _readingTaskQuestionMarkRepository.UpdatePartialFromQueryAsync(x => x.RowId == inDto.RowId, x => new ReadingTaskQuestionMark() { InstanceId = null, SeriesId = null, StudyId = null, MarkTool = string.Empty, // PicturePath = string.Empty, 稽查需要显示截图 NumberOfFrames = null, MeasureData = string.Empty, OrderMarkName = string.Empty, OtherInstanceId = null, OtherSeriesId = null, OtherStudyId = null, OtherMarkTool = string.Empty, OtherPicturePath = string.Empty, OtherNumberOfFrames = null, OtherMeasureData = string.Empty, }); return await _readingTaskQuestionMarkRepository.SaveChangesAsync(); } /// /// 保存表格问题标记 /// /// /// /// [HttpPost] [Route("/SaveTableQuestionMark/{param}")] public async Task SaveTableQuestionMark(SaveTableQuestionMarkInDto inDto, string param) { inDto.FristAddTaskId = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.TableQuestionId == inDto.TableQuestionId && x.RowId == inDto.RowId).Select(x => x.FristAddTaskId).FirstOrDefaultAsync(); inDto.FristAddTaskId = inDto.FristAddTaskId == null ? inDto.VisitTaskId : inDto.FristAddTaskId; var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); await _readingTableQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId && x.RowId == inDto.RowId.Value && x.TableQuestionId == inDto.TableQuestionId); await _readingTableQuestionAnswerRepository.AddAsync(new ReadingTableQuestionAnswer() { Answer = inDto.Answer, QuestionId = inDto.QuestionId, TableQuestionId = inDto.TableQuestionId, VisitTaskId = inDto.VisitTaskId, TrialId = visitTaskInfo.TrialId, RowIndex = inDto.RowIndex, RowId = inDto.RowId.Value, }); await _readingTaskQuestionMarkRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId && x.RowId == inDto.RowId.Value && x.TableQuestionId == inDto.TableQuestionId); var readingTaskQuestionMark = _mapper.Map(inDto); await _readingTaskQuestionMarkRepository.AddAsync(readingTaskQuestionMark); await _readingTaskQuestionMarkRepository.SaveChangesAsync(); await _readingCalculateService.CalculateTask(new CalculateTaskInDto() { IsChangeOtherTask = false, VisitTaskId = inDto.VisitTaskId, ComputationTrigger = (ComputationTrigger)int.Parse(param), }); return inDto; } /// /// 获取既往病灶的OtherPicture /// /// /// [HttpPost] public async Task> GetPreviousOtherPicturePath(GetPreviousOtherPicturePathInDto inDto) { List result = new List() { }; if (inDto.RowId != null) { var rowinfo = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.RowId).FirstNotNullAsync(); var taskInfoList = await _generalCalculateService.GetReadingReportTaskList(rowinfo.VisitTaskId); var visitTaskIds = taskInfoList.Where(x => x.VisitTaskId != rowinfo.VisitTaskId).Select(x => x.VisitTaskId).ToList(); result = await _readingTableAnswerRowInfoRepository.Where(x => x.QuestionId == rowinfo.QuestionId && x.RowIndex == rowinfo.RowIndex && visitTaskIds.Contains(x.VisitTaskId)) .OrderBy(x => x.VisitTask.VisitTaskNum).Select(x => new GetPreviousOtherPicturePathOutDto() { VisitTaskId = x.VisitTaskId, PicturePath = x.OtherPicturePath, TaskBlindName = x.VisitTask.TaskBlindName }).ToListAsync(); } else if (inDto.VisitTaskId != null && inDto.QuestionType != null) { var taskInfoList = await _generalCalculateService.GetReadingReportTaskList(inDto.VisitTaskId.Value); var visitTaskIds = taskInfoList.Where(x => x.VisitTaskId != inDto.VisitTaskId.Value).Select(x => x.VisitTaskId).ToList(); result = await _readingTaskQuestionMarkRepository.Where(x => x.ReadingQuestionTrial.QuestionType == inDto.QuestionType && visitTaskIds.Contains(x.VisitTaskId)) .OrderBy(x => x.VisitTask.VisitTaskNum).Select(x => new GetPreviousOtherPicturePathOutDto() { VisitTaskId = x.VisitTaskId, PicturePath = x.OtherPicturePath, TaskBlindName = x.VisitTask.TaskBlindName }).ToListAsync(); } return result.Where(x => x.PicturePath != string.Empty && x.PicturePath != null).ToList(); } /// /// 提交自定义标记 /// /// /// [HttpPost] public async Task SubmitCustomTag(ReadingCustomTagDto inDto) { var entity = await _readingCustomTagRepository.InsertOrUpdateAsync(inDto, true); return ResponseOutput.Ok(entity.Id.ToString()); } /// /// 删除自定义标记 /// /// /// [HttpPost("{id:guid}")] public async Task DeleteCustomTag(Guid id) { var success = await _readingCustomTagRepository.DeleteFromQueryAsync(t => t.Id == id, true); return ResponseOutput.Ok(); } /// /// 获取自定义标记 /// /// /// [HttpPost] public async Task> GetCustomTag(GetCustomTagInDto inQuery) { var result = await _readingCustomTagRepository.Where(x => x.VisitTaskId == inQuery.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); result.AddRange(await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inQuery.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync()); return result; } /// /// 获取手册 /// /// /// [HttpPost] public async Task> GetManualList(GetManualListInDto inDto) { UserTypeEnum userType = (UserTypeEnum)_userInfo.UserTypeEnumInt; List canViewUserType = new List() { UserTypeEnum.IndependentReviewer, UserTypeEnum.IQC, }; return await _trialDocumentRepository.Where(x => x.TrialId == inDto.TrialId && x.TrialDocConfirmedUserList.Any(y => y.ConfirmUserId == _userInfo.UserRoleId && y.ConfirmTime != null) && x.NeedConfirmedUserTypeList.Any(y => y.NeedConfirmUserTypeId == _userInfo.UserTypeId)) .WhereIf(userType == UserTypeEnum.IndependentReviewer, t => t.FileType.Code == "2" || t.FileType.Code == "6") .WhereIf(userType == UserTypeEnum.IQC, t => t.FileType.Code == "4" || t.FileType.Code == "5") .WhereIf(!canViewUserType.Contains(userType), t => false) .IgnoreQueryFilters() .Select(x => new GetManualListOutDto() { Id = x.Id, Name = x.Name, Path = x.Path }).ToListAsync(); } /// /// 获取任务附加问题 /// /// /// [HttpPost] public async Task<(List, bool)> GetTaskAdditionalQuestion(GetTaskAdditionalQuestionInDto inDto) { var answerList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).IgnoreAutoIncludes().ToListAsync(); var taskInfo = await _visitTaskRepository.Where(x => inDto.VisitTaskId == x.Id).FirstNotNullAsync(); var result = await _readingQuestionTrialRepository.Where(x => x.IsAdditional && x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId).IgnoreAutoIncludes().IgnoreQueryFilters().ProjectTo(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder).ToListAsync(); result.ForEach(x => { var answer = answerList.Where(y => y.ReadingQuestionTrialId == x.Id).FirstOrDefault(); if (answer != null) { x.Answer = answer.Answer; } }); var resultData = result.Where(x => x.Type == "group").ToList(); resultData.ForEach(x => { x.Childrens = result.Where(y => y.GroupId == x.Id).ToList(); }); return (resultData, true); } /// /// 提交附加问题 /// /// /// [HttpPost] public async Task SubmitTaskAdditionalQuestion(SubmitTaskAdditionalQuestionInDto inDto) { var taskInfo = await _visitTaskRepository.Where(x => inDto.VisitTaskId == x.Id).FirstNotNullAsync(); var questionids = inDto.AnswerList.Select(x => x.QuestionId).ToList(); await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && questionids.Contains(x.ReadingQuestionTrialId)); await _readingTaskQuestionAnswerRepository.AddRangeAsync(inDto.AnswerList.Select(x => new ReadingTaskQuestionAnswer() { VisitTaskId = inDto.VisitTaskId, ReadingQuestionCriterionTrialId = taskInfo.TrialReadingCriterionId, Answer = x.Answer, ReadingQuestionTrialId = x.QuestionId, TrialId = taskInfo.TrialId, SubjectId = taskInfo.SubjectId }).ToList()); return await _readingTaskQuestionAnswerRepository.SaveChangesAsync(); } /// /// 维护任务关系 /// /// public async Task MaintainTaskRelated() { List relations = new List(); var visitList = await _visitTaskRepository.Where(x => x.PastResultTaskIds != "[]" && x.RelatedVisitTaskIds != "[]").Select(x => new { x.Id, x.RelatedVisitTaskIds, x.PastResultTaskIds }).ToListAsync(); List relatedIds = new List(); List PastResultds = new List(); foreach (var item in visitList) { try { PastResultds = JsonConvert.DeserializeObject>(item.PastResultTaskIds) ?? new List(); } catch (Exception) { PastResultds = new List(); } try { relatedIds = JsonConvert.DeserializeObject>(item.RelatedVisitTaskIds) ?? new List(); } catch (Exception) { relatedIds = new List(); } relations.AddRange(PastResultds.Select(x => new ReadingTaskRelation() { RelevanceTaskId = x, TaskId = item.Id, RelevanceType = RelevanceType.PastResult, })); relations.AddRange(relatedIds.Select(x => new ReadingTaskRelation() { RelevanceTaskId = x, TaskId = item.Id, RelevanceType = RelevanceType.Related, })); await _readingTaskRelationRepository.BatchDeleteNoTrackingAsync(x => x.TaskId == item.Id); } await _readingTaskRelationRepository.AddRangeAsync(relations); await _readingTaskRelationRepository.SaveChangesAsync(); } /// /// 修改计算问题 /// /// /// [HttpPost] [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task ChangeCalculationAnswer(ChangeCalculationAnswerInDto inDto) { var visitTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var questionAnswerList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); var tableQuestionAnswerList = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); var rowInfoList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); foreach (var item in inDto.QuestionAnswer) { if (questionAnswerList.Any(x => x.ReadingQuestionTrialId == item.QuestionId)) { await _readingTaskQuestionAnswerRepository.UpdatePartialFromQueryAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionTrialId == item.QuestionId, x => new ReadingTaskQuestionAnswer() { Answer = item.Answer, }); } else { await _readingTaskQuestionAnswerRepository.AddAsync(new ReadingTaskQuestionAnswer() { Answer = item.Answer, ReadingQuestionCriterionTrialId = visitTask.TrialReadingCriterionId, ReadingQuestionTrialId = item.QuestionId, SubjectId = visitTask.SubjectId, VisitTaskId = inDto.VisitTaskId, TrialId = visitTask.TrialId }); } } foreach (var item in inDto.TableQuestionAnswer.Where(x => x.RowId != null)) { if (tableQuestionAnswerList.Any(x => x.QuestionId == item.QuestionId && x.RowId == item.RowId && x.TableQuestionId == item.TableQuestionId)) { await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowId == item.RowId && x.TableQuestionId == item.TableQuestionId, x => new ReadingTableQuestionAnswer() { Answer = item.Answer, }); } else { var rowInfo = rowInfoList.Where(x => x.Id == item.RowId).FirstOrDefault() ?? new ReadingTableAnswerRowInfo(); await _readingTableQuestionAnswerRepository.AddAsync(new ReadingTableQuestionAnswer() { Answer = item.Answer, QuestionId = item.QuestionId, TableQuestionId = item.TableQuestionId, RowIndex = rowInfo.RowIndex, RowId = rowInfo.Id, VisitTaskId = inDto.VisitTaskId, TrialId = visitTask.TrialId }); } } await _readingTableQuestionAnswerRepository.SaveChangesAsync(); } /// /// 阅读临床数据 /// /// /// [HttpPost] [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task ReadClinicalData(ReadClinicalDataInDto inDto) { await _visitTaskRepository.UpdatePartialFromQueryAsync(inDto.VisitTaskId, x => new VisitTask { IsReadClinicalData = true }); await _visitTaskRepository.SaveChangesAsync(); } /// /// 添加默认值到任务里面 /// /// [NonDynamicMethod] public async Task AddDefaultValueToTask(Guid visitTaskId) { var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); var questions = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == visitTaskInfo.TrialReadingCriterionId).ToListAsync(); questions = questions.Where(x => !x.DefaultValue.IsNullOrEmpty()).ToList(); var taskAnswerIds = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Select(x => x.ReadingQuestionTrialId).ToListAsync(); questions = questions.Where(x => !taskAnswerIds.Contains(x.Id)).ToList(); List questionAnswers = questions.Select(x => new ReadingTaskQuestionAnswer() { Answer = x.DefaultValue, Id = NewId.NextGuid(), ReadingQuestionCriterionTrialId = visitTaskInfo.TrialReadingCriterionId, ReadingQuestionTrialId = x.Id, SubjectId = visitTaskInfo.SubjectId, TrialId = visitTaskInfo.TrialId, VisitTaskId = visitTaskId, }).ToList(); await _readingTaskQuestionAnswerRepository.AddRangeAsync(questionAnswers); await _readingTaskQuestionAnswerRepository.SaveChangesAsync(); } #region 阅片页面 关联信息查询 以及基本验证 /// /// 根据任务ID获取ReadingTool /// /// /// [HttpPost] public async Task GetReadingTool(GetReadingToolInDto indto) { var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == indto.VisitTaskId).FirstNotNullAsync(); var criterionTrialInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == visitTaskInfo.TrialReadingCriterionId).FirstNotNullAsync(); GetReadingToolOutDto result = new GetReadingToolOutDto() { TrialReadingCriterionId = visitTaskInfo.TrialReadingCriterionId, ReadingTool = criterionTrialInfo.ReadingTool, CriterionType = criterionTrialInfo.CriterionType, }; return result; } /// /// 获取关联的阅片任务 /// /// /// [HttpPost] public async Task<(List, object)> GetRelatedVisitTask(GetRelatedVisitTaskInDto inDto) { var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); var baselineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == taskInfo.SubjectId && x.IsBaseLine && !x.IsLostVisit).Select(x => x.Id).FirstNotNullAsync(); var taskQuery = _visitTaskRepository.Where(x => (x.TrialId == taskInfo.TrialId && x.SubjectId == taskInfo.SubjectId && x.ArmEnum == taskInfo.ArmEnum && x.DoctorUserId == taskInfo.DoctorUserId && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.TaskState == TaskState.Effect && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.ReadingCategory == ReadingCategory.Visit) || x.Id == inDto.VisitTaskId) .WhereIf(taskInfo.TrialReadingCriterion.IsReadingTaskViewInOrder != ReadingOrder.SubjectRandom, x => (x.VisitTaskNum <= taskInfo.VisitTaskNum && x.ReadingTaskState == ReadingTaskState.HaveSigned) || x.Id == inDto.VisitTaskId); if (taskInfo.ReadingTaskState == ReadingTaskState.HaveSigned) { taskQuery = _visitTaskRepository.Where(x => taskInfo.RelatedVisitTaskIdList.Contains(x.Id) || x.Id == taskInfo.Id); } var result = await taskQuery.Include(x => x.Subject).OrderBy(x => x.VisitTaskNum).ThenBy(x => x.TaskState) .Select(x => new GetRelatedVisitTaskOutDto() { TaskBlindName = x.TaskBlindName, TaskName = x.TaskName, ReadingTaskState = x.ReadingTaskState, VisitId = x.SourceSubjectVisitId, SubjectCode = x.Subject.Code, VisitTaskId = x.Id, VisitTaskNum = x.VisitTaskNum, IsBaseLineTask = x.SourceSubjectVisitId == baselineVisitId, IsCurrentTask = x.Id == inDto.VisitTaskId, IsConvertedTask = x.IsConvertedTask, IsFirstChangeTask = x.BeforeConvertedTaskId != null, IsExistUnprocessedFeedback = x.UserFeedBackList.Any(y => y.State == 0), }).ToListAsync(); switch (taskInfo.TrialReadingCriterion.IsReadingTaskViewInOrder) { case ReadingOrder.InOrder: /// 有序不做处理 break; case ReadingOrder.Random: result = result.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToList(); break; case ReadingOrder.SubjectRandom: // 受试者随机 当前任务为第一个 其他的 随机 var self = result.Where(x => x.VisitTaskId == inDto.VisitTaskId).FirstOrDefault(); Random random = new Random(); var otherList = result.Where(x => x.VisitTaskId != inDto.VisitTaskId).OrderBy(x => random.Next()).ToList(); var newList = new List() { }; newList.AddRange(otherList); newList.Add(self); result = newList; break; } var visitaskIds = result.Select(x => x.VisitTaskId).ToList(); var otherStudys = await _readingTableAnswerRowInfoRepository.Where(x => visitaskIds.Contains(x.VisitTaskId)) .Where(x => x.CTSeriesId != null && x.PTSeriesId != null) .Select(x => new { x.OtherStudyId, x.CTSeriesId, x.PTSeriesId, x.VisitTaskId, x.UpdateTime }).ToListAsync(); foreach (var item in result) { var clinicalDataList = await _readingClinicalDataService.GetClinicalDataList(new GetReadingOrTaskClinicalDataListInDto() { SubjectId = taskInfo.SubjectId, TrialId = taskInfo.TrialId, VisitTaskId = item.VisitTaskId, }); item.IsExistsClinicalData = clinicalDataList.Count > 0; var otherStudy = otherStudys.Where(x => x.VisitTaskId == item.VisitTaskId).OrderByDescending(x => x.UpdateTime).FirstOrDefault(); if (otherStudy != null) { item.PTSeriesId = otherStudy.PTSeriesId; item.CTSeriesId = otherStudy.CTSeriesId; item.OtherStudyId = otherStudy.OtherStudyId; } } return (result, new { ReadingTaskState = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.ReadingTaskState).FirstOrDefaultAsync() }); } /// /// 获取既往任务名称和编号 /// /// [HttpPost] public async Task> GetReadingPastResultList(GetReadingPastResultListInDto inDto) { var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var taskQuery = _visitTaskRepository.Where(x => x.TrialId == taskInfo.TrialId && x.SubjectId == taskInfo.SubjectId && x.VisitTaskNum < taskInfo.VisitTaskNum && x.ArmEnum == taskInfo.ArmEnum && x.Id != inDto.VisitTaskId && x.DoctorUserId == taskInfo.DoctorUserId && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.TaskState == TaskState.Effect && x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.ReadingCategory == taskInfo.ReadingCategory ); if (taskInfo.ReadingTaskState == ReadingTaskState.HaveSigned) { taskQuery = _visitTaskRepository.Where(x => taskInfo.PastResultTaskIdList.Contains(x.Id)); } var readingPastResultList = await taskQuery.OrderBy(x => x.VisitTaskNum).ThenBy(x => x.TaskState).Select(x => new GetReadingPastResultListOutDto() { VisitTaskId = x.Id, TaskBlindName = x.TaskBlindName, TaskName = x.TaskName, ReadModuleVisitId = x.ReadModule != null ? x.ReadModule.SubjectVisitId : null, VisitName = x.SourceSubjectVisit != null ? x.SourceSubjectVisit.VisitName : x.ReadModule == null ? string.Empty : x.ReadModule.SubjectVisit.VisitName, VisitBlindName = x.TaskBlindName, VisitTaskNum = x.VisitTaskNum, JudgeResultArm = x.JudgeResultTask == null ? null : x.JudgeResultTask.ArmEnum, }).ToListAsync(); foreach (var item in readingPastResultList) { if (item.ReadModuleVisitId != null) { item.VisitBlindName = (await _visitTaskRepository.Where(x => x.SourceSubjectVisitId == item.ReadModuleVisitId && x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate).Select(x => x.TaskBlindName).FirstOrDefaultAsync()) ?? string.Empty; } } return readingPastResultList; } /// /// 获取阅片的受试者信息 /// /// /// [HttpPost] public async Task GetReadingSubjectInfo(GetReadingSubjectInfoInDto inDto) { var visitTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var subjectCode = await _subjectRepository.Where(x => x.Id == visitTask.SubjectId).Select(x => x.Code).FirstOrDefaultAsync(); var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == visitTask.TrialReadingCriterionId).Select(x => new { x.IsReadingShowPreviousResults, x.IsReadingShowSubjectInfo }).FirstNotNullAsync(); var trialInfo = await _trialRepository.Where(x => x.Id == visitTask.TrialId).Select(x => new { x.ClinicalInformationTransmissionEnum, }).FirstOrDefaultAsync(); return new GetReadingSubjectInfoOutDto() { VisitTaskId = visitTask.Id, SubjectId = visitTask.SubjectId, SubjectCode = visitTask.BlindSubjectCode.IsNullOrEmpty() ? subjectCode ?? string.Empty : visitTask.BlindSubjectCode, ReadingCategory = visitTask.ReadingCategory, TaskBlindName = visitTask.TaskBlindName, IsReadingShowPreviousResults = criterionInfo.IsReadingShowPreviousResults, IsReadingShowSubjectInfo = criterionInfo.IsReadingShowSubjectInfo, }; } /// /// 验证是否为基线访视任务 /// /// /// /// private async Task VerifyIsBaseLineTask(Guid visitTaskId) { var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); if (taskinfo.ReadingCategory != ReadingCategory.Visit) { throw new BusinessValidationFailedException(_localizer["ReadingImage_NotVisit"]); } if (await _subjectVisitRepository.AnyAsync(x => x.Id == taskinfo.SourceSubjectVisitId && x.IsBaseLine)) { throw new BusinessValidationFailedException(_localizer["ReadingImage_CantSplit"]); } } /// /// 验证任务是否签名 /// /// /// /// private async Task VerifyTaskIsSign(Guid visitTaskid) { var taskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskid).FirstNotNullAsync(); if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskid && x.ReadingTaskState == ReadingTaskState.HaveSigned)) { throw new BusinessValidationFailedException(_localizer["ReadingImage_BeSigned"]); } if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskid && x.TaskState != TaskState.Effect)) { throw new BusinessValidationFailedException(_localizer["ReadingImage_Beinvalid"]); } if (await _visitTaskRepository.AnyAsync(x => x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.IsAnalysisCreate && taskInfo.IsAnalysisCreate && x.SubjectId == taskInfo.SubjectId && x.TaskState == TaskState.Effect && ((x.ReReadingApplyState == ReReadingApplyState.DocotorHaveApplyed && x.DoctorUserId == taskInfo.DoctorUserId) || x.ReReadingApplyState == ReReadingApplyState.TrialGroupHaveApplyed) )) { throw new BusinessValidationFailedException(_localizer["ReadingImage_PresenceReview"]); } } #endregion #region 访视任务 - Dicom 阅片 表格问题相关查询 /// /// 获取DIcom阅片问题答案 /// /// /// [HttpPost] public async Task<(List, object)> GetDicomReadingQuestionAnswer(GetDicomReadingQuestionAnswerInDto inDto) { //await AddDefaultValueToTask(inDto.VisitTaskId); var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var result = await GetReadingQuestion(taskInfo.TrialReadingCriterionId, taskInfo.Id, inDto.QuestionClassify, inDto.GroupClassifyList); return (result, new { QuestionMarkInfoList = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(), ReadingTaskState = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.ReadingTaskState).FirstOrDefaultAsync() }); } /// /// 获取阅片外层问题 /// /// /// /// /// /// [NonDynamicMethod] public async Task> GetReadingQuestion(Guid trialReadingCriterionId, Guid? visitTaskId, QuestionClassify? questionClassify, List? groupClassifyList) { var criterionIdInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == trialReadingCriterionId).FirstNotNullAsync(); var groupIds = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == trialReadingCriterionId && (x.Type == ReadingQestionType.Table || x.Type == ReadingQestionType.BasicTable)).Select(x => x.GroupId).Distinct().ToListAsync(); var questionIds = await _readingQuestionTrialRepository .Where(x => x.IsShowInDicom) .Where(x => groupIds.Contains(x.GroupId)).Select(x => x.Id).ToListAsync(); //排除表格问题 以及在表格问题分组的外层问题 var questions = await _readingQuestionTrialRepository .Where(x => !questionIds.Contains(x.Id)) .WhereIf(questionClassify != null, x => x.QuestionClassify == questionClassify) .Where(x => x.IsShowInDicom && x.ReadingQuestionCriterionTrialId == trialReadingCriterionId && x.Type != ReadingQestionType.Table && x.Type != ReadingQestionType.BasicTable) .ProjectTo(_mapper.ConfigurationProvider, new { isEn_Us = _userInfo.IsEn_Us }).OrderBy(x => x.ShowOrder).ToListAsync(); var answers = new List(); var lastTaskAnswer = new List(); if (visitTaskId != null) { answers = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).ToListAsync(); var taskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); var laskTaskId = await _visitTaskRepository.Where(x => (x.SubjectId == taskInfo.SubjectId && x.TaskState == TaskState.Effect && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.DoctorUserId == taskInfo.DoctorUserId && x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.VisitTaskNum < taskInfo.VisitTaskNum && x.ArmEnum == taskInfo.ArmEnum && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.ReadingCategory == ReadingCategory.Visit) || x.Id == taskInfo.BeforeConvertedTaskId ).OrderByDescending(x => x.VisitTaskNum).Select(x => x.Id).FirstOrDefaultAsync(); if (criterionIdInfo.IsReadingTaskViewInOrder != ReadingOrder.InOrder) { // 无序的话 不要查 laskTaskId = Guid.NewGuid(); } lastTaskAnswer = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == laskTaskId).ToListAsync(); var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).ProjectTo(_mapper.ConfigurationProvider).FirstNotNullAsync(); if (taskinfo.VisitTaskNum == 0) { questions = questions.Where(x => x.LimitShow == LimitShow.AllShow || x.LimitShow == LimitShow.BaseLineShow).ToList(); } else { questions = questions.Where(x => x.LimitShow == LimitShow.AllShow || x.LimitShow == LimitShow.FollowShow).ToList(); } questions.ForEach(x => { x.CrterionDictionaryGroup = ReadingCommon.GetCrterionDictionaryGroup(taskinfo.IsConvertedTask); }); if (taskinfo.IsConvertedTask && taskinfo.BeforeConvertedTaskId != null) { questions.ForEach(x => { x.IsFirstChangeTask = true; }); } } else { var crterionDictionaryGroup = new List() { CrterionDictionaryGroup.General, CrterionDictionaryGroup.BeforeConvert }; questions.ForEach(x => { x.CrterionDictionaryGroup = crterionDictionaryGroup; }); } //排除表格问题 同时排除组问题 var groupids = questions.Where(x => x.Type != ReadingQestionType.Group).Select(x => x.GroupId).ToList(); var result = questions.Where(x => x.Type == ReadingQestionType.Group && groupids.Contains(x.Id)) .WhereIf(groupClassifyList != null, x => x.GroupClassify != null && groupClassifyList != null && groupClassifyList.Contains(x.GroupClassify.Value)) .ToList(); foreach (var item in result) { GetDicomReadingAnswer(item, questions, answers, lastTaskAnswer); } return result; } private void GetDicomReadingAnswer(DicomReadingQuestionAnswer item, List questions, List answers, List lastTaskAnswers) { var answer = answers.Where(x => x.ReadingQuestionTrialId == item.Id).Select(x => x.Answer).FirstIsNullReturnEmpty(); item.Answer = answer.IsNullOrEmpty() ? item.DefaultValue : answer; var lastTaskAnswer = lastTaskAnswers.Where(x => x.ReadingQuestionTrialId == item.Id).Select(x => x.Answer).FirstIsNullReturnEmpty(); item.LastTaskAnswer = lastTaskAnswer.IsNullOrEmpty() ? item.DefaultValue : lastTaskAnswer; item.Childrens = questions.Where(x => x.ParentId == item.Id || (x.GroupId == item.Id && x.ParentId == null)).ToList(); if (item.Childrens != null && item.Childrens.Count > 0) { foreach (var question in item.Childrens) { GetDicomReadingAnswer(question, questions, answers, lastTaskAnswers); } } } /// /// 获取阅片报告 /// /// /// [HttpPost] public async Task GetReadingReportEvaluation(GetReadingReportEvaluationInDto indto) { return await _readingCalculateService.GetReadingReportEvaluation(indto); } /// /// 获取表格答案行信息 /// /// /// /// (QuestionId) 可为空 /// /// [HttpGet] public async Task> GetTableAnswerRowInfoList(GetTableAnswerRowInfoInDto inDto) { var result = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId) .WhereIf(inDto.QuestionId != null, x => x.QuestionId == inDto.QuestionId) .ProjectTo(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex) .ToListAsync(); //var tableQuestionMarkList = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); //result.ForEach(x => //{ // x.TableQuestionMarkList = tableQuestionMarkList.Where(y => y.RowId == x.RowId).ToList(); //}); var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider).FirstNotNullAsync(); if (taskInfo.IsConvertedTask && taskInfo.BeforeConvertedTaskId != null) { result.ForEach(x => { x.IsFirstChangeTask = true; }); } result.ForEach(x => { x.OrderMarkName = x.OrderMark + x.RowIndexNum.GetLesionMark(); }); var questionMark = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); questionMark.ForEach(x => { x.IsFirstChangeTask = x.VisitTaskId == inDto.VisitTaskId; }); result.AddRange(questionMark); result = result.OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex).ThenBy(x => x.OrderMarkName).ToList(); return result; } /// /// 获取表格问题及答案(2022-08-26) /// /// /// [HttpPost] public async Task<(GetReadingQuestionAndAnswerOutDto, object)> GetReadingQuestionAndAnswer(GetReadingQuestionAndAnswerInDto inDto) { //await AddDefaultValueToTask(inDto.VisitTaskId); var result = new GetReadingQuestionAndAnswerOutDto(); var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == taskinfo.TrialReadingCriterionId).FirstNotNullAsync(); result.ReadingTaskState = taskinfo.ReadingTaskState; var baseLineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == taskinfo.SubjectId && x.IsBaseLine).Select(x => x.Id).FirstOrDefaultAsync(); result.IsBaseLineTask = taskinfo.SourceSubjectVisitId == baseLineVisitId; var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var tableAnswers = await _readingTableQuestionAnswerRepository .ProjectTo(_mapper.ConfigurationProvider) .Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); var tableAnsweRowInfos = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); var organIds = tableAnsweRowInfos.Where(x => x.OrganInfoId != null).Select(x => x.OrganInfoId).Distinct().ToList(); var organList = await _organInfoRepository.Where(x => organIds.Contains(x.Id)).ToListAsync(); var questionPage = await GetReadingTableQuestion( new GetReadingTableQuestionOrAnswerInDto() { TrialReadingCriterionId = taskinfo.TrialReadingCriterionId, TaskId = inDto.VisitTaskId, TableAnswers = tableAnswers, TableAnsweRowInfos = tableAnsweRowInfos, OrganInfos = organList, QuestionClassify = inDto.QuestionClassify, } ); result.SinglePage = questionPage.SinglePage; result.MultiPage = questionPage.MultiPage; result.PublicPage = questionPage.PublicPage; result.BlindName = visitTaskInfo.TaskBlindName; result.TaskNum = visitTaskInfo.VisitTaskNum; result.QuestionMarkInfoList = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); var spleenLength = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionTrial.QuestionType == QuestionType.SpleenLength).Select(x => x.Answer).FirstOrDefaultAsync(); return (result, new { readingTaskState = visitTaskInfo.ReadingTaskState, FormType = criterionInfo.FormType, TaskNum = visitTaskInfo.VisitTaskNum, SpleenLength = spleenLength, }); ; } /// /// 获取自定义问题以及答案 /// /// /// [HttpPost] public async Task<(GetReadingTableQuestionOutDto, object)> GetCustomTableQuestionAnswer(GetCustomTableQuestionAnswerInDto inDto) { //await _readingCalculateService.AddTaskLesionAnswerFromLastTask(new AddTaskLesionAnswerFromLastTaskInDto() { //VisitTaskId=inDto.VisitTaskId //}); var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.SourceSubjectVisit).FirstNotNullAsync(); var tableAnswers = await _readingTableQuestionAnswerRepository .ProjectTo(_mapper.ConfigurationProvider) .Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); var tableAnsweRowInfos = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); var organIds = tableAnsweRowInfos.Where(x => x.OrganInfoId != null).Select(x => x.OrganInfoId).Distinct().ToList(); var organList = await _organInfoRepository.Where(x => organIds.Contains(x.Id)).ToListAsync(); // 删除病灶不删除病灶标记 所以查询question的时候 已经删除的病灶对应的标记的信息要排除 var rowids = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.Id).ToListAsync(); List rowidnull = rowids.Select(x => (Guid?)x).ToList(); var tableQuestionMarkList = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.RowId == null || rowidnull.Contains(x.RowId) ).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); return (await GetReadingTableQuestion( new GetReadingTableQuestionOrAnswerInDto() { TrialReadingCriterionId = taskInfo.TrialReadingCriterionId, TaskId = taskInfo.Id, TableAnswers = tableAnswers, TableAnsweRowInfos = tableAnsweRowInfos, IsGetallQuestion = true, OrganInfos = organList, QuestionClassify = inDto.QuestionClassify, } ), new { IsBaseline = taskInfo.SourceSubjectVisit != null && taskInfo.SourceSubjectVisit.IsBaseLine, ReadingTaskState = taskInfo.ReadingTaskState, QuestionMarkInfoList = tableQuestionMarkList, }); } /// /// 获取表格问题及答案 只返回表格问题(任务和标准) /// /// /// [NonDynamicMethod] public async Task GetReadingTableQuestion(GetReadingTableQuestionOrAnswerInDto inDto) { var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).FirstNotNullAsync(); var tableQuestionMarkList = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.TaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); var qusetionList = await _readingQuestionTrialRepository .Where(x => x.IsShowInDicom) .WhereIf(inDto.QuestionClassify != null, x => x.QuestionClassify == inDto.QuestionClassify) .Where(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId).ProjectTo(_mapper.ConfigurationProvider, new { isEn_Us = _userInfo.IsEn_Us }).OrderBy(x => x.ShowOrder).ToListAsync(); var taskInfo = new VisitTaskDto(); if (inDto.TaskId != null) { taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.TaskId).ProjectTo(_mapper.ConfigurationProvider).FirstNotNullAsync(); if (taskInfo.VisitTaskNum == 0) { qusetionList = qusetionList.Where(x => x.LimitShow == LimitShow.AllShow || x.LimitShow == LimitShow.BaseLineShow).ToList(); } else { qusetionList = qusetionList.Where(x => x.LimitShow == LimitShow.AllShow || x.LimitShow == LimitShow.FollowShow).ToList(); } qusetionList.ForEach(x => { x.CrterionDictionaryGroup = ReadingCommon.GetCrterionDictionaryGroup(taskInfo.IsConvertedTask); }); } else { qusetionList.ForEach(x => { x.CrterionDictionaryGroup = new List() { CrterionDictionaryGroup.General, CrterionDictionaryGroup.BeforeConvert }; }); } //是否是预览 if (inDto.IsGetPreview == false) { switch (criterionInfo.ReadingTool) { case ReadingTool.Dicom: // 是否获取所有问题 if (inDto.IsGetallQuestion) { qusetionList = qusetionList.Where(x => x.IsShowInDicom).OrderBy(x => x.ShowOrder).ToList(); } else { List types = new List() { ReadingQestionType.Table, ReadingQestionType.BasicTable, ReadingQestionType.Group, }; qusetionList = qusetionList.Where(x => x.IsShowInDicom || types.Contains(x.Type)).OrderBy(x => x.ShowOrder).ToList(); if (inDto.TaskId != null) { if (taskInfo.IsConvertedTask) { qusetionList = qusetionList.Where(x => x.ConvertShowType == ConvertShowType.All || x.ConvertShowType == ConvertShowType.AfterShow).OrderBy(x => x.ShowOrder).ToList(); } else { qusetionList = qusetionList.Where(x => x.ConvertShowType == ConvertShowType.All || x.ConvertShowType == ConvertShowType.BeforeShow).OrderBy(x => x.ShowOrder).ToList(); } } var usedGuropIds = qusetionList.Where(x => x.Type == ReadingQestionType.Table || x.Type == ReadingQestionType.BasicTable).Select(x => x.GroupId).ToList(); qusetionList = qusetionList.Where(x => usedGuropIds.Contains(x.Id) || usedGuropIds.Contains(x.GroupId)).ToList(); } break; case ReadingTool.NoDicom: qusetionList = qusetionList.Where(x => x.IsShowInDicom).OrderBy(x => x.ShowOrder).ToList(); break; } } var answers = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.TaskId).ToListAsync(); qusetionList.ForEach(x => { var answer = answers.Where(y => y.ReadingQuestionTrialId == x.Id).Select(x => x.Answer).FirstOrDefault() ?? string.Empty; x.Answer = answer.IsNullOrEmpty() ? x.DefaultValue : answer; }); #endregion var groupList = new List(); var qusetionIds = qusetionList.Select(x => x.Id).ToList(); var tableQuestionList = await _readingTableQuestionTrialRepository .WhereIf(inDto.QuestionClassify != null, x => x.QuestionClassify == inDto.QuestionClassify) .Where(x => qusetionIds.Contains(x.ReadingQuestionId)) .ProjectTo(_mapper.ConfigurationProvider, new { isEn_Us = _userInfo.IsEn_Us }) .OrderBy(x => x.ShowOrder).ToListAsync(); var result = new GetReadingTableQuestionOutDto(); List baseLineTableAnswer = new List(); List lastTaskTableAnswer = new List(); bool isFirstChangeTask = false; if (inDto.TaskId != null) { taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.TaskId).ProjectTo(_mapper.ConfigurationProvider).FirstNotNullAsync(); // 取基线 var baseLineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == taskInfo.SubjectId && x.IsBaseLine).Select(x => x.Id).FirstNotNullAsync(); var baselineTaskId = await _visitTaskRepository.Where(x => x.SourceSubjectVisitId == baseLineVisitId && x.ArmEnum == taskInfo.ArmEnum && x.DoctorUserId == taskInfo.DoctorUserId && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.TaskState == TaskState.Effect && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId ).Select(x => x.Id).FirstNotNullAsync(); baseLineTableAnswer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == baselineTaskId).Include(x => x.ReadingTableQuestionTrial).ToListAsync(); var laskTaskId = await _visitTaskRepository.Where(x => (x.SubjectId == taskInfo.SubjectId && x.TaskState == TaskState.Effect && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.DoctorUserId == taskInfo.DoctorUserId && x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.VisitTaskNum < taskInfo.VisitTaskNum && x.ArmEnum == taskInfo.ArmEnum && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.ReadingCategory == ReadingCategory.Visit) || x.Id == taskInfo.BeforeConvertedTaskId ).OrderByDescending(x => x.VisitTaskNum).Select(x => x.Id).FirstOrDefaultAsync(); if (criterionInfo.IsReadingTaskViewInOrder != ReadingOrder.InOrder) { // 无序的话 不要查 laskTaskId = Guid.NewGuid(); } lastTaskTableAnswer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == laskTaskId).Include(x => x.ReadingTableQuestionTrial).ToListAsync(); if (taskInfo.BeforeConvertedTaskId != null) { isFirstChangeTask = true; } } if (criterionInfo.FormType == FormType.MultiplePage) { qusetionList = qusetionList.Where(x => x.ReadingCriterionPageId != null).ToList(); var readingCriterionPageIds = qusetionList.OrderBy(x => x.PageShowOrder).Select(x => x.ReadingCriterionPageId).Distinct().ToList(); foreach (var item in readingCriterionPageIds) { var newPageQusetionList = qusetionList.Where(x => x.ReadingCriterionPageId == item).ToList(); var firstData = newPageQusetionList.FirstOrDefault(); var page = new TrialReadQuestionData() { PageName = firstData!.PageName, IsPage = true, IsPublicPage = firstData.IsPublicPage, }; var pageGroupList = newPageQusetionList.Where(x => x.Type == ReadingQestionType.Group).ToList(); pageGroupList.ForEach(x => { FindChildQuestion(x, newPageQusetionList, tableQuestionList, inDto.TableAnswers, inDto.TableAnsweRowInfos, inDto.OrganInfos, baseLineTableAnswer, isFirstChangeTask, lastTaskTableAnswer, tableQuestionMarkList, inDto.TaskId); }); page.Childrens = pageGroupList.Where(x => !(x.Type == ReadingQestionType.Group && x.Childrens.Count == 0)).ToList(); groupList.Add(page); } result.PublicPage = groupList.Where(x => x.IsPublicPage!.Value).ToList(); result.MultiPage = groupList.Where(x => !x.IsPublicPage!.Value).ToList(); } else { qusetionList = qusetionList.Where(x => x.ReadingCriterionPageId == null).ToList(); groupList = qusetionList.Where(x => x.Type == ReadingQestionType.Group).ToList(); groupList.ForEach(x => { FindChildQuestion(x, qusetionList, tableQuestionList, inDto.TableAnswers, inDto.TableAnsweRowInfos, inDto.OrganInfos, baseLineTableAnswer, isFirstChangeTask, lastTaskTableAnswer, tableQuestionMarkList, inDto.TaskId); }); groupList = groupList.Where(x => !(x.Type == ReadingQestionType.Group && x.Childrens.Count == 0)).ToList(); result.SinglePage = groupList; } return result; } /// /// 获取子元素 /// /// /// /// /// /// /// /// /// /// /// private async void FindChildQuestion(TrialReadQuestionData item, List questionlists, List tableQuestionLists, List tableAnswers, List tableAnsweRowInfos, List organInfos, List baseLineTableAnswer, bool isFirstChangeTask, List lastTaskTableAnswer, List TableQuestionMarkList, Guid? TaskId) { item.Childrens = questionlists.Where(x => x.ParentId == item.Id || (x.GroupId == item.Id && x.ParentId == null)).ToList(); item.TableQuestions = new TrialReadTableQuestion(); item.TableQuestions.Questions = tableQuestionLists.Where(x => x.ReadingQuestionId == item.Id).OrderBy(x => x.ShowOrder).ToList(); item.TableQuestions.Questions.ForEach(x => { x.RelationQuestions = _mapper.Map>(tableQuestionLists.Where(z => (z.DependParentId ?? default(Guid)) == x.Id)); x.RelationQuestions.ForEach(y => { y.Childrens = new List(); y.GroupName = string.Empty; y.ImageCount = 0; y.ParentId = item.Id; y.LesionType = item.LesionType; y.RelationQuestions = new List(); }); }); var thisAnswer = tableAnswers.Where(x => x.QuestionId == item.Id).ToList(); var orders = thisAnswer.Select(x => x.RowIndex).Distinct().OrderBy(x => x).ToList(); item.TableQuestions.Answers = new List>(); var needChangeType = new List() { QuestionMark.Organ, QuestionMark.Location, QuestionMark.Part, }; foreach (var x in orders) { Dictionary answers = new Dictionary(); var rowInfo = tableAnsweRowInfos.First(y => y.RowIndex == x && y.QuestionId == item.Id); if (rowInfo == null) { continue; } var rowAnswer = thisAnswer.Where(y => y.RowId == rowInfo.Id).OrderBy(y => y.ShowOrder).ToList(); var organInfo = organInfos.Where(x => x.Id == rowInfo.OrganInfoId).FirstOrDefault(); rowAnswer.ForEach(z => { if (organInfo != null && needChangeType.Contains(z.QuestionMark)) { if (_userInfo.IsEn_Us) { switch (z.QuestionMark) { case QuestionMark.Organ: answers.Add(z.TableQuestionId.ToString(), organInfo.TULOCEN); break; case QuestionMark.Location: if (organInfo.IsCanEditPosition) { answers.Add(z.TableQuestionId.ToString(), z.Answer); } else { answers.Add(z.TableQuestionId.ToString(), organInfo.TULATEN); } break; case QuestionMark.Part: answers.Add(z.TableQuestionId.ToString(), organInfo.PartEN); break; } } else { switch (z.QuestionMark) { case QuestionMark.Organ: answers.Add(z.TableQuestionId.ToString(), organInfo.TULOC); break; case QuestionMark.Location: if (organInfo.IsCanEditPosition) { answers.Add(z.TableQuestionId.ToString(), z.Answer); } else { answers.Add(z.TableQuestionId.ToString(), organInfo.TULAT); } break; case QuestionMark.Part: answers.Add(z.TableQuestionId.ToString(), organInfo.Part); break; } } } else { answers.Add(z.TableQuestionId.ToString(), z.Answer); } }); answers.Add("LesionType", rowInfo.LesionType.GetEnumNullInt()); answers.Add("BlindName", rowInfo.BlindName); answers.Add("IsFirstChangeTask", isFirstChangeTask.ToString()); answers.Add("FromMark", rowInfo.FromMark); answers.Add("IsDicomReading", rowInfo.IsDicomReading.ToString()); answers.Add("MeasureData", rowInfo == null ? string.Empty : rowInfo.MeasureData); answers.Add("OtherMeasureData", rowInfo == null || rowInfo.OtherMeasureData == null ? string.Empty : rowInfo.OtherMeasureData.ToString()); answers.Add("OtherStudyId", rowInfo == null || rowInfo.OtherStudyId == null ? string.Empty : rowInfo.OtherStudyId.ToString()); answers.Add("OtherSeriesId", rowInfo == null || rowInfo.OtherSeriesId == null ? string.Empty : rowInfo.OtherSeriesId.ToString()); answers.Add("OtherInstanceId", rowInfo == null || rowInfo.OtherInstanceId == null ? string.Empty : rowInfo.OtherInstanceId.ToString()); answers.Add("OtherPicturePath", rowInfo == null || rowInfo.OtherPicturePath == null ? string.Empty : rowInfo.OtherPicturePath.ToString()); answers.Add("OtherNumberOfFrames", rowInfo == null || rowInfo.OtherNumberOfFrames == null ? string.Empty : rowInfo.OtherNumberOfFrames.ToString()); answers.Add("OtherMarkTool", rowInfo == null || rowInfo.OtherMarkTool == null ? string.Empty : rowInfo.OtherMarkTool.ToString()); answers.Add("RowIndex", x.ToString()); JsonSerializerSettings settings = new JsonSerializerSettings { FloatParseHandling = FloatParseHandling.Double, }; answers.Add("TableQuestionMarkList", rowInfo == null ? "[]" : JsonConvert.SerializeObject(TableQuestionMarkList.Where(x => x.RowId == rowInfo.Id).ToList(), settings)); answers.Add("RowId", rowInfo == null ? string.Empty : rowInfo.Id.ToString()); answers.Add("MarkTool", rowInfo.MarkTool); answers.Add("StudyId", rowInfo.StudyId.ToString()); answers.Add("OrganInfoId", rowInfo.OrganInfoId.ToString()); answers.Add("IsFristAdd", (rowInfo.FristAddTaskId == TaskId).ToString()); answers.Add("IsCanEditPosition", rowInfo.IsCanEditPosition.ToString()); answers.Add("InstanceId", rowInfo == null ? string.Empty : rowInfo.InstanceId.ToString()); answers.Add("PTSeriesId", rowInfo == null ? string.Empty : rowInfo.PTSeriesId.ToString()); answers.Add("CTSeriesId", rowInfo == null ? string.Empty : rowInfo.CTSeriesId.ToString()); answers.Add("SeriesId", rowInfo == null ? string.Empty : rowInfo.SeriesId.ToString()); answers.Add("IsCurrentTaskAdd", rowInfo == null ? false.ToString() : rowInfo.IsCurrentTaskAdd.ToString()); answers.Add("SplitOrMergeLesionName", rowInfo == null ? string.Empty : rowInfo.SplitName.IsNullOrEmpty() ? rowInfo.MergeName : rowInfo.SplitName); answers.Add("SplitOrMergeType", rowInfo == null ? string.Empty : rowInfo.SplitOrMergeType == null ? string.Empty : ((int)rowInfo.SplitOrMergeType).ToString()); answers.Add("LastTaskState", lastTaskTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty); answers.Add("LastTaskMajorAxis", lastTaskTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.MajorAxis && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty); answers.Add("LastTaskShortAxis", lastTaskTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.ShortAxis && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty); answers.Add("BaseLineMajorAxis", baseLineTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.MajorAxis && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty); answers.Add("BaseLineShortAxis", baseLineTableAnswer.Where(n => n.QuestionId == item.Id && n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.ShortAxis && n.RowIndex == x).Select(n => n.Answer).FirstOrDefault() ?? string.Empty); if (rowInfo.LesionType == LesionType.BaselineLesions) { answers.Add("BaseLineLesionNumber", baseLineTableAnswer.Where(n => n.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && n.RowIndex == rowInfo.RowIndex).Select(x => x.Answer).FirstIsNullReturnEmpty()); } item.TableQuestions.Answers.Add(answers); }; if (item.Childrens != null && item.Childrens.Count != 0) { item.Childrens.ForEach(x => { FindChildQuestion(x, questionlists, tableQuestionLists, tableAnswers, tableAnsweRowInfos, organInfos, baseLineTableAnswer, isFirstChangeTask, lastTaskTableAnswer, TableQuestionMarkList, TaskId); }); } } #region 访视任务 - Dicom 阅片 表格问题 病灶的拆分与合并 /// /// 拆分病灶 分裂病灶 /// /// [HttpPost] [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task SplitLesion(SplitLesionInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); await VerifyIsBaseLineTask(inDto.VisitTaskId); var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); var rowAnswer = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.RowId).AsNoTracking().FirstNotNullAsync(); var tableAnswers = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == rowAnswer.RowIndex && x.QuestionId == inDto.QuestionId).Include(x => x.ReadingTableQuestionTrial).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); var maxRowIndex = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId && x.RowIndex < Math.Floor(rowAnswer.RowIndex + 1)).OrderByDescending(x => x.RowIndex).Select(x => x.RowIndex).FirstOrDefaultAsync(); var newRowIndex = maxRowIndex + (decimal)0.01; rowAnswer.RowIndex = newRowIndex; rowAnswer.MergeRowId = null; rowAnswer.FristAddTaskId = inDto.VisitTaskId; rowAnswer.SplitOrMergeType = SplitOrMergeType.Split; rowAnswer.FromMark = string.Empty; rowAnswer.ReportMark = string.Empty; rowAnswer.SplitRowId = rowAnswer.Id; rowAnswer.Id = NewId.NextGuid(); rowAnswer.InstanceId = null; rowAnswer.SeriesId = null; rowAnswer.IsCurrentTaskAdd = true; rowAnswer.MeasureData = string.Empty; rowAnswer.OtherMeasureData = null; List needSaveMark = new List() { QuestionMark.Organ, QuestionMark.Location, QuestionMark.Part, QuestionMark.IsLymph, }; switch (taskInfo.TrialReadingCriterion.CriterionType) { case CriterionType.Lugano2014: List needSetNa = new List() { QuestionMark.LowPPDAddPercent, QuestionMark.NadirPPD, /// /// PPD最低点所在访视 /// QuestionMark.LowPPDVisit , /// /// PPD最低点LDi /// QuestionMark.LowPPDLDi, /// /// PPD最低点SDi /// QuestionMark.LowPPDSDi, /// /// 相比最低点PPD增加百分比 /// QuestionMark.LowPPDAddPercent, /// /// 相比PPD最低点LDi增加值 /// QuestionMark.LowPPDLDiAdded, /// /// 相比PPD最低点SDi增加值 /// QuestionMark.LowPPDSDiAdded, }; tableAnswers.ForEach(x => { x.Answer = needSetNa.Contains(x.QuestionMark) ? "NA" : x.Answer; }); break; case CriterionType.mRECISTHCC: needSaveMark = new List() { QuestionMark.Organ, QuestionMark.Location, QuestionMark.Part, QuestionMark.IsLymph, QuestionMark.TypicalIntrahepaticLesion, }; break; } tableAnswers.ForEach(x => { x.Id = NewId.NextGuid(); x.RowIndex = newRowIndex; x.VisitTaskId = inDto.VisitTaskId; x.RowId = rowAnswer.Id; x.Answer = needSaveMark.Contains(x.QuestionMark) ? x.Answer : string.Empty; }); await _readingTableAnswerRowInfoRepository.AddAsync(rowAnswer); await _readingTableQuestionAnswerRepository.AddRangeAsync(_mapper.Map>(tableAnswers)); await _readingTableAnswerRowInfoRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.RowId, x => new ReadingTableAnswerRowInfo() { SplitOrMergeType = SplitOrMergeType.SplitMain }); await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); } /// /// 合并病灶 融合 /// /// [HttpPost] public async Task MergeLesion(MergeLesionInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); await VerifyIsBaseLineTask(inDto.VisitTaskId); var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); var mergeRow = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.MergeMainRowId).Include(x => x.ReadingQuestionTrial).FirstNotNullAsync(); var mark = mergeRow.ReadingQuestionTrial.OrderMark + mergeRow.RowIndex.GetLesionMark(); await _readingTableQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => inDto.MergeRowIdList.Contains(x.RowId) && x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State, x => new ReadingTableQuestionAnswer() { Answer = TargetState.Loss.GetEnumInt(), }); await _readingTableQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => inDto.MergeRowIdList.Contains(x.RowId) && (x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.MajorAxis || x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.ShortAxis), x => new ReadingTableQuestionAnswer() { Answer = "0", }); await _readingTableAnswerRowInfoRepository.UpdatePartialFromQueryAsync(x => inDto.MergeRowIdList.Contains(x.Id), x => new ReadingTableAnswerRowInfo() { MergeRowId = inDto.MergeMainRowId, SplitOrMergeType = SplitOrMergeType.Merge, }); await _readingTableAnswerRowInfoRepository.UpdatePartialFromQueryAsync(inDto.MergeMainRowId, x => new ReadingTableAnswerRowInfo() { SplitOrMergeType = SplitOrMergeType.MergeMain, }); await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); await _readingCalculateService.CalculateTask(new CalculateTaskInDto() { IsChangeOtherTask = false, VisitTaskId = inDto.VisitTaskId, ComputationTrigger = ComputationTrigger.MergeLesion, }); // 保存完了计算疾病进展 switch (taskinfo.TrialReadingCriterion.CriterionType) { case CriterionType.Lugano2014: await _luganoCalculateService.CalculateMergeTargetLesionStatus(new CalculateTargetLesionStatusInDto() { QuestionId = inDto.QuestionId, VisitTaskId = inDto.VisitTaskId, RowNumber = mergeRow.RowIndex, }); break; } } /// /// 获取可合并的病灶 /// /// /// [HttpPost] public async Task> GetCanMergeLesion(GetCanMergeLesionInDto inDto) { var rowinfo = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.RowId).Include(x => x.ReadingQuestionTrial).FirstNotNullAsync(); var taskInfo = await _visitTaskRepository.Where(x => x.Id == rowinfo.VisitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); // 需要排除的状态 var needFilterState = new List(); var query = _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == rowinfo.VisitTaskId && x.QuestionId == rowinfo.QuestionId && x.Id != rowinfo.Id) .Where(x => x.SplitOrMergeType != SplitOrMergeType.Split && x.SplitOrMergeType != SplitOrMergeType.SplitMain && x.SplitOrMergeType != SplitOrMergeType.Merge && x.SplitOrMergeType != SplitOrMergeType.MergeMain && x.SplitOrMergeType != SplitOrMergeType.Merged); switch (taskInfo.TrialReadingCriterion.CriterionType) { case CriterionType.Lugano2014: // (无法评估 或者 状态为消失的非靶病灶) 并且不能是无法评估的病灶 query = query.Where(x => (x.MeasureData == string.Empty || (x.LesionAnswerList.Any(y => y.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && y.Answer == TargetState.Loss.GetEnumInt()) && x.LesionAnswerList.Any(y => y.ReadingTableQuestionTrial.QuestionMark == QuestionMark.IsLymph && y.Answer == ReadingYesOrNo.No.GetEnumInt()) )) && !x.LesionAnswerList.Any(y => y.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && y.Answer == TargetState.UnableEvaluate.GetEnumInt()) ); break; } var result = await query .Select(x => new GetCanMergeLesionOutDto() { RowId = x.Id, RowIndex = x.RowIndex, OrderMarkName = x.ReadingQuestionTrial.OrderMark + x.RowIndex.GetLesionMark(), OrganInfoId = x.OrganInfoId }).OrderBy(x => x.RowIndex).ToListAsync(); var organIds = result.Where(x => x.OrganInfoId != null).Select(x => x.OrganInfoId).Distinct().ToList(); var organList = await _organInfoRepository.Where(x => organIds.Contains(x.Id)).ToListAsync(); result.ForEach(x => { if (_userInfo.IsEn_Us) { x.Part = organList.Where(y => y.Id == x.OrganInfoId).Select(y => y.PartEN).FirstIsNullReturnEmpty(); } else { x.Part = organList.Where(y => y.Id == x.OrganInfoId).Select(y => y.Part).FirstIsNullReturnEmpty(); } }); return result; } #endregion #region 访视任务 - Dicom 阅片 提交、修改 /// /// 保存影像质量 /// /// /// [HttpPost] [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task SaveImageQuality(ChangeDicomReadingQuestionAnswerInDto inDto) { inDto.UpdateMark = true; return await ChangeDicomReadingQuestionAnswer(inDto); } /// /// 保存任务问题 带动态稽查参数 /// /// /// 请求类型 /// [Route("/SaveTaskQuestion/{param}")] [HttpPost] public async Task SaveTaskQuestion(ChangeDicomReadingQuestionAnswerInDto inDto, string param) { var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); try { param = param == string.Empty ? "0" : param; inDto.ComputationTrigger = (ComputationTrigger)int.Parse(param); } catch (Exception) { } var result = await SaveImageQuality(inDto); // 自动计算 await _readingCalculateService.CalculateTask(new CalculateTaskInDto() { IsChangeOtherTask = false, VisitTaskId = inDto.VisitTaskId, ComputationTrigger = inDto.ComputationTrigger, }); return result; } ///// ///// 保存ECRF ///// ///// ///// //[HttpPost] //public async Task SaveImageQuality(ChangeDicomReadingQuestionAnswerInDto inDto) //{ // return await ChangeDicomReadingQuestionAnswer(inDto); //} /// /// 修改肿瘤学评估结果 /// /// /// [HttpPost] [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task ChangeDicomReadingQuestionAnswer(ChangeDicomReadingQuestionAnswerInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var tumorQuestionId = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId && x.QuestionType == QuestionType.Tumor).Select(x => x.Id).FirstOrDefaultAsync(); var tumorAnswer = inDto.Answers.Where(x => x.Id == tumorQuestionId).FirstOrDefault(); if (tumorAnswer != null) { var isConvertedTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.IsConvertedTask).FirstOrDefaultAsync(); var reportVerify = await _readingCalculateService.GetReportVerify(new GetReportVerifyInDto() { BeforeConvertedTaskId = taskInfo.BeforeConvertedTaskId, IsConvertTask = isConvertedTask, VisitTaskId = inDto.VisitTaskId }); if (tumorAnswer.Answer == reportVerify.TumorEvaluate) { await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == inDto.VisitTaskId, x => new VisitTask() { IsChangeTumorEvaluate = false }); } else { await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == inDto.VisitTaskId, x => new VisitTask() { IsChangeTumorEvaluate = true }); } } var criterionId = taskInfo.TrialReadingCriterionId; var questionIds = inDto.Answers.Select(x => x.Id).ToList(); await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && questionIds.Contains(x.ReadingQuestionTrialId)); var needAddAnswer = inDto.Answers.Select(x => new ReadingTaskQuestionAnswer() { Answer = x.Answer, SubjectId = taskInfo.SubjectId, ReadingQuestionCriterionTrialId = criterionId, ReadingQuestionTrialId = x.Id, TrialId = taskInfo.TrialId, VisitTaskId = inDto.VisitTaskId, }).ToList(); await _readingTaskQuestionAnswerRepository.AddRangeAsync(needAddAnswer); if (inDto.UpdateMark) { var questionMarkList = await _readingTaskQuestionMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).Select(x => new { x.QuestionId, x.FristAddTaskId, }).ToListAsync(); var markquestionId = inDto.QuestionMarkInfoList.Select(y => y.QuestionId).ToList(); var needDeleteMarkQuestonIds = inDto.Answers.Where(x => x.Answer == string.Empty).Select(x => x.Id).ToList(); await _readingTaskQuestionMarkRepository.BatchUpdateNoTrackingAsync(x => (x.QuestionType == QuestionType.SplenicTopPosition || x.QuestionType == QuestionType.SplenicBottomPosition) && x.VisitTaskId == inDto.VisitTaskId && needDeleteMarkQuestonIds.Contains(x.QuestionId), x => new ReadingTaskQuestionMark() { PicturePath = string.Empty, MeasureData = string.Empty, }); await _readingTaskQuestionMarkRepository.BatchUpdateNoTrackingAsync(x => (x.QuestionType == QuestionType.LiverSUVmax || x.QuestionType == QuestionType.MediastinumSUVmax) && x.VisitTaskId == inDto.VisitTaskId && needDeleteMarkQuestonIds.Contains(x.QuestionId), x => new ReadingTaskQuestionMark() { OtherPicturePath = string.Empty, OtherMeasureData = string.Empty, }); await _readingTaskQuestionMarkRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && markquestionId.Contains(x.QuestionId)); var datetime = DateTime.Now; var markList = _mapper.Map, List>(inDto.QuestionMarkInfoList); markList.ForEach(x => { x.Id = NewId.NextGuid(); x.VisitTaskId = inDto.VisitTaskId; x.CreateTime = datetime; x.FristAddTaskId = questionMarkList.Where(y => y.QuestionId == x.QuestionId).Select(x => x.FristAddTaskId).FirstOrDefault() ?? inDto.VisitTaskId; }); await _readingTaskQuestionMarkRepository.AddRangeAsync(markList); } await _readingTaskQuestionAnswerRepository.SaveChangesAsync(); return ResponseOutput.Ok(true); } /// /// 删除表格行数据 /// /// /// [HttpPost] [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task DeleteReadingRowAnswer(DeleteReadingRowAnswerInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); var deleteRowInfo = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.RowId).FirstOrDefaultAsync(); if (deleteRowInfo == null) { return ResponseOutput.Ok(true); } inDto.QuestionId = deleteRowInfo.QuestionId; if (await _readingTableAnswerRowInfoRepository.AnyAsync(x => x.SplitRowId == deleteRowInfo.Id && x.MergeRowId == deleteRowInfo.Id)) { throw new BusinessValidationFailedException(_localizer["ReadingImage_DeleteError"]); } var index = await _readingCalculateService.GetDeleteLesionStatrIndex(inDto); await _readingTableQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => x.RowId == inDto.RowId, x => new ReadingTableQuestionAnswer() { IsDeleted = true }); if (!(await _readingTableAnswerRowInfoRepository.AnyAsync(x => x.SplitRowId == deleteRowInfo.SplitRowId && x.Id != deleteRowInfo.Id))) { await _readingTableAnswerRowInfoRepository.BatchUpdateNoTrackingAsync(x => x.Id == deleteRowInfo.SplitRowId, x => new ReadingTableAnswerRowInfo() { SplitOrMergeType = null, }); } await _readingTableAnswerRowInfoRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.RowId, x => new ReadingTableAnswerRowInfo() { IsDeleted = true }); await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); if (inDto.IsNeedSort) { var rowInfoList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId, true).Include(x => x.ReadingQuestionTrial).OrderBy(x => x.RowIndex).ToListAsync(); var answerlist = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId, true).ToListAsync(); foreach (var item in rowInfoList.Where(x => x.RowIndex % 1 == 0)) { string measureDataStr = string.Empty; if (item.MeasureData != null && item.MeasureData != string.Empty) { dynamic measureData = JObject.Parse(item.MeasureData); measureData.data.remark = item.ReadingQuestionTrial.OrderMark + ((decimal)index).GetLesionMark(); measureDataStr = JsonConvert.SerializeObject(measureData); } string? otherMeasureDataStr = null; if (item.OtherMeasureData != null && item.OtherMeasureData != string.Empty) { dynamic otherMeasureData = JObject.Parse(item.OtherMeasureData); otherMeasureData.data.remark = item.ReadingQuestionTrial.OrderMark + ((decimal)index).GetLesionMark(); otherMeasureDataStr = JsonConvert.SerializeObject(otherMeasureData); } foreach (var answerItem in answerlist.Where(x => x.RowIndex == item.RowIndex)) { answerItem.RowIndex = index; } foreach (var rowAnswerItem in rowInfoList.Where(x => x.RowIndex == item.RowIndex)) { rowAnswerItem.RowIndex = index; rowAnswerItem.MeasureData = measureDataStr; rowAnswerItem.OtherMeasureData = otherMeasureDataStr; } //await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == item.RowIndex && x.QuestionId == inDto.QuestionId, x => new ReadingTableQuestionAnswer() //{ // RowIndex = index //}); //await _readingTableAnswerRowInfoRepository.UpdatePartialFromQueryAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == item.RowIndex && x.QuestionId == inDto.QuestionId, x => new ReadingTableAnswerRowInfo() //{ // RowIndex = index, // MeasureData = measureDataStr, //}); var spiltList = rowInfoList.Where(x => x.RowIndex % 1 != 0 && x.RowIndex > item.RowIndex && x.RowIndex < Math.Floor(item.RowIndex + 1)).OrderBy(x => x.RowIndex).ToList(); decimal spiltindex = 0.01M; foreach (var spiltitem in spiltList) { string spiltmeasureDataStr = string.Empty; if (spiltitem.MeasureData != null && spiltitem.MeasureData != string.Empty) { dynamic spiltmeasureData = JObject.Parse(spiltitem.MeasureData); spiltmeasureData.data.remark = item.ReadingQuestionTrial.OrderMark + ((decimal)index + spiltindex).GetLesionMark(); spiltmeasureDataStr = JsonConvert.SerializeObject(spiltmeasureData); } string? spiltOtherMeasureDataStr = null; if (item.OtherMeasureData != null && item.OtherMeasureData != string.Empty) { dynamic otherMeasureData = JObject.Parse(item.OtherMeasureData); otherMeasureData.data.remark = item.ReadingQuestionTrial.OrderMark + ((decimal)index).GetLesionMark(); spiltOtherMeasureDataStr = JsonConvert.SerializeObject(otherMeasureData); } foreach (var answerItem in answerlist.Where(x => x.RowIndex == spiltitem.RowIndex)) { answerItem.RowIndex = index + spiltindex; } foreach (var rowAnswerItem in rowInfoList.Where(x => x.RowIndex == spiltitem.RowIndex)) { rowAnswerItem.RowIndex = index + spiltindex; rowAnswerItem.MeasureData = spiltmeasureDataStr; rowAnswerItem.OtherMeasureData = spiltOtherMeasureDataStr; } //await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == spiltitem.RowIndex && x.QuestionId == inDto.QuestionId, x => new ReadingTableQuestionAnswer() //{ // RowIndex = index + spiltindex //}); //await _readingTableAnswerRowInfoRepository.UpdatePartialFromQueryAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == spiltitem.RowIndex && x.QuestionId == inDto.QuestionId, x => new ReadingTableAnswerRowInfo() //{ // RowIndex = index + spiltindex, // MeasureData = spiltmeasureDataStr, //}); spiltindex += 0.01M; } index++; } await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); } // 自动计算 await _readingCalculateService.CalculateTask(new CalculateTaskInDto() { IsChangeOtherTask = false, VisitTaskId = inDto.VisitTaskId, ComputationTrigger = ComputationTrigger.RemoveLesion, }); switch (taskinfo.TrialReadingCriterion.CriterionType) { case CriterionType.Lugano2014: if (deleteRowInfo.RowIndex % 1 != 0) { await _luganoCalculateService.CalculateTargetLesionStatus(new CalculateTargetLesionStatusInDto() { QuestionId = inDto.QuestionId, VisitTaskId = inDto.VisitTaskId, RowNumber = deleteRowInfo.RowIndex }); } break; } return ResponseOutput.Ok(true); } /// /// 提交表格行信息 /// /// /// /// [HttpPost] [Route("/SubmitTaskRowInfo/{param}")] public async Task SubmitTaskRowInfo(SubmitTableQuestionInDto inDto, string param) { inDto.ComputationTrigger = (ComputationTrigger)int.Parse(param); return await SubmitTableQuestion(inDto); } /// /// 提交表格问题答案 提交病灶 保存病灶 /// /// /// [HttpPost] [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task SubmitTableQuestion(SubmitTableQuestionInDto inDto) { SubmitTableQuestionOutDto result = new SubmitTableQuestionOutDto(); await VerifyTaskIsSign(inDto.VisitTaskId); if (inDto.InstanceId != null && inDto.IsDicomReading) { if (!(await _dicomInstanceRepository.AnyAsync(x => x.Id == inDto.InstanceId && x.SeriesId == inDto.SeriesId))) { throw new BusinessValidationFailedException(_localizer["ReadingImage_Idnotcorrespond"]); } } var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.TrialReadingCriterion).Include(x => x.SourceSubjectVisit).FirstNotNullAsync(); inDto.BlindName = taskinfo.TaskBlindName; var questionInfo = await _readingQuestionTrialRepository.Where(x => x.Id == inDto.QuestionId).FirstNotNullAsync(); switch (taskinfo.TrialReadingCriterion.CriterionType) { // 对于非靶病灶,如果状态选择为显著增大,请验证: // 1) 对于非淋巴结病灶,验证当前访视该病灶的长径 > 上一访视该病灶的长径。 // 约束条件:两次访视该病灶的长径有测量值。 // 提示语:当前访视该非淋巴结病灶的长径小于上一访视的值,不能设置为显著增大。 // 2) 对于淋巴结病灶,验证当前访视该病灶的短径 > 上一访视该病灶的短径。 // 约束条件:两次访视该病灶的短径有测量值。 // 提示语:当前访视该淋巴结病灶的短径小于上一访视的值,不能设置为显著增大。 case CriterionType.RECIST1Point1: var lastTaskinfo = await _visitTaskRepository .Where(x => x.IsAnalysisCreate == taskinfo.IsAnalysisCreate && x.SubjectId == taskinfo.SubjectId && x.ReadingCategory == taskinfo.ReadingCategory && x.DoctorUserId == taskinfo.DoctorUserId && x.ArmEnum == taskinfo.ArmEnum && x.TrialReadingCriterionId == taskinfo.TrialReadingCriterionId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.TaskState == TaskState.Effect && x.IsSelfAnalysis == taskinfo.IsSelfAnalysis && x.VisitTaskNum < taskinfo.VisitTaskNum ).OrderByDescending(x => x.VisitTaskNum).FirstOrDefaultAsync(); if (lastTaskinfo != null) { var tablequestionList = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == taskinfo.TrialReadingCriterionId && x.ReadingQuestionTrial.LesionType == LesionType.NonTargetLesions).ToListAsync(); // 判断表格问题是否为空 if (tablequestionList.Count > 0) { // 找到状态值 var stateQuestion = tablequestionList.Where(x => x.QuestionMark == QuestionMark.State).FirstOrDefault(); if (stateQuestion != null) { // 判断是否为非靶病灶 if (inDto.QuestionId == tablequestionList[0].ReadingQuestionId && inDto.AnswerList.Any(x => x.TableQuestionId == stateQuestion.Id && x.Answer.EqEnum(NoTargetState.Increase))) { var lymphQuestion = tablequestionList.Where(x => x.QuestionMark == QuestionMark.IsLymph).FirstOrDefault(); if (lymphQuestion != null) { // 判断是否是淋巴结 if (inDto.AnswerList.Any(x => x.TableQuestionId == lymphQuestion.Id && x.Answer.EqEnum(YesOrNoOrNa.Yes))) { var shortAxisQuestion = tablequestionList.Where(x => x.QuestionMark == QuestionMark.ShortAxis).FirstOrDefault(); if (shortAxisQuestion != null) { var lastAnswer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == lastTaskinfo.Id && x.TableQuestionId == shortAxisQuestion.Id && x.RowIndex == inDto.RowIndex ).Select(x => x.Answer).FirstOrDefaultAsync(); var thisAnswer = inDto.AnswerList.Where(x => x.TableQuestionId == shortAxisQuestion.Id).Select(x => x.Answer).FirstOrDefault(); if (!lastAnswer.IsNullOrEmpty() && !thisAnswer.IsNullOrEmpty()) { var lastvalue = 0m; var thisvalue = 0m; try { lastvalue = decimal.Parse(lastAnswer); thisvalue = decimal.Parse(thisAnswer); } catch (Exception) { } if (lastvalue >= thisvalue) { throw new BusinessValidationFailedException(_localizer["ReadingImage_IsLymphNotbigger"]); } } } } else { var majorAxisQuestion = tablequestionList.Where(x => x.QuestionMark == QuestionMark.MajorAxis).FirstOrDefault(); if (majorAxisQuestion != null) { var lastAnswer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == lastTaskinfo.Id && x.TableQuestionId == majorAxisQuestion.Id && x.RowIndex == inDto.RowIndex ).Select(x => x.Answer).FirstOrDefaultAsync(); var thisAnswer = inDto.AnswerList.Where(x => x.TableQuestionId == majorAxisQuestion.Id).Select(x => x.Answer).FirstOrDefault(); if (!lastAnswer.IsNullOrEmpty() && !thisAnswer.IsNullOrEmpty()) { var lastvalue = 0m; var thisvalue = 0m; try { lastvalue = decimal.Parse(lastAnswer); thisvalue = decimal.Parse(thisAnswer); } catch (Exception) { } if (lastvalue >= thisvalue) { throw new BusinessValidationFailedException(_localizer["ReadingImage_NotLymphNotbigger"]); } } } } } } } } } break; case CriterionType.Lugano2014: var targetTablequestionList = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == taskinfo.TrialReadingCriterionId && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion).ToListAsync(); var targetlymphQuestion = targetTablequestionList.Where(x => x.QuestionMark == QuestionMark.IsLymph).FirstOrDefault(); // 判断是否存在淋巴结问题 if (targetlymphQuestion != null && taskinfo.SourceSubjectVisit.VisitNum == 0) { // 判断是否为淋巴结 if (inDto.QuestionId == targetTablequestionList[0].ReadingQuestionId && inDto.AnswerList.Any(x => x.TableQuestionId == targetlymphQuestion.Id && x.Answer.EqEnum(ReadingYesOrNo.No))) { if (await _readingTableQuestionAnswerRepository.CountAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.TableQuestionId == targetlymphQuestion.Id && x.Answer == ReadingYesOrNo.No.GetEnumInt() && x.RowId != inDto.RowId) >= 2) { // 靶病灶只能添加两个非淋巴结病灶 throw new BusinessValidationFailedException(_localizer["ReadingImage_LuganoMaxTowNoTarget"]); } } } break; case CriterionType.mRECISTHCC: //var orginInfo=await _organTrialInfoRepository.Where(x =>x.TrialCriterionId== taskinfo.TrialReadingCriterionId&& x.OrganInfoId == inDto.OrganInfoId).FirstOrDefaultAsync(); //if (orginInfo != null && orginInfo.TULOCEN == "Liver") //{ // var otherorganCount=await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId && x.Id!=inDto.Id&&x.OrganInfo.TULOCEN == "Liver").CountAsync(); // if (otherorganCount >=2) // { // throw new BusinessValidationFailedException(_localizer["ReadingImageTask_HCCOrganRepeat"]); // } //} // 如果当前添加 是 非靶病灶 并且 典型肝内病灶为 是 时 如果 靶病灶的典型肝内病灶 为是的 数量<2 给提示 // 验证去掉 //if (questionInfo.LesionType == LesionType.NonTargetLesions) //{ // // 非靶病灶 // var tablequestionList = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == taskinfo.TrialReadingCriterionId && x.ReadingQuestionId == inDto.QuestionId).ToListAsync(); // // 判断表格问题是否为空 // var tableQuestion = tablequestionList.Where(x => x.QuestionMark == QuestionMark.TypicalIntrahepaticLesion).FirstOrDefault(); // if (tableQuestion != null) // { // if (inDto.AnswerList.Where(x => x.TableQuestionId == tableQuestion.Id).Select(x => x.Answer).FirstOrDefault().EqEnum(ReadingYesOrNo.Yes)) // { // var yesString = ((int)(object)ReadingYesOrNo.Yes).ToString(); // var targetList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion // && x.LesionAnswerList.Any(y => y.Answer == yesString && y.ReadingTableQuestionTrial.QuestionMark == QuestionMark.TypicalIntrahepaticLesion) // ).ToListAsync(); // if (targetList.Count() < 2) // { // throw new BusinessValidationFailedException(_localizer["ReadingImageTask_PriorityTarget"]); // } // } // } //} break; } var criterionId = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.TrialReadingCriterionId).FirstOrDefaultAsync(); var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == criterionId).FirstNotNullAsync(); var tableQuestionIds = inDto.AnswerList.Select(x => x.TableQuestionId).ToList(); var tableAnswerList = await _readingTableQuestionAnswerRepository.Where(x => x.RowId == inDto.RowId).ToListAsync(); var tableQuestionIdGroup = tableQuestionIds.GroupBy(x => new { TableQuestionId = x }).Select(x => new TableQuestionData { TableQuestionId = x.Key.TableQuestionId, Count = x.Count() }).ToList(); if (tableQuestionIdGroup.Any(x => x.Count > 1)) { throw new BusinessValidationFailedException(_localizer["ReadingImage_Twice"]); } if (inDto.RowIndex % 1 == 0) { if (questionInfo.MaxQuestionCount != null && questionInfo.MaxQuestionCount != 0 && inDto.RowId == null) { if (questionInfo.MaxQuestionCount < ( (await _readingTableAnswerRowInfoRepository.Where(x => ((x.RowIndex % 1) == 0) && x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId ).CountAsync()) + 1)) { throw new BusinessValidationFailedException(_localizer["ReadingImage_MaxQuestion", _userInfo.IsEn_Us ? questionInfo.QuestionEnName : questionInfo.QuestionName, questionInfo.MaxQuestionCount]); } } var tableQuestions = await _readingTableQuestionTrialRepository.Where(x => tableQuestionIds.Contains(x.Id) && x.MaxRowCount != null && x.MaxRowCount != 0).ToListAsync(); List questionMarks = new List() { QuestionMark.Part, QuestionMark.Organ, }; string msg = string.Empty; foreach (var item in tableQuestions) { var answer = inDto.AnswerList.Where(x => x.TableQuestionId == item.Id).Select(x => x.Answer).FirstOrDefault(); if (!answer.IsNullOrEmpty()) { Dictionary errorMsgDic = new Dictionary() { {CriterionType.RECIST1Point1, _localizer["ReadingImage_Maxlesion", item.MaxRowCount!.Value]}, {CriterionType.PCWG3, _localizer["ReadingImage_PCWGMaximum", item.MaxRowCount.Value]}, }; var rowCount = 0; if ((item.QuestionMark == QuestionMark.Part || item.QuestionMark == QuestionMark.Organ) && inDto.OrganInfoId != null) { var organIds = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId && ((x.RowIndex % 1) == 0) && x.OrganInfoId != null && x.RowIndex != inDto.RowIndex).Select(x => x.OrganInfoId).ToListAsync(); organIds.Add(inDto.OrganInfoId); var orginInfos = await _organInfoRepository.Where(x => organIds.Contains(x.Id)).ToListAsync(); List orginInfoList = new List(); foreach (var organId in organIds) { orginInfoList.Add(orginInfos.Where(x => x.Id == organId).FirstOrDefault()); } var currentOrginInfo = orginInfos.Where(x => x.Id == inDto.OrganInfoId).FirstOrDefault() ?? new OrganInfo(); if (item.QuestionMark == QuestionMark.Part) { rowCount = orginInfoList.Where(x => x.Part == currentOrginInfo.Part).Count(); } else { rowCount = orginInfoList.Where(x => x.TULOC == currentOrginInfo.TULOC).Count(); } if (rowCount > item.MaxRowCount.Value) { if (rowCount > item.MaxRowCount.Value) { try { msg = errorMsgDic[criterionInfo.CriterionType]; } catch (Exception) { msg = _localizer["ReadingImage_Maximum", item.QuestionName.LanguageName(item.QuestionEnName, _userInfo.IsEn_Us), item.MaxRowCount.Value, item.MaxRowCount.Value]; } throw new BusinessValidationFailedException(msg); } } } else { rowCount = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.TableQuestionId == item.Id && ((x.RowIndex % 1) == 0) && x.Answer == answer && x.RowIndex != inDto.RowIndex).CountAsync(); if (rowCount > item.MaxRowCount.Value - 1) { try { msg = errorMsgDic[criterionInfo.CriterionType]; } catch (Exception) { msg = _localizer["ReadingImage_Maximum", item.QuestionName.LanguageName(item.QuestionEnName, _userInfo.IsEn_Us), item.MaxRowCount.Value, rowCount]; } throw new BusinessValidationFailedException(msg); } } } } } var isCurrentTaskAddList = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == (inDto.RowId ?? default(Guid))).Select(x => x.IsCurrentTaskAdd).ToListAsync(); bool isCurrentTaskAdd = true; if (isCurrentTaskAddList.Count > 0) { isCurrentTaskAdd = isCurrentTaskAddList[0]; } ReadingTableAnswerRowInfo? rowInfo = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == (inDto.RowId ?? default(Guid))).IgnoreAutoIncludes().FirstOrDefaultAsync(); rowInfo = rowInfo == null ? new ReadingTableAnswerRowInfo() : rowInfo; //await _readingTableQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.RowId == (inDto.RowId ?? default(Guid))); //await _readingTableAnswerRowInfoRepository.BatchDeleteNoTrackingAsync(x => x.Id == (inDto.RowId ?? default(Guid))); _mapper.Map(inDto, rowInfo); rowInfo.Id = inDto.RowId == null ? NewId.NextGuid() : inDto.RowId.Value; result.RowId = rowInfo.Id; rowInfo.IsCurrentTaskAdd = isCurrentTaskAdd; rowInfo.FristAddTaskId = inDto.RowId == null ? inDto.VisitTaskId : rowInfo.FristAddTaskId; if (inDto.RowId == null) { rowInfo.FromMark = inDto.FromMark ?? string.Empty; rowInfo.ReportMark = inDto.ReportMark ?? string.Empty; rowInfo.MarkTool = inDto.MarkTool ?? string.Empty; rowInfo.PicturePath = inDto.PicturePath ?? string.Empty; rowInfo.MeasureData = inDto.MeasureData ?? string.Empty; //await _readingTableAnswerRowInfoRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == inDto.RowIndex && x.QuestionId == inDto.QuestionId); List answerList = inDto.AnswerList.Select(x => new ReadingTableQuestionAnswer() { Answer = x.Answer, Id = NewId.NextGuid(), TrialId = inDto.TrialId, QuestionId = inDto.QuestionId, TableQuestionId = x.TableQuestionId, RowIndex = inDto.RowIndex, RowId = rowInfo.Id, VisitTaskId = inDto.VisitTaskId }).ToList(); await _readingTableAnswerRowInfoRepository.AddAsync(rowInfo); await _readingTableQuestionAnswerRepository.AddRangeAsync(answerList); } else { await _readingTableAnswerRowInfoRepository.UpdateFromDTOAsync(inDto); foreach (var item in inDto.AnswerList) { if (tableAnswerList.Any(x => x.TableQuestionId == item.TableQuestionId)) { await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(x => x.RowId == inDto.RowId && x.TableQuestionId == item.TableQuestionId, x => new ReadingTableQuestionAnswer() { Answer = item.Answer }); } else { await _readingTableQuestionAnswerRepository.AddAsync(new ReadingTableQuestionAnswer() { Answer = item.Answer, QuestionId = inDto.QuestionId, TableQuestionId = item.TableQuestionId, RowId = inDto.RowId.Value, TrialId = taskinfo.TrialId, RowIndex = rowInfo.RowIndex, VisitTaskId = inDto.VisitTaskId, }); } } } await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); await _readingCalculateService.CalculateTask(new CalculateTaskInDto() { IsChangeOtherTask = false, VisitTaskId = inDto.VisitTaskId, ComputationTrigger = inDto.ComputationTrigger, }); // 保存完了计算疾病进展 switch (taskinfo.TrialReadingCriterion.CriterionType) { case CriterionType.Lugano2014: if (inDto.RowIndex % 1 != 0) { await _luganoCalculateService.CalculateTargetLesionStatus(new CalculateTargetLesionStatusInDto() { QuestionId = inDto.QuestionId, VisitTaskId = inDto.VisitTaskId, RowNumber = inDto.RowIndex }); } break; } return result; } /// /// 提交Dicom阅片信息 /// /// /// [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task SubmitDicomVisitTask(SubmitDicomVisitTaskInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); //// 修改编号 //var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); //// 获取标准表格外层问题 //var questionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId && x.LesionType != null && x.ReadingTableQuestionTrialList.Any(x => x.QuestionMark == QuestionMark.AutoId)) // .SelectMany(x => x.ReadingTableQuestionTrialList).Where(x => x.QuestionMark == QuestionMark.AutoId).Select(x => new // { // x.ReadingQuestionId, // TableQuestionId = x.Id, // }).ToListAsync(); //var questionIds = questionList.Select(x => x.ReadingQuestionId).ToList(); //var questionMarkList = await _readingQuestionTrialRepository.Where(x => questionIds.Contains(x.Id)).Select(x => new //{ // QuestionId = x.Id, // x.OrderMark, //}).ToListAsync(); //var rowInfo = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && questionIds.Contains(x.QuestionId)).ToListAsync(); //List questionAnswerList = new List(); //foreach (var item in questionList) //{ // await _readingTableQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.QuestionId == item.ReadingQuestionId // && x.TableQuestionId == item.TableQuestionId && x.VisitTaskId == inDto.VisitTaskId); // var orderMark = questionMarkList.Where(x => x.QuestionId == item.ReadingQuestionId).Select(x => x.OrderMark).FirstOrDefault(); // foreach (var row in rowInfo.Where(x => x.QuestionId == item.ReadingQuestionId)) // { // questionAnswerList.Add(new ReadingTableQuestionAnswer() // { // Answer = orderMark + row.RowIndex.GetLesionMark(), // Id = NewId.NextGuid(), // QuestionId = item.ReadingQuestionId, // RowId = row.Id, // RowIndex = row.RowIndex, // TableQuestionId = item.TableQuestionId, // TrialId = taskInfo.TrialId, // VisitTaskId = taskInfo.Id, // }); // } //} //await _readingTableQuestionAnswerRepository.AddRangeAsync(questionAnswerList); //await _readingTableQuestionAnswerRepository.SaveChangesAsync(); await SubmitTaskChangeState(inDto.VisitTaskId); return ResponseOutput.Ok(true); } #endregion #region Dicom 非dicom 公用 /// /// 验证默认问题是否回答 /// /// /// /// [HttpPost] public async Task VerifyDefaultQuestionBeAnswer(VerifyVisitTaskQuestionsInDto inDto) { var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.TrialReadingCriterion).Include(x => x.SourceSubjectVisit).FirstNotNullAsync(); var criterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == taskInfo.TrialReadingCriterionId).FirstNotNullAsync(); var readingQuestionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId && x.Type != "group") .WhereIf(taskInfo.SourceSubjectVisit.IsBaseLine, x => ((x.IsRequired == IsRequired.Required && x.ShowQuestion == ShowQuestion.Show) && (x.LimitEdit == LimitEdit.None || x.LimitEdit == LimitEdit.OnlyBaseLine))) .WhereIf(!taskInfo.SourceSubjectVisit.IsBaseLine, x => ((x.IsRequired == IsRequired.Required && x.ShowQuestion == ShowQuestion.Show) && (x.LimitEdit == LimitEdit.None || x.LimitEdit == LimitEdit.OnlyVisit))) .WhereIf(taskInfo.TrialReadingCriterion.CriterionType == CriterionType.PCWG3, x => x.QuestionType != QuestionType.SiteVisitForTumorEvaluation) //.WhereIf(!criterion.IseCRFShowInDicomReading,x=>x.IsShowInDicom) .ToListAsync(); var answerQuestionIds = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.Answer != string.Empty).Select(x => x.ReadingQuestionTrialId).ToListAsync(); readingQuestionList = readingQuestionList.Where(x => !answerQuestionIds.Contains(x.Id)).ToList(); if (readingQuestionList.Count > 0) { throw new BusinessValidationFailedException(_localizer["ReadingImage_RequiredQuestion", string.Join(',', readingQuestionList.Select(x => x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us)))]); } return ResponseOutput.Ok(true); } /// /// 验证访视提交 /// /// /// [HttpPost] public async Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto) { //验证后处理影像必须传 if (_visitTaskRepository.Any(t => t.Id == inDto.VisitTaskId && t.TrialReadingCriterion.ImageUploadEnum != ReadingImageUpload.None)) { if (!_taskStudyRepository.Any(t => t.VisitTaskId == inDto.VisitTaskId)) { return ResponseOutput.NotOk(_localizer["ReadingImage_BackImageNotExist"]); } } await VerifyTaskIsSign(inDto.VisitTaskId); await VerifyDefaultQuestionBeAnswer(inDto); // 转化后的任务不应该有新病灶 var isConvertedTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.IsConvertedTask).FirstNotNullAsync(); if (isConvertedTask && (await _readingTableAnswerRowInfoRepository.AnyAsync(x => x.ReadingQuestionTrial.LesionType == LesionType.NewLesions && x.VisitTaskId == inDto.VisitTaskId))) { throw new BusinessValidationFailedException(_localizer["ReadingImage_NotNewFocus"]); } var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var isBaseline = await _subjectVisitRepository.Where(x => x.Id == taskInfo.SourceSubjectVisitId).Select(x => x.IsBaseLine).FirstOrDefaultAsync(); var readingQuestionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId && x.Type != "group" && (x.IsJudgeQuestion || (x.IsRequired == IsRequired.Required && x.ShowQuestion == ShowQuestion.Show)) ).ToListAsync(); if (isBaseline) { readingQuestionList = readingQuestionList.Where(x => x.LimitEdit != LimitEdit.OnlyVisit).ToList(); } else { readingQuestionList = readingQuestionList.Where(x => x.LimitEdit != LimitEdit.OnlyBaseLine).ToList(); } var answerQuestionIds = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).Select(x => x.ReadingQuestionTrialId).ToListAsync(); readingQuestionList = readingQuestionList.Where(x => !answerQuestionIds.Contains(x.Id)).ToList(); if (readingQuestionList.Count > 0) { throw new BusinessValidationFailedException(_localizer["ReadingImage_RequiredQuestion", string.Join(',', readingQuestionList.Select(x => x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us)))]); } // 各个标准不同 await _readingCalculateService.VerifyVisitTaskQuestions(inDto); var clinicalDataList = await _readingClinicalDataService.GetClinicalDataList(new GetReadingOrTaskClinicalDataListInDto() { SubjectId = taskInfo.SubjectId, TrialId = taskInfo.TrialId, VisitTaskId = taskInfo.Id, }); var isBaseLine = false; if (taskInfo.SourceSubjectVisitId != null) { isBaseLine = await _subjectVisitRepository.Where(x => x.Id == taskInfo.SourceSubjectVisitId).Select(x => x.IsBaseLine).FirstOrDefaultAsync(); } var isNeedReadClinicalData = false; if (isBaseLine) { isNeedReadClinicalData = clinicalDataList.Count > 0; } else { isNeedReadClinicalData = clinicalDataList.Where(x => x.ClinicalDataLevel != ClinicalLevel.Subject).Count() > 0; } if (isNeedReadClinicalData && !taskInfo.IsReadClinicalData) { throw new BusinessValidationFailedException(_localizer["ReadingImage_ClinicalRead"]); } return ResponseOutput.Ok(true); } /// /// 清除跳过阅片的缓存 /// /// [HttpPost] public async Task ClearSkipReadingCache() { await _fusionCache.RemoveAsync(CacheKeys.SkipReadingCacheKey(_userInfo.UserRoleId)); return true; } /// /// 设置跳过阅片的缓存 /// /// /// [HttpPost] public async Task SetSkipReadingCache(SetSkipReadingCacheInDto inDto) { var clearSkipReadingCache = await _fusionCache.GetOrDefaultAsync(CacheKeys.SkipReadingCacheKey(_userInfo.UserRoleId)); if (clearSkipReadingCache == null || clearSkipReadingCache == string.Empty) { List cacheIds = new List(); cacheIds.Add(inDto.VisitTaskId); await _fusionCache.SetAsync(CacheKeys.SkipReadingCacheKey(_userInfo.UserRoleId), JsonConvert.SerializeObject(cacheIds), TimeSpan.FromHours(24)); } else { List? cacheIds = JsonConvert.DeserializeObject>(clearSkipReadingCache); cacheIds.Add(inDto.VisitTaskId); await _fusionCache.SetAsync(CacheKeys.SkipReadingCacheKey(_userInfo.UserRoleId), JsonConvert.SerializeObject(cacheIds), TimeSpan.FromHours(24)); } return true; } /// /// 获取下一个阅片任务 /// /// /// [HttpPost] public async Task GetNextTask(GetNextTaskInDto inDto) { if (inDto.VisitTaskId == null) { await VerifyReadingRestTime(); } GetReadingTaskDto? task = new GetReadingTaskDto(); var trialReadingCriterionId = inDto.TrialReadingCriterionId; if (trialReadingCriterionId == null && inDto.VisitTaskId == null) { throw new BusinessValidationFailedException(_localizer["ReadingImage_IDMust"]); } #region 跳过阅片 var clearSkipReadingCache = await _fusionCache.GetOrDefaultAsync(CacheKeys.SkipReadingCacheKey(_userInfo.UserRoleId)); List cacheSkipIds = new List(); if (clearSkipReadingCache != null && clearSkipReadingCache != string.Empty) { cacheSkipIds = JsonConvert.DeserializeObject>(clearSkipReadingCache); } #endregion var trialReadingCriterion = await _readingQuestionCriterionTrialRepository.FindAsync(trialReadingCriterionId ?? Guid.Empty); if (inDto.VisitTaskId != null) { task = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => new GetReadingTaskDto() { VisitTaskId = x.Id, TaskBlindName = x.TaskBlindName, SubjectId = x.SubjectId, ReadingCategory = x.ReadingCategory, ArmEnum = x.ArmEnum, VisistId = x.SourceSubjectVisitId != null ? x.SourceSubjectVisitId.Value : default(Guid), VisitNum = x.VisitTaskNum, TrialReadingCriterionId = x.TrialReadingCriterionId, }).FirstNotNullAsync(); trialReadingCriterionId = task.TrialReadingCriterionId; } else if (inDto.SubjectId != null && trialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.InOrder) { var subjectTaskList = (await _visitTaskService.GetSubjectReadingIQueryable(new GetReadingIQueryableInDto() { TrialId = inDto.TrialId, TrialReadingCriterionId = trialReadingCriterionId!.Value, PageIndex = 1, PageSize = 99999, })).CurrentPageData; var index = 0; subjectTaskList.ForEach(x => { x.Index = index; index++; }); var subjectIndex = subjectTaskList.Where(x => x.SubjectId == inDto.SubjectId && x.SubjectCode == inDto.SubjectCode).Select(x => x.Index).FirstOrDefault(); var currentSubject = subjectTaskList.Where(x => x.Index >= subjectIndex && !x.ExistReadingApply) // 排除跳过的 .Where(x => x.UnReadCanReadTaskList.Select(y => y.Id).Intersect(cacheSkipIds).Count() == 0) .OrderBy(x => x.Index).FirstOrDefault(); if (currentSubject == null) { throw new BusinessValidationFailedException(_localizer["ReadingImage_TaskFinish"], ApiResponseCodeEnum.CloseCurrentWindows); } task = currentSubject.UnReadCanReadTaskList .Select(x => new GetReadingTaskDto() { ReadingCategory = x.ReadingCategory, SubjectCode = currentSubject.SubjectCode, SubjectId = currentSubject.SubjectId, TaskBlindName = x.TaskBlindName, VisitNum = x.VisitNum, ArmEnum = x.ArmEnum, VisistId = x.VisistId ?? default(Guid), VisitTaskId = x.Id, TrialReadingCriterionId = x.TrialReadingCriterionId, }).FirstOrDefault(); } else if (inDto.SubjectId != null && trialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.SubjectRandom) { var subjectTaskList = (await _visitTaskService.GetSubjectReadingIQueryable(new GetReadingIQueryableInDto() { TrialId = inDto.TrialId, TrialReadingCriterionId = trialReadingCriterionId!.Value, PageIndex = 1, PageSize = 99999, })).CurrentPageData; if (subjectTaskList.Count() == 0) { throw new BusinessValidationFailedException(_localizer["ReadingImage_TaskFinish"], ApiResponseCodeEnum.CloseCurrentWindows); } var taskList = subjectTaskList.FirstOrDefault()!.UnReadCanReadTaskList; // 排除跳过的 List remainingItems = taskList.Select(x => x.Id).Except(cacheSkipIds).ToList(); //受试者随机固定排序 taskList = taskList.Where(x => remainingItems.Contains(x.Id)).OrderBy(t => t.TaskBlindName).ToList(); // 当前受试者没有就找其他受试者 if (taskList.Count() == 0) { var allsubjectTaskList = (await _visitTaskService.GetSubjectReadingIQueryable(new GetReadingIQueryableInDto() { TrialId = inDto.TrialId, TrialReadingCriterionId = trialReadingCriterionId!.Value, PageIndex = 1, PageSize = 99999, })).CurrentPageData; foreach (var item in allsubjectTaskList) { var canReadList = item.UnReadCanReadTaskList.Where(x => remainingItems.Contains(x.Id)).OrderBy(t => t.TaskBlindName).ToList(); if (canReadList.Count() > 0) { taskList = canReadList; break; } } } if (taskList.Count() == 0) { throw new BusinessValidationFailedException(_localizer["ReadingImage_TaskFinish"], ApiResponseCodeEnum.CloseCurrentWindows); } #region 随机废弃 //Random random = new Random(); ////返回的范围是 0- taskList.Count-1 //int randomIndex = random.Next(taskList.Count); //var visitTaskId = taskList[randomIndex].Id; #endregion var visitTaskId = taskList[0].Id; task = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Select(x => new GetReadingTaskDto() { VisitTaskId = x.Id, ArmEnum = x.ArmEnum, TaskBlindName = x.TaskBlindName, ReadingCategory = x.ReadingCategory, VisistId = x.SourceSubjectVisitId != null ? x.SourceSubjectVisitId.Value : x.ReadModule == null ? default(Guid) : x.ReadModule.SubjectVisitId, VisitNum = x.VisitTaskNum, SubjectId = x.SubjectId, SubjectCode = x.Subject.Code, TrialReadingCriterionId = x.TrialReadingCriterionId, }).FirstOrDefaultAsync(); } else { var query = _visitTaskRepository.Where(x => x.TrialId == inDto.TrialId && x.TrialReadingCriterionId == trialReadingCriterionId && x.ReadingTaskState != ReadingTaskState.HaveSigned && x.DoctorUserId == _userInfo.UserRoleId && x.TrialReadingCriterionId == trialReadingCriterionId && x.TaskState == TaskState.Effect) .Where(x => !cacheSkipIds.Contains(x.Id)); //如果是随机阅片 Random random = new Random(); var skipcount = 0; var minRandomOrder = query.Where(t => t.RandomOrder != null).Select(t => t.RandomOrder).MinOrDefault(); //以随机序号优先,阅片中优先先给IR if (minRandomOrder != null) { query = query.Where(x => x.RandomOrder == minRandomOrder); skipcount = 0; } else { //没有随机序号的,那么就按照阅片中最新的时间给 var maxReadingTime = query.MaxOrDefault(x => x.FirstReadingTime); if (maxReadingTime != null) { query = query.Where(x => x.FirstReadingTime == maxReadingTime); skipcount = 0; } } var count = await query.CountAsync(); if (count >= 2) { skipcount = random.Next(0, count - 1); } if (count == 0) { throw new BusinessValidationFailedException(_localizer["ReadingImage_TaskFinish"], ApiResponseCodeEnum.CloseCurrentWindows); } task = await query .Select(x => new GetReadingTaskDto() { VisitTaskId = x.Id, ArmEnum = x.ArmEnum, TaskBlindName = x.TaskBlindName, ReadingCategory = x.ReadingCategory, VisistId = x.SourceSubjectVisitId != null ? x.SourceSubjectVisitId.Value : x.ReadModule == null ? default(Guid) : x.ReadModule.SubjectVisitId, VisitNum = x.VisitTaskNum, SubjectId = x.SubjectId, SubjectCode = x.Subject.Code, TrialReadingCriterionId = x.TrialReadingCriterionId, }).Skip(skipcount).FirstOrDefaultAsync(); } if (task == null) { throw new BusinessValidationFailedException(_localizer["ReadingImage_TaskFinish"], ApiResponseCodeEnum.CloseCurrentWindows); } else { //触发任务随机编号 await _downloadAndUploadService.SubejctRandomReadingTaskNameDeal(task.SubjectId, task.TrialReadingCriterionId); task.TaskBlindName = await _visitTaskRepository.Where(t => t.Id == task.VisitTaskId).Select(t => t.TaskBlindName).FirstOrDefaultAsync() ?? ""; } if (task.SubjectCode.IsNullOrEmpty()) { task.SubjectCode = await _subjectRepository.Where(x => x.Id == task.SubjectId).Select(x => x.Code).FirstNotNullAsync(); } await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == task.VisitTaskId && x.TaskState == TaskState.Effect && x.ReadingTaskState != ReadingTaskState.HaveSigned, x => new VisitTask() { FirstReadingTime = DateTime.Now, }); await _visitTaskRepository.SaveChangesAsync(); var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == task.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider).FirstNotNullAsync(); task.SubjectCode = visitTaskInfo.BlindSubjectCode.IsNullOrEmpty() ? task.SubjectCode : visitTaskInfo.BlindSubjectCode; var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == visitTaskInfo.TrialReadingCriterionId).Select(x => new { x.IsReadingShowPreviousResults, x.IsReadingShowSubjectInfo, x.DigitPlaces, x.ReadingVersionEnum, x.CriterionType, x.IseCRFShowInDicomReading, x.IsReadingTaskViewInOrder, x.ReadingToolList, }).FirstNotNullAsync(); task.IsReadingShowPreviousResults = criterionInfo.IsReadingShowPreviousResults; task.IsReadingShowSubjectInfo = criterionInfo.IsReadingShowSubjectInfo; task.IsReadingTaskViewInOrder = criterionInfo.IsReadingTaskViewInOrder; var isBaseLine = false; if (visitTaskInfo.SourceSubjectVisitId != null) { task.IsExistsNoDicomFile = await _noneDicomStudyRepository.AnyAsync(x => x.SubjectVisitId == visitTaskInfo.SourceSubjectVisitId && x.FileCount > 0); isBaseLine = await _subjectVisitRepository.Where(x => x.Id == visitTaskInfo.SourceSubjectVisitId).Select(x => x.IsBaseLine).FirstOrDefaultAsync(); } var clinicalDataList = await _readingClinicalDataService.GetClinicalDataList(new GetReadingOrTaskClinicalDataListInDto() { SubjectId = task.SubjectId, TrialId = inDto.TrialId, VisitTaskId = task.VisitTaskId, }); task.IsExistsClinicalData = clinicalDataList.Count > 0; task.IsReadClinicalData = visitTaskInfo.IsReadClinicalData; if (isBaseLine) { task.IsNeedReadClinicalData = clinicalDataList.Count > 0; } else { task.IsNeedReadClinicalData = clinicalDataList.Where(x => x.ClinicalDataLevel != ClinicalLevel.Subject).Count() > 0; } if (visitTaskInfo.ReadingTaskState == ReadingTaskState.WaitReading) { await _readingCalculateService.AddTaskLesionAnswerFromLastTask(new AddTaskLesionAnswerFromLastTaskInDto() { VisitTaskId = task.VisitTaskId }); } var trialInfo = await _trialRepository.Where(x => x.Id == visitTaskInfo.TrialId).FirstNotNullAsync(); // 如果已经签名 就不需要再读了 task.IsNeedReadClinicalData = visitTaskInfo.ReadingTaskState == ReadingTaskState.HaveSigned ? false : task.IsNeedReadClinicalData; task.DigitPlaces = criterionInfo.DigitPlaces; task.CriterionType = criterionInfo.CriterionType; task.IseCRFShowInDicomReading = criterionInfo.IseCRFShowInDicomReading; task.IsFirstChangeTask = visitTaskInfo.IsConvertedTask && visitTaskInfo.BeforeConvertedTaskId != null; task.IsConvertedTask = visitTaskInfo.IsConvertedTask; var blindSubjectCode = await _visitTaskRepository.Where(x => x.Id == task.VisitTaskId).Select(x => x.BlindSubjectCode).FirstNotNullAsync(); task.SubjectCode = blindSubjectCode.IsNullOrEmpty() ? task.SubjectCode : blindSubjectCode; task.ExistsManual = (await GetManualList(new GetManualListInDto() { TrialId = visitTaskInfo.TrialId })).Count > 0; task.ReadingTaskState = visitTaskInfo.ReadingTaskState; task.IsShowStudyName = trialInfo.IsShowStudyName; task.IsBaseLine = isBaseLine; task.ReadingVersionEnum = criterionInfo.ReadingVersionEnum; task.ReadingToolList = criterionInfo.ReadingToolList; task.IsExistUnprocessedFeedback = await _userFeedBackRepository.AnyAsync(x => x.VisitTaskId == task.VisitTaskId && x.State == 0); // 添加默认答案 if (inDto.VisitTaskId == null && visitTaskInfo.ReadingTaskState != ReadingTaskState.HaveSigned) { await AddDefaultValueToTask(task.VisitTaskId); } return task; } /// /// 重置阅片任务 /// /// /// [HttpPost] public async Task ResetReadingTask(ResetReadingTaskInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); if (taskinfo.ReadingCategory != ReadingCategory.Visit) { throw new BusinessValidationFailedException(_localizer["ReadingImage_CannotReset"]); } await _readingTableAnswerRowInfoRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId); await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId); await _readingTableQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId); await _readingTaskQuestionMarkRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId); await _readingCustomTagRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId); await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == inDto.VisitTaskId, x => new VisitTask() { ReadingTaskState = ReadingTaskState.WaitReading }); await _visitTaskRepository.SaveChangesAsync(); _userInfo.IsNotNeedInspection = true; await _readingCalculateService.AddTaskLesionAnswerFromLastTask(new AddTaskLesionAnswerFromLastTaskInDto() { VisitTaskId = inDto.VisitTaskId }); await AddDefaultValueToTask(inDto.VisitTaskId); return new ResetReadingTaskOutDto() { }; } /// /// 验证阅片休息时间 /// /// [HttpPost] public async Task VerifyReadingRestTime() { var userTypeEnum = (UserTypeEnum)_userInfo.UserTypeEnumInt; if (userTypeEnum != UserTypeEnum.IndependentReviewer) { return true; } var startReadingTimeKey = _userInfo.UserRoleId.ToString() + "StartReadingTime"; var startRestTimeKey = _userInfo.UserRoleId.ToString() + "StartRestTime"; int readingMinute = _verifyConfig.CurrentValue.ContinuousReadingTimeMin; // 为60整数 int restMinute = _verifyConfig.CurrentValue.ReadingRestTimeMin; // var startReadingTime = await _fusionCache.GetOrDefaultAsync(CacheKeys.StartReadingTimeKey(_userInfo.UserRoleId)); var startRestTime = await _fusionCache.GetOrDefaultAsync(CacheKeys.StartRestTime(_userInfo.UserRoleId)); if (startReadingTime == null && startRestTime == null) { await _fusionCache.SetAsync(CacheKeys.StartReadingTimeKey(_userInfo.UserRoleId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromHours(48)); } else if (startRestTime != null) { var cacheStartRestTime = DateTime.Parse(startRestTime!.ToString()); int timespanMin = (DateTime.Now - cacheStartRestTime).Minutes; if (timespanMin <= restMinute) { throw new BusinessValidationFailedException(_localizer["ReadingImage_NeedRest", 2, 10]); } else { // 休息时间>10分钟 删除休息时间的缓存 记录开始阅片时间 await _fusionCache.RemoveAsync(CacheKeys.StartRestTime(_userInfo.UserRoleId)); await _fusionCache.SetAsync(CacheKeys.StartReadingTimeKey(_userInfo.UserRoleId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromHours(48)); } } // 如果开始阅片时间 不为空 else if (startReadingTime != null) { #region 两小时 var cacheDate = DateTime.Parse(startReadingTime!.ToString()); int timespanMin = (DateTime.Now - cacheDate).Minutes; if (timespanMin > readingMinute) { await _fusionCache.RemoveAsync(CacheKeys.StartReadingTimeKey(_userInfo.UserRoleId)); await _fusionCache.SetAsync(CacheKeys.StartRestTime(_userInfo.UserRoleId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromHours(48)); throw new BusinessValidationFailedException(_localizer["ReadingImage_NeedRest", readingMinute / 60m, restMinute]); } #endregion } return true; } /// /// 重置阅片时间 登录和解锁调用 /// /// [HttpPost] public async Task ResetReadingRestTime(Guid? userRoleId) { var roleId = (userRoleId != null && userRoleId != Guid.Empty) ? (Guid)userRoleId : _userInfo.UserRoleId; //int readingMinute = 120; // 为60整数 int restMinute = 10; // var startReadingTime = await _fusionCache.GetOrDefaultAsync(CacheKeys.StartReadingTimeKey(roleId)); var startRestTime = await _fusionCache.GetOrDefaultAsync(CacheKeys.StartRestTime(roleId)); if (startRestTime != null) { var cacheStartRestTime = DateTime.Parse(startRestTime!.ToString()); int timespanMin = (DateTime.Now - cacheStartRestTime).Minutes; if (timespanMin > restMinute) { await _fusionCache.RemoveAsync(CacheKeys.StartRestTime(roleId)); } } else if (startReadingTime != null) { await _fusionCache.SetAsync(CacheKeys.StartReadingTimeKey(roleId), DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), TimeSpan.FromHours(48)); } //前端屏幕解锁才调用 if (userRoleId == null) { await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = _userInfo.IdentityUserId, OptType = UserOptType.WebUnlock }, true); } return true; } /// /// 签名提交任务修改状态 /// /// /// private async Task SubmitTaskChangeState(Guid visitTaskId) { await VerifyTaskIsSign(visitTaskId); await _visitTaskRepository.UpdatePartialFromQueryAsync(visitTaskId, x => new VisitTask() { ReadingTaskState = ReadingTaskState.HaveSigned, SignTime = DateTime.Now, }); await _visitTaskRepository.SaveChangesAsync(); bool isConverted = false; var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); var isConvertedTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Select(x => x.IsConvertedTask).FirstNotNullAsync(); switch (taskinfo.TrialReadingCriterion.CriterionType) { case CriterionType.IRECIST1Point1: if (!isConvertedTask && (await _readingTaskQuestionAnswerRepository.AnyAsync(x => x.VisitTaskId == visitTaskId && x.ReadingQuestionTrial.QuestionType == QuestionType.Tumor && x.Answer == (((int)OverallAssessment.PD)).ToString())) ) { isConverted = true; } break; } // 创建任务关联关系 await CreateTaskRelated(visitTaskId); // 是否触发转变任务 if (isConverted) { await _visitTaskHelpeService.AddConvertedTask(visitTaskId); } else { // 触裁判任务 await TriggerJudgeQuestion(visitTaskId); // 添加阅片期任务 await AddReadingTask(visitTaskId); // 完成阅片修改状态 //await FinishReadUpdateState(visitTaskId); await _visitTaskRepository.SaveChangesAsync(); await _trialEmailNoticeConfigService.BaseBusinessScenarioSendEmailAsync(visitTaskId); } } /// /// 签名时创建任务关联 /// /// private async Task CreateTaskRelated(Guid visitTaskId) { var taskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); // 判断是否有序阅片 var isReadingTaskViewInOrder = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == taskInfo.TrialReadingCriterionId).Select(x => x.IsReadingTaskViewInOrder).FirstNotNullAsync(); // 判断任务类型 // 关联访视Id List relatedVisitTaskIdList = new List(); // 既往任务Id List pastResultTaskIdList = new List(); // 冻结任务Id List reportRelatedTaskIdList = new List(); if (isReadingTaskViewInOrder == ReadingOrder.InOrder) { pastResultTaskIdList = await _visitTaskRepository.Where(x => x.TrialId == taskInfo.TrialId && x.SubjectId == taskInfo.SubjectId && x.VisitTaskNum < taskInfo.VisitTaskNum && x.ArmEnum == taskInfo.ArmEnum && x.DoctorUserId == taskInfo.DoctorUserId && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.TaskState == TaskState.Effect && x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.ReadingCategory == taskInfo.ReadingCategory && x.Id != taskInfo.Id ).OrderBy(x => x.VisitTaskNum).ThenBy(x => x.TaskState).Select(x => x.Id).ToListAsync(); reportRelatedTaskIdList = await _visitTaskRepository.Where(x => x.TrialId == taskInfo.TrialId && x.SubjectId == taskInfo.SubjectId && x.VisitTaskNum <= taskInfo.VisitTaskNum && x.ArmEnum == taskInfo.ArmEnum && x.DoctorUserId == taskInfo.DoctorUserId && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.ReadingTaskState == ReadingTaskState.HaveSigned && (x.TaskState == TaskState.Effect || x.TaskState == TaskState.Freeze) && x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.ReadingCategory == taskInfo.ReadingCategory && x.Id != taskInfo.Id ).OrderBy(x => x.VisitTaskNum).ThenBy(x => x.TaskState).Select(x => x.Id).ToListAsync(); switch (taskInfo.ReadingCategory) { case ReadingCategory.Visit: case ReadingCategory.Global: relatedVisitTaskIdList = await _visitTaskRepository.Where(x => x.TrialId == taskInfo.TrialId && x.SubjectId == taskInfo.SubjectId && x.ReadingCategory == ReadingCategory.Visit && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.ArmEnum == taskInfo.ArmEnum && x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.DoctorUserId == taskInfo.DoctorUserId && x.TaskState == TaskState.Effect && x.VisitTaskNum <= taskInfo.VisitTaskNum).Select(x => x.Id).ToListAsync(); break; case ReadingCategory.Oncology: // 肿瘤学这里很特殊 因为没有裁判的时候 可能取R1可能取R2 为了和之前阅片的时候保持统一 // 所以在保存肿瘤学答案的时候就存起来 现在签名的时候 创建关系 relatedVisitTaskIdList = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Select(x => x.RelatedVisitTaskIdList).FirstNotNullAsync(); break; } } else { if (taskInfo.ReadingCategory == ReadingCategory.Visit) { switch (isReadingTaskViewInOrder) { case ReadingOrder.SubjectRandom: relatedVisitTaskIdList = await _visitTaskRepository.Where(x => x.TrialId == taskInfo.TrialId && x.SubjectId == taskInfo.SubjectId && x.ReadingCategory == ReadingCategory.Visit && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && //x.ReadingTaskState == ReadingTaskState.HaveSigned && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.ArmEnum == taskInfo.ArmEnum && x.IsSelfAnalysis == taskInfo.IsSelfAnalysis && x.BlindSubjectCode == taskInfo.BlindSubjectCode && x.DoctorUserId == taskInfo.DoctorUserId && x.TaskState == TaskState.Effect && x.Id != taskInfo.Id).Select(x => x.Id).ToListAsync(); break; default: relatedVisitTaskIdList.Add(taskInfo.Id); break; } } } await _visitTaskRepository.UpdatePartialFromQueryAsync(taskInfo.Id, x => new VisitTask() { ReportRelatedTaskIds = JsonConvert.SerializeObject(reportRelatedTaskIdList), PastResultTaskIds = JsonConvert.SerializeObject(pastResultTaskIdList), RelatedVisitTaskIds = JsonConvert.SerializeObject(relatedVisitTaskIdList), }); await _readingTaskRelationRepository.AddRangeAsync(pastResultTaskIdList.Select(x => new ReadingTaskRelation() { RelevanceTaskId = x, TaskId = visitTaskId, RelevanceType = RelevanceType.PastResult, })); await _readingTaskRelationRepository.AddRangeAsync(relatedVisitTaskIdList.Select(x => new ReadingTaskRelation() { RelevanceTaskId = x, TaskId = visitTaskId, RelevanceType = RelevanceType.Related, })); await _readingTaskRelationRepository.AddRangeAsync(reportRelatedTaskIdList.Select(x => new ReadingTaskRelation() { RelevanceTaskId = x, TaskId = visitTaskId, RelevanceType = RelevanceType.ReportResult, })); await _visitTaskRepository.SaveChangesAsync(); } /// /// 阅片期 -全局和肿瘤学任务的生成 /// /// [HttpPost] [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task AddReadingTask(Guid visitTaskId, Guid? trialId = null) { // ****** 先生成阅片期 阅片期任务阅片完成之后生成肿瘤学的 如果没有阅片期 直接生成肿瘤学 *********//// #region 建立关系 // 访视阅完产生 全局 Dictionary typeChangeDic = new Dictionary(); typeChangeDic.Add(ModuleTypeEnum.InPlanSubjectVisit, ReadingCategory.Visit); typeChangeDic.Add(ModuleTypeEnum.OutPlanSubjectVisit, ReadingCategory.Visit); //typeChange.Add(ModuleTypeEnum.Read, ReadingCategory.ReadingPeriod); typeChangeDic.Add(ModuleTypeEnum.Global, ReadingCategory.Global); typeChangeDic.Add(ModuleTypeEnum.Referee, ReadingCategory.Judge); typeChangeDic.Add(ModuleTypeEnum.Oncology, ReadingCategory.Oncology); #endregion var taskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); List needReadList = new List(); if (!taskInfo.IsAnalysisCreate) { // 任务类型 switch (taskInfo.ReadingCategory) { case ReadingCategory.Visit: needReadList = await _readModuleRepository.Where(x => x.SubjectVisitId == taskInfo.SourceSubjectVisitId && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId) .Select(x => new ReadingGenerataTaskDTO { IsUrgent = x.IsUrgent ?? false, SubjectId = x.SubjectId, VisitNum = x.SubjectVisit.VisitNum, ReadingName = x.ModuleName, ReadModuleId = x.Id, ReadingCategory = typeChangeDic[x.ModuleType], }).ToListAsync(); if (needReadList.Any(x => x.ReadingCategory == ReadingCategory.Global) && taskInfo.TrialReadingCriterion.IsGlobalReading) { needReadList = needReadList.Where(x => x.ReadingCategory != ReadingCategory.Oncology).ToList(); await _visitTaskHelpeService.AddTaskAsync(new GenerateTaskCommand() { OriginalVisitId = visitTaskId, ReadingCategory = GenerateTaskCategory.Global, TrialId = taskInfo.TrialId, ReadingGenerataTaskList = needReadList }); } else if (needReadList.Any(x => x.ReadingCategory == ReadingCategory.Oncology)) { // 添加肿瘤学 if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskId && x.JudgeVisitTaskId == null)) { await AddOncologyTask(needReadList.Where(x => x.ReadingCategory == ReadingCategory.Oncology).First().ReadModuleId); } } //needReadList = needReadList.Where(x => _visitTaskRepository.Where(y => y.SouceReadModuleId == x.ReadModuleId).Count() == 0).ToList(); break; // 肿瘤学 case ReadingCategory.Global: var subjectVisitId = await _readModuleRepository.Where(x => x.Id == taskInfo.SouceReadModuleId).Select(x => x.SubjectVisitId).FirstOrDefaultAsync(); var oncologyReadId = await _readModuleRepository.Where(x => x.SubjectVisitId == subjectVisitId && x.ModuleType == ModuleTypeEnum.Oncology && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId ).Select(x => x.Id).FirstOrDefaultAsync(); if (await _visitTaskRepository.AnyAsync(x => x.Id == visitTaskId && x.JudgeVisitTaskId == null)) { await AddOncologyTask(oncologyReadId); } break; } } } #endregion } }