using Amazon.Runtime.Internal.Auth; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; using MassTransit; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Panda.DynamicWebApi.Attributes; using System.Linq.Dynamic.Core; namespace IRaCIS.Core.Application.Service { /// /// 非Dicom /// public partial class ReadingImageTaskService : BaseService, IReadingImageTaskService { /// /// 提交访视阅片问题 /// /// /// [NonDynamicMethod] public async Task SubmitVisitTaskQuestions(SubmitVisitTaskQuestionsInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); await this.SaveVisitTaskQuestions(inDto); await this.SubmitTaskChangeState(inDto.VisitTaskId); return ResponseOutput.Ok(true); } /// /// 保存答案和非Dicom标记绑定关系 /// /// /// [HttpPost] public async Task SaveAnswerAndBindingNoneDicomMark(AddNoneDicomMarkAndBinding inDto) { var visitTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); // 说明要移除标记数据 if (inDto.MeasureData == string.Empty) { // 先找到绑定关系 var binding = await _readingNoneDicomMarkBindingRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId && x.RowId == inDto.RowId && x.TableQuestionId == inDto.TableQuestionId).FirstOrDefaultAsync(); if (binding != null) { if ((await _readingNoneDicomMarkBindingRepository.Where(x => x.NoneDicomMarkId == binding.NoneDicomMarkId).CountAsync()) == 1) { await _readingNoneDicomMarkBindingRepository.DeleteFromQueryAsync(x => x.Id == binding.Id); } } } else { // 找到标记信息 var mark = await _readingNoneDicomMarkRepository.Where(x => x.MarkId == inDto.MarkId).FirstOrDefaultAsync(); if (mark != null) { if (mark.MeasureData != inDto.MeasureData || mark.Path != inDto.Path|| mark.OrderMarkName != inDto.OrderMarkName || mark.MarkTool != inDto.MarkTool) { await _readingNoneDicomMarkRepository.UpdatePartialFromQueryAsync(x => x.Id == mark.Id, u => new Domain.Models.ReadingNoneDicomMark() { MeasureData = inDto.MeasureData, MarkTool=inDto.MarkTool, OrderMarkName=inDto.OrderMarkName, Path = inDto.Path }); } } else { // 添加标记信息 mark = new ReadingNoneDicomMark() { Id = NewId.NextGuid(), VisitTaskId = inDto.VisitTaskId, StudyId = inDto.StudyId, MarkTool = inDto.MarkTool, OrderMarkName = inDto.OrderMarkName, NoneDicomFileId = inDto.NoneDicomFileId, Path = inDto.Path, PicturePath = inDto.PicturePath, MeasureData = inDto.MeasureData, MarkId = inDto.MarkId }; await _readingNoneDicomMarkRepository.AddAsync(mark); } await _readingNoneDicomMarkBindingRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId && x.RowId == inDto.RowId && x.TableQuestionId == inDto.TableQuestionId); await _readingNoneDicomMarkBindingRepository.AddAsync(new ReadingNoneDicomMarkBinding() { Id = NewId.NextGuid(), VisitTaskId = inDto.VisitTaskId, QuestionId = inDto.QuestionId, RowId = inDto.RowId, TableQuestionId = inDto.TableQuestionId, NoneDicomMarkId = mark.Id, MarkId = mark.MarkId }); } // 处理答案 if (inDto.RowId == null) { await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionTrialId == inDto.QuestionId); await _readingTaskQuestionAnswerRepository.AddAsync(new ReadingTaskQuestionAnswer() { Id = NewId.NextGuid(), SubjectId = visitTask.SubjectId, Answer = inDto.Answer, ReadingQuestionTrialId = inDto.QuestionId, VisitTaskId = inDto.VisitTaskId, TrialId = visitTask.TrialId }); } else { await _readingTableQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowId == inDto.RowId&&x.TableQuestionId==inDto.TableQuestionId); var rowinfo=await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.RowId.Value).FirstNotNullAsync(); await _readingTableQuestionAnswerRepository.AddAsync(new ReadingTableQuestionAnswer() { Id = NewId.NextGuid(), RowId = inDto.RowId.Value, Answer = inDto.Answer, QuestionId= inDto.QuestionId, TableQuestionId= inDto.TableQuestionId.Value, VisitTaskId = inDto.VisitTaskId, TrialId = visitTask.TrialId, RowIndex= rowinfo.RowIndex, }); } await _visitTaskRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } /// /// 修改比例修改答案 /// /// /// [HttpPost] public async Task ChangePlottingScaleChangeAnswer(ChangePlottingScaleChangeAnswerInDto inDto) { if (inDto.IsRemovePlottingScale) { await _readingNoneDicomMarkBindingRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingNoneDicomMark.NoneDicomFileId == inDto.NoneDicomFileId); } else { var answerList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); var tableAnswerList = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); foreach (var item in inDto.AnswerList) { if (item.RowId == null) { var answer= answerList.Where(x => x.ReadingQuestionTrialId == item.QuestionId).FirstOrDefault(); if (answer!=null) { await _readingTaskQuestionAnswerRepository.UpdatePartialFromQueryAsync(answer.Id, x => new ReadingTaskQuestionAnswer() { Answer = item.Answer }); } } else { var answer = tableAnswerList.Where(x => x.QuestionId == item.QuestionId&&x.RowId==item.RowId&&x.TableQuestionId==item.TableQuestionId).FirstOrDefault(); if (answer != null) { await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(answer.Id, x => new ReadingTableQuestionAnswer() { Answer = item.Answer }); } } } await _readingNoneDicomMarkRepository.UpdatePartialFromQueryAsync(x=>x.VisitTaskId==inDto.VisitTaskId&&x.Path==inDto.Path, x => new ReadingNoneDicomMark() { PicturePath = inDto.PicturePath }); } await _visitTaskRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } /// /// 修改比例修改答案 现在弃用了 /// /// /// /// private async Task ChangePlottingScale(Guid? id, decimal proportion) { var markInfo = await _readingNoneDicomMarkRepository.Where(x => x.Id == id).Select(x => new { x.NoneDicomFileId, x.VisitTaskId }).FirstNotNullAsync(); var visitTask = await _visitTaskRepository.Where(x => x.Id == markInfo.VisitTaskId).Include(x=>x.TrialReadingCriterion).FirstNotNullAsync(); var digitPlaces = visitTask.TrialReadingCriterion.DigitPlaces??0; if (proportion == -1) { await _readingNoneDicomMarkBindingRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == markInfo.VisitTaskId && x.ReadingNoneDicomMark.NoneDicomFileId == markInfo.NoneDicomFileId); } else { var bindingList= await _readingNoneDicomMarkBindingRepository.Where(x => x.VisitTaskId == markInfo.VisitTaskId && x.ReadingNoneDicomMark.NoneDicomFileId == markInfo.NoneDicomFileId) .ToListAsync(); List ImageToolAttributeList = new List() { "length", "perimeter", "area" }; var questionAnswerList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == markInfo.VisitTaskId && bindingList.Select(b => b.QuestionId).Contains(x.ReadingQuestionTrialId) && ImageToolAttributeList.Contains(x.ReadingQuestionTrial.ImageToolAttribute)).Include(x=>x.ReadingQuestionTrial) .ToListAsync(); foreach (var item in questionAnswerList) { var answerValue = item.Answer.IsNullOrEmptyReturn0(); switch (item.ReadingQuestionTrial.ImageToolAttribute) { case "length": case "perimeter": answerValue = answerValue * proportion; break; case "area": answerValue = answerValue * proportion * proportion; break; } await _readingTaskQuestionAnswerRepository.UpdatePartialFromQueryAsync(item.Id, x => new ReadingTaskQuestionAnswer() { Answer= decimal.Round(answerValue, digitPlaces).ToString("F" + digitPlaces.ToString()) }); } var tableQuestionAnswerList = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == markInfo.VisitTaskId && bindingList.Select(b => b.TableQuestionId).Contains(x.TableQuestionId) && ImageToolAttributeList.Contains(x.ReadingTableQuestionTrial.ImageToolAttribute)).Include(x => x.ReadingTableQuestionTrial) .ToListAsync(); foreach (var item in tableQuestionAnswerList) { var answerValue = item.Answer.IsNullOrEmptyReturn0(); switch (item.ReadingTableQuestionTrial.ImageToolAttribute) { case "length": case "perimeter": answerValue = answerValue * proportion; break; case "area": answerValue = answerValue * proportion * proportion; break; } await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(item.Id, x => new ReadingTableQuestionAnswer() { Answer = decimal.Round(answerValue, digitPlaces).ToString("F" + digitPlaces.ToString()) }); } } return ResponseOutput.Ok(); } /// /// 删除绑定关系 /// /// /// [HttpPost] public async Task DeleteBinding(DeleteBindingInDto inDto) { await _readingNoneDicomMarkBindingRepository.DeleteFromQueryAsync(x =>x.Id==inDto.BindingIdId, true); return ResponseOutput.Ok(); } /// /// 获取非Dicom标记和绑定关系 /// /// /// [HttpPost] public async Task GetNoneDicomMarkAndBinding(GetNoneDicomMarkAndBindingInDto inDto) { GetNoneDicomMarkAndBindingOutDto result=new GetNoneDicomMarkAndBindingOutDto (); result.NoneDicomMarkList = await _readingNoneDicomMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId) .ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); result.BindingList = await _readingNoneDicomMarkBindingRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId) .ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); return result; } /// /// 添加非Dicom标记 /// /// /// [HttpPost] public async Task AddNoneDicomMark(AddNoneDicomMarkInDto inDto) { var entity = await _readingNoneDicomMarkRepository.InsertOrUpdateAsync(inDto,true); await _visitTaskRepository.SaveChangesAsync(); return ResponseOutput.Ok(entity.Id); } /// /// 获取非Dicom标记 /// /// /// [HttpPost] public async Task GetNoneDicomMarkListOutDto(GetNoneDicomMarkListInDtoDto inDto) { var result = await _readingNoneDicomMarkRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId) .ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); return new GetNoneDicomMarkListOutDto() { NoneDicomMarkList = result }; } /// /// 删除非Dicom标记 /// /// /// [HttpPost("{id:guid}")] public async Task DeleteTrialFileType(Guid id) { var success = await _readingNoneDicomMarkRepository.DeleteFromQueryAsync(t => t.Id == id, true); return ResponseOutput.Ok(); } /// /// 保存任务问题 /// /// /// [HttpPost] [TrialGlobalLimit("AfterStopCannNotOpt")] public async Task SaveVisitTaskQuestions(SubmitVisitTaskQuestionsInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); var subjectId = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.SubjectId).FirstOrDefaultAsync(); await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionCriterionTrialId == inDto.ReadingQuestionCriterionTrialId); List readingTaskAnswerList = inDto.AnswerList.Select(x => new ReadingTaskQuestionAnswer() { Id = NewId.NextGuid(), SubjectId = subjectId, Answer = x.Answer, ReadingQuestionCriterionTrialId = inDto.ReadingQuestionCriterionTrialId, ReadingQuestionTrialId = x.ReadingQuestionTrialId, VisitTaskId = inDto.VisitTaskId, TrialId = inDto.TrialId }).ToList(); await _readingTaskQuestionAnswerRepository.AddRangeAsync(readingTaskAnswerList); var result = await _visitTaskRepository.SaveChangesAsync(); return ResponseOutput.Ok(result); } /// /// 获取阅片非Dicom文件 /// /// /// [HttpPost] public async Task>> GetReadingImageFile(GetReadingImgInDto inDto) { var task = await GetNextTask(new GetNextTaskInDto() { TrialId = inDto.TrialId, SubjectId = inDto.SubjectId, VisitTaskId = inDto.VisistTaskId, }); List visitIds = new List(); if (task.ReadingCategory == ReadingCategory.Visit) { visitIds.Add(task.VisistId); } else { // 阅片期取前面所有的图像 visitIds.AddRange(await _subjectVisitRepository.Where(x => x.VisitNum <= task.VisitNum && x.SubjectId == task.SubjectId).Select(x => x.Id).ToListAsync()); } var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisistTaskId).Select(t => new { t.BlindSubjectCode, t.ReadingTaskState, t.TrialReadingCriterionId, t.TrialReadingCriterion.IsImageFilter, t.TrialReadingCriterion.CriterionModalitys }).FirstNotNullAsync(); IQueryable noneDicomStudyQueryable = default; noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.IsReading) .Where(t => visitIds.Contains(t.SubjectVisitId) && t.NoneDicomFileList.Any(t => !t.FileType.Contains(StaticData.FileType.Zip))) .WhereIf(taskinfo.IsImageFilter == true, t => taskinfo.CriterionModalitys.Contains(t.Modality)) .ProjectTo(_mapper.ConfigurationProvider, new { isFilterZip = true, isReading = true }); if (inDto.VisistTaskId != null && _noneDicomStudyFileSystem.Any(t => t.VisitTaskId == inDto.VisistTaskId)) { noneDicomStudyQueryable = _noneDicomStudyRepository.Where(t => t.IsReading) .Where(t => t.TaskNoneDicomFileList.Any(t => t.VisitTaskId == inDto.VisistTaskId)) .Where(t => taskinfo.IsImageFilter ? ("|" + taskinfo.CriterionModalitys + "|").Contains("|" + t.Modality + "|") : true) .Where(t => visitIds.Contains(t.SubjectVisitId)) .ProjectTo(_mapper.ConfigurationProvider, new { isFilterZip = true, isReading = true, visiTaskId = inDto.VisistTaskId }); } List result = await noneDicomStudyQueryable.OrderBy(x => x.ImageDate).ThenBy(x => x.CreateTime).ToListAsync(); var nonoDicomStudyFileIds = await _readingNoneDicomMarkRepository.Where(x => x.VisitTaskId == inDto.VisistTaskId).ToListAsync(); if (nonoDicomStudyFileIds.Count > 0 && taskinfo.ReadingTaskState == ReadingTaskState.HaveSigned) { var studyId = nonoDicomStudyFileIds.Select(x => x.StudyId).FirstOrDefault(); var noneDicomids = nonoDicomStudyFileIds.Select(x => x.NoneDicomFileId).ToList(); var noneDicomStudyViewMark = new NoneDicomStudyView() { Id = Guid.NewGuid() }; noneDicomStudyViewMark.IsCriticalSequence = true; noneDicomStudyViewMark.NoneDicomStudyFileList = await _noneDicomStudyFileRepository.Where(x => noneDicomids.Contains(x.Id)).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); foreach (var item in noneDicomStudyViewMark.NoneDicomStudyFileList) { item.MarkTime = nonoDicomStudyFileIds.Where(x => x.NoneDicomFileId == item.Id).Select(x => x.CreateTime).FirstOrDefault(); } noneDicomStudyViewMark.NoneDicomStudyFileList= noneDicomStudyViewMark.NoneDicomStudyFileList.OrderBy(x => x.MarkTime).ToList(); result.Insert(0, noneDicomStudyViewMark); } var trialInfo = await _trialRepository.Where(x => x.Id == inDto.TrialId).Select(x => new { x.ClinicalInformationTransmissionEnum, }).FirstOrDefaultAsync(); var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == taskinfo.TrialReadingCriterionId).Select(x => new { x.IsReadingShowPreviousResults, x.IsReadingShowSubjectInfo, x.CriterionName, x.Id, x.ReadingTool, }).FirstOrDefaultAsync(); bool isExistsClinicalData = false; if (trialInfo.ClinicalInformationTransmissionEnum == 1) { isExistsClinicalData = (await _readingClinicalDataService.GetClinicalDataList(new GetReadingOrTaskClinicalDataListInDto() { SubjectId = task.SubjectId, TrialId = inDto.TrialId, VisitTaskId = task.VisitTaskId, })).Count() > 0; } var taskInfo = await _visitTaskRepository.Where(x => x.Id == task.VisitTaskId).FirstNotNullAsync(); return ResponseOutput.Ok(result, new { VisitTaskId = task.VisitTaskId, SubjectId = task.SubjectId, SubjectCode = taskInfo.BlindSubjectCode.IsNullOrEmpty() ? task.SubjectCode : taskInfo.BlindSubjectCode, ReadingCategory = task.ReadingCategory, TaskBlindName = task.TaskBlindName, IsReadingShowPreviousResults = criterionInfo.IsReadingShowPreviousResults, IsReadingShowSubjectInfo = criterionInfo.IsReadingShowSubjectInfo, IsExistsClinicalData = isExistsClinicalData, TrialCriterionName = criterionInfo.CriterionName, TrialCriterionId = criterionInfo.Id }); } } }