using DocumentFormat.OpenXml.Office.SpreadSheetML.Y2023.MsForms; using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; using IRaCIS.Core.Infrastructure; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using MiniExcelLibs; using Org.BouncyCastle.Asn1.X509; using System.Data; using System.IO; namespace IRaCIS.Core.Application.Service.ReadingCalculate { [ApiExplorerSettings(GroupName = "Image")] public class ReadingCalculateService(IEnumerable _criterionServices, IRepository _visitTaskRepository, IRepository _readingImportFileRepository, IHttpContextAccessor httpContext, IOSSService oSSService, IRepository _readingQuestionCriterionTrialRepository, IStringLocalizer _localizer, IUserInfo _userInfo ) : BaseService, IReadingCalculateService { private ICriterionCalculateService _useCriterion; /// /// 标准和服务对应 /// Dictionary CalculateServiceDic = new Dictionary() { {CriterionType.RECIST1Point1,typeof(RECIST1Point1CalculateService) }, //RECIST1.1 {CriterionType.PCWG3,typeof(PCWG3CalculateService) }, {CriterionType.SelfDefine,typeof(SelfDefineCalculateService) }, {CriterionType.RECIST1Pointt1_MB,typeof(RECIST1Point1_BMCalculateService) }, {CriterionType.IRECIST1Point1,typeof(IRECIST1Point1CalculateService) }, {CriterionType.Lugano2014,typeof(LuganoCalculateService) }, {CriterionType.Lugano2014WithoutPET,typeof(LuganoWithoutPETCalculateService) }, {CriterionType.IVUS,typeof(IVUSCalculateService) }, {CriterionType.OCT,typeof(OCTCalculateService) }, {CriterionType.MRIPDFF,typeof(MRIPDFFCalculateService) }, {CriterionType.mRECISTHCC,typeof(MRECISTHCCCalculateService) }, }; /// /// 阅片导入 /// /// [HttpPost] public async Task ReadingImport() { var request = httpContext.HttpContext!.Request; var file = request.Form.Files[0]; Guid visitTaskId = Guid.Parse(request.Form["VisitTaskId"]); string tableName = request.Form["TableName"].ToString(); var service = await this.GetService(visitTaskId); if (service != null) { var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); var streamCopy = new MemoryStream(); // 将上传的文件内容复制到 MemoryStream await file.CopyToAsync(streamCopy); // 重置流的位置,以便后续读取 streamCopy.Position = 0; var ossRelativePath = await oSSService.UploadToOSSAsync(streamCopy, $"{visitTaskInfo.TrialId.ToString()}/InspectionUpload/ReadingImport", file.FileName); await _readingImportFileRepository.AddAsync(new ReadingImportFile() { FilePath = ossRelativePath, VisitTaskId = visitTaskId, TrialId = visitTaskInfo.TrialId, SubjectId = visitTaskInfo.SubjectId, SubjectVisitId = visitTaskInfo.SourceSubjectVisitId, TrialReadingCriterionId = visitTaskInfo.TrialReadingCriterionId, TableName = tableName, }); await service.ReadingImport(); } } /// /// 获取Service /// /// /// public async Task GetService(Guid visitTaskId) { if (_useCriterion == null) { var criterionId = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Select(x => x.TrialReadingCriterionId).FirstNotNullAsync(); var criterionType = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == criterionId).Select(x => x.CriterionType).FirstOrDefaultAsync(); if (criterionType == null) { throw new BusinessValidationFailedException(_localizer["ReadingCalculate_NoDeveloped"]); } try { CriterionType thisCriterionType = criterionType; Type thisServiceType = CalculateServiceDic[thisCriterionType]; _useCriterion = _criterionServices.FirstOrDefault(x => x.GetType().Name == thisServiceType.Name); } catch (Exception) { _useCriterion = null; } return _useCriterion; } else { return _useCriterion; } } /// /// 自动计算 并修改值 /// /// /// public async Task CalculateTask(CalculateTaskInDto inDto) { _userInfo.IsNotNeedInspection = true; var service = await this.GetService(inDto.VisitTaskId); if (service != null) { await service.CalculateTask(inDto); } } /// /// 验证访视提交 /// /// /// public async Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto) { var service = await this.GetService(inDto.VisitTaskId); if (service != null) { await service.VerifyVisitTaskQuestions(inDto); } } /// /// 获取阅片的计算数据 /// /// /// [HttpPost] public async Task GetReadingCalculationData(GetReadingCalculationDataInDto inDto) { var service = await this.GetService(inDto.VisitTaskId); return await service.GetReadingCalculationData(inDto); } /// /// 将上一次的访视病灶添加到这一次 /// /// /// public async Task AddTaskLesionAnswerFromLastTask(AddTaskLesionAnswerFromLastTaskInDto inDto) { var service = await this.GetService(inDto.VisitTaskId); var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var result = new AddTaskLesionAnswerFromLastTaskOutDto(); var readingTaskState = visitTaskInfo.ReadingTaskState; if (service != null && visitTaskInfo.SourceSubjectVisitId != null) { if (readingTaskState == ReadingTaskState.WaitReading) { if (visitTaskInfo.ReadingCategory == ReadingCategory.Visit) { result = await service.AddTaskLesionAnswerFromLastTask(inDto); await service.CalculateTask(new CalculateTaskInDto() { IsChangeOtherTask = false, VisitTaskId = inDto.VisitTaskId, ComputationTrigger = ComputationTrigger.InitialCalculation, }); } } } if (readingTaskState == ReadingTaskState.WaitReading) { await _visitTaskRepository.UpdatePartialFromQueryAsync(inDto.VisitTaskId, x => new VisitTask() { ReadingTaskState = ReadingTaskState.Reading, }, true); } return result; } /// /// 获取报告验证的信息(这里每个标准可能不一样 返回用object) /// /// /// public async Task GetReportVerify(GetReportVerifyInDto inDto) { var service = await this.GetService(inDto.VisitTaskId); if (service != null) { return await service.GetReportVerify(inDto); } else { return new GetReportVerifyOutDto() { }; } } /// /// 获取报告图表数据 /// /// /// [HttpPost] public async Task GetReportsChartData(GetReportsChartDataInDto inDto) { var criterionId = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.TrialReadingCriterionId).FirstNotNullAsync(); var criterionType = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == criterionId).Select(x => x.CriterionType).FirstOrDefaultAsync(); var data = await GetReadingReportEvaluation(new GetReadingReportEvaluationInDto() { TrialId = inDto.TrialId, VisitTaskId = inDto.VisitTaskId, }); GetReportsChartDataOutDto result = new GetReportsChartDataOutDto() { VisitTaskNameList = data.VisitTaskList.Select(x => x.BlindName).ToList(), LatestScanDateList = data.VisitTaskList.Select(x => x.LatestScanDate).ToList(), ChartDataList = new List() { }, }; result.VisitTaskNameList = data.VisitTaskList.Select(x => x.BlindName).ToList(); if (inDto.ReportChartTypeEnum != null) { var reportData = await GetReportsChartTypeData(new GetReportsChartTypeDataInDto() { CriterionType = criterionType, Data = data, ReportChartTypeEnum = inDto.ReportChartTypeEnum.Value, }); result.ChartDataList = reportData.ChartDataList; result.Unit = reportData.Unit; } else if (inDto.QuestionId != null) { var question = data.TaskQuestions.SelectMany(x => x.Childrens) .Where(x => x.QuestionId == inDto.QuestionId.Value).FirstOrDefault(); if (question != null) { result.Unit = question.Unit; ReportChartData chartData = new ReportChartData() { Name = question.QuestionName, Value = new List(), }; foreach (var answer in question.Answer) { chartData.Value.Add(answer.Answer); } result.ChartDataList.Add(chartData); } } else { var lesion = data.TaskQuestions // 问题 靶病灶 .SelectMany(x => x.Childrens) // 病灶 .SelectMany(x => x.Childrens).Where(x => x.RowIndex == inDto.RowIndex) // 表格问题 .SelectMany(x => x.Childrens).Where(x => x.TableQuestionId == inDto.TableQuestionId) .FirstOrDefault(); if (lesion != null) { result.Unit = lesion.Unit; ReportChartData chartData = new ReportChartData() { Name = lesion.QuestionName, Value = new List(), }; foreach (var answer in lesion.Answer) { chartData.Value.Add(answer.Answer); } result.ChartDataList.Add(chartData); } } 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 }); var alldata = r1Data.VisitTaskList.Count() > r2Data.VisitTaskList.Count() ? r1Data : r2Data; var visitTaskName = alldata.VisitTaskList.Select(x => x.BlindName).ToList(); var length = alldata.VisitTaskList.Count(); // -1转为空 List negativeToString = new List() { QuestionType.DaysBetween, }; 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 visitAnswerType = QuestionType.Tumor; if (criterion.CriterionType == CriterionType.PCWG3) { visitAnswerType = QuestionType.SiteVisitForTumorEvaluation; } result.Evaluation.Add(visitTaskName.Select(x=> new EvaluationValue() { Value=x }).ToList()); var r1baseLine= r1.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 = r1.TaskQuestions .SelectMany(x => x.Childrens) .Where(x => x.QuestionType == visitAnswerType) .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); if (criterion.ReadingType == ReadingMethod.Double) { var r2baseLine = r2.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 = r2.TaskQuestions .SelectMany(x => x.Childrens) .Where(x => x.QuestionType == visitAnswerType) .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 (alldata.TaskQuestions == null || alldata.VisitTaskList == null) return groups; foreach (var g in alldata.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 itemdata= data.TaskQuestions.SelectMany(x => x.Childrens) .Where(x => x.QuestionId == item.QuestionId) .FirstOrDefault(); var cd = new ReportChartData { Name = item?.QuestionName??string.Empty, Value = itemdata?.Answer?.Select(a => a.Answer).ToList() ?? new List() }; if (negativeToString.Contains(item.QuestionType)) { cd.Value.ForEach(item1 => { item1 = item1 == "-1" ? string.Empty : item1; }); } chartList.Add(cd); } groups.Add(new ChartItem { Arm = arm, ChartType = null, GroupName = g.GroupName, Unit = items.FirstOrDefault()?.Unit, VisitTaskNameList = alldata.VisitTaskList.Select(x => x.BlindName).ToList(), LatestScanDateList = alldata.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 = alldata.VisitTaskList?.Select(x => x.BlindName).ToList() ?? new List(), LatestScanDateList = alldata.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); } if (criterion.CriterionType == CriterionType.PCWG3) { result.TargetCharts = new List() { }; } return result; } /// /// 获取阅片报告 /// /// public async Task GetReadingReportEvaluation(GetReadingReportEvaluationInDto inDto) { var service = await this.GetService(inDto.VisitTaskId); if (service != null) { var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var result = await service.GetReadingReportEvaluation(inDto); // 这里统一处理字典 Dictionary> dictionaryGroup = result.VisitTaskList.ToDictionary(x => x.VisitTaskId, x => x.CrterionDictionaryGroup); result.TaskQuestions.ForEach(y => { SetCrterionDictionaryGroup(y, dictionaryGroup); }); // 处理标红 高亮 #region 当第N个 存在被评估为NE的单个靶病灶 评估为 为是 之后 N+1 之后的最低点访视 都标红 var index = result.TaskQuestions.SelectMany(x => x.Childrens).Where(x => x.QuestionType == QuestionType.NETarget).SelectMany(x => x.Answer).ToList().FindIndex(x => x.Answer == ExistOrNA.Exist.GetEnumInt()); if (index >= 0) { result.TaskQuestions.ForEach(x => { x.Childrens.ForEach(y => { if (y.QuestionType == QuestionType.LowVisit) { int idx = 0; y.Answer.ForEach(z => { if (idx > index) { z.IsHighlight = true; } idx++; }); } }); }); } #endregion return result; } else { return new GetReadingReportEvaluationOutDto(); } } public void SetCrterionDictionaryGroup(ReadingReportDto item, Dictionary> dictionaryGroup) { item.Answer.ForEach(z => { try { z.CrterionDictionaryGroup = dictionaryGroup[z.VisitTaskId]; } catch (Exception) { } }); item.Childrens.ForEach(x => { SetCrterionDictionaryGroup(x, dictionaryGroup); }); } /// /// 删除病灶获取起始病灶序号 /// /// public async Task GetDeleteLesionStatrIndex(DeleteReadingRowAnswerInDto inDto) { var service = await this.GetService(inDto.VisitTaskId); if (service != null) { return await service.GetDeleteLesionStatrIndex(inDto); } else { return 1; } } } }