using IRaCIS.Core.Domain.Share; using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Application.Service.Reading.Dto; using MassTransit; using IRaCIS.Core.Infra.EFCore.Common; using Panda.DynamicWebApi.Attributes; using AutoMapper; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Application.Service; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Application.Interfaces; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Microsoft.Extensions.Caching.Memory; namespace IRaCIS.Application.Services { /// <summary> /// IR影像阅片 /// </summary> [ApiExplorerSettings(GroupName = "Reading")] public partial class ReadingImageTaskService : BaseService, IReadingImageTaskService { private readonly IRepository<NoneDicomStudy> _noneDicomStudyRepository; private readonly IRepository<VisitTask> _visitTaskRepository; private readonly IRepository<Trial> _trialRepository; private readonly IRepository<ReadingTableQuestionAnswer> _readingTableQuestionAnswerRepository; private readonly IRepository<ReadingOncologyTaskInfo> _readingOncologyTaskInfoRepository; private readonly IVisitTaskHelpeService _visitTaskHelpeService; private readonly IVisitTaskService _visitTaskService; private readonly IReadingClinicalDataService _readingClinicalDataService; private readonly IReadingCalculateService _readingCalculateService; private readonly IRepository<SubjectVisit> _subjectVisitRepository; private readonly IRepository<Subject> _subjectRepository; private readonly IRepository<ReadingGlobalTaskInfo> _readingGlobalTaskInfoRepository; private readonly IRepository<ReadingCriterionPage> _readingCriterionPageRepository; private readonly IRepository<ReadingJudgeInfo> _readingJudgeInfoRepository; private readonly IRepository<ReadModule> _readModuleRepository; private readonly IRepository<DicomInstance> _dicomInstanceRepository; private readonly IRepository<ReadingCriterionDictionary> _readingCriterionDictionaryRepository; private readonly IRepository<TumorAssessment> _tumorAssessmentRepository; private readonly IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository; private readonly IRepository<ReadingTableQuestionSystem> _readingTableQuestionSystemRepository; private readonly IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository; private readonly IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository; private readonly IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository; private readonly IRepository<ReadingQuestionCriterionSystem> _readingQuestionCriterionSystemRepository; private readonly IRepository<ReadingQuestionSystem> _readingQuestionSystem; private readonly IRepository<NoneDicomStudyFile> _noneDicomStudyFileSystem; private readonly IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository; private readonly IMemoryCache _cache; private readonly ITrialEmailNoticeConfigService _trialEmailNoticeConfigService; public ReadingImageTaskService( IMapper mapper, IRepository<NoneDicomStudy> noneDicomStudyRepository, IRepository<VisitTask> visitTaskRepository, IRepository<Trial> TrialRepository, IRepository<ReadingTableQuestionAnswer> ReadingTableQuestionAnswerRepository, IRepository<ReadingOncologyTaskInfo> ReadingOncologyTaskInfoRepository, IVisitTaskHelpeService visitTaskHelpeService, IVisitTaskService visitTaskService, IReadingClinicalDataService readingClinicalDataService, IReadingCalculateService readingCalculateService, IRepository<SubjectVisit> subjectVisitRepository, IRepository<Subject> subjectRepository, IRepository<ReadingGlobalTaskInfo> readingGlobalTaskInfoRepository, IRepository<ReadingCriterionPage> readingCriterionPageRepository, IRepository<ReadingJudgeInfo> readingJudgeInfoRepository, IRepository<ReadModule> readModuleRepository, IRepository<DicomInstance> dicomInstanceRepository, IMemoryCache cache, IRepository<ReadingCriterionDictionary> readingCriterionDictionaryRepository, IRepository<TumorAssessment> tumorAssessmentRepository, IRepository<ReadingTableAnswerRowInfo> readingTableAnswerRowInfoRepository, IRepository<ReadingTableQuestionSystem> readingTableQuestionSystemRepository, IRepository<ReadingTableQuestionTrial> readingTableQuestionTrialRepository, IRepository<ReadingTaskQuestionAnswer> readingTaskQuestionAnswerRepository, IRepository<ReadingQuestionCriterionTrial> readingQuestionCriterionTrialRepository, IRepository<ReadingQuestionCriterionSystem> readingQuestionCriterionSystemRepository, IRepository<ReadingQuestionSystem> ReadingQuestionSystem, ITrialEmailNoticeConfigService trialEmailNoticeConfigService, IRepository<NoneDicomStudyFile> noneDicomStudyFileSystem, IRepository<ReadingQuestionTrial> readingQuestionTrialRepository ) { base._mapper = mapper; this._noneDicomStudyRepository = noneDicomStudyRepository; this._visitTaskRepository = visitTaskRepository; this._trialRepository = TrialRepository; this._readingTableQuestionAnswerRepository = ReadingTableQuestionAnswerRepository; this._readingOncologyTaskInfoRepository = ReadingOncologyTaskInfoRepository; this._visitTaskHelpeService = visitTaskHelpeService; this._visitTaskService = visitTaskService; this._readingClinicalDataService = readingClinicalDataService; this._readingCalculateService = readingCalculateService; this._subjectVisitRepository = subjectVisitRepository; this._subjectRepository = subjectRepository; this._readingGlobalTaskInfoRepository = readingGlobalTaskInfoRepository; this._readingCriterionPageRepository = readingCriterionPageRepository; this._readingJudgeInfoRepository = readingJudgeInfoRepository; this._readModuleRepository = readModuleRepository; this._dicomInstanceRepository = dicomInstanceRepository; this._readingCriterionDictionaryRepository = readingCriterionDictionaryRepository; this._tumorAssessmentRepository = tumorAssessmentRepository; this._readingTableAnswerRowInfoRepository = readingTableAnswerRowInfoRepository; this._readingTableQuestionSystemRepository = readingTableQuestionSystemRepository; this._readingTableQuestionTrialRepository = readingTableQuestionTrialRepository; this._readingTaskQuestionAnswerRepository = readingTaskQuestionAnswerRepository; this._readingQuestionCriterionTrialRepository = readingQuestionCriterionTrialRepository; this._readingQuestionCriterionSystemRepository = readingQuestionCriterionSystemRepository; this._readingQuestionSystem = ReadingQuestionSystem; this._noneDicomStudyFileSystem = noneDicomStudyFileSystem; this._readingQuestionTrialRepository = readingQuestionTrialRepository; this._cache = cache; this._trialEmailNoticeConfigService = trialEmailNoticeConfigService; } /// <summary> /// 阅读临床数据 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task ReadClinicalData(ReadClinicalDataInDto inDto) { await _visitTaskRepository.UpdatePartialFromQueryAsync(inDto.VisitTaskId, x => new VisitTask { IsReadClinicalData = true }); await _visitTaskRepository.SaveChangesAsync(); } /// <summary> /// 添加默认值到任务里面 /// </summary> /// <returns></returns> [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<ReadingTaskQuestionAnswer> 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 阅片页面 关联信息查询 以及基本验证 /// <summary> /// 根据任务ID获取ReadingTool /// </summary> /// <param name="indto"></param> /// <returns></returns> [HttpPost] public async Task<GetReadingToolOutDto> 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; } /// <summary> /// 获取关联的阅片任务 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<(List<GetRelatedVisitTaskOutDto>, 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 result = await _visitTaskRepository .WhereIf(taskInfo.TaskState != TaskState.Effect, x => x.Id == inDto.VisitTaskId) .Where(x => (x.TrialId == taskInfo.TrialId && x.SubjectId == taskInfo.SubjectId && x.ArmEnum == taskInfo.ArmEnum && x.DoctorUserId == taskInfo.DoctorUserId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.TaskState == TaskState.Effect && x.VisitTaskNum <= taskInfo.VisitTaskNum && x.IsAnalysisCreate == taskInfo.IsAnalysisCreate && x.ReadingCategory == ReadingCategory.Visit) || x.Id == inDto.VisitTaskId) .Select(x => new GetRelatedVisitTaskOutDto() { TaskBlindName = x.TaskBlindName, TaskName = x.TaskName, ReadingTaskState = x.ReadingTaskState, VisitId = x.SourceSubjectVisitId, VisitTaskId = x.Id, VisitTaskNum = x.VisitTaskNum, IsBaseLineTask = x.SourceSubjectVisitId == baselineVisitId, IsCurrentTask = x.Id == inDto.VisitTaskId, }).OrderBy(x => x.VisitTaskNum).ToListAsync(); if (!taskInfo.TrialReadingCriterion.IsReadingTaskViewInOrder) { result = result.Where(x => x.VisitTaskId == inDto.VisitTaskId).ToList(); } return (result, new { ReadingTaskState = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.ReadingTaskState).FirstOrDefaultAsync() }); } /// <summary> /// 获取既往任务名称和编号 /// </summary> /// <returns></returns> [HttpPost] public async Task<List<GetReadingPastResultListOutDto>> GetReadingPastResultList(GetReadingPastResultListInDto inDto) { var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var readingPastResultList = await _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) .WhereIf(taskInfo.ReadingCategory != ReadingCategory.Visit, x => x.ReadingCategory == taskInfo.ReadingCategory) .ProjectTo<GetReadingPastResultListOutDto>(_mapper.ConfigurationProvider).OrderBy(x => x.VisitTaskNum).ToListAsync(); return readingPastResultList; } /// <summary> /// 获取阅片的受试者信息 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<GetReadingSubjectInfoOutDto> GetReadingSubjectInfo(GetReadingSubjectInfoInDto inDto) { var visitTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstOrDefaultAsync(); 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 }).FirstOrDefaultAsync(); 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 : visitTask.BlindSubjectCode, ReadingCategory = visitTask.ReadingCategory, TaskBlindName = visitTask.TaskBlindName, IsReadingShowPreviousResults = criterionInfo.IsReadingShowPreviousResults, IsReadingShowSubjectInfo = criterionInfo.IsReadingShowSubjectInfo, }; } /// <summary> /// 验证是否为基线访视任务 /// </summary> /// <param name="visitTaskId"></param> /// <returns></returns> /// <exception cref="BusinessValidationFailedException"></exception> 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"]); } } /// <summary> /// 验证任务是否签名 /// </summary> /// <param name="visitTaskid"></param> /// <returns></returns> /// <exception cref="BusinessValidationFailedException"></exception> private async Task VerifyTaskIsSign(Guid visitTaskid) { 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"]); } } #endregion #region 访视任务 - Dicom 阅片 表格问题相关查询 /// <summary> /// 获取DIcom阅片问题答案 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<(List<DicomReadingQuestionAnswer>, 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); return (result, new { ReadingTaskState = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.ReadingTaskState).FirstOrDefaultAsync() }); } /// <summary> /// 获取阅片外层问题 /// </summary> /// <param name="trialReadingCriterionId"></param> /// <param name="visitTaskId"></param> /// <returns></returns> [NonDynamicMethod] public async Task<List<DicomReadingQuestionAnswer>> GetReadingQuestion(Guid trialReadingCriterionId, Guid? visitTaskId) { var criterionIdInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == trialReadingCriterionId).FirstNotNullAsync(); //排除表格问题 var questions = await _readingQuestionTrialRepository .WhereIf(criterionIdInfo.IseCRFShowInDicomReading, x => x.ReadingQuestionCriterionTrialId == trialReadingCriterionId && x.Type != ReadingQestionType.Table) .WhereIf(!criterionIdInfo.IseCRFShowInDicomReading, x => x.IsShowInDicom && x.ReadingQuestionCriterionTrialId == trialReadingCriterionId && x.Type != ReadingQestionType.Table) .ProjectTo<DicomReadingQuestionAnswer>(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder).ToListAsync(); var answers = new List<ReadingTaskQuestionAnswer>(); if (visitTaskId != null) { answers = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).ToListAsync(); ; } //排除表格问题 同时排除组问题 var groups = questions.Where(x => x.Type != ReadingQestionType.Group).Select(x => x.GroupName).ToList(); var result = questions.Where(x => x.Type == ReadingQestionType.Group && groups.Contains(x.GroupName)).ToList(); foreach (var item in result) { GetDicomReadingAnswer(item, questions, answers); } return result; } private void GetDicomReadingAnswer(DicomReadingQuestionAnswer item, List<DicomReadingQuestionAnswer> questions, List<ReadingTaskQuestionAnswer> answers) { var answer= answers.Where(x => x.ReadingQuestionTrialId == item.Id).Select(x => x.Answer).FirstIsNullReturnEmpty(); item.Answer = answer.IsNullOrEmpty() ? item.DefaultValue : answer; item.Childrens = questions.Where(x => x.ParentId == item.Id || ((item.Type == ReadingQestionType.Group && x.Type != ReadingQestionType.Group && x.ParentId == null && x.GroupName == item.GroupName))).ToList(); if (item.Childrens != null && item.Childrens.Count > 0) { foreach (var question in item.Childrens) { GetDicomReadingAnswer(question, questions, answers); } } } /// <summary> /// 获取阅片报告 /// </summary> /// <param name="indto"></param> /// <returns></returns> [HttpPost] public async Task<GetReadingReportEvaluationOutDto> GetReadingReportEvaluation(GetReadingReportEvaluationInDto indto) { return await _readingCalculateService.GetReadingReportEvaluation(indto); } /// <summary> /// 获取表格答案行信息 /// </summary> /// <param name="inDto"></param> /// <remarks> /// (QuestionId) 可为空 /// </remarks> /// <returns></returns> [HttpGet] public async Task<List<GetTableAnswerRowInfoOutDto>> GetTableAnswerRowInfoList(GetTableAnswerRowInfoInDto inDto) { await _readingCalculateService.AddTaskLesionAnswerFromLastTask(new AddTaskLesionAnswerFromLastTaskInDto() { VisitTaskId = inDto.VisitTaskId }); var result = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId) .WhereIf(inDto.QuestionId != null, x => x.QuestionId == inDto.QuestionId) .ProjectTo<GetTableAnswerRowInfoOutDto>(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex) .ToListAsync(); result.ForEach(x => { x.OrderMarkName = x.OrderMark + x.RowIndexNum.GetLesionMark(); }); return result; } /// <summary> /// 获取表格问题及答案(2022-08-26) /// </summary> /// <param name="inDto"></param> /// <returns></returns> [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<ReadingTableQuestionAnswerInfo>(_mapper.ConfigurationProvider) .Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); var tableAnsweRowInfos = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ProjectTo<TableAnsweRowInfo>(_mapper.ConfigurationProvider).ToListAsync(); var questionPage = await GetReadingTableQuestion( new GetReadingTableQuestionOrAnswerInDto() { TrialReadingCriterionId = taskinfo.TrialReadingCriterionId, TaskId = inDto.VisitTaskId, TableAnswers = tableAnswers, TableAnsweRowInfos = tableAnsweRowInfos } ); result.SinglePage = questionPage.SinglePage; result.MultiPage = questionPage.MultiPage; result.PublicPage = questionPage.PublicPage; result.BlindName = visitTaskInfo.TaskBlindName; result.TaskNum = visitTaskInfo.VisitTaskNum; return (result, new { readingTaskState = visitTaskInfo.ReadingTaskState, FormType = criterionInfo.FormType, TaskNum = visitTaskInfo.VisitTaskNum, }); ; } /// <summary> /// 获取自定义问题以及答案 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<(GetReadingTableQuestionOutDto, bool)> GetCustomTableQuestionAnswer(GetCustomTableQuestionAnswerInDto inDto) { var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var tableAnswers = await _readingTableQuestionAnswerRepository .ProjectTo<ReadingTableQuestionAnswerInfo>(_mapper.ConfigurationProvider) .Where(x => x.VisitTaskId == inDto.VisitTaskId).ToListAsync(); var tableAnsweRowInfos = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).ProjectTo<TableAnsweRowInfo>(_mapper.ConfigurationProvider).ToListAsync(); return (await this.GetReadingTableQuestion( new GetReadingTableQuestionOrAnswerInDto() { TrialReadingCriterionId = taskInfo.TrialReadingCriterionId, TaskId = taskInfo.Id, TableAnswers = tableAnswers, TableAnsweRowInfos = tableAnsweRowInfos, IsGetallQuestion = true } ), true); } /// <summary> /// 获取表格问题及答案 只返回表格问题(任务和标准) /// </summary> /// <param name="inDto"></param> /// <returns></returns> [NonDynamicMethod] public async Task<GetReadingTableQuestionOutDto> GetReadingTableQuestion(GetReadingTableQuestionOrAnswerInDto inDto) { var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).FirstNotNullAsync(); var qusetionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId).ProjectTo<TrialReadQuestionData>(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder).ToListAsync(); //是否是预览 if (inDto.IsGetPreview == false) { // 是否获取所有问题 if (inDto.IsGetallQuestion) { if (!criterionInfo.IseCRFShowInDicomReading) { qusetionList = qusetionList.Where(x => x.IsShowInDicom).OrderBy(x => x.ShowOrder).ToList(); } } else { if (!criterionInfo.IseCRFShowInDicomReading) { qusetionList = qusetionList.Where(x => x.IsShowInDicom && (x.Type == ReadingQestionType.Table || x.Type == ReadingQestionType.Group)).OrderBy(x => x.ShowOrder).ToList(); } var usedGurops = qusetionList.Where(x => x.Type == ReadingQestionType.Table).Select(x => x.GroupName).ToList(); qusetionList = qusetionList.Where(x => usedGurops.Contains(x.GroupName)).ToList(); } } 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<TrialReadQuestionData>(); var qusetionIds = qusetionList.Select(x => x.Id).ToList(); var tableQuestionList = await _readingTableQuestionTrialRepository.Where(x => qusetionIds.Contains(x.ReadingQuestionId)) .ProjectTo<TableQuestionTrial>(_mapper.ConfigurationProvider) .OrderBy(x => x.ShowOrder).ToListAsync(); var result = new GetReadingTableQuestionOutDto(); 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 || (x.ParentId == null && x.GroupName.IsNullOrEmpty())).ToList(); pageGroupList.ForEach(x => { this.FindChildQuestion(x, newPageQusetionList, tableQuestionList, inDto.TableAnswers, inDto.TableAnsweRowInfos); }); 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 || (x.ParentId == null && x.GroupName.IsNullOrEmpty())).ToList(); groupList.ForEach(x => { this.FindChildQuestion(x, qusetionList, tableQuestionList, inDto.TableAnswers, inDto.TableAnsweRowInfos); }); groupList = groupList.Where(x => !(x.Type == ReadingQestionType.Group && x.Childrens.Count() == 0)).ToList(); result.SinglePage = groupList; } return result; } /// <summary> /// 获取子元素 /// </summary> /// <param name="item"></param> /// <param name="questionlists"></param> /// <param name="tableQuestionLists"></param> private void FindChildQuestion(TrialReadQuestionData item, List<TrialReadQuestionData> questionlists, List<TableQuestionTrial> tableQuestionLists, List<ReadingTableQuestionAnswerInfo> tableAnswers, List<TableAnsweRowInfo> tableAnsweRowInfos) { item.Childrens = questionlists.Where(x => x.ParentId == item.Id || (item.Type == ReadingQestionType.Group && x.Type != ReadingQestionType.Group && x.ParentId == null && x.GroupName == item.GroupName)).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 = tableQuestionLists.Where(z => (z.DependParentId ?? default(Guid)) == x.Id).Select(x => new GetTrialReadingQuestionOutDto { Childrens = new List<GetTrialReadingQuestionOutDto>(), ShowOrder = x.ShowOrder, GroupName = string.Empty, Id = x.Id, DictionaryCode = x.DictionaryCode, Type = x.Type, TableQuestionType = x.TableQuestionType, DependParentId = x.DependParentId, IsDepend = x.IsDepend, QuestionMark = x.QuestionMark, TypeValue = x.TypeValue, RelevanceId = x.RelevanceId, RelevanceValue = x.RelevanceValue, ImageCount = 0, ParentId = item.Id, DataTableColumn = x.DataTableColumn, LesionType = item.LesionType, QuestionName = x.QuestionName, RelationQuestions = new List<GetTrialReadingQuestionOutDto>(), Remark = x.Remark, ValueType = x.ValueType, Unit = x.Unit, }).ToList(); }); 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<Dictionary<string, string>>(); orders.ForEach(x => { Dictionary<string, string> answers = new Dictionary<string, string>(); var rowInfo = tableAnsweRowInfos.Where(y => y.RowIndex == x && y.QuestionId == item.Id).FirstOrDefault(); var rowAnswer = thisAnswer.Where(y => y.RowId == rowInfo.Id).OrderBy(y => y.ShowOrder).ToList(); rowAnswer.ForEach(z => { answers.Add(z.TableQuestionId.ToString(), z.Answer); }); answers.Add("BlindName", rowInfo.BlindName); answers.Add("IsDicomReading", rowInfo.IsDicomReading.ToString()); answers.Add("MeasureData", rowInfo == null ? string.Empty : rowInfo.MeasureData); answers.Add("RowIndex", x.ToString()); answers.Add("RowId", rowInfo.Id.ToString()); answers.Add("StudyId", rowInfo.StudyId.ToString()); answers.Add("OrganInfoId", rowInfo.OrganInfoId.ToString()); answers.Add("IsCanEditPosition", rowInfo.IsCanEditPosition.ToString()); answers.Add("InstanceId", rowInfo == null ? string.Empty : rowInfo.InstanceId.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.SplitName.IsNullOrEmpty() ? rowInfo.MergeName : rowInfo.SplitName); answers.Add("SplitOrMergeType", rowInfo.SplitOrMergeType == null ? string.Empty : ((int)rowInfo.SplitOrMergeType).ToString()); item.TableQuestions.Answers.Add(answers); }); if (item.Childrens != null && item.Childrens.Count != 0) { item.Childrens.ForEach(x => { this.FindChildQuestion(x, questionlists, tableQuestionLists, tableAnswers, tableAnsweRowInfos); }); } } #region 访视任务 - Dicom 阅片 表格问题 病灶的拆分与合并 /// <summary> /// 拆分病灶 /// </summary> /// <returns></returns> [HttpPost] public async Task SplitLesion(SplitLesionInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); await this.VerifyIsBaseLineTask(inDto.VisitTaskId); 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).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.SplitOrMergeType = SplitOrMergeType.Split; rowAnswer.SplitRowId = rowAnswer.Id; rowAnswer.Id = NewId.NextGuid(); rowAnswer.InstanceId = null; rowAnswer.SeriesId = null; rowAnswer.IsCurrentTaskAdd = true; rowAnswer.MeasureData = string.Empty; List<QuestionMark?> needRemoveMark = new List<QuestionMark?>() { QuestionMark.MajorAxis, QuestionMark.ShortAxis, QuestionMark.State, }; tableAnswers.ForEach(x => { x.Id = NewId.NextGuid(); x.RowIndex = newRowIndex; x.VisitTaskId = inDto.VisitTaskId; x.RowId = rowAnswer.Id; x.Answer = needRemoveMark.Contains(x.ReadingTableQuestionTrial.QuestionMark) ? string.Empty : x.Answer; x.ReadingTableQuestionTrial = null; }); await _readingTableAnswerRowInfoRepository.AddAsync(rowAnswer); await _readingTableQuestionAnswerRepository.AddRangeAsync(tableAnswers); await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); } /// <summary> /// 合并病灶 /// </summary> /// <returns></returns> [HttpPost] public async Task MergeLesion(MergeLesionInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); await this.VerifyIsBaseLineTask(inDto.VisitTaskId); var rowsInfo = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && (x.Id == inDto.MainRowId || x.Id == inDto.MergeRowId)).ToListAsync(); if (rowsInfo.Count() != 2) { throw new BusinessValidationFailedException(_localizer["ReadingImage_NotaTask"]); } var minaid = rowsInfo.Where(x => x.Id == inDto.MainRowId).Select(x => x.Id).FirstOrDefault(); var mergeid = rowsInfo.Where(x => x.Id == inDto.MergeRowId).Select(x => x.Id).FirstOrDefault(); List<QuestionMark?> needRemoveMark = new List<QuestionMark?>() { QuestionMark.MajorAxis, QuestionMark.ShortAxis, }; var mainAnswer = await _readingTableQuestionAnswerRepository.Where(x => x.RowId == minaid).Include(x => x.ReadingTableQuestionTrial).ToListAsync(); foreach (var item in mainAnswer) { await _readingTableQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => x.RowId == mergeid && x.TableQuestionId == item.TableQuestionId, x => new ReadingTableQuestionAnswer() { Answer = needRemoveMark.Contains(item.ReadingTableQuestionTrial.QuestionMark) ? string.Empty : item.Answer, }); } await _readingTableAnswerRowInfoRepository.UpdatePartialFromQueryAsync(mergeid, x => new ReadingTableAnswerRowInfo() { MergeRowId = minaid, SplitOrMergeType = SplitOrMergeType.Merge, }); await _readingTableAnswerRowInfoRepository.UpdatePartialFromQueryAsync(mergeid, x => new ReadingTableAnswerRowInfo() { MergeRowId = minaid, SplitOrMergeType = SplitOrMergeType.Merge, }); await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); } #endregion #region 访视任务 - Dicom 阅片 提交、修改 /// <summary> /// 保存影像质量 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<IResponseOutput> SaveImageQuality(ChangeDicomReadingQuestionAnswerInDto inDto) { return await ChangeDicomReadingQuestionAnswer(inDto); } ///// <summary> ///// 保存ECRF ///// </summary> ///// <param name="inDto"></param> ///// <returns></returns> //[HttpPost] //public async Task<IResponseOutput> SaveImageQuality(ChangeDicomReadingQuestionAnswerInDto inDto) //{ // return await ChangeDicomReadingQuestionAnswer(inDto); //} /// <summary> /// 修改肿瘤学评估结果 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<IResponseOutput> ChangeDicomReadingQuestionAnswer(ChangeDicomReadingQuestionAnswerInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); 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); await _readingTaskQuestionAnswerRepository.SaveChangesAsync(); return ResponseOutput.Ok(true); } /// <summary> /// 删除表格行数据 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<IResponseOutput> DeleteReadingRowAnswer(DeleteReadingRowAnswerInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); var deleteRowInfo = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.RowId).FirstNotNullAsync(); if (deleteRowInfo == null) { return ResponseOutput.Ok(true); } 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.UpdatePartialFromQueryAsync(x => x.RowId == inDto.RowId, x => new ReadingTableQuestionAnswer() { IsDeleted = true }); await _readingTableAnswerRowInfoRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.RowId,x=>new ReadingTableAnswerRowInfo() { IsDeleted=true }); await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); 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); } 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; } //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); } 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; } //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 this._readingCalculateService.CalculateTask(new CalculateTaskInDto() { IsChangeOtherTask = false, VisitTaskId = inDto.VisitTaskId, }); return ResponseOutput.Ok(true); } /// <summary> /// 提交表格问题答案 病灶 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<SubmitTableQuestionOutDto> SubmitTableQuestion(SubmitTableQuestionInDto inDto) { SubmitTableQuestionOutDto result = new SubmitTableQuestionOutDto(); await VerifyTaskIsSign(inDto.VisitTaskId); if (inDto.InstanceId != null) { 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).FirstNotNullAsync(); var questionInfo = await _readingQuestionTrialRepository.Where(x => x.Id == inDto.QuestionId).FirstNotNullAsync(); 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 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) { if (questionInfo.MaxQuestionCount < ( (await _readingTableAnswerRowInfoRepository.Where(x => x.RowIndex != inDto.RowIndex && ((x.RowIndex % 1) == 0) && x.VisitTaskId == inDto.VisitTaskId && x.QuestionId == inDto.QuestionId ).CountAsync()) + 1)) { throw new BusinessValidationFailedException(_localizer["ReadingImage_MaxQuestion", questionInfo.MaxQuestionCount]); } } var tableQuestions = await _readingTableQuestionTrialRepository.Where(x => tableQuestionIds.Contains(x.Id) && x.MaxRowCount != null && x.MaxRowCount != 0).ToListAsync(); foreach (var item in tableQuestions) { var answer = inDto.AnswerList.Where(x => x.TableQuestionId == item.Id).Select(x => x.Answer).FirstOrDefault(); if (!answer.IsNullOrEmpty()) { var 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) { Dictionary<CriterionType, string> errorMsgDic = new Dictionary<CriterionType, string>() { {CriterionType.RECIST1Pointt1, _localizer["ReadingImage_Maxlesion", item.MaxRowCount.Value]}, }; string msg = string.Empty; try { msg = errorMsgDic[criterionInfo.CriterionType]; } catch (Exception) { msg = _localizer["ReadingImage_Maximum", item.QuestionName, 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))).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))); rowInfo.Id = inDto.RowId == null ? NewId.NextGuid() : inDto.RowId.Value; rowInfo.TrialId = inDto.TrialId; rowInfo.QuestionId = inDto.QuestionId; rowInfo.MeasureData = inDto.MeasureData; rowInfo.BlindName = inDto.BlindName; rowInfo.IsDicomReading = inDto.IsDicomReading; rowInfo.IsCurrentTaskAdd = isCurrentTaskAdd; rowInfo.NumberOfFrames = inDto.NumberOfFrames; rowInfo.FristAddTaskNum = taskinfo.VisitTaskNum; rowInfo.PicturePath = inDto.PicturePath; rowInfo.RowIndex = inDto.RowIndex; rowInfo.OrganInfoId = inDto.OrganInfoId; rowInfo.InstanceId = inDto.InstanceId; rowInfo.SeriesId = inDto.SeriesId; rowInfo.VisitTaskId = inDto.VisitTaskId; rowInfo.OrderMark = questionInfo.OrderMark; rowInfo.StudyId = inDto.StudyId; rowInfo.IsCanEditPosition = inDto.IsCanEditPosition; result.RowId = rowInfo.Id; if (inDto.RowId == null) { List<ReadingTableQuestionAnswer> 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.UpdatePartialFromQueryAsync(rowInfo.Id, x => new ReadingTableAnswerRowInfo() { TrialId = rowInfo.TrialId, QuestionId = rowInfo.QuestionId, MeasureData = rowInfo.MeasureData, BlindName = rowInfo.BlindName, IsDicomReading = rowInfo.IsDicomReading, IsCurrentTaskAdd = isCurrentTaskAdd, OrganInfoId=rowInfo.OrganInfoId, PicturePath = rowInfo.PicturePath, NumberOfFrames=rowInfo.NumberOfFrames, RowIndex = rowInfo.RowIndex, InstanceId = rowInfo.InstanceId, SeriesId = rowInfo.SeriesId, VisitTaskId = rowInfo.VisitTaskId, StudyId = rowInfo.StudyId, IsCanEditPosition = rowInfo.IsCanEditPosition, }); foreach(var item in inDto.AnswerList) { await _readingTableQuestionAnswerRepository.UpdatePartialFromQueryAsync(x => x.RowId == inDto.RowId && x.TableQuestionId == item.TableQuestionId, x => new ReadingTableQuestionAnswer() { Answer = item.Answer }); } } await _visitTaskRepository.UpdatePartialFromQueryAsync(inDto.VisitTaskId, x => new VisitTask() { ReadingTaskState = ReadingTaskState.Reading, }); await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); await this._readingCalculateService.CalculateTask(new CalculateTaskInDto() { IsChangeOtherTask = false, VisitTaskId = inDto.VisitTaskId, }); return result; } /// <summary> /// 提交Dicom阅片信息 /// </summary> /// <param name="inDto"></param> /// <returns></returns> public async Task<IResponseOutput> 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<ReadingTableQuestionAnswer> questionAnswerList = new List<ReadingTableQuestionAnswer>(); //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 this.SubmitTaskChangeState(inDto.VisitTaskId); return ResponseOutput.Ok(true); } #endregion #region Dicom 非dicom 公用 /// <summary> /// 验证默认问题是否回答 /// </summary> /// <param name="inDto"></param> /// <returns></returns> /// <exception cref="BusinessValidationFailedException"></exception> [HttpPost] public async Task<IResponseOutput> VerifyDefaultQuestionBeAnswer(VerifyVisitTaskQuestionsInDto inDto) { var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var criterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == taskInfo.TrialReadingCriterionId).FirstNotNullAsync(); var readingQuestionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId && (x.IsJudgeQuestion || (x.IsRequired == IsRequired.Required && x.ShowQuestion == ShowQuestion.Show)) ) .WhereIf(!criterion.IseCRFShowInDicomReading,x=>x.IsShowInDicom).ToListAsync(); 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))]); } return ResponseOutput.Ok(true); } /// <summary> /// 验证访视提交 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<IResponseOutput> VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto) { await VerifyTaskIsSign(inDto.VisitTaskId); var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var readingQuestionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId && (x.IsJudgeQuestion || (x.IsRequired == IsRequired.Required && x.ShowQuestion == ShowQuestion.Show)) ).ToListAsync(); 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))]); } 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); } /// <summary> /// 获取下一个阅片任务 /// </summary> /// <param name="inDto"></param> /// <returns></returns> [HttpPost] public async Task<GetReadingTaskDto> 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"]); } 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, VisistId = x.SourceSubjectVisitId != null ? x.SourceSubjectVisitId.Value : default(Guid), VisitNum = x.VisitTaskNum, TrialReadingCriterionId = x.TrialReadingCriterionId, }).FirstOrDefaultAsync(); trialReadingCriterionId = task.TrialReadingCriterionId; } else if (inDto.SubjectId != null) { var subjectTaskList = (await _visitTaskService.GetOrderReadingIQueryable(new GetOrderReadingIQueryableInDto() { TrialId = inDto.TrialId, TrialReadingCriterionId = inDto.TrialReadingCriterionId, })).Item2; 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).OrderBy(x => x.Index).FirstOrDefault(); if (currentSubject == null) { throw new BusinessValidationFailedException(_localizer["ReadingImage_TaskFinish"]); } task = currentSubject.UnReadTaskList.Select(x => new GetReadingTaskDto() { ReadingCategory = x.ReadingCategory, SubjectCode = currentSubject.SubjectCode, SubjectId = currentSubject.SubjectId, TaskBlindName = x.TaskBlindName, VisitNum = x.VisitNum, VisistId = x.VisistId ?? default(Guid), VisitTaskId = x.Id, TrialReadingCriterionId = x.TrialReadingCriterionId, }).FirstOrDefault(); } else { task = await _visitTaskRepository.Where(x => x.TrialId == inDto.TrialId && x.TrialReadingCriterionId == trialReadingCriterionId && x.ReadingTaskState != ReadingTaskState.HaveSigned && x.DoctorUserId == _userInfo.Id && x.TrialReadingCriterionId == trialReadingCriterionId && x.TaskState == TaskState.Effect).Select(x => new GetReadingTaskDto() { VisitTaskId = x.Id, 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(); if (task == null) { throw new BusinessValidationFailedException(_localizer["ReadingImage_TaskFinish"]); } } if (task.SubjectCode.IsNullOrEmpty()) { task.SubjectCode = await _subjectRepository.Where(x => x.Id == task.SubjectId).Select(x => x.Code).FirstOrDefaultAsync(); } await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == task.VisitTaskId && x.FirstReadingTime == null, x => new VisitTask() { FirstReadingTime = DateTime.Now, }); await _visitTaskRepository.SaveChangesAsync(); var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == task.VisitTaskId).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.CriterionType, x.IseCRFShowInDicomReading, x.IsReadingTaskViewInOrder, }).FirstOrDefaultAsync(); 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; } task.DigitPlaces = criterionInfo.DigitPlaces; task.CriterionType = criterionInfo.CriterionType; task.IseCRFShowInDicomReading = criterionInfo.IseCRFShowInDicomReading; var blindSubjectCode = await _visitTaskRepository.Where(x => x.Id == task.VisitTaskId).Select(x => x.BlindSubjectCode).FirstNotNullAsync(); task.SubjectCode = blindSubjectCode.IsNullOrEmpty() ? task.SubjectCode : blindSubjectCode; return task; } /// <summary> /// 验证阅片休息时间 /// </summary> /// <returns></returns> [HttpPost] public async Task VerifyReadingRestTime() { var cacheKey = _userInfo.Id.ToString(); var value = _cache.Get(cacheKey); if (value == null) { _cache.Set(cacheKey, DateTime.Now.ToString(), TimeSpan.FromHours(5)); } else { #region 两小时 var cacheDate = DateTime.Parse(value.ToString()); int timespanMin = (DateTime.Now - cacheDate).Minutes; if (timespanMin > 120 && timespanMin < 140) { throw new BusinessValidationFailedException(_localizer["ReadingImage_NeedRest",2,20]); } else if (timespanMin > 140) { cacheDate = cacheDate.AddMinutes((Math.Floor((double)(timespanMin / 140))) * 140); _cache.Set(cacheKey, cacheDate.ToString(), TimeSpan.FromHours(5)); } #endregion #region 测试用的5分钟 //var cacheDate = DateTime.Parse(value.ToString()); //int timespanMin = (DateTime.Now - cacheDate).Minutes; //if (timespanMin >= 5 && timespanMin <= 10) //{ // throw new BusinessValidationFailedException("您已连续阅片2个小时,请休息20分钟后,再继续阅片。"); //} //else if (timespanMin > 10) //{ // cacheDate = cacheDate.AddMinutes((Math.Floor((double)(timespanMin / 10))) * 10); // _cache.Set(cacheKey, cacheDate.ToString(), TimeSpan.FromHours(5)); //} #endregion } } /// <summary> /// 签名提交任务修改状态 /// </summary> /// <param name="visitTaskId"></param> /// <returns></returns> 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(); // 触裁判任务 await this.TriggerJudgeQuestion(visitTaskId); // 添加阅片期任务 await this.AddReadingTask(visitTaskId); // 完成阅片修改状态 //await this.FinishReadUpdateState(visitTaskId); await _visitTaskRepository.SaveChangesAsync(); await _trialEmailNoticeConfigService.BaseBusinessScenarioSendEmailAsync(visitTaskId); } /// <summary> /// 阅片期 -全局和肿瘤学任务的生成 /// </summary> /// <returns></returns> [HttpPost] public async Task AddReadingTask(Guid visitTaskId) { // ****** 先生成阅片期 阅片期任务阅片完成之后生成肿瘤学的 如果没有阅片期 直接生成肿瘤学 *********//// #region 建立关系 // 访视阅完产生 全局 Dictionary<ModuleTypeEnum, ReadingCategory> typeChangeDic = new Dictionary<ModuleTypeEnum, ReadingCategory>(); 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).FirstNotNullAsync(); List<ReadingGenerataTaskDTO> needReadList = new List<ReadingGenerataTaskDTO>(); if (!taskInfo.IsAnalysisCreate) { // 任务类型 switch (taskInfo.ReadingCategory) { case ReadingCategory.Visit: needReadList = await _readModuleRepository.Where(x => x.SubjectVisitId == taskInfo.SourceSubjectVisitId && x.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && x.ReadingSetType == ReadingSetType.ImageReading) .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)) { needReadList = needReadList.Where(x => x.ReadingCategory != ReadingCategory.Oncology).ToList(); } //needReadList = needReadList.Where(x => _visitTaskRepository.Where(y => y.SouceReadModuleId == x.ReadModuleId).Count() == 0).ToList(); await _visitTaskHelpeService.AddTaskAsync(new GenerateTaskCommand() { OriginalVisitId = visitTaskId, ReadingCategory = GenerateTaskCategory.Global, TrialId = taskInfo.TrialId, ReadingGenerataTaskList = needReadList }); 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 } }