diff --git a/IRaCIS.Core.API/_ServiceExtensions/SerilogSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/SerilogSetup.cs index 1d9b30a9b..99ec49653 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/SerilogSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/SerilogSetup.cs @@ -35,7 +35,7 @@ namespace IRaCIS.Core.API .Enrich.FromLogContext() .Filter.ByExcluding(logEvent => logEvent.Properties.ContainsKey("RequestPath") && logEvent.Properties["RequestPath"].ToString().Contains("/health")) .WriteTo.Console() - .WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,retainedFileCountLimit:60); + .WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,retainedFileCountLimit:365); #region 根据环境配置是否打开错误发送邮件通知 diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index b128a3fe2..cf0fb265e 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -3834,6 +3834,13 @@ + + + 获取报告图表汇总 + + + + 获取阅片报告 @@ -6872,6 +6879,13 @@ + + + 获取图表数据汇总 + + + + 获取报告图表数据 @@ -14285,6 +14299,13 @@ + + + 获取图表数据汇总 + + + + 设置已阅读关键文件 diff --git a/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs b/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs index 77f950fba..438f8f25f 100644 --- a/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs +++ b/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs @@ -97,6 +97,8 @@ namespace IRaCIS.Core.Application.ViewModel [NotDefault] public Guid TrialId { get; set; } + public string EmailTopic { get; set; } = string.Empty; + public EmailBusinessScenario? BusinessScenarioEnum { get; set; } public CriterionType? CriterionTypeEnum { get; set; } diff --git a/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs b/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs index 16ae85809..294871348 100644 --- a/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs +++ b/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs @@ -1674,6 +1674,7 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi var trialConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => new { t.IsEnrollementQualificationConfirm, t.IsPDProgressView }).First(); var trialEmailNoticeConfigQueryable = _trialEmailNoticeConfigRepository.Where(t => t.TrialId == inQuery.TrialId) + .WhereIf(inQuery.EmailTopic.IsNotNullOrEmpty(), t => t.EmailTopic.Contains(inQuery.EmailTopic)||t.EmailTopicCN.Contains(inQuery.EmailTopic)) .WhereIf(inQuery.IsDistinguishCriteria == false, t => t.IsDistinguishCriteria == false) .WhereIf(inQuery.IsDistinguishCriteria == true, t => t.IsDistinguishCriteria == true) .WhereIf(inQuery.CriterionTypeEnum != null, t => t.CriterionTypeList.Any(c => c == inQuery.CriterionTypeEnum)) diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/_MapConfig.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/_MapConfig.cs index 4b271380f..f74509831 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/_MapConfig.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/_MapConfig.cs @@ -92,6 +92,9 @@ namespace IRaCIS.Core.Application.Service CreateMap() .ForMember(o => o.SubjectCode, t => t.MapFrom(u => u.SubjectVisit.Subject.Code)) .ForMember(o => o.VisitName, t => t.MapFrom(u => u.SubjectVisit.VisitName)); + CreateMap() + .ForMember(o => o.SubjectCode, t => t.MapFrom(u => u.SubjectVisit.Subject.Code)) + .ForMember(o => o.VisitName, t => t.MapFrom(u => u.SubjectVisit.VisitName)); CreateMap(); diff --git a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs index e4e6f8eb1..8e7b22ef9 100644 --- a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs +++ b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs @@ -1,4 +1,4 @@ -using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Domain.Share; using Newtonsoft.Json; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; @@ -198,9 +198,9 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto public GetReportVerifyOutDto CalculateResult { get; set; } public ReadingTaskState ReadingTaskState { get; set; } - public List VisitTaskList { get; set; } + public List VisitTaskList { get; set; } =new List { }; - public List TaskQuestions { get; set; } + public List TaskQuestions { get; set; } =new List { }; public List LesionCountList { get; set; } = new List(); @@ -491,6 +491,56 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto public List Value { get; set; } } + public class GetReportsChartTypeDataInDto + { + public ReportChartType ReportChartTypeEnum { get; set; } + + public CriterionType CriterionType { get; set; } + public GetReadingReportEvaluationOutDto Data { get; set; } + } + + public class GetReportsChartSummaryInDto + { + public Guid SubjectId { get; set; } + + public Guid TrialCriterionId { get; set; } + } + + public class GetReportsChartSummaryOutDto + { + public EvaluationColumn Evaluation { get; set; } + + public List TargetCharts { get; set; } = new List(); + + public List QuestionCharts { get; set; } = new List(); + } + + + public class EvaluationColumn + { + public List> Evaluation { get; set; } + public string DictionaryCode { get; set; } + } + + + public class EvaluationValue + { + public string Value { get; set; } + + public string DictionaryCode { get; set; } + } + + public class ChartItem + { + public Arm Arm { get; set; } + public ReportChartType? ChartType { get; set; } + public string GroupName { get; set; } + public ValueUnit? Unit { get; set; } + public List VisitTaskNameList { get; set; } = new List(); + public List LatestScanDateList { get; set; } = new List(); + public List ChartDataList { get; set; } = new List(); + } + public class GetReportsChartDataInDto { public Guid VisitTaskId { get; set; } diff --git a/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs b/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs index d01b97d29..42a22e345 100644 --- a/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs +++ b/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs @@ -94,6 +94,17 @@ namespace IRaCIS.Core.Application.Service return await _readingCalculateService.GetReportsChartData(inDto); } + /// + /// 获取图表数据汇总 + /// + /// + /// + [HttpPost] + public async Task GetReportsChartSummary(GetReportsChartSummaryInDto inDto) + { + return await _readingCalculateService.GetReportsChartSummary(inDto); + } + /// /// 设置已阅读关键文件 /// diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/General/GeneralCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/General/GeneralCalculateService.cs index aa8bd2cda..4364366a5 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/General/GeneralCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/General/GeneralCalculateService.cs @@ -531,7 +531,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate /// public async Task GetReadingCalculateDto(Guid visitTaskId) { - var visitTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); + var visitTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x=>x.SourceSubjectVisit).FirstNotNullAsync(); var criterionInfo = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == visitTask.TrialReadingCriterionId).FirstNotNullAsync(); var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == (visitTask.SourceSubjectVisitId ?? default(Guid))).FirstOrDefaultAsync(); diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/General/ReadingCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/General/ReadingCalculateService.cs index e59d61d3f..24d460cc7 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/General/ReadingCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/General/ReadingCalculateService.cs @@ -76,14 +76,14 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate await _readingImportFileRepository.AddAsync(new ReadingImportFile() { - + FilePath = ossRelativePath, VisitTaskId = visitTaskId, TrialId = visitTaskInfo.TrialId, SubjectId = visitTaskInfo.SubjectId, SubjectVisitId = visitTaskInfo.SourceSubjectVisitId, TrialReadingCriterionId = visitTaskInfo.TrialReadingCriterionId, - TableName= tableName, + TableName = tableName, }); @@ -248,6 +248,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate /// /// /// + [HttpPost] public async Task GetReportsChartData(GetReportsChartDataInDto inDto) { var criterionId = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.TrialReadingCriterionId).FirstNotNullAsync(); @@ -260,103 +261,26 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate VisitTaskId = inDto.VisitTaskId, }); - GetReportsChartDataOutDto result = new GetReportsChartDataOutDto() + GetReportsChartDataOutDto result = new GetReportsChartDataOutDto() { VisitTaskNameList = data.VisitTaskList.Select(x => x.BlindName).ToList(), LatestScanDateList = data.VisitTaskList.Select(x => x.LatestScanDate).ToList(), - ChartDataList =new List() { }, + ChartDataList = new List() { }, }; - + result.VisitTaskNameList = data.VisitTaskList.Select(x => x.BlindName).ToList(); if (inDto.ReportChartTypeEnum != null) { - switch (inDto.ReportChartTypeEnum) + var reportData = await GetReportsChartTypeData(new GetReportsChartTypeDataInDto() { - case ReportChartType.Target: - { - // 这是病灶 - var target = data.TaskQuestions.SelectMany(x => x.Childrens) - .Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x=>x.Childrens) - .ToList(); - - - foreach (var item in target) - { - ReportChartData chartData = new ReportChartData() - { - Name = item.QuestionName, - Value= new List(), - }; - - for (var i = 0; i < result.VisitTaskNameList.Count; i++) - { - - switch (criterionType) - { - case CriterionType.RECIST1Point1: - case CriterionType.RECIST1Pointt1_MB: - case CriterionType.mRECISTHCC: - case CriterionType.IRECIST1Point1: - // 淋巴结的短径 - if (item.Childrens.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer[i].Answer.EqEnum(ReadingYesOrNo.Yes))) - { - chartData.Value.Add(item.Childrens.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer[i].Answer).FirstOrDefault()); - result.Unit = item.Childrens.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Unit).FirstOrDefault(); - } - else - { - chartData.Value.Add(item.Childrens.Where(x => x.QuestionMark == QuestionMark.MajorAxis).Select(x => x.Answer[i].Answer).FirstOrDefault()); - result.Unit = item.Childrens.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Unit).FirstOrDefault(); - } - break; - - case CriterionType.Lugano2014: - case CriterionType.Lugano2014WithoutPET: - chartData.Value.Add(item.Childrens.Where(x => x.QuestionMark == QuestionMark.PPD).Select(x => x.Answer[i].Answer).FirstOrDefault()); - result.Unit = item.Childrens.Where(x => x.QuestionMark == QuestionMark.PPD).Select(x => x.Unit).FirstOrDefault(); - break; - } - - - } - - result.ChartDataList.Add(chartData); - } - - } - break; - - case ReportChartType.BaseLineTarget: - // 这是病灶 - var baseTarget = data.TaskQuestions.SelectMany(x => x.Childrens) - .Where(x => x.LesionType == LesionType.BaselineLesions).SelectMany(x => x.Childrens) - .ToList(); - - foreach (var item in baseTarget) - { - ReportChartData chartData = new ReportChartData() - { - Name = item.QuestionName, - Value = new List(), - }; - - for (var i = 0; i < result.VisitTaskNameList.Count; i++) - { - - chartData.Value.Add(item.Childrens.Where(x => x.QuestionMark == QuestionMark.LesionNumber).Select(x => x.Answer[i].Answer).FirstOrDefault()); - result.Unit = item.Childrens.Where(x => x.QuestionMark == QuestionMark.LesionNumber).Select(x => x.Unit).FirstOrDefault(); - - - } - - result.ChartDataList.Add(chartData); - } - break; - default: - break; - } + CriterionType = criterionType, + Data = data, + ReportChartTypeEnum = inDto.ReportChartTypeEnum.Value, + }); + result.ChartDataList = reportData.ChartDataList; + result.Unit = reportData.Unit; } else if (inDto.QuestionId != null) { @@ -411,6 +335,293 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate return result; } + + private async Task GetReportsChartTypeData(GetReportsChartTypeDataInDto inDto) + { + var visitTaskNameList = inDto.Data.VisitTaskList.Select(x => x.BlindName).ToList(); + GetReportsChartDataOutDto result = new GetReportsChartDataOutDto() { + + ChartDataList=new List() { }, + + }; + switch (inDto.ReportChartTypeEnum) + { + case ReportChartType.Target: + { + // 这是病灶 + var target = inDto.Data.TaskQuestions.SelectMany(x => x.Childrens) + .Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.Childrens) + .ToList(); + + + foreach (var item in target) + { + ReportChartData chartData = new ReportChartData() + { + Name = item.QuestionName, + Value = new List(), + }; + + for (var i = 0; i < visitTaskNameList.Count; i++) + { + + switch (inDto.CriterionType) + { + case CriterionType.RECIST1Point1: + case CriterionType.RECIST1Pointt1_MB: + case CriterionType.mRECISTHCC: + case CriterionType.IRECIST1Point1: + // 淋巴结的短径 + if (item.Childrens.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer[i].Answer.EqEnum(ReadingYesOrNo.Yes))) + { + chartData.Value.Add(item.Childrens.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer[i].Answer).FirstOrDefault()); + result.Unit = item.Childrens.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Unit).FirstOrDefault(); + } + else + { + chartData.Value.Add(item.Childrens.Where(x => x.QuestionMark == QuestionMark.MajorAxis).Select(x => x.Answer[i].Answer).FirstOrDefault()); + result.Unit = item.Childrens.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Unit).FirstOrDefault(); + } + break; + + case CriterionType.Lugano2014: + case CriterionType.Lugano2014WithoutPET: + chartData.Value.Add(item.Childrens.Where(x => x.QuestionMark == QuestionMark.PPD).Select(x => x.Answer[i].Answer).FirstOrDefault()); + result.Unit = item.Childrens.Where(x => x.QuestionMark == QuestionMark.PPD).Select(x => x.Unit).FirstOrDefault(); + break; + } + + + } + + result.ChartDataList.Add(chartData); + } + + } + break; + + case ReportChartType.BaseLineTarget: + // 这是病灶 + var baseTarget = inDto.Data.TaskQuestions.SelectMany(x => x.Childrens) + .Where(x => x.LesionType == LesionType.BaselineLesions).SelectMany(x => x.Childrens) + .ToList(); + + foreach (var item in baseTarget) + { + ReportChartData chartData = new ReportChartData() + { + Name = item.QuestionName, + Value = new List(), + }; + + for (var i = 0; i < result.VisitTaskNameList.Count; i++) + { + + chartData.Value.Add(item.Childrens.Where(x => x.QuestionMark == QuestionMark.LesionNumber).Select(x => x.Answer[i].Answer).FirstOrDefault()); + result.Unit = item.Childrens.Where(x => x.QuestionMark == QuestionMark.LesionNumber).Select(x => x.Unit).FirstOrDefault(); + + + } + + result.ChartDataList.Add(chartData); + } + break; + default: + break; + } + + return result; + } + + /// + /// 获取报告图表汇总 + /// + /// + /// + [HttpPost] + public async Task GetReportsChartSummary(GetReportsChartSummaryInDto inDto) + { + var criterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialCriterionId).FirstNotNullAsync(); + var result= new GetReportsChartSummaryOutDto(); + var r1Data = await GetData(new List() { Arm.SingleReadingArm, Arm.DoubleReadingArm1 }); + var r2Data = await GetData(new List() { Arm.DoubleReadingArm2 }); + async Task GetData(List arms) + { + var data = new GetReadingReportEvaluationOutDto() { }; + var task = await _visitTaskRepository.Where(x => + x.SubjectId == inDto.SubjectId + && arms.Contains(x.ArmEnum) + && x.ReadingCategory== ReadingCategory.Visit + && x.ReadingTaskState == ReadingTaskState.HaveSigned + && x.TaskState == TaskState.Effect + && x.TrialReadingCriterionId==inDto.TrialCriterionId + ).OrderByDescending(x => x.VisitTaskNum).FirstOrDefaultAsync(); + if (task != null) + { + data = await GetReadingReportEvaluation(new GetReadingReportEvaluationInDto() + { + TrialId = task.TrialId, + VisitTaskId = task.Id, + }); + } + return data; + } + + + EvaluationColumn BuildEvaluationTable(GetReadingReportEvaluationOutDto r1, GetReadingReportEvaluationOutDto r2) + { + EvaluationColumn result = new EvaluationColumn() + { + Evaluation = new List>() { } + }; + + var data = r1.VisitTaskList.Count() > r2.VisitTaskList.Count() ? r1 : r2; + var visitTaskName = data.VisitTaskList.Select(x => x.BlindName).ToList(); + var length = data.VisitTaskList.Count(); + result.Evaluation.Add(visitTaskName.Select(x=> new EvaluationValue() { + Value=x + }).ToList()); + + var r1baseLine= data.TaskQuestions + .SelectMany(x => x.Childrens) + .Where(x => x.QuestionType == QuestionType.ExistDisease) + .SelectMany(x => x.Answer.Select(a => new EvaluationValue + { + DictionaryCode = x.DictionaryCode, + Value = a.Answer + })) + .ToList(); + + + var r1data = data.TaskQuestions + .SelectMany(x => x.Childrens) + .Where(x => x.QuestionType == QuestionType.Tumor) + .SelectMany(x => x.Answer.Select(a => new EvaluationValue + { + DictionaryCode = x.DictionaryCode, + Value = a.Answer + })) + .ToList(); + + r1data = r1baseLine.Take(1).Concat(r1data.Skip(1)).ToList(); + + r1data= r1data.Concat(Enumerable.Repeat(new EvaluationValue() { Value = "" }, length)) + .Take(length) + .ToList(); + result.Evaluation.Add(r1data); + + + + var r2baseLine = data.TaskQuestions + .SelectMany(x => x.Childrens) + .Where(x => x.QuestionType == QuestionType.ExistDisease) + .SelectMany(x => x.Answer.Select(a => new EvaluationValue + { + DictionaryCode = x.DictionaryCode, + Value = a.Answer + })) + .ToList(); + + + var r2data = data.TaskQuestions + .SelectMany(x => x.Childrens) + .Where(x => x.QuestionType == QuestionType.Tumor) + .SelectMany(x => x.Answer.Select(a => new EvaluationValue + { + DictionaryCode = x.DictionaryCode, + Value = a.Answer + })) + .ToList(); + + r2data = r2baseLine.Take(1).Concat(r2data.Skip(1)).ToList(); + + r2data = r2data.Concat(Enumerable.Repeat(new EvaluationValue() { Value = "" }, length)) + .Take(length) + .ToList(); + result.Evaluation.Add(r2data); + + return result; + } + + List BuildShowChartGroups(GetReadingReportEvaluationOutDto data, Arm arm) + { + var groups = new List(); + if (data.TaskQuestions == null || data.VisitTaskList == null) return groups; + foreach (var g in data.TaskQuestions) + { + var items = g.Childrens?.Where(c => c.ShowChartTypeEnum != ShowChartType.NotShow).ToList() ?? new List(); + if (items.Count == 0) continue; + var chartList = new List(); + foreach (var item in items) + { + var cd = new ReportChartData + { + Name = item.QuestionName, + Value = item.Answer?.Select(a => a.Answer).ToList() ?? new List() + }; + chartList.Add(cd); + } + groups.Add(new ChartItem + { + Arm = arm, + ChartType = null, + GroupName = g.GroupName, + Unit = items.FirstOrDefault()?.Unit, + VisitTaskNameList = data.VisitTaskList.Select(x => x.BlindName).ToList(), + LatestScanDateList = data.VisitTaskList.Select(x => x.LatestScanDate).ToList(), + ChartDataList = chartList + }); + } + return groups; + } + + async Task BuildTargetChart(GetReadingReportEvaluationOutDto data, Arm arm) + { + var item = new ChartItem + { + Arm = arm, + ChartType = ReportChartType.Target, + GroupName = _localizer["Tumor_TargetLesions"], + VisitTaskNameList = data.VisitTaskList?.Select(x => x.BlindName).ToList() ?? new List(), + LatestScanDateList = data.VisitTaskList?.Select(x => x.LatestScanDate).ToList() ?? new List(), + ChartDataList = new List(), + }; + if (data.VisitTaskList != null && data.TaskQuestions != null) + { + var chart = await GetReportsChartTypeData(new GetReportsChartTypeDataInDto + { + CriterionType = criterion.CriterionType, + Data = data, + ReportChartTypeEnum = ReportChartType.Target + }); + item.ChartDataList = chart.ChartDataList; + item.Unit = chart.Unit; + } + return item; + } + + + result.Evaluation = BuildEvaluationTable(r1Data, r2Data); + if (r1Data != null) + { + var r1Target = await BuildTargetChart(r1Data, Arm.DoubleReadingArm1); + result.TargetCharts.Add(r1Target); + var r1Groups = BuildShowChartGroups(r1Data, Arm.DoubleReadingArm1); + result.QuestionCharts.AddRange(r1Groups); + } + + if (r2Data != null) + { + var r2Target = await BuildTargetChart(r2Data, Arm.DoubleReadingArm2); + result.TargetCharts.Add(r2Target); + var r2Groups = BuildShowChartGroups(r2Data, Arm.DoubleReadingArm2); + result.QuestionCharts.AddRange(r2Groups); + } + + return result; + + } + /// /// 获取阅片报告 /// diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/IRECIST1Point1CalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/IRECIST1Point1CalculateService.cs index a0658c9ae..c436ce0bc 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/IRECIST1Point1CalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/IRECIST1Point1CalculateService.cs @@ -663,30 +663,33 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate List stateIsNullList = tableAnswerList.Select(x => x.OrderMark + x.RowIndex.GetLesionMark()).ToList(); + // 交集 List allExists = measureDataList.Intersect(stateIsNullList).ToList(); + // 差集 measureDataList = measureDataList.Except(allExists).ToList(); stateIsNullList = stateIsNullList.Except(allExists).ToList(); - - if (measureDataList.Count() > 0) { + // 无标记 errorMassage += _localizer["ReadingCalculate_NoMarker", string.Join(',', measureDataList)] + ","; } - - if (tableAnswerList.Count > 0) + if (stateIsNullList.Count > 0) { + // 状态为空 errorMassage += _localizer["ReadingCalculate_StatusIsEmpty", string.Join(',', stateIsNullList)] + ","; } if (allExists.Count > 0) { - errorMassage += _localizer["ReadingCalculate_NoMarkerEmpty", string.Join(',', stateIsNullList)] + ","; + // 未做标记且状态为空 + errorMassage += _localizer["ReadingCalculate_NoMarkerEmpty", string.Join(',', allExists)] + ","; } if (errorMassage != string.Empty) { + errorMassage = _localizer["ReadingCalculate_Questionable"] + errorMassage; throw new BusinessValidationFailedException(errorMassage); } diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs index 3ec83c3bf..e5f10cb0e 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs @@ -14,6 +14,13 @@ namespace IRaCIS.Core.Application.Service /// Task CalculateTask(CalculateTaskInDto inDto); + /// + /// 获取图表数据汇总 + /// + /// + /// + Task GetReportsChartSummary(GetReportsChartSummaryInDto inDto); + /// /// 获取报告图表数据 /// diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs index bab7e7a45..7fec5ce2c 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/MRECISTHCCCalculateService.cs @@ -479,8 +479,9 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate List measureDataList = rowAnswerList.Where(x => !unableEvaluateRowIds.Contains(x.Id)).Select(x => x.OrderMark + x.RowIndex.GetLesionMark()).ToList(); List stateIsNullList = tableAnswerList.Select(x => x.OrderMark + x.RowIndex.GetLesionMark()).ToList(); + // 交集 List allExists = measureDataList.Intersect(stateIsNullList).ToList(); - // 取差 + // 差集 measureDataList = measureDataList.Except(allExists).ToList(); stateIsNullList = stateIsNullList.Except(allExists).ToList(); if (measureDataList.Count() > 0) @@ -489,7 +490,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate errorMassage += _localizer["ReadingCalculate_NoMarker", string.Join(',', measureDataList)] + ","; } - if (tableAnswerList.Count > 0) + if (stateIsNullList.Count > 0) { // 状态为空 errorMassage += _localizer["ReadingCalculate_StatusIsEmpty", string.Join(',', stateIsNullList)] + ","; @@ -498,7 +499,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate if (allExists.Count > 0) { // 未做标记且状态为空 - errorMassage += _localizer["ReadingCalculate_NoMarkerEmpty", string.Join(',', stateIsNullList)] + ","; + errorMassage += _localizer["ReadingCalculate_NoMarkerEmpty", string.Join(',', allExists)] + ","; } diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs index b1cb1fe49..32ad07dc4 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs @@ -481,8 +481,10 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate List measureDataList = rowAnswerList.Where(x => !unableEvaluateRowIds.Contains(x.Id)).Select(x => x.OrderMark + x.RowIndex.GetLesionMark()).ToList(); List stateIsNullList = tableAnswerList.Select(x => x.OrderMark + x.RowIndex.GetLesionMark()).ToList(); + + // 交集 List allExists = measureDataList.Intersect(stateIsNullList).ToList(); - // 取差 + // 差集 measureDataList = measureDataList.Except(allExists).ToList(); stateIsNullList = stateIsNullList.Except(allExists).ToList(); if (measureDataList.Count() > 0) @@ -491,7 +493,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate errorMassage += _localizer["ReadingCalculate_NoMarker", string.Join(',', measureDataList)] + ","; } - if (tableAnswerList.Count > 0) + if (stateIsNullList.Count > 0) { // 状态为空 errorMassage += _localizer["ReadingCalculate_StatusIsEmpty", string.Join(',', stateIsNullList)] + ","; @@ -500,7 +502,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate if (allExists.Count > 0) { // 未做标记且状态为空 - errorMassage += _localizer["ReadingCalculate_NoMarkerEmpty", string.Join(',', stateIsNullList)] + ","; + errorMassage += _localizer["ReadingCalculate_NoMarkerEmpty", string.Join(',', allExists)] + ","; } diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1_BMCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1_BMCalculateService.cs index 95e3483b3..555a28e5b 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1_BMCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1_BMCalculateService.cs @@ -482,25 +482,27 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate List stateIsNullList = tableAnswerList.Select(x => x.OrderMark + x.RowIndex.GetLesionMark()).ToList(); + // 交集 List allExists = measureDataList.Intersect(stateIsNullList).ToList(); + // 差集 measureDataList = measureDataList.Except(allExists).ToList(); stateIsNullList = stateIsNullList.Except(allExists).ToList(); - - if (measureDataList.Count() > 0) { + // 无标记 errorMassage += _localizer["ReadingCalculate_NoMarker", string.Join(',', measureDataList)] + ","; } - - if (tableAnswerList.Count > 0) + if (stateIsNullList.Count > 0) { + // 状态为空 errorMassage += _localizer["ReadingCalculate_StatusIsEmpty", string.Join(',', stateIsNullList)] + ","; } if (allExists.Count > 0) { - errorMassage += _localizer["ReadingCalculate_NoMarkerEmpty", string.Join(',', stateIsNullList)] + ","; + // 未做标记且状态为空 + errorMassage += _localizer["ReadingCalculate_NoMarkerEmpty", string.Join(',', allExists)] + ","; } diff --git a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialStatService.cs b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialStatService.cs index 53ca77c94..3662b3b53 100644 --- a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialStatService.cs +++ b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialStatService.cs @@ -16,6 +16,7 @@ namespace IRaCIS.Core.Application; [ApiExplorerSettings(GroupName = "Trial")] public class TrialStatService( IRepository _trialRepository, + IRepository _readingTrialCriterionDictionaryRepository, IRepository _readingQuestionTrialRepository, IRepository _subjectVisitRepository, IRepository _trialDocumentRepository, @@ -90,7 +91,7 @@ public class TrialStatService( CheckQuestion_ClosedCount = t.SubjectVisitList.Where(t => inQuery.TrialSiteId != null ? t.TrialSiteId == inQuery.TrialSiteId : true) .Where(t => t.CheckChallengeState == CheckChanllengeTypeEnum.Closed).Count(), CheckQuestion_IngCount = t.SubjectVisitList.Where(t => inQuery.TrialSiteId != null ? t.TrialSiteId == inQuery.TrialSiteId : true) - .Where(t => t.CheckChallengeState != CheckChanllengeTypeEnum.Closed).Count(), + .Where(t => t.CheckChallengeState == CheckChanllengeTypeEnum.CRCWaitPMReply || t.CheckChallengeState == CheckChanllengeTypeEnum.PMWaitCRCReply).Count(), MedicalReviewQuestion_ClosedCount = t.TaskMedicalReviewList.Where(t => inQuery.TrialSiteId != null ? t.VisitTask.Subject.TrialSiteId == inQuery.TrialSiteId : true) @@ -119,7 +120,7 @@ public class TrialStatService( var trialReadingCriterionId = inQuery.TrialReadingCriterionId; //每次查询必须是单标准的 - var criterion = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == trialReadingCriterionId).Select(t => new { t.CriterionType, t.CriterionGroup, t.IsGlobalReading, t.IsArbitrationReading, t.IsOncologyReading, t.CriterionName, t.ArbitrationRule, t.TrialId }).FirstNotNullAsync(); + var criterion = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == trialReadingCriterionId).Select(t => new { t.Id, t.CriterionType, t.CriterionGroup, t.IsGlobalReading, t.IsArbitrationReading, t.IsOncologyReading, t.CriterionName, t.ArbitrationRule, t.TrialId }).FirstNotNullAsync(); if (criterion.CriterionGroup == CriterionGroup.Nontumorous) @@ -240,15 +241,18 @@ public class TrialStatService( // 先把 resultList 转成内存字典 var resultDict = resultList.ToDictionary(r => r.OverallTumorEvaluation, r => r.SubjectCodeList); + + // 查询字典表,先把数据拉出来到内存,再合并 - var translateList = _dictionaryRepository - .Where(t => t.Parent.Code == dicName) + var translateList = _readingTrialCriterionDictionaryRepository + .Where(t => t.ParentCode == dicName && t.CriterionId == criterion.Id) .Select(t => new { - t.Code, - t.Value, + t.Dictionary.Code, + t.Dictionary.Value, }) .ToList() + .Where(t => t.Code != "-1") .Select(t => new EfficacyEvaluationStatViewModel { DictionaryCode = dicName, @@ -268,7 +272,7 @@ public class TrialStatService( var pdInfo = translateList .WhereIf(criterion.CriterionType == CriterionType.IRECIST1Point1, t => t.OverallTumorEvaluation == "ICPD") - .WhereIf(criterion.CriterionType == CriterionType.IRECIST1Point1, t => t.OverallTumorEvaluation == "PD") + .WhereIf(criterion.CriterionType == CriterionType.RECIST1Point1, t => t.OverallTumorEvaluation == "PD") .FirstOrDefault(); var firstPdList = new List(); diff --git a/IRaCIS.Core.Application/Service/Visit/SubjectVisitService.cs b/IRaCIS.Core.Application/Service/Visit/SubjectVisitService.cs index 268b171e5..bdddf04e0 100644 --- a/IRaCIS.Core.Application/Service/Visit/SubjectVisitService.cs +++ b/IRaCIS.Core.Application/Service/Visit/SubjectVisitService.cs @@ -28,6 +28,8 @@ namespace IRaCIS.Core.Application.Services IRepository _subjectRepository, IRepository _dicomInstanceRepository, IRepository _taskStudyRepository, + IRepository _taskSeriesRepository, + IRepository _taskInstanceRepository, IServiceProvider _serviceProvider, IRepository _dicomSeriesRepository, IRepository _trialReadingCriterionRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ISubjectVisitService @@ -337,29 +339,48 @@ namespace IRaCIS.Core.Application.Services [HttpPost] public async Task GetDicomSeriesInfo(GetDicomSeriesInfoInDto inDto) { - DicomSeriesDTO series = await _dicomSeriesRepository.Where(s => s.Id == inDto.SeriesId).ProjectTo(_mapper.ConfigurationProvider).FirstNotNullAsync(); + DicomSeriesDTO? series = await _dicomSeriesRepository.Where(s => s.Id == inDto.SeriesId).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync(); - var instanceList = await _dicomInstanceRepository.Where(t => t.SeriesId == inDto.SeriesId) - .Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.SliceLocation, t.FileSize }).ToListAsync(); + if (series != null) + { + var instanceList = await _dicomInstanceRepository.Where(t => t.SeriesId == inDto.SeriesId) + .Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.SliceLocation, t.FileSize }).ToListAsync(); - series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k => - new InstanceBasicInfo() - { - Id = k.Id, - NumberOfFrames = k.NumberOfFrames, - HtmlPath = k.HtmlPath, - Path = k.Path, - InstanceNumber = k.InstanceNumber, - FileSize = k.FileSize + series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k => + new InstanceBasicInfo() + { + Id = k.Id, + NumberOfFrames = k.NumberOfFrames, + HtmlPath = k.HtmlPath, + Path = k.Path, + InstanceNumber = k.InstanceNumber, + FileSize = k.FileSize - }).ToList(); + }).ToList(); + } + else + { + series = await _taskSeriesRepository .Where(s => s.Id == inDto.SeriesId).ProjectTo(_mapper.ConfigurationProvider).FirstNotNullAsync(); + + var instanceList = await _taskInstanceRepository.Where(t => t.SeriesId == inDto.SeriesId) + .Select(t => new { t.SeriesId, t.StudyId, t.Id, t.InstanceNumber, t.Path, t.NumberOfFrames, t.WindowCenter, t.WindowWidth, t.HtmlPath, t.SliceLocation, t.FileSize }).ToListAsync(); - //series.WindowWidth = instanceList.FirstOrDefault()!.WindowWidth; - //series.WindowCenter = instanceList.FirstOrDefault()!.WindowCenter; + series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k => + new InstanceBasicInfo() + { + Id = k.Id, + NumberOfFrames = k.NumberOfFrames, + HtmlPath = k.HtmlPath, + Path = k.Path, + InstanceNumber = k.InstanceNumber, + FileSize = k.FileSize + + }).ToList(); + } return series; } diff --git a/IRaCIS.Core.Infra.EFCore/Common/AuditingData.cs b/IRaCIS.Core.Infra.EFCore/Common/AuditingData.cs index e1975b1dd..c735d76fa 100644 --- a/IRaCIS.Core.Infra.EFCore/Common/AuditingData.cs +++ b/IRaCIS.Core.Infra.EFCore/Common/AuditingData.cs @@ -3644,22 +3644,53 @@ namespace IRaCIS.Core.Infra.EFCore.Common var entity = item.Entity as ReadingNoneDicomMarkBinding; var selfDefineIdentification = string.Empty; - switch (type) + + var answer = string.Empty; + Guid? questionId=Guid.Empty; + string tableQuestionName = string.Empty; + var rowMark= string.Empty; + if (entity.TableQuestionId == null) { - case "Add": - selfDefineIdentification = "SaveTaskQuestion/-10/ReadingTaskQuestionAnswer/Add/AddMark"; - break; - case "Update": - selfDefineIdentification = "SaveTaskQuestion/-10/ReadingTaskQuestionAnswer/Add/UpdateMark"; - break; - case "Deleted": - selfDefineIdentification = "SaveTaskQuestion/-10/ReadingTaskQuestionAnswer/Add/DeleteMark"; - break; + switch (type) + { + case "Add": + selfDefineIdentification = "SaveTaskQuestion/-10/ReadingTaskQuestionAnswer/Add/AddMark"; + break; + case "Update": + selfDefineIdentification = "SaveTaskQuestion/-10/ReadingTaskQuestionAnswer/Add/UpdateMark"; + break; + case "Deleted": + selfDefineIdentification = "SaveTaskQuestion/-10/ReadingTaskQuestionAnswer/Add/DeleteMark"; + break; + } + + questionId = entity.QuestionId; + answer = entitys.Where(x => x.Entity.GetType() == typeof(ReadingTaskQuestionAnswer)).Select(x => x.Entity as ReadingTaskQuestionAnswer).Select(x => x.Answer).FirstOrDefault(); + } + else + { + switch (type) + { + case "Add": + selfDefineIdentification = "saveTableQuestionMark/-10/ReadingTableQuestionAnswer/Add/AddMark"; + break; + case "Update": + selfDefineIdentification = "saveTableQuestionMark/-10/ReadingTableQuestionAnswer/Add/UpdateMark"; + break; + case "Deleted": + selfDefineIdentification = "saveTableQuestionMark/-10/ReadingTableQuestionAnswer/Add/DeleteMark"; + break; + } + questionId = entity.QuestionId; + tableQuestionName= _dbContext.ReadingTableQuestionTrial.Where(x => x.Id == entity.TableQuestionId).Select(x => _userInfo.IsEn_Us ? x.QuestionEnName : x.QuestionName).FirstOrDefault(); + answer = entitys.Where(x => x.Entity.GetType() == typeof(ReadingTableQuestionAnswer)).Select(x => x.Entity as ReadingTableQuestionAnswer).Select(x => x.Answer).FirstOrDefault(); + rowMark= _dbContext.ReadingTableAnswerRowInfo.Where(x => x.Id == entity.RowId).Select(x => x.RowMark).FirstOrDefault(); } - var answer = entitys.Where(x => x.Entity.GetType() == typeof(ReadingTaskQuestionAnswer)).FirstOrDefault(); - var mark= entitys.Where(x => x.Entity.GetType() == typeof(ReadingNoneDicomMark)).Select(x=>x.Entity as ReadingNoneDicomMark).FirstOrDefault(); + + + var mark = entitys.Where(x => x.Entity.GetType() == typeof(ReadingNoneDicomMark)).Select(x => x.Entity as ReadingNoneDicomMark).FirstOrDefault(); if (mark == null) { mark = await _dbContext.ReadingNoneDicomMark.Where(x => x.Id == entity.NoneDicomMarkId).FirstOrDefaultAsync(); @@ -3668,13 +3699,8 @@ namespace IRaCIS.Core.Infra.EFCore.Common var QuestionName = string.Empty; if (answer != null) { - QuestionName= _dbContext.ReadingQuestionTrial.Where(x => x.Id == (answer.Entity as ReadingTaskQuestionAnswer).ReadingQuestionTrialId).Select(x => _userInfo.IsEn_Us ? x.QuestionEnName : x.QuestionName).FirstOrDefault(); + QuestionName= _dbContext.ReadingQuestionTrial.Where(x => x.Id == questionId).Select(x => _userInfo.IsEn_Us ? x.QuestionEnName : x.QuestionName).FirstOrDefault(); } - //var selfDefineIdentification = "ReadingImageTask/submitCustomTag/ReadingTaskQuestionMark/"; - //if (type == "Deleted") - //{ - // selfDefineIdentification = "ReadingImageTask/deleteCustomTag/ReadingTaskQuestionMark/"; - //} await InsertInspection(entity, type, x => new InspectionConvertDTO() { @@ -3682,10 +3708,12 @@ namespace IRaCIS.Core.Infra.EFCore.Common }, new { - MarkName= mark==null|| type== "Deleted" ? string.Empty: mark.OrderMarkName, + RowMark= rowMark, + TableQuestionName = tableQuestionName, + MarkName = mark==null|| type== "Deleted" ? string.Empty: mark.OrderMarkName, PicturePath= mark == null ? string.Empty : mark.PicturePath, QuestionName = QuestionName, - QuestinonAnswer= answer==null?string.Empty:(answer.Entity as ReadingTaskQuestionAnswer).Answer + QuestinonAnswer= answer }); }