diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj index 5aa992945..9741b8644 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj @@ -107,8 +107,4 @@ - - - - diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index 21197f7a8..004f4304e 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -780,6 +780,337 @@ + + + 自动计算 并修改值 + + + + + + + 验证访视提交 + + + + + + + 将上一次的访视病灶添加到这一次 + + + + + + + 获取报告验证的信息(这里每个标准可能不一样 返回用object) + + + + + + + 自动计算 并修改值 + + + + + + + 验证访视提交 + + + + + + + 将上一次的访视病灶添加到这一次 + + + + + + + 获取报告验证的信息(这里每个标准可能不一样 返回用object) + + + + + + + 标准和服务对应 + + + + + 获取Service + + + + + + + 自动计算 并修改值 + + + + + + + 验证访视提交 + + + + + + + 将上一次的访视病灶添加到这一次 + + + + + + + 获取报告验证的信息(这里每个标准可能不一样 返回用object) + + + + + + + 获取Sod的值 + + + + + 计算任务 + + + + + + + 获取报告验证的信息(这里每个标准可能不一样 返回用object) + + + + + + + 自动计算 + + + + + + + 获取报告整体整体评估 + + + + + + + 获取报告是否存在疾病 + + + + + + + 验证访视提交 + + + + + + + 获取ReadingCalculateDto + + + + + + + 将上一次的访视病灶添加到这一次 + + + + + + + 获取SOD + + + 靶病灶径线之和(SOD) + 非淋巴结的长径 和淋巴结的短径 + + + + + + 非淋巴结靶病灶长径之和 + + + + + + + 与基线SOD相比变化量(mm) + + + + + + + 与基线访视相比SOD变化百分比 + + + + + + + 与整个访视期间SOD最低点相比增加的值(mm) + + + + 要更新之前的 + + + + + + 与整个访视期间SOD最低点相比增加的百分比 + + + + 要更新之前的 + + + + + + 整个访视期间SOD最低点访视名称 + + + + 要更新之前的 + + + + + + 是否存在非淋巴结靶病灶 + + + + + + + 是否存在淋巴结靶病灶且该病灶比上一访视短径增加5MM以上 + + + + + + + 被评估为NE的单个靶病灶 + + + + + + + 整体肿瘤评估 + + + + + + + 是否存在疾病 + + + + + + + 修改与整个访视期间SOD最低点相比增加的值(mm) + + + + + + + 修改整个访视期间SOD最低点相比增加的百分比 + + + + + + + 修改最低方式点名称 + + + + + + + 修改所有访视任务的答案 + + + + + + + + + 获取基线SOD + + + + + + + 获取最低方式 + + + + + + + 获取访视任务信息 + + + + + + + 获取上一个访视任务Id + + + + + + 获取靶病灶评估 + + + + + + + 获取非靶病灶评估 + + + + + + + 获取新病灶评估 + + + + 名称 @@ -3937,248 +4268,6 @@ - - - 阅片计算 - - - 阅片验证 - - - - - 获取Sod的值 - - - - - 计算任务 - - - - - - - 自动计算 - - - - - - - 获取报告整体整体评估 - - - - - - - 获取报告是否存在疾病 - - - - - - - 验证访视提交 - - - - - - - 获取ReadingCalculateDto - - - - - - - 获取SOD - - - 靶病灶径线之和(SOD) - 非淋巴结的长径 和淋巴结的短径 - - - - - - 非淋巴结靶病灶长径之和 - - - - - - - 与基线SOD相比变化量(mm) - - - - - - - 与基线访视相比SOD变化百分比 - - - - - - - 与整个访视期间SOD最低点相比增加的值(mm) - - - - 要更新之前的 - - - - - - 与整个访视期间SOD最低点相比增加的百分比 - - - - 要更新之前的 - - - - - - 整个访视期间SOD最低点访视名称 - - - - 要更新之前的 - - - - - - 是否存在非淋巴结靶病灶 - - - - - - - 是否存在淋巴结靶病灶且该病灶比上一访视短径增加5MM以上 - - - - - - - 被评估为NE的单个靶病灶 - - - - - - - 整体肿瘤评估 - - - - - - - 是否存在疾病 - - - - - - - 修改与整个访视期间SOD最低点相比增加的值(mm) - - - - - - - 修改整个访视期间SOD最低点相比增加的百分比 - - - - - - - 修改最低方式点名称 - - - - - - - 修改所有访视任务的答案 - - - - - - - - - 获取基线SOD - - - - - - - 获取最低方式 - - - - - - - 获取访视任务信息 - - - - - - - 获取上一个访视任务Id - - - - - - 获取靶病灶评估 - - - - - - - 获取非靶病灶评估 - - - - - - - 获取新病灶评估 - - - - - - - 标准验证 - - - - - - RECIST 1.1验证 - - - - 阅片医学审核 @@ -5143,11 +5232,6 @@ IOrganInfoService - - - IReadingCalculateService - - ITrialExternalUserService @@ -7714,13 +7798,6 @@ - - - 添加基线表格数据到其他任务 - - - - 获取阅片报告 diff --git a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs index b5c93edf3..d23867fa0 100644 --- a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs +++ b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs @@ -116,10 +116,10 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto public class GetReadingReportEvaluationOutDto { - public string TumorEvaluate { get; set; } - - public string IsExistDisease { get; set; } + public object ReportCalculateResult{ get; set; } + + public object CalculateResult { get; set; } public ReadingTaskState ReadingTaskState { get; set; } public List VisitTaskList { get; set; } @@ -1051,13 +1051,13 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto public Func> Fun { get; set; } } - public class VerifyVisitTaskQuestionsOutDto + public class GetReportVerifyInDto { - public bool IsVerified { get; set; } - - public string ErrorMessage { get; set; } + public Guid VisitTaskId { get; set; } } + + public class VerifyVisitTaskQuestionsInDto { /// diff --git a/IRaCIS.Core.Application/Service/Reading/Interface/IReadingCalculateService.cs b/IRaCIS.Core.Application/Service/Reading/Interface/IReadingCalculateService.cs deleted file mode 100644 index e8401a0d6..000000000 --- a/IRaCIS.Core.Application/Service/Reading/Interface/IReadingCalculateService.cs +++ /dev/null @@ -1,25 +0,0 @@ -//-------------------------------------------------------------------- -// 此代码由T4模板自动生成 byzhouhang 20210918 -// 生成时间 2022-08-22 09:33:28 -// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。 -//-------------------------------------------------------------------- - -using IRaCIS.Core.Application.Service.Reading.Dto; -using IRaCIS.Core.Application.ViewModel; -namespace IRaCIS.Core.Application.Interfaces -{ - /// - /// IReadingCalculateService - /// - public interface IReadingCalculateService - { - Task CalculateTask(CalculateTaskInDto inDto); - - - Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto); - - Task GetReportTumor(Guid visitTaskId); - - Task GetReportIsExistDisease(Guid visitTaskId); - } -} diff --git a/IRaCIS.Core.Application/Service/Reading/ReadingCalculateService.cs b/IRaCIS.Core.Application/Service/Reading/ReadingCalculateService.cs deleted file mode 100644 index 72c0fba2e..000000000 --- a/IRaCIS.Core.Application/Service/Reading/ReadingCalculateService.cs +++ /dev/null @@ -1,1203 +0,0 @@ -//-------------------------------------------------------------------- -// 此代码由T4模板自动生成 byzhouhang 20210918 -// 生成时间 2022-08-22 09:33:24 -// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。 -//-------------------------------------------------------------------- - -using IRaCIS.Core.Domain.Models; -using Microsoft.AspNetCore.Mvc; -using IRaCIS.Core.Application.Interfaces; -using IRaCIS.Core.Application.ViewModel; -using Panda.DynamicWebApi.Attributes; -using IRaCIS.Core.Domain.Share; -using IRaCIS.Core.Infra.EFCore.Common; -using Microsoft.Extensions.Caching.Memory; -using IRaCIS.Core.Application.Service.Reading.Dto; -using IRaCIS.Core.Infrastructure; - -namespace IRaCIS.Core.Application.Service -{ - /// - /// 阅片计算 - /// - - [ApiExplorerSettings(GroupName = "Reading")] - public partial class ReadingCalculateService : BaseService, IReadingCalculateService - { - private readonly IRepository _readingTableQuestionAnswerRepository; - private readonly IRepository _visitTaskRepository; - private readonly IRepository _readingQuestionCriterionTrialRepository; - private readonly IRepository _readingTableQuestionTrialRepository; - private readonly IRepository _readingTableAnswerRowInfoRepository; - private readonly IRepository _readingQuestionTrialRepository; - private readonly IRepository _subjectVisitRepository; - private readonly IRepository _tumorAssessmentRepository; - private readonly IRepository _readingTaskQuestionAnswerRepository; - - public ReadingCalculateService( - IRepository readingTableQuestionAnswerRepository, - IRepository visitTaskRepository, - IRepository readingQuestionCriterionTrialRepository, - IRepository readingTableQuestionTrialRepository, - IRepository readingTableAnswerRowInfoRepository, - IRepository readingQuestionTrialRepository, - IRepository subjectVisitRepository, - IRepository tumorAssessmentRepository, - IRepository readingTaskQuestionAnswerRepository - ) - { - this._readingTableQuestionAnswerRepository = readingTableQuestionAnswerRepository; - this._visitTaskRepository = visitTaskRepository; - this._readingQuestionCriterionTrialRepository = readingQuestionCriterionTrialRepository; - this._readingTableQuestionTrialRepository = readingTableQuestionTrialRepository; - this._readingTableAnswerRowInfoRepository = readingTableAnswerRowInfoRepository; - this._readingQuestionTrialRepository = readingQuestionTrialRepository; - this._subjectVisitRepository = subjectVisitRepository; - this._tumorAssessmentRepository = tumorAssessmentRepository; - this._readingTaskQuestionAnswerRepository = readingTaskQuestionAnswerRepository; - } - - #region 临时对象 单个请求的生命周期 避免重复查询数据库 - - private List visitTaskAnswerList; - - /// - /// 获取Sod的值 - /// - private decimal? sODData; - #endregion - - /// - /// 计算任务 - /// - /// - /// - [HttpPost] - public async Task CalculateTask(CalculateTaskInDto inDto) - { - ReadingCalculateDto readingData = await GetReadingCalculateDto(inDto.VisitTaskId); - readingData.IsChangeOtherTask = inDto.IsChangeOtherTask; - await ReadingCalculate(readingData); - } - - /// - /// 自动计算 - /// - /// - /// - public async Task ReadingCalculate(ReadingCalculateDto inDto) - { - - #region 计算 这里顺序非常重要 后面计算的值要依赖前面计算的结果 - var needAddList = new List(); - - - List calculateList = new List() - { - //靶病灶径线之和(SOD) - new ReadingCalculateData (){QuestionType=QuestionType.SOD,GetDecimalNullFun=GetSODData}, - - //非淋巴结靶病灶长径之和 - new ReadingCalculateData (){QuestionType=QuestionType.SumOfDiameter,GetDecimalNullFun=GetSumOfDiameter}, - - //与基线SOD相比变化量(mm) - new ReadingCalculateData (){QuestionType=QuestionType.SODChange,GetDecimalNullFun=GetSODChange}, - - //与基线访视相比SOD变化百分比 - new ReadingCalculateData (){QuestionType=QuestionType.SODPercent,GetDecimalNullFun=GetSODPercent}, - - //与整个访视期间SOD最低点相比增加的值(mm) //其他任务需要改 - new ReadingCalculateData (){QuestionType=QuestionType.LowestIncrease,GetDecimalNullFun=GetLowestIncrease,/*ChangeAllTaskFun=ChangeAllLowestIncrease*/}, - - //与整个访视期间SOD最低点相比增加的百分比 //其他任务需要改 - new ReadingCalculateData (){QuestionType=QuestionType.LowPercent,GetDecimalNullFun=GetLowPercent,/*ChangeAllTaskFun=ChangeAllLowPercent*/}, - - //整个访视期间SOD最低点访视名称 //其他任务需要改 - new ReadingCalculateData (){QuestionType=QuestionType.LowVisit,GetStringFun=GetLowVisit,/*ChangeAllTaskFun=ChangeAllLowVisitName*/}, - - //是否存在非淋巴结靶病灶 - new ReadingCalculateData (){QuestionType=QuestionType.IsLymphTarget,GetStringFun=GetIsLymphTarget}, - - //是否存在淋巴结靶病灶且该病灶比上一访视短径增加5MM以上 - new ReadingCalculateData (){QuestionType=QuestionType.IsAddFive,GetStringFun=GetIsAddFive}, - - //被评估为NE的单个靶病灶 - new ReadingCalculateData (){QuestionType=QuestionType.NETarget,GetStringFun=GetNETarget}, - - //靶病灶评估 - new ReadingCalculateData (){QuestionType=QuestionType.TargetLesion,GetStringFun=GetTargetLesionEvaluate}, - - //非靶病灶评估 - new ReadingCalculateData (){QuestionType=QuestionType.NoTargetLesion,GetStringFun=GetNoTargetLesionEvaluate}, - - //是否存在新病灶 - new ReadingCalculateData (){QuestionType=QuestionType.NewLesions,GetStringFun=GetNewLesionEvaluate}, - - //整体肿瘤评估 - new ReadingCalculateData (){QuestionType=QuestionType.Tumor,GetStringFun=GetTumor}, - - //是否存在疾病 - new ReadingCalculateData (){QuestionType=QuestionType.ExistDisease,GetStringFun=GetIsExistDisease}, - - }; - - - var typeNAList = new List - { - QuestionType.SODChange, - QuestionType.SODPercent, - QuestionType.LowestIncrease, - QuestionType.LowPercent, - }; - - foreach (var calculate in calculateList) - { - var item=inDto.QuestionInfo.FirstOrDefault(x => x.QuestionType == calculate.QuestionType); - - if (item != null) - { - //计算答案 - if(inDto.IsOnlyChangeAllTask==false) - { - - #region 计算答案 - if (calculate.GetDecimalFun != null) - { - item.Answer = (await calculate.GetDecimalFun(inDto)).ToString(); - - } - else if (calculate.GetDecimalNullFun != null) - { - var value = await calculate.GetDecimalNullFun(inDto); - if (value == null) - { - if (typeNAList.Contains(item.QuestionType ?? QuestionType.SOD)) - { - item.Answer = nameof(YesOrNoOrNa.NA); - - } - else - { - item.Answer = string.Empty; - - } - - } - else - - { - item.Answer = value.ToString(); - } - } - else if (calculate.GetStringFun != null) - { - item.Answer = await calculate.GetStringFun(inDto); - } - #endregion - needAddList.Add(new ReadingTaskQuestionAnswer() - { - Answer = item.Answer, - ReadingQuestionTrialId = item.QuestionId, - }); - } - - // 修改全局 - if (inDto.IsChangeOtherTask && calculate.ChangeAllTaskFun != null) - { - await calculate.ChangeAllTaskFun(new ChangeAllTaskDto() - { - calculateDto = inDto, - QuestionId = item.QuestionId, - }); - } - - } - } - - - - var questionIds = needAddList.Select(x => x.ReadingQuestionTrialId).ToList(); - - await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => questionIds.Contains(x.ReadingQuestionTrialId) && x.VisitTaskId == inDto.VisitTaskId); - needAddList.ForEach(x => - { - x.SubjectId = inDto.SubjectId; - x.ReadingQuestionCriterionTrialId = inDto.CriterionId; - x.VisitTaskId = inDto.VisitTaskId; - x.TrialId = inDto.TrialId; - x.SubjectId = inDto.SubjectId; - }); - - await _readingTaskQuestionAnswerRepository.AddRangeAsync(needAddList); - - await _readingTaskQuestionAnswerRepository.SaveChangesAsync(); - #endregion - - - } - - - /// - /// 获取报告整体整体评估 - /// - /// - /// - public async Task GetReportTumor(Guid visitTaskId) - { - return await GetTumor(await GetReadingCalculateDto(visitTaskId)); - } - - /// - /// 获取报告是否存在疾病 - /// - /// - /// - public async Task GetReportIsExistDisease(Guid visitTaskId) - { - return await GetIsExistDisease(await GetReadingCalculateDto(visitTaskId)); - } - - /// - /// 验证访视提交 - /// - /// - /// - public async Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto) - { - - ReadingCalculateDto data = await GetReadingCalculateDto(inDto.VisitTaskId); - data.IsChangeOtherTask = true; - data.IsOnlyChangeAllTask = true; - await ReadingCalculate(data); - - VerifyVisitTaskQuestionsOutDto result = new VerifyVisitTaskQuestionsOutDto() { - IsVerified=true, - ErrorMessage=string.Empty, - }; - - List types = new List() { - //new VerifyVisitTaskDto (){ QuestionType=QuestionType.TargetLesion,Fun=this.GetTargetLesionEvaluate }, - //new VerifyVisitTaskDto (){ QuestionType=QuestionType.NoTargetLesion,Fun=this.GetNoTargetLesionEvaluate }, - //new VerifyVisitTaskDto (){ QuestionType=QuestionType.NewLesions,Fun=this.GetNewLesionEvaluate }, - new VerifyVisitTaskDto (){ QuestionType=QuestionType.Tumor,Fun=this.GetTumor }, - }; - - foreach (var type in types) - { - var question=data.QuestionInfo.Where(x => x.QuestionType == type.QuestionType).FirstOrDefault(); - if (question != null) - { - var calculateAnswer = await type.Fun(data); - if (question.Answer != calculateAnswer) - { - result.IsVerified = false; - var msg = $"问题【{question.QuesionName}】的答案与计算的答案不一致"; - result.ErrorMessage += result.ErrorMessage == string.Empty ? msg : "," + msg; - } - } - } - if (!result.ErrorMessage.IsNullOrEmpty()) - { - throw new BusinessValidationFailedException(result.ErrorMessage); - } - return result; - } - - /// - /// 获取ReadingCalculateDto - /// - /// - /// - public async Task GetReadingCalculateDto(Guid visitTaskId) - { - var visitTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); - var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == (visitTask.SourceSubjectVisitId ?? default(Guid))).FirstOrDefaultAsync(); - - var baseLineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == visitTask.SubjectId && x.IsBaseLine).Select(x => x.Id).FirstOrDefaultAsync(); - - - var rowInfoList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == visitTaskId).ToListAsync(); - - var baseLinetaskId = await _visitTaskRepository.Where(x => x.SourceSubjectVisitId == baseLineVisitId && x.TaskState == TaskState.Effect && x.ArmEnum == visitTask.ArmEnum).Select(x => x.Id).FirstOrDefaultAsync(); - var criterionId = await _readingQuestionCriterionTrialRepository.Where(x => x.TrialId == visitTask.TrialId && x.IsConfirm).Select(x => x.Id).FirstOrDefaultAsync(); - List questionInfos = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == criterionId).Select(x => new QuestionInfo() - { - LesionType = x.LesionType, - QuestionId = x.Id, - QuesionName=x.QuestionName, - QuestionType = x.QuestionType, - }).ToListAsync(); - - var questionAnswers = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Select(x => new - { - x.ReadingQuestionTrialId, - x.Answer - }).ToListAsync(); - - var tableQuestion = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Include(x => x.ReadingTableQuestionTrial).Select(x => new TableQuestionInfo() - { - Answer = x.Answer, - QuestionMark = x.ReadingTableQuestionTrial.QuestionMark, - TableQuestionId = x.TableQuestionId, - QuestionId = x.QuestionId, - QuestionType=x.ReadingQuestionTrial.QuestionType, - RowIndex = x.RowIndex, - RowId=x.RowId, - }).ToListAsync(); - - foreach (var item in questionInfos) - { - item.Answer = questionAnswers.Where(y => y.ReadingQuestionTrialId == item.QuestionId).Select(x => x.Answer).FirstOrDefault() ?? string.Empty; - - - var thisItemRowInfo = rowInfoList.Where(x => x.QuestionId == item.QuestionId).ToList(); - - var thisItemTableQuestions = tableQuestion.Where(x => x.QuestionId == item.QuestionId).ToList(); - - item.TableRowInfoList = thisItemRowInfo.Select(x => new TableRowInfo() - { - RowIndex = x.RowIndex, - MeasureData = x.MeasureData, - TableQuestionList = tableQuestion.Where(y => y.QuestionId == item.QuestionId && y.RowId == x.Id).ToList(), - - }).ToList(); - - - - - } - - ReadingCalculateDto readingData = new ReadingCalculateDto() - { - SubjectId = visitTask.SubjectId, - VisitTaskId = visitTaskId, - SubjectVisitId = visitTask.SourceSubjectVisitId!.Value, - QuestionInfo = questionInfos, - CriterionId = criterionId, - TrialId = visitTask.TrialId, - IsBaseLine = subjectVisit!.IsBaseLine, - DoctorUserId = visitTask.DoctorUserId, - BaseLineTaskId= baseLinetaskId, - ArmEnum=visitTask.ArmEnum, - VisitName= subjectVisit.VisitName, - BlindName= subjectVisit.BlindName, - }; - - return readingData; - } - - - - - #region 获取SOD - - /// - /// 获取SOD - /// - /// - /// 靶病灶径线之和(SOD) - /// 非淋巴结的长径 和淋巴结的短径 - /// - /// - public async Task GetSODData(ReadingCalculateDto inDto) - { - if (sODData != null) - { - return sODData.Value; - } - - var tableQuestion = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); - - if (tableQuestion.Count() == 0) - { - return null; - } - - decimal result = 0; - - foreach (var item in tableQuestion) - { - if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph &&x.Answer.EqEnum(YesOrNoOrNa.Yes))) - { - // 淋巴结的短径 - result += (item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault()).IsNullOrEmptyReturn0(); - } - - if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(YesOrNoOrNa.No))) - { - // 非淋巴结的长径 - result += item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.MajorAxis).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0(); - } - } - - sODData = result; - - return sODData.Value; - - - - } - #endregion - - #region 非淋巴结靶病灶长径之和 - /// - /// 非淋巴结靶病灶长径之和 - /// - /// - /// - public async Task GetSumOfDiameter(ReadingCalculateDto inDto) - { - var tableQuestion = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); - - if (tableQuestion.Count() == 0) - { - return null; - } - - decimal result = 0; - - foreach (var item in tableQuestion) - { - if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(YesOrNoOrNa.No))) - { - // 非淋巴结的长径 - result += item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.MajorAxis).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0(); - } - } - - - return result; - } - #endregion - - #region 与基线SOD相比变化量(mm) - /// - /// 与基线SOD相比变化量(mm) - /// - /// - /// - public async Task GetSODChange(ReadingCalculateDto inDto) - { - - var value = await GetSODData(inDto); - - if (value == null||inDto.IsBaseLine) - { - return null; - } - return value.NullChange0() - await GetBaseLineSOD(inDto); - } - #endregion - - #region 与基线访视相比SOD变化百分比 - /// - /// 与基线访视相比SOD变化百分比 - /// - /// - /// - public async Task GetSODPercent(ReadingCalculateDto inDto) - { - var thisSOD = await GetSODData(inDto); - - if (thisSOD == null||inDto.IsBaseLine) - { - return null; - } - - var baseLineSOD = await GetBaseLineSOD(inDto); - - if (baseLineSOD == 0) - { - return 100; - } - else - { - return decimal.Round((thisSOD.NullChange0()- baseLineSOD) * 100 / baseLineSOD, 2); - } - } - #endregion - - #region 与整个访视期间SOD最低点相比增加的值(mm) - /// - /// 与整个访视期间SOD最低点相比增加的值(mm) - /// - /// - /// - /// 要更新之前的 - /// - /// - public async Task GetLowestIncrease(ReadingCalculateDto inDto) - { - var value = await GetSODData(inDto); - if (value == null||inDto.IsBaseLine) - { - return null; - } - var decimalAnswerList = await GetLowSODVisit(inDto); - var minSOD = decimalAnswerList.OrderBy(x => x.SOD).Select(x => x.SOD).FirstOrDefault(); - return value.NullChange0() - minSOD; - } - #endregion - - #region 与整个访视期间SOD最低点相比增加的百分比 - /// - /// 与整个访视期间SOD最低点相比增加的百分比 - /// - /// - /// - /// 要更新之前的 - /// - /// - public async Task GetLowPercent(ReadingCalculateDto inDto) - { - var thisSOD = await GetSODData(inDto); - if (thisSOD == null||inDto.IsBaseLine) - { - return null; - } - var decimalAnswerList = await GetLowSODVisit(inDto); - var minSOD = decimalAnswerList.OrderBy(x => x.SOD).Select(x => x.SOD).FirstOrDefault(); - - if (minSOD == 0) - { - return 100; - } - else - { - return decimal.Round((thisSOD.NullChange0()- minSOD) * 100 / minSOD, 2); - } - - - } - #endregion - - #region 整个访视期间SOD最低点访视名称 - /// - /// 整个访视期间SOD最低点访视名称 - /// - /// - /// - /// 要更新之前的 - /// - /// - public async Task GetLowVisit(ReadingCalculateDto inDto) - { - if (inDto.IsBaseLine) - { - return nameof(YesOrNoOrNa.NA); - } - - var decimalAnswerList = await GetLowSODVisit(inDto); - return decimalAnswerList.OrderBy(x => x.SOD).Select(x => x.BlindName).FirstOrDefault() ?? string.Empty; - } - #endregion - - #region 是否存在非淋巴结靶病灶 - /// - /// 是否存在非淋巴结靶病灶 - /// - /// - /// - public async Task GetIsLymphTarget(ReadingCalculateDto inDto) - { - var result = IsLymph.No.GetEnumInt(); - var tableQuestion = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); - - foreach (var item in tableQuestion) - { - if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(IsLymph.Yes))) - { - result= IsLymph.Yes.GetEnumInt(); - } - } - - - - return result; - } - #endregion - - #region 是否存在淋巴结靶病灶且该病灶比上一访视短径增加5MM以上 - /// - /// 是否存在淋巴结靶病灶且该病灶比上一访视短径增加5MM以上 - /// - /// - /// - public async Task GetIsAddFive(ReadingCalculateDto inDto) - { - if (inDto.IsBaseLine) - { - return YesOrNoOrNa.NA.GetEnumInt(); - } - - var LastVisitTaskId = await this.GetLastVisitTaskId(inDto); - - var questionIds = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).Select(x => x.QuestionId).ToList(); - var lastQuestionAsnwer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == LastVisitTaskId && questionIds.Contains(x.QuestionId)).Include(x=>x.ReadingQuestionTrial).Include(x => x.ReadingTableQuestionTrial).ToListAsync(); - var rowIndexs = lastQuestionAsnwer.Where(x=>x.ReadingTableQuestionTrial.QuestionMark==QuestionMark.IsLymph&& x.Answer.EqEnum(YesOrNoOrNa.Yes)).Select(x => x.RowIndex).Distinct().OrderBy(x => x).ToList(); - var thisQuestionAsnwer = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); - - var isExists = false; - foreach (var item in rowIndexs) - { - var lastValue = lastQuestionAsnwer.Where(x => x.RowIndex == item && x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0(); - - var thisRowData = thisQuestionAsnwer.Where(x => x.RowIndex == item).SelectMany(x => x.TableQuestionList).ToList(); - var thisValue = thisRowData.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0(); - - if (thisValue - lastValue > 5) - { - isExists = true; - } - } - - return isExists? YesOrNoOrNa.Yes.GetEnumInt() : YesOrNoOrNa.No.GetEnumInt(); - - } - #endregion - - #region 被评估为NE的单个靶病灶 - /// - /// 被评估为NE的单个靶病灶 - /// - /// - /// - public async Task GetNETarget(ReadingCalculateDto inDto) - { - if (inDto.IsBaseLine) - { - return ExistOrNA.NA.GetEnumInt(); - } - - var result = inDto.QuestionInfo.Any(x => x.QuestionType == QuestionType.TargetLesion && x.Answer.EqEnum(TargetAssessment.NE)); - - return result ? ExistOrNA.Exist.GetEnumInt() : ExistOrNA.NotExist.GetEnumInt(); - } - #endregion - - #region 整体肿瘤评估 - - /// - /// 整体肿瘤评估 - /// - /// - /// - public async Task GetTumor(ReadingCalculateDto inDto) - { - - if (inDto.IsBaseLine) - { - return OverallAssessment.NA.GetEnumInt(); - } - - var targetLesion = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.TargetLesion).Select(x => x.Answer).FirstOrDefault(); - var noTargetLesion = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.NoTargetLesion).Select(x => x.Answer).FirstOrDefault(); - var newLesions = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.NewLesions).Select(x => x.Answer).FirstOrDefault(); - var result = await _tumorAssessmentRepository.Where(x => - x.TargetLesion == (TargetAssessment)int.Parse(targetLesion.IsNullOrEmpty()? TargetAssessment.NA.GetEnumInt(): targetLesion) && - x.NonTargetLesions == (NoTargetAssessment)int.Parse(noTargetLesion.IsNullOrEmpty() ? NoTargetAssessment.NA.GetEnumInt(): noTargetLesion) && - x.NewLesion == (NewLesionAssessment)int.Parse(newLesions.IsNullOrEmpty() ? NewLesionAssessment.NA.GetEnumInt(): newLesions)).Select(x => x.OverallEfficacy).ToListAsync(); - - return result.Count == 0 ? OverallAssessment.NE.GetEnumInt() : result[0].GetEnumInt(); - } - #endregion - - #region 是否存在疾病 - /// - /// 是否存在疾病 - /// - /// - /// - public async Task GetIsExistDisease(ReadingCalculateDto inDto) - { - if (!inDto.IsBaseLine) - { - return string.Empty; - } - - var lesionCount = inDto.QuestionInfo.SelectMany(x => x.TableRowInfoList).Count(); - - return lesionCount>0 ? ExistDisease.Yes.GetEnumInt() : ExistDisease.No.GetEnumInt(); - } - #endregion - - - #region 修改其他标准 - - #region 修改与整个访视期间SOD最低点相比增加的值(mm) - - /// - /// 修改与整个访视期间SOD最低点相比增加的值(mm) - /// - /// - /// - public async Task ChangeAllLowestIncrease(ChangeAllTaskDto inDto) - { - var visitTaskList = await GetVisitTaskAnswerList(inDto.calculateDto); - - var lowSod = (await GetLowSODVisit(inDto.calculateDto)).Select(x => x.SOD).OrderBy(x => x).FirstOrDefault(); - - foreach (var item in visitTaskList.Where(x=>x.VisitTaskId!=inDto.calculateDto.BaseLineTaskId)) - { - await _readingTaskQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => x.VisitTaskId == item.VisitTaskId && x.ReadingQuestionTrialId == inDto.QuestionId, x => new ReadingTaskQuestionAnswer() - { - Answer = (item.SOD - lowSod).ToString() - }) ; - } - } - - #endregion - - - #region 修改整个访视期间SOD最低点相比增加的百分比 - - /// - /// 修改整个访视期间SOD最低点相比增加的百分比 - /// - /// - /// - public async Task ChangeAllLowPercent(ChangeAllTaskDto inDto) - { - var visitTaskList = await GetVisitTaskAnswerList(inDto.calculateDto); - - var lowSod = (await GetLowSODVisit(inDto.calculateDto)).Select(x => x.SOD).OrderBy(x => x).FirstOrDefault(); - - foreach (var item in visitTaskList.Where(x => x.VisitTaskId != inDto.calculateDto.BaseLineTaskId)) - { - decimal percent = 0; - if (lowSod == 0) - { - percent= 100; - } - else - { - percent= decimal.Round((item.SOD - lowSod) * 100 / lowSod, 2); - } - - await _readingTaskQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => x.VisitTaskId == item.VisitTaskId && x.ReadingQuestionTrialId == inDto.QuestionId, x => new ReadingTaskQuestionAnswer() - { - Answer = percent.ToString() - }); - } - } - - #endregion - - #region 修改最低方式点名称 - /// - /// 修改最低方式点名称 - /// - /// - /// - public async Task ChangeAllLowVisitName(ChangeAllTaskDto inDto) - { - // 找到所有访视任务的Id - - var visitTaskIds = await _visitTaskRepository.Where(x => !x.IsAnalysisCreate && x.ReadingCategory == ReadingCategory.Visit && - x.TaskState == TaskState.Effect && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.DoctorUserId == inDto.calculateDto.DoctorUserId).Select(x => x.Id).ToListAsync(); - - var answer = (await GetLowSODVisit(inDto.calculateDto)).OrderBy(x=>x.SOD).Select(x=>x.BlindName).FirstOrDefault(); - visitTaskIds = visitTaskIds.Where(x => x != inDto.calculateDto.BaseLineTaskId).ToList(); - await this.ChangeAllVisitTaskAnswer(visitTaskIds, inDto.QuestionId, answer); - - } - #endregion - - - #endregion - - #region 通用方法 - - #region 修改所有访视任务的答案 - /// - /// 修改所有访视任务的答案 - /// - /// - /// - /// - /// - private async Task ChangeAllVisitTaskAnswer(List visitTaskGuids, Guid questionId, string answer) - { - await _readingTaskQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => visitTaskGuids.Contains(x.VisitTaskId) && x.ReadingQuestionTrialId == questionId, x => new ReadingTaskQuestionAnswer() - { - Answer = answer - }); - } - #endregion - - - #region 获取基线SOD - /// - /// 获取基线SOD - /// - /// - /// - private async Task GetBaseLineSOD(ReadingCalculateDto inDto) - { - if (await _visitTaskRepository.AnyAsync(x => x.Id == inDto.VisitTaskId && x.SourceSubjectVisit.IsBaseLine&&!x.IsAnalysisCreate&&x.DoctorUserId==inDto.DoctorUserId)) - { - return 0; - } - - // 先找到基线的任务 - var baseLineTaskId = await _visitTaskRepository.Where(x => x.SubjectId == inDto.SubjectId && x.ReadingCategory == ReadingCategory.Visit - && x.SourceSubjectVisit.IsBaseLine && x.TaskState == TaskState.Effect&&!x.IsAnalysisCreate&&x.DoctorUserId==inDto.DoctorUserId) - .Select(x => x.Id).FirstOrDefaultAsync(); - - - var baseLineSOD =(await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == baseLineTaskId && x.ReadingQuestionTrial.QuestionType == QuestionType.SOD).Select(x => x.Answer).FirstOrDefaultAsync()).IsNullOrEmptyReturn0(); - return baseLineSOD; - } - #endregion - - - /// - /// 获取最低方式 - /// - /// - /// - public async Task> GetLowSODVisit(ReadingCalculateDto inDto) - { - var taskAnswerList = await GetVisitTaskAnswerList(inDto); - - taskAnswerList = taskAnswerList.Where(x => x.VisitTaskId != inDto.VisitTaskId).ToList(); - - var taskIds = taskAnswerList.Select(x => x.VisitTaskId).ToList(); - - var unableEvaluateTaskIds = await _readingTableQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId ) && - x.ReadingTableQuestionTrial.QuestionMark== QuestionMark.State - &&x.ReadingQuestionTrial.LesionType== LesionType.TargetLesion - &&x.Answer== TargetState.UnableEvaluate.GetEnumInt() - ) - .Select(x =>x.VisitTaskId).Distinct().ToListAsync(); - - taskAnswerList = taskAnswerList.Where(x => !unableEvaluateTaskIds.Contains(x.VisitTaskId)).ToList(); - return taskAnswerList.OrderBy(x => x.SOD).ToList(); - } - - #region 获取访视任务信息 - /// - /// 获取访视任务信息 - /// - /// - /// - public async Task> GetVisitTaskAnswerList(ReadingCalculateDto inDto) - { - if (visitTaskAnswerList == null) - { - // 查询的时候要把自己排除 因为查询出来的可能不是计算出的最新的 - visitTaskAnswerList = await _readingTaskQuestionAnswerRepository.Where(x =>x.VisitTaskId!=inDto.VisitTaskId&&x.VisitTask.ReadingCategory == ReadingCategory.Visit - && x.SubjectId == inDto.SubjectId && x.VisitTask.ReadingTaskState == ReadingTaskState.HaveSigned &&x.VisitTask.ArmEnum==inDto.ArmEnum&& x.VisitTask.TaskState == TaskState.Effect && x.ReadingQuestionTrial.QuestionType == QuestionType.SOD) - .Select(x => new VisitTaskAnswerInfo - { - VisitTaskId = x.VisitTaskId, - QuestionId = x.ReadingQuestionTrialId, - VisitName = x.VisitTask.SourceSubjectVisit.VisitName, - BlindName=x.VisitTask.SourceSubjectVisit.BlindName, - - SOD = x.Answer.IsNullOrEmptyReturn0(), - }).ToListAsync(); - - // 这里是需要加上自己的 基线不用管 - if (visitTaskAnswerList.Count > 0) - { - visitTaskAnswerList.Add(new VisitTaskAnswerInfo() - { - VisitTaskId = inDto.VisitTaskId, - QuestionId= visitTaskAnswerList[0].QuestionId, - VisitName=inDto.VisitName, - SOD=(await GetSODData(inDto)).ToString().IsNullOrEmptyReturn0(), - }); - } - - - } - - return visitTaskAnswerList; - } - #endregion - - /// - /// 获取上一个访视任务Id - /// - /// - private async Task GetLastVisitTaskId(ReadingCalculateDto inDto) - { - // 拿到这一个访视 - var thisNum = await _subjectVisitRepository.Where(x => x.Id == inDto.SubjectVisitId).Select(x => x.VisitNum).FirstOrDefaultAsync(); - - // 先找到上一个访视 - var lastVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == inDto.SubjectId && !x.IsLostVisit && x.VisitNum < thisNum).OrderByDescending(x => x.VisitNum).Select(x => x.Id).FirstOrDefaultAsync(); - - // 找到访视任务Id - - var LastVisitTaskId = await _visitTaskRepository.Where(x => x.ReadingCategory == ReadingCategory.Visit && x.TaskState == TaskState.Effect && !x.IsAnalysisCreate && x.SourceSubjectVisitId == lastVisitId&&x.DoctorUserId==inDto.DoctorUserId).Select(x => x.Id).FirstOrDefaultAsync(); - - return LastVisitTaskId; - } - #endregion - - #region 计算阅片问题 外层问题 - - #region 获取靶病灶评估 - /// - /// 获取靶病灶评估 - /// - /// - /// - public async Task GetTargetLesionEvaluate(ReadingCalculateDto inDto) - { - var tableQuestion = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); - if (inDto.IsBaseLine) - { - return TargetAssessment.NA.GetEnumInt(); - } - if (tableQuestion.Count() == 0) - { - return string.Empty; - } - TargetLesionCalculateDto resultData = new TargetLesionCalculateDto() - { - //非淋巴结靶病灶长径之和 decimal - SumOfDiameter = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.SumOfDiameter).Sum(x => x.Answer.IsNullOrEmptyReturn0()), - - //所有淋巴结靶病灶的短径小于10mm bool - DiameterLessThan10 = true, - - // SOD变化百分比 - SODPercent = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.SODPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()), - - // SOD 百分比与基线期SOD相比减小≥30% bool - SODPercentBigger30 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.SODPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()) >= 30, - - // SOD 百分比 与基线期SOD相比减小<30% bool - SODPercentLess30 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.SODPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()) < 30, - - // SOD 百分比 整体访视期间SOD最低点SOD相比增加<20% - LowPercentLess20 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.LowPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()) <20, - - // SOD 百分比 比整体访视期间SOD最低点SOD增加≥20% - LowPercentBigger20 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.LowPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()) >= 20, - - // SOD 变化值 比整体访视期间SOD最低点SOD绝对增加值<5 mm - LowChangeLess5 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.LowestIncrease).Sum(x => x.Answer.IsNullOrEmptyReturn0()) < 5, - - // 比整体访视期间SOD最低点SOD绝对增加值≥5 mm - LowChangeBigger5 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.LowestIncrease).Sum(x => x.Answer.IsNullOrEmptyReturn0()) >= 5, - - // 被评估为NE的单个靶病灶 是否存在状态为不可评估的靶病灶 - ExixtsNETargetLesion = tableQuestion.SelectMany(x => x.TableQuestionList).Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(TargetState.UnableEvaluate)), - - //// 上次访视点整体肿瘤评估 - LastTargetLesionEvaluate = string.Empty, - - // 当前访视点非淋巴结病灶长径>0 - CurrentMajoreBigger0 = true, - - // 至少一个淋巴结靶病灶短径≥10 mm - CurrenShortBigger10 = true, - - // 该淋巴结靶病灶短径绝对增加值≥5 mm - IsAddFive = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.IsAddFive && x.Answer.EqEnum(YesOrNoOrNa.Yes)).Count() > 0, - }; - - - - - foreach (var item in tableQuestion) - { - if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(YesOrNoOrNa.Yes))) - { - // 淋巴结的短径 - resultData.DiameterLessThan10 = (item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault()).IsNullOrEmptyReturn0() < 10; - - // 至少一个淋巴结靶病灶短径≥10 mm - resultData.CurrenShortBigger10 = (item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault()).IsNullOrEmptyReturn0() >= 10; - } - - if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && !x.Answer.EqEnum(YesOrNoOrNa.Yes))) - { - // 当前访视点非淋巴结病灶 - resultData.CurrentMajoreBigger0 = (item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.MajorAxis).Select(x => x.Answer).FirstOrDefault()).IsNullOrEmptyReturn0() > 0; - } - } - - - var lastVisitTaskId = await GetLastVisitTaskId(inDto); - var questionId = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.Tumor).Select(x => x.QuestionId).FirstOrDefault(); - resultData.LastTargetLesionEvaluate=(await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == lastVisitTaskId && x.ReadingQuestionTrialId == questionId) - .Select(x => x.Answer).FirstOrDefaultAsync()) ?? string.Empty; - - - - - - TargetAssessment result = TargetAssessment.NA; - if (resultData.SumOfDiameter == 0 && resultData.DiameterLessThan10 && !resultData.ExixtsNETargetLesion) - { - result = TargetAssessment.CR; - } - else if ( - (resultData.SODPercentBigger30 && resultData.LowPercentLess20 && !resultData.ExixtsNETargetLesion) - || - (resultData.SODPercentBigger30 && resultData.LowChangeLess5 && !resultData.ExixtsNETargetLesion) - ) - { - result = TargetAssessment.PR; - } - else if ( - (resultData.SODPercentLess30 && resultData.LowPercentLess20 && !resultData.ExixtsNETargetLesion) - || - (resultData.SODPercentLess30 && resultData.LowChangeLess5 && !resultData.ExixtsNETargetLesion) - ) - { - result = TargetAssessment.SD; - } - else if (resultData.LowPercentBigger20 && resultData.LowChangeBigger5) - { - result = TargetAssessment.PD; - } - else if ( - (resultData.LowPercentLess20 && resultData.ExixtsNETargetLesion) - || - (resultData.LowPercentBigger20 && resultData.LowChangeLess5 && resultData.ExixtsNETargetLesion) - ) - { - result = TargetAssessment.NE; - } - - else if (!resultData.ExixtsNETargetLesion&& resultData.SumOfDiameter==0&& resultData.SODPercent == 0) - { - result = TargetAssessment.ND; - } - - else if ( - (resultData.LastTargetLesionEvaluate.EqEnum(TargetAssessment.CR) && resultData.CurrenShortBigger10 && resultData.IsAddFive) - || - (resultData.LastTargetLesionEvaluate.EqEnum(TargetAssessment.CR) && resultData.CurrentMajoreBigger0) - ) - { - result = TargetAssessment.PD; - } - - - return result.GetEnumInt(); - } - #endregion - - #region 获取非靶病灶评估 - - /// - /// 获取非靶病灶评估 - /// - /// - /// - public async Task GetNoTargetLesionEvaluate(ReadingCalculateDto inDto) - { - - NoTargetAssessment result = NoTargetAssessment.NA; - - if (inDto.IsBaseLine) - { - return result.GetEnumInt(); - } - - var tableRows = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.NonTargetLesions).SelectMany(x => x.TableRowInfoList).ToList(); - - var tableQuestions = tableRows.SelectMany(x => x.TableQuestionList).ToList(); - - //任意单个病灶 / 病灶组评估为“显著增大” - if (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NoTargetState.Increase))) - { - result = NoTargetAssessment.PD; - } - //所有单个病灶/病灶组状态评估状态为“消失” - else if (!tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NoTargetState.Loss) )) - { - result = NoTargetAssessment.PD; - } - // 任意单个病灶/病灶组评估为“无法评估”并且没有“显著增大” - else if (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NoTargetState.Increase)) && - !tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && !x.Answer.EqEnum(NoTargetState.Increase) ) - ) - { - result = NoTargetAssessment.NE; - } - // 基线时没有非靶病灶 - else if (tableQuestions.Count() == 0) - { - result = NoTargetAssessment.ND; - } - - // 所有单个病灶/病灶组评估为”存在”或者有些评估为“消失”有些评估为“存在”,且没有“显著增大”和“无法评估”的病灶 - - else if (!tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && !x.Answer.EqEnum(NoTargetState.Exist)) - || (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NoTargetState.Exist) || x.Answer.EqEnum(NoTargetState.Loss)) && !tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && (x.Answer != "显著增大" || x.Answer != "无法评估"))) - - ) - { - result = NoTargetAssessment.NN; - } - else - { - return string.Empty; - } - - return result.GetEnumInt(); - - } - - #endregion - - #region 获取新病灶评估 - /// - /// 获取新病灶评估 - /// - /// - /// - public async Task GetNewLesionEvaluate(ReadingCalculateDto inDto) - { - - NewLesionAssessment result = NewLesionAssessment.NA; - if (inDto.IsBaseLine) - { - return result.GetEnumInt(); - } - - var tableRows = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.NewLesions).SelectMany(x => x.TableRowInfoList).ToList(); - - var tableQuestions = tableRows.SelectMany(x => x.TableQuestionList).ToList(); - - - - // 当前访视存在至少一个明确新病灶 - if (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NewLesionState.Exist))) - { - result= NewLesionAssessment.Yes; - } - //当前访视不存在明确新病灶且存在至少一个疑似新病灶 - else if (!tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && !x.Answer.EqEnum(NewLesionState.Exist)) || - tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NewLesionState.Suspected)) - ) - { - result = NewLesionAssessment.Suspected; - } - - //只要有任何一个新病灶状态为“无法评估” - else if (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NewLesionState.UnableEvaluate))) - { - result = NewLesionAssessment.NE; - } - else - { - result = NewLesionAssessment.No; - } - return result.GetEnumInt(); - - } - #endregion - - #endregion - - } -} diff --git a/IRaCIS.Core.Application/Service/Reading/ReadingCriterionServiceVerify.cs b/IRaCIS.Core.Application/Service/Reading/ReadingCriterionServiceVerify.cs deleted file mode 100644 index 63f0fbbfc..000000000 --- a/IRaCIS.Core.Application/Service/Reading/ReadingCriterionServiceVerify.cs +++ /dev/null @@ -1,81 +0,0 @@ -using IRaCIS.Core.Domain.Models; -using Microsoft.AspNetCore.Mvc; -using IRaCIS.Core.Application.Interfaces; -using IRaCIS.Core.Application.ViewModel; -using Panda.DynamicWebApi.Attributes; -using IRaCIS.Core.Domain.Share; -using IRaCIS.Core.Infra.EFCore.Common; -using Microsoft.Extensions.Caching.Memory; -using IRaCIS.Core.Application.Service.Reading.Dto; -using IRaCIS.Core.Infrastructure; - -namespace IRaCIS.Core.Application.Service -{ - /// - /// 阅片验证 - /// - [NonDynamicWebApi] - public partial class ReadingCalculateService : BaseService, IReadingCalculateService - { - - /// - /// 标准验证 - /// - /// - public async Task CriterionVerify(Guid visitTaskId) - { - var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).Include(x=>x.TrialReadingCriterion).FirstNotNullAsync(); - ReadingCalculateDto readingData = await GetReadingCalculateDto(visitTaskId); - - - - } - - - /// - /// RECIST 1.1验证 - /// - /// - /// - public async Task RECIST1Point1Verify(ReadingCalculateDto inDto) - { - var tableAnswerList = inDto.QuestionInfo.SelectMany(x => x.TableRowInfoList).SelectMany(x=>x.TableQuestionList).ToList(); - - List errorList = new List(); - - // 判断是否为基线 - if (inDto.IsBaseLine) - { - // 不能有状态为 无法评估 消失 太小 显著增大 疑似的病灶 - List targetStates = new List() { - TargetState.TooSmall.GetEnumInt(), - TargetState.Loss.GetEnumInt(), - TargetState.UnableEvaluate.GetEnumInt(), - }; - - if (tableAnswerList.Any(x => x.QuestionMark == QuestionMark.State && targetStates.Contains(x.Answer))) - { - errorList.Add("基线不能有状态为 无法评估 消失 太小 显著增大 疑似的病灶!"); - - } - - if (inDto.QuestionInfo.Where(x => x.LesionType == LesionType.NewLesions).SelectMany(x => x.TableRowInfoList).Count() > 0) - { - errorList.Add($"基线不能有新病灶!"); - } - - } - else - { - - } - - if (errorList.Count > 0) - { - throw new BusinessValidationFailedException(string.Join(',',errorList)); - } - } - - - } -} diff --git a/IRaCIS.Core.Application/Service/Reading/ReadingImageTaskService.cs b/IRaCIS.Core.Application/Service/Reading/ReadingImageTaskService.cs index 1755de725..aa8cbf332 100644 --- a/IRaCIS.Core.Application/Service/Reading/ReadingImageTaskService.cs +++ b/IRaCIS.Core.Application/Service/Reading/ReadingImageTaskService.cs @@ -391,103 +391,6 @@ namespace IRaCIS.Application.Services } - /// - /// 添加基线表格数据到其他任务 - /// - /// - /// - - private async Task AddBaseLineAnswerToOtherTask(Guid visitTaskId) - { - var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); - - var baseLineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == taskinfo.SubjectId && x.IsBaseLine).Select(x => x.Id).FirstOrDefaultAsync(); - - // 判断当前任务是否是基线 - if (taskinfo.SourceSubjectVisitId != baseLineVisitId) - { - // 判断当前任务是是否有表格问题答案 - if (!(await _readingTableQuestionAnswerRepository.AnyAsync(x => x.VisitTaskId == visitTaskId))) - { - - var LastVisitTaskId = await _visitTaskRepository.Where(x => x.ReadingCategory == ReadingCategory.Visit&&x.SubjectId==taskinfo.SubjectId&&x.ReadingTaskState==ReadingTaskState.HaveSigned &&x.VisitTaskNum< taskinfo.VisitTaskNum&&x.TaskState==TaskState.Effect&&x.ArmEnum==taskinfo.ArmEnum - ).OrderByDescending(x=>x.VisitTaskNum).Select(x => x.Id).FirstOrDefaultAsync(); - - - - var copyTableAnswers = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == LastVisitTaskId).Select(x => new CopyTableAnswerDto() { - Answer = x.Answer, - QuestionId = x.QuestionId, - RowId=x.RowId, - QuestionMark = x.ReadingTableQuestionTrial.QuestionMark, - TableQuestionId = x.TableQuestionId, - - RowIndex = x.RowIndex, - TrialId = x.TrialId - }).ToListAsync(); - - var tableRowAnswers = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == LastVisitTaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); - - - tableRowAnswers.ForEach(x => - { - x.VisitTaskId = visitTaskId; - x.IsCurrentTaskAdd = false; - x.Id = NewId.NextGuid(); - x.SeriesId = null; - x.InstanceId = null; - x.MeasureData = string.Empty; - }); - - tableRowAnswers.ForEach(x => - { - x.SplitRowId = tableRowAnswers.Where(y => y.OriginalId == x.SplitRowId).Select(y => y.Id).FirstOrDefault(); - x.MergeRowId = tableRowAnswers.Where(y => y.OriginalId == x.MergeRowId).Select(y => y.Id).FirstOrDefault(); - - }); - - List notNeedCopyMarks = new List() - { - QuestionMark.MajorAxis, - QuestionMark.ShortAxis, - QuestionMark.State, - }; - - var tableAnswers = copyTableAnswers.Select(x => new ReadingTableQuestionAnswer - { - Id = NewId.NextGuid(), - Answer = notNeedCopyMarks.Contains(x.QuestionMark) ? string.Empty : x.Answer, - QuestionId = x.QuestionId, - RowIndex = x.RowIndex, - RowId= tableRowAnswers.Where(y=>y.OriginalId==x.RowId).Select(x=>x.Id).FirstOrDefault(), - TableQuestionId = x.TableQuestionId, - TrialId = x.TrialId, - VisitTaskId = visitTaskId, - }); - - - await _visitTaskRepository.UpdatePartialFromQueryAsync(visitTaskId, x => new VisitTask() - { - ReadingTaskState = ReadingTaskState.Reading, - - }); - - tableRowAnswers.ForEach(x => - { - x.MergeRow = null; - x.SplitRow = null; - }); - await _readingTableAnswerRowInfoRepository.AddRangeAsync(tableRowAnswers); - await _readingTableQuestionAnswerRepository.AddRangeAsync(tableAnswers); - await _readingTableQuestionAnswerRepository.SaveChangesAsync(); - - } - } - - return taskinfo.SourceSubjectVisitId == baseLineVisitId; - - } - /// /// 获取阅片报告 /// @@ -498,8 +401,10 @@ namespace IRaCIS.Application.Services { GetReadingReportEvaluationOutDto result = new GetReadingReportEvaluationOutDto(); - result.TumorEvaluate = await _readingCalculateService.GetReportTumor(indto.VisitTaskId); - result.IsExistDisease= await _readingCalculateService.GetReportIsExistDisease(indto.VisitTaskId); + result.CalculateResult = await _readingCalculateService.GetReportVerify(new GetReportVerifyInDto() { + VisitTaskId=indto.VisitTaskId + }); + var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == indto.VisitTaskId).FirstNotNullAsync(); result.ReadingTaskState = visitTaskInfo.ReadingTaskState; var taskInfoList = await _visitTaskRepository.Where(x => (x.SubjectId == visitTaskInfo.SubjectId && x.TaskState == TaskState.Effect @@ -665,8 +570,11 @@ namespace IRaCIS.Application.Services [HttpGet] public async Task> GetTableAnswerRowInfoList(GetTableAnswerRowInfoInDto inDto) { - await this.AddBaseLineAnswerToOtherTask(inDto.VisitTaskId); - var result= await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId) + 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(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder).ThenBy(x => x.RowIndex) .ToListAsync(); diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/Dto/CriterionCalculateDto.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/Dto/CriterionCalculateDto.cs new file mode 100644 index 000000000..caebebb9f --- /dev/null +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/Dto/CriterionCalculateDto.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.ViewModel +{ + public class AddTaskLesionAnswerFromLastTaskInDto + { + public Guid VisitTaskId { get; set; } + } + + + public class AddTaskLesionAnswerFromLastTaskOutDto + { + public bool IsBaseLine { get; set; } + } +} diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/ICriterionCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/ICriterionCalculateService.cs new file mode 100644 index 000000000..45cd57e6d --- /dev/null +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/ICriterionCalculateService.cs @@ -0,0 +1,44 @@ +using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Core.Application.ViewModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.Service +{ + public interface ICriterionCalculateService + { + + /// + /// 自动计算 并修改值 + /// + /// + /// + Task CalculateTask(CalculateTaskInDto inDto); + + /// + /// 验证访视提交 + /// + /// + /// + Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto); + + /// + /// 将上一次的访视病灶添加到这一次 + /// + /// + /// + Task AddTaskLesionAnswerFromLastTask(AddTaskLesionAnswerFromLastTaskInDto inDto); + + /// + /// 获取报告验证的信息(这里每个标准可能不一样 返回用object) + /// + /// + /// + Task GetReportVerify(GetReportVerifyInDto inDto); + + + } +} diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs new file mode 100644 index 000000000..fdff8f9f5 --- /dev/null +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs @@ -0,0 +1,41 @@ +using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Core.Application.ViewModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.Service +{ + public interface IReadingCalculateService + { + /// + /// 自动计算 并修改值 + /// + /// + /// + Task CalculateTask(CalculateTaskInDto inDto); + + /// + /// 验证访视提交 + /// + /// + /// + Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto); + + /// + /// 将上一次的访视病灶添加到这一次 + /// + /// + /// + Task AddTaskLesionAnswerFromLastTask(AddTaskLesionAnswerFromLastTaskInDto inDto); + + /// + /// 获取报告验证的信息(这里每个标准可能不一样 返回用object) + /// + /// + /// + Task GetReportVerify(GetReportVerifyInDto inDto); + } +} diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs new file mode 100644 index 000000000..69dc54359 --- /dev/null +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs @@ -0,0 +1,1331 @@ +using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Core.Domain.Share; +using Microsoft.AspNetCore.Mvc; +using IRaCIS.Core.Domain.Models; +using Microsoft.AspNetCore.Mvc; +using IRaCIS.Core.Application.Interfaces; +using IRaCIS.Core.Application.ViewModel; +using Panda.DynamicWebApi.Attributes; +using IRaCIS.Core.Infra.EFCore.Common; +using Microsoft.Extensions.Caching.Memory; + +using IRaCIS.Core.Infrastructure; +using MassTransit; + +namespace IRaCIS.Core.Application.Service.ReadingCalculate +{ + + public class RECIST1Point1CalculateService : BaseService, ICriterionCalculateService + { + private readonly IRepository _readingTableQuestionAnswerRepository; + private readonly IRepository _visitTaskRepository; + private readonly IRepository _readingQuestionCriterionTrialRepository; + private readonly IRepository _readingTableQuestionTrialRepository; + private readonly IRepository _readingTableAnswerRowInfoRepository; + private readonly IRepository _readingQuestionTrialRepository; + private readonly IRepository _subjectVisitRepository; + private readonly IRepository _tumorAssessmentRepository; + private readonly IRepository _readingTaskQuestionAnswerRepository; + + public RECIST1Point1CalculateService( + IRepository readingTableQuestionAnswerRepository, + IRepository visitTaskRepository, + IRepository readingQuestionCriterionTrialRepository, + IRepository readingTableQuestionTrialRepository, + IRepository readingTableAnswerRowInfoRepository, + IRepository readingQuestionTrialRepository, + IRepository subjectVisitRepository, + IRepository tumorAssessmentRepository, + IRepository readingTaskQuestionAnswerRepository + ) + { + this._readingTableQuestionAnswerRepository = readingTableQuestionAnswerRepository; + this._visitTaskRepository = visitTaskRepository; + this._readingQuestionCriterionTrialRepository = readingQuestionCriterionTrialRepository; + this._readingTableQuestionTrialRepository = readingTableQuestionTrialRepository; + this._readingTableAnswerRowInfoRepository = readingTableAnswerRowInfoRepository; + this._readingQuestionTrialRepository = readingQuestionTrialRepository; + this._subjectVisitRepository = subjectVisitRepository; + this._tumorAssessmentRepository = tumorAssessmentRepository; + this._readingTaskQuestionAnswerRepository = readingTaskQuestionAnswerRepository; + } + + #region 临时对象 单个请求的生命周期 避免重复查询数据库 + + private List visitTaskAnswerList; + + /// + /// 获取Sod的值 + /// + private decimal? sODData; + #endregion + + /// + /// 计算任务 + /// + /// + /// + [HttpPost] + public async Task CalculateTask(CalculateTaskInDto inDto) + { + ReadingCalculateDto readingData = await GetReadingCalculateDto(inDto.VisitTaskId); + readingData.IsChangeOtherTask = inDto.IsChangeOtherTask; + await ReadingCalculate(readingData); + } + + /// + /// 获取报告验证的信息(这里每个标准可能不一样 返回用object) + /// + /// + /// + public async Task GetReportVerify(GetReportVerifyInDto inDto) + { + return new + { + TumorEvaluate = await this.GetReportTumor(inDto.VisitTaskId), + IsExistDisease = await this.GetReportIsExistDisease(inDto.VisitTaskId), + + }; + } + + + /// + /// 自动计算 + /// + /// + /// + public async Task ReadingCalculate(ReadingCalculateDto inDto) + { + + #region 计算 这里顺序非常重要 后面计算的值要依赖前面计算的结果 + var needAddList = new List(); + + + List calculateList = new List() + { + //靶病灶径线之和(SOD) + new ReadingCalculateData (){QuestionType=QuestionType.SOD,GetDecimalNullFun=GetSODData}, + + //非淋巴结靶病灶长径之和 + new ReadingCalculateData (){QuestionType=QuestionType.SumOfDiameter,GetDecimalNullFun=GetSumOfDiameter}, + + //与基线SOD相比变化量(mm) + new ReadingCalculateData (){QuestionType=QuestionType.SODChange,GetDecimalNullFun=GetSODChange}, + + //与基线访视相比SOD变化百分比 + new ReadingCalculateData (){QuestionType=QuestionType.SODPercent,GetDecimalNullFun=GetSODPercent}, + + //与整个访视期间SOD最低点相比增加的值(mm) //其他任务需要改 + new ReadingCalculateData (){QuestionType=QuestionType.LowestIncrease,GetDecimalNullFun=GetLowestIncrease,/*ChangeAllTaskFun=ChangeAllLowestIncrease*/}, + + //与整个访视期间SOD最低点相比增加的百分比 //其他任务需要改 + new ReadingCalculateData (){QuestionType=QuestionType.LowPercent,GetDecimalNullFun=GetLowPercent,/*ChangeAllTaskFun=ChangeAllLowPercent*/}, + + //整个访视期间SOD最低点访视名称 //其他任务需要改 + new ReadingCalculateData (){QuestionType=QuestionType.LowVisit,GetStringFun=GetLowVisit,/*ChangeAllTaskFun=ChangeAllLowVisitName*/}, + + //是否存在非淋巴结靶病灶 + new ReadingCalculateData (){QuestionType=QuestionType.IsLymphTarget,GetStringFun=GetIsLymphTarget}, + + //是否存在淋巴结靶病灶且该病灶比上一访视短径增加5MM以上 + new ReadingCalculateData (){QuestionType=QuestionType.IsAddFive,GetStringFun=GetIsAddFive}, + + //被评估为NE的单个靶病灶 + new ReadingCalculateData (){QuestionType=QuestionType.NETarget,GetStringFun=GetNETarget}, + + //靶病灶评估 + new ReadingCalculateData (){QuestionType=QuestionType.TargetLesion,GetStringFun=GetTargetLesionEvaluate}, + + //非靶病灶评估 + new ReadingCalculateData (){QuestionType=QuestionType.NoTargetLesion,GetStringFun=GetNoTargetLesionEvaluate}, + + //是否存在新病灶 + new ReadingCalculateData (){QuestionType=QuestionType.NewLesions,GetStringFun=GetNewLesionEvaluate}, + + //整体肿瘤评估 + new ReadingCalculateData (){QuestionType=QuestionType.Tumor,GetStringFun=GetTumor}, + + //是否存在疾病 + new ReadingCalculateData (){QuestionType=QuestionType.ExistDisease,GetStringFun=GetIsExistDisease}, + + }; + + + var typeNAList = new List + { + QuestionType.SODChange, + QuestionType.SODPercent, + QuestionType.LowestIncrease, + QuestionType.LowPercent, + }; + + foreach (var calculate in calculateList) + { + var item = inDto.QuestionInfo.FirstOrDefault(x => x.QuestionType == calculate.QuestionType); + + if (item != null) + { + //计算答案 + if (inDto.IsOnlyChangeAllTask == false) + { + + #region 计算答案 + if (calculate.GetDecimalFun != null) + { + item.Answer = (await calculate.GetDecimalFun(inDto)).ToString(); + + } + else if (calculate.GetDecimalNullFun != null) + { + var value = await calculate.GetDecimalNullFun(inDto); + if (value == null) + { + if (typeNAList.Contains(item.QuestionType ?? QuestionType.SOD)) + { + item.Answer = nameof(YesOrNoOrNa.NA); + + } + else + { + item.Answer = string.Empty; + + } + + } + else + + { + item.Answer = value.ToString(); + } + } + else if (calculate.GetStringFun != null) + { + item.Answer = await calculate.GetStringFun(inDto); + } + #endregion + needAddList.Add(new ReadingTaskQuestionAnswer() + { + Answer = item.Answer, + ReadingQuestionTrialId = item.QuestionId, + }); + } + + // 修改全局 + if (inDto.IsChangeOtherTask && calculate.ChangeAllTaskFun != null) + { + await calculate.ChangeAllTaskFun(new ChangeAllTaskDto() + { + calculateDto = inDto, + QuestionId = item.QuestionId, + }); + } + + } + } + + + + var questionIds = needAddList.Select(x => x.ReadingQuestionTrialId).ToList(); + + await _readingTaskQuestionAnswerRepository.BatchDeleteNoTrackingAsync(x => questionIds.Contains(x.ReadingQuestionTrialId) && x.VisitTaskId == inDto.VisitTaskId); + needAddList.ForEach(x => + { + x.SubjectId = inDto.SubjectId; + x.ReadingQuestionCriterionTrialId = inDto.CriterionId; + x.VisitTaskId = inDto.VisitTaskId; + x.TrialId = inDto.TrialId; + x.SubjectId = inDto.SubjectId; + }); + + await _readingTaskQuestionAnswerRepository.AddRangeAsync(needAddList); + + await _readingTaskQuestionAnswerRepository.SaveChangesAsync(); + #endregion + + + } + + + /// + /// 获取报告整体整体评估 + /// + /// + /// + public async Task GetReportTumor(Guid visitTaskId) + { + return await GetTumor(await GetReadingCalculateDto(visitTaskId)); + } + + /// + /// 获取报告是否存在疾病 + /// + /// + /// + public async Task GetReportIsExistDisease(Guid visitTaskId) + { + return await GetIsExistDisease(await GetReadingCalculateDto(visitTaskId)); + } + + /// + /// 验证访视提交 + /// + /// + /// + public async Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto) + { + + var tableAnswerList = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && (x.Answer == string.Empty || x.Answer == null) + && x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State + ) + .Select(x => new + { + x.ReadingQuestionTrial.OrderMark, + x.RowIndex, + QuestionMark = x.ReadingTableQuestionTrial.QuestionMark, + Answer = x.Answer, + + }).ToListAsync(); + + + string errorMassage = string.Empty; + + var rowAnswerList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && (x.MeasureData == string.Empty || x.MeasureData == null)) + .Select(x => new + { + x.ReadingQuestionTrial.OrderMark, + x.RowIndex, + x.Id, + }).ToListAsync(); + + + var unableEvaluateRowIds = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.Answer == TargetState.UnableEvaluate.GetEnumInt() + && x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State + ) + .Select(x => x.RowId).Distinct().ToListAsync(); + + + IEnumerable measureDataList = rowAnswerList.Where(x => !unableEvaluateRowIds.Contains(x.Id)).Select(x => x.OrderMark + x.RowIndex.GetLesionMark()).ToList(); + + + if (rowAnswerList.Count > 0) + { + errorMassage += $" 病灶{ string.Join(',', measureDataList)}不存在标记,"; + } + + + if (tableAnswerList.Count > 0) + { + errorMassage += $" 病灶{ string.Join(',', tableAnswerList)}状态为空,"; + } + + + if (errorMassage != string.Empty) + { + throw new BusinessValidationFailedException(errorMassage); + } + + + } + + /// + /// 获取ReadingCalculateDto + /// + /// + /// + public async Task GetReadingCalculateDto(Guid visitTaskId) + { + var visitTask = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); + var subjectVisit = await _subjectVisitRepository.Where(x => x.Id == (visitTask.SourceSubjectVisitId ?? default(Guid))).FirstOrDefaultAsync(); + + var baseLineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == visitTask.SubjectId && x.IsBaseLine).Select(x => x.Id).FirstOrDefaultAsync(); + + + var rowInfoList = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == visitTaskId).ToListAsync(); + + var baseLinetaskId = await _visitTaskRepository.Where(x => x.SourceSubjectVisitId == baseLineVisitId && x.TaskState == TaskState.Effect && x.ArmEnum == visitTask.ArmEnum).Select(x => x.Id).FirstOrDefaultAsync(); + var criterionId = await _readingQuestionCriterionTrialRepository.Where(x => x.TrialId == visitTask.TrialId && x.IsConfirm).Select(x => x.Id).FirstOrDefaultAsync(); + List questionInfos = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == criterionId).Select(x => new QuestionInfo() + { + LesionType = x.LesionType, + QuestionId = x.Id, + QuesionName = x.QuestionName, + QuestionType = x.QuestionType, + }).ToListAsync(); + + var questionAnswers = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Select(x => new + { + x.ReadingQuestionTrialId, + x.Answer + }).ToListAsync(); + + var tableQuestion = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId).Include(x => x.ReadingTableQuestionTrial).Select(x => new TableQuestionInfo() + { + Answer = x.Answer, + QuestionMark = x.ReadingTableQuestionTrial.QuestionMark, + TableQuestionId = x.TableQuestionId, + QuestionId = x.QuestionId, + QuestionType = x.ReadingQuestionTrial.QuestionType, + RowIndex = x.RowIndex, + RowId = x.RowId, + }).ToListAsync(); + + foreach (var item in questionInfos) + { + item.Answer = questionAnswers.Where(y => y.ReadingQuestionTrialId == item.QuestionId).Select(x => x.Answer).FirstOrDefault() ?? string.Empty; + + + var thisItemRowInfo = rowInfoList.Where(x => x.QuestionId == item.QuestionId).ToList(); + + var thisItemTableQuestions = tableQuestion.Where(x => x.QuestionId == item.QuestionId).ToList(); + + item.TableRowInfoList = thisItemRowInfo.Select(x => new TableRowInfo() + { + RowIndex = x.RowIndex, + MeasureData = x.MeasureData, + TableQuestionList = tableQuestion.Where(y => y.QuestionId == item.QuestionId && y.RowId == x.Id).ToList(), + + }).ToList(); + + + + + } + + ReadingCalculateDto readingData = new ReadingCalculateDto() + { + SubjectId = visitTask.SubjectId, + VisitTaskId = visitTaskId, + SubjectVisitId = visitTask.SourceSubjectVisitId!.Value, + QuestionInfo = questionInfos, + CriterionId = criterionId, + TrialId = visitTask.TrialId, + IsBaseLine = subjectVisit!.IsBaseLine, + DoctorUserId = visitTask.DoctorUserId, + BaseLineTaskId = baseLinetaskId, + ArmEnum = visitTask.ArmEnum, + VisitName = subjectVisit.VisitName, + BlindName = subjectVisit.BlindName, + }; + + return readingData; + } + + #region 将上一次的访视病灶添加到这一次 + + /// + /// 将上一次的访视病灶添加到这一次 + /// + /// + /// + public async Task AddTaskLesionAnswerFromLastTask(AddTaskLesionAnswerFromLastTaskInDto inDto) + { + var visitTaskId = inDto.VisitTaskId; + + var taskinfo = await _visitTaskRepository.Where(x => x.Id == visitTaskId).FirstNotNullAsync(); + + var baseLineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == taskinfo.SubjectId && x.IsBaseLine).Select(x => x.Id).FirstOrDefaultAsync(); + + // 判断当前任务是否是基线 + if (taskinfo.SourceSubjectVisitId != baseLineVisitId) + { + // 判断当前任务是是否有表格问题答案 + if (!(await _readingTableQuestionAnswerRepository.AnyAsync(x => x.VisitTaskId == visitTaskId))) + { + + var LastVisitTaskId = await _visitTaskRepository.Where(x => x.ReadingCategory == ReadingCategory.Visit && x.SubjectId == taskinfo.SubjectId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.VisitTaskNum < taskinfo.VisitTaskNum && x.TaskState == TaskState.Effect && x.ArmEnum == taskinfo.ArmEnum + ).OrderByDescending(x => x.VisitTaskNum).Select(x => x.Id).FirstOrDefaultAsync(); + + + + var copyTableAnswers = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == LastVisitTaskId).Select(x => new CopyTableAnswerDto() + { + Answer = x.Answer, + QuestionId = x.QuestionId, + RowId = x.RowId, + QuestionMark = x.ReadingTableQuestionTrial.QuestionMark, + TableQuestionId = x.TableQuestionId, + + RowIndex = x.RowIndex, + TrialId = x.TrialId + }).ToListAsync(); + + var tableRowAnswers = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == LastVisitTaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); + + + tableRowAnswers.ForEach(x => + { + x.VisitTaskId = visitTaskId; + x.IsCurrentTaskAdd = false; + x.Id = NewId.NextGuid(); + x.SeriesId = null; + x.InstanceId = null; + x.MeasureData = string.Empty; + }); + + tableRowAnswers.ForEach(x => + { + x.SplitRowId = tableRowAnswers.Where(y => y.OriginalId == x.SplitRowId).Select(y => y.Id).FirstOrDefault(); + x.MergeRowId = tableRowAnswers.Where(y => y.OriginalId == x.MergeRowId).Select(y => y.Id).FirstOrDefault(); + + }); + + List notNeedCopyMarks = new List() + { + QuestionMark.MajorAxis, + QuestionMark.ShortAxis, + QuestionMark.State, + }; + + var tableAnswers = copyTableAnswers.Select(x => new ReadingTableQuestionAnswer + { + Id = NewId.NextGuid(), + Answer = notNeedCopyMarks.Contains(x.QuestionMark) ? string.Empty : x.Answer, + QuestionId = x.QuestionId, + RowIndex = x.RowIndex, + RowId = tableRowAnswers.Where(y => y.OriginalId == x.RowId).Select(x => x.Id).FirstOrDefault(), + TableQuestionId = x.TableQuestionId, + TrialId = x.TrialId, + VisitTaskId = visitTaskId, + }); + + + await _visitTaskRepository.UpdatePartialFromQueryAsync(visitTaskId, x => new VisitTask() + { + ReadingTaskState = ReadingTaskState.Reading, + + }); + + tableRowAnswers.ForEach(x => + { + x.MergeRow = null; + x.SplitRow = null; + }); + await _readingTableAnswerRowInfoRepository.AddRangeAsync(tableRowAnswers); + await _readingTableQuestionAnswerRepository.AddRangeAsync(tableAnswers); + await _readingTableQuestionAnswerRepository.SaveChangesAsync(); + + } + } + + return new AddTaskLesionAnswerFromLastTaskOutDto() + { + + IsBaseLine = taskinfo.SourceSubjectVisitId == baseLineVisitId, + }; + + } + #endregion + + #region 获取SOD + + /// + /// 获取SOD + /// + /// + /// 靶病灶径线之和(SOD) + /// 非淋巴结的长径 和淋巴结的短径 + /// + /// + public async Task GetSODData(ReadingCalculateDto inDto) + { + if (sODData != null) + { + return sODData.Value; + } + + var tableQuestion = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); + + if (tableQuestion.Count() == 0) + { + return null; + } + + decimal result = 0; + + foreach (var item in tableQuestion) + { + if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(YesOrNoOrNa.Yes))) + { + // 淋巴结的短径 + result += (item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault()).IsNullOrEmptyReturn0(); + } + + if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(YesOrNoOrNa.No))) + { + // 非淋巴结的长径 + result += item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.MajorAxis).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0(); + } + } + + sODData = result; + + return sODData.Value; + + + + } + #endregion + + #region 非淋巴结靶病灶长径之和 + /// + /// 非淋巴结靶病灶长径之和 + /// + /// + /// + public async Task GetSumOfDiameter(ReadingCalculateDto inDto) + { + var tableQuestion = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); + + if (tableQuestion.Count() == 0) + { + return null; + } + + decimal result = 0; + + foreach (var item in tableQuestion) + { + if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(YesOrNoOrNa.No))) + { + // 非淋巴结的长径 + result += item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.MajorAxis).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0(); + } + } + + + return result; + } + #endregion + + #region 与基线SOD相比变化量(mm) + /// + /// 与基线SOD相比变化量(mm) + /// + /// + /// + public async Task GetSODChange(ReadingCalculateDto inDto) + { + + var value = await GetSODData(inDto); + + if (value == null || inDto.IsBaseLine) + { + return null; + } + return value.NullChange0() - await GetBaseLineSOD(inDto); + } + #endregion + + #region 与基线访视相比SOD变化百分比 + /// + /// 与基线访视相比SOD变化百分比 + /// + /// + /// + public async Task GetSODPercent(ReadingCalculateDto inDto) + { + var thisSOD = await GetSODData(inDto); + + if (thisSOD == null || inDto.IsBaseLine) + { + return null; + } + + var baseLineSOD = await GetBaseLineSOD(inDto); + + if (baseLineSOD == 0) + { + return 100; + } + else + { + return decimal.Round((thisSOD.NullChange0() - baseLineSOD) * 100 / baseLineSOD, 2); + } + } + #endregion + + #region 与整个访视期间SOD最低点相比增加的值(mm) + /// + /// 与整个访视期间SOD最低点相比增加的值(mm) + /// + /// + /// + /// 要更新之前的 + /// + /// + public async Task GetLowestIncrease(ReadingCalculateDto inDto) + { + var value = await GetSODData(inDto); + if (value == null || inDto.IsBaseLine) + { + return null; + } + var decimalAnswerList = await GetLowSODVisit(inDto); + var minSOD = decimalAnswerList.OrderBy(x => x.SOD).Select(x => x.SOD).FirstOrDefault(); + return value.NullChange0() - minSOD; + } + #endregion + + #region 与整个访视期间SOD最低点相比增加的百分比 + /// + /// 与整个访视期间SOD最低点相比增加的百分比 + /// + /// + /// + /// 要更新之前的 + /// + /// + public async Task GetLowPercent(ReadingCalculateDto inDto) + { + var thisSOD = await GetSODData(inDto); + if (thisSOD == null || inDto.IsBaseLine) + { + return null; + } + var decimalAnswerList = await GetLowSODVisit(inDto); + var minSOD = decimalAnswerList.OrderBy(x => x.SOD).Select(x => x.SOD).FirstOrDefault(); + + if (minSOD == 0) + { + return 100; + } + else + { + return decimal.Round((thisSOD.NullChange0() - minSOD) * 100 / minSOD, 2); + } + + + } + #endregion + + #region 整个访视期间SOD最低点访视名称 + /// + /// 整个访视期间SOD最低点访视名称 + /// + /// + /// + /// 要更新之前的 + /// + /// + public async Task GetLowVisit(ReadingCalculateDto inDto) + { + if (inDto.IsBaseLine) + { + return nameof(YesOrNoOrNa.NA); + } + + var decimalAnswerList = await GetLowSODVisit(inDto); + return decimalAnswerList.OrderBy(x => x.SOD).Select(x => x.BlindName).FirstOrDefault() ?? string.Empty; + } + #endregion + + #region 是否存在非淋巴结靶病灶 + /// + /// 是否存在非淋巴结靶病灶 + /// + /// + /// + public async Task GetIsLymphTarget(ReadingCalculateDto inDto) + { + var result = IsLymph.No.GetEnumInt(); + var tableQuestion = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); + + foreach (var item in tableQuestion) + { + if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(IsLymph.Yes))) + { + result = IsLymph.Yes.GetEnumInt(); + } + } + + + + return result; + } + #endregion + + #region 是否存在淋巴结靶病灶且该病灶比上一访视短径增加5MM以上 + /// + /// 是否存在淋巴结靶病灶且该病灶比上一访视短径增加5MM以上 + /// + /// + /// + public async Task GetIsAddFive(ReadingCalculateDto inDto) + { + if (inDto.IsBaseLine) + { + return YesOrNoOrNa.NA.GetEnumInt(); + } + + var LastVisitTaskId = await this.GetLastVisitTaskId(inDto); + + var questionIds = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).Select(x => x.QuestionId).ToList(); + var lastQuestionAsnwer = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == LastVisitTaskId && questionIds.Contains(x.QuestionId)).Include(x => x.ReadingQuestionTrial).Include(x => x.ReadingTableQuestionTrial).ToListAsync(); + var rowIndexs = lastQuestionAsnwer.Where(x => x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(YesOrNoOrNa.Yes)).Select(x => x.RowIndex).Distinct().OrderBy(x => x).ToList(); + var thisQuestionAsnwer = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); + + var isExists = false; + foreach (var item in rowIndexs) + { + var lastValue = lastQuestionAsnwer.Where(x => x.RowIndex == item && x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0(); + + var thisRowData = thisQuestionAsnwer.Where(x => x.RowIndex == item).SelectMany(x => x.TableQuestionList).ToList(); + var thisValue = thisRowData.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0(); + + if (thisValue - lastValue > 5) + { + isExists = true; + } + } + + return isExists ? YesOrNoOrNa.Yes.GetEnumInt() : YesOrNoOrNa.No.GetEnumInt(); + + } + #endregion + + #region 被评估为NE的单个靶病灶 + /// + /// 被评估为NE的单个靶病灶 + /// + /// + /// + public async Task GetNETarget(ReadingCalculateDto inDto) + { + if (inDto.IsBaseLine) + { + return ExistOrNA.NA.GetEnumInt(); + } + + var result = inDto.QuestionInfo.Any(x => x.QuestionType == QuestionType.TargetLesion && x.Answer.EqEnum(TargetAssessment.NE)); + + return result ? ExistOrNA.Exist.GetEnumInt() : ExistOrNA.NotExist.GetEnumInt(); + } + #endregion + + #region 整体肿瘤评估 + + /// + /// 整体肿瘤评估 + /// + /// + /// + public async Task GetTumor(ReadingCalculateDto inDto) + { + + if (inDto.IsBaseLine) + { + return OverallAssessment.NA.GetEnumInt(); + } + + var targetLesion = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.TargetLesion).Select(x => x.Answer).FirstOrDefault(); + var noTargetLesion = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.NoTargetLesion).Select(x => x.Answer).FirstOrDefault(); + var newLesions = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.NewLesions).Select(x => x.Answer).FirstOrDefault(); + var result = await _tumorAssessmentRepository.Where(x => + x.TargetLesion == (TargetAssessment)int.Parse(targetLesion.IsNullOrEmpty() ? TargetAssessment.NA.GetEnumInt() : targetLesion) && + x.NonTargetLesions == (NoTargetAssessment)int.Parse(noTargetLesion.IsNullOrEmpty() ? NoTargetAssessment.NA.GetEnumInt() : noTargetLesion) && + x.NewLesion == (NewLesionAssessment)int.Parse(newLesions.IsNullOrEmpty() ? NewLesionAssessment.NA.GetEnumInt() : newLesions)).Select(x => x.OverallEfficacy).ToListAsync(); + + return result.Count == 0 ? OverallAssessment.NE.GetEnumInt() : result[0].GetEnumInt(); + } + #endregion + + #region 是否存在疾病 + /// + /// 是否存在疾病 + /// + /// + /// + public async Task GetIsExistDisease(ReadingCalculateDto inDto) + { + if (!inDto.IsBaseLine) + { + return string.Empty; + } + + var lesionCount = inDto.QuestionInfo.SelectMany(x => x.TableRowInfoList).Count(); + + return lesionCount > 0 ? ExistDisease.Yes.GetEnumInt() : ExistDisease.No.GetEnumInt(); + } + #endregion + + + #region 修改其他标准 + + #region 修改与整个访视期间SOD最低点相比增加的值(mm) + + /// + /// 修改与整个访视期间SOD最低点相比增加的值(mm) + /// + /// + /// + public async Task ChangeAllLowestIncrease(ChangeAllTaskDto inDto) + { + var visitTaskList = await GetVisitTaskAnswerList(inDto.calculateDto); + + var lowSod = (await GetLowSODVisit(inDto.calculateDto)).Select(x => x.SOD).OrderBy(x => x).FirstOrDefault(); + + foreach (var item in visitTaskList.Where(x => x.VisitTaskId != inDto.calculateDto.BaseLineTaskId)) + { + await _readingTaskQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => x.VisitTaskId == item.VisitTaskId && x.ReadingQuestionTrialId == inDto.QuestionId, x => new ReadingTaskQuestionAnswer() + { + Answer = (item.SOD - lowSod).ToString() + }); + } + } + + #endregion + + + #region 修改整个访视期间SOD最低点相比增加的百分比 + + /// + /// 修改整个访视期间SOD最低点相比增加的百分比 + /// + /// + /// + public async Task ChangeAllLowPercent(ChangeAllTaskDto inDto) + { + var visitTaskList = await GetVisitTaskAnswerList(inDto.calculateDto); + + var lowSod = (await GetLowSODVisit(inDto.calculateDto)).Select(x => x.SOD).OrderBy(x => x).FirstOrDefault(); + + foreach (var item in visitTaskList.Where(x => x.VisitTaskId != inDto.calculateDto.BaseLineTaskId)) + { + decimal percent = 0; + if (lowSod == 0) + { + percent = 100; + } + else + { + percent = decimal.Round((item.SOD - lowSod) * 100 / lowSod, 2); + } + + await _readingTaskQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => x.VisitTaskId == item.VisitTaskId && x.ReadingQuestionTrialId == inDto.QuestionId, x => new ReadingTaskQuestionAnswer() + { + Answer = percent.ToString() + }); + } + } + + #endregion + + #region 修改最低方式点名称 + /// + /// 修改最低方式点名称 + /// + /// + /// + public async Task ChangeAllLowVisitName(ChangeAllTaskDto inDto) + { + // 找到所有访视任务的Id + + var visitTaskIds = await _visitTaskRepository.Where(x => !x.IsAnalysisCreate && x.ReadingCategory == ReadingCategory.Visit && + x.TaskState == TaskState.Effect && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.DoctorUserId == inDto.calculateDto.DoctorUserId).Select(x => x.Id).ToListAsync(); + + var answer = (await GetLowSODVisit(inDto.calculateDto)).OrderBy(x => x.SOD).Select(x => x.BlindName).FirstOrDefault(); + visitTaskIds = visitTaskIds.Where(x => x != inDto.calculateDto.BaseLineTaskId).ToList(); + await this.ChangeAllVisitTaskAnswer(visitTaskIds, inDto.QuestionId, answer); + + } + #endregion + + + #endregion + + #region 通用方法 + + #region 修改所有访视任务的答案 + /// + /// 修改所有访视任务的答案 + /// + /// + /// + /// + /// + private async Task ChangeAllVisitTaskAnswer(List visitTaskGuids, Guid questionId, string answer) + { + await _readingTaskQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => visitTaskGuids.Contains(x.VisitTaskId) && x.ReadingQuestionTrialId == questionId, x => new ReadingTaskQuestionAnswer() + { + Answer = answer + }); + } + #endregion + + + #region 获取基线SOD + /// + /// 获取基线SOD + /// + /// + /// + private async Task GetBaseLineSOD(ReadingCalculateDto inDto) + { + if (await _visitTaskRepository.AnyAsync(x => x.Id == inDto.VisitTaskId && x.SourceSubjectVisit.IsBaseLine && !x.IsAnalysisCreate && x.DoctorUserId == inDto.DoctorUserId)) + { + return 0; + } + + // 先找到基线的任务 + var baseLineTaskId = await _visitTaskRepository.Where(x => x.SubjectId == inDto.SubjectId && x.ReadingCategory == ReadingCategory.Visit + && x.SourceSubjectVisit.IsBaseLine && x.TaskState == TaskState.Effect && !x.IsAnalysisCreate && x.DoctorUserId == inDto.DoctorUserId) + .Select(x => x.Id).FirstOrDefaultAsync(); + + + var baseLineSOD = (await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == baseLineTaskId && x.ReadingQuestionTrial.QuestionType == QuestionType.SOD).Select(x => x.Answer).FirstOrDefaultAsync()).IsNullOrEmptyReturn0(); + return baseLineSOD; + } + #endregion + + + /// + /// 获取最低方式 + /// + /// + /// + public async Task> GetLowSODVisit(ReadingCalculateDto inDto) + { + var taskAnswerList = await GetVisitTaskAnswerList(inDto); + + taskAnswerList = taskAnswerList.Where(x => x.VisitTaskId != inDto.VisitTaskId).ToList(); + + var taskIds = taskAnswerList.Select(x => x.VisitTaskId).ToList(); + + var unableEvaluateTaskIds = await _readingTableQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId) && + x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State + && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion + && x.Answer == TargetState.UnableEvaluate.GetEnumInt() + ) + .Select(x => x.VisitTaskId).Distinct().ToListAsync(); + + taskAnswerList = taskAnswerList.Where(x => !unableEvaluateTaskIds.Contains(x.VisitTaskId)).ToList(); + return taskAnswerList.OrderBy(x => x.SOD).ToList(); + } + + #region 获取访视任务信息 + /// + /// 获取访视任务信息 + /// + /// + /// + public async Task> GetVisitTaskAnswerList(ReadingCalculateDto inDto) + { + if (visitTaskAnswerList == null) + { + // 查询的时候要把自己排除 因为查询出来的可能不是计算出的最新的 + visitTaskAnswerList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId != inDto.VisitTaskId && x.VisitTask.ReadingCategory == ReadingCategory.Visit + && x.SubjectId == inDto.SubjectId && x.VisitTask.ReadingTaskState == ReadingTaskState.HaveSigned && x.VisitTask.ArmEnum == inDto.ArmEnum && x.VisitTask.TaskState == TaskState.Effect && x.ReadingQuestionTrial.QuestionType == QuestionType.SOD) + .Select(x => new VisitTaskAnswerInfo + { + VisitTaskId = x.VisitTaskId, + QuestionId = x.ReadingQuestionTrialId, + VisitName = x.VisitTask.SourceSubjectVisit.VisitName, + BlindName = x.VisitTask.SourceSubjectVisit.BlindName, + + SOD = x.Answer.IsNullOrEmptyReturn0(), + }).ToListAsync(); + + // 这里是需要加上自己的 基线不用管 + if (visitTaskAnswerList.Count > 0) + { + visitTaskAnswerList.Add(new VisitTaskAnswerInfo() + { + VisitTaskId = inDto.VisitTaskId, + QuestionId = visitTaskAnswerList[0].QuestionId, + VisitName = inDto.VisitName, + SOD = (await GetSODData(inDto)).ToString().IsNullOrEmptyReturn0(), + }); + } + + + } + + return visitTaskAnswerList; + } + #endregion + + /// + /// 获取上一个访视任务Id + /// + /// + private async Task GetLastVisitTaskId(ReadingCalculateDto inDto) + { + // 拿到这一个访视 + var thisNum = await _subjectVisitRepository.Where(x => x.Id == inDto.SubjectVisitId).Select(x => x.VisitNum).FirstOrDefaultAsync(); + + // 先找到上一个访视 + var lastVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == inDto.SubjectId && !x.IsLostVisit && x.VisitNum < thisNum).OrderByDescending(x => x.VisitNum).Select(x => x.Id).FirstOrDefaultAsync(); + + // 找到访视任务Id + + var LastVisitTaskId = await _visitTaskRepository.Where(x => x.ReadingCategory == ReadingCategory.Visit && x.TaskState == TaskState.Effect && !x.IsAnalysisCreate && x.SourceSubjectVisitId == lastVisitId && x.DoctorUserId == inDto.DoctorUserId).Select(x => x.Id).FirstOrDefaultAsync(); + + return LastVisitTaskId; + } + #endregion + + #region 计算阅片问题 外层问题 + + #region 获取靶病灶评估 + /// + /// 获取靶病灶评估 + /// + /// + /// + public async Task GetTargetLesionEvaluate(ReadingCalculateDto inDto) + { + var tableQuestion = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.TargetLesion).SelectMany(x => x.TableRowInfoList).ToList(); + if (inDto.IsBaseLine) + { + return TargetAssessment.NA.GetEnumInt(); + } + if (tableQuestion.Count() == 0) + { + return string.Empty; + } + TargetLesionCalculateDto resultData = new TargetLesionCalculateDto() + { + //非淋巴结靶病灶长径之和 decimal + SumOfDiameter = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.SumOfDiameter).Sum(x => x.Answer.IsNullOrEmptyReturn0()), + + //所有淋巴结靶病灶的短径小于10mm bool + DiameterLessThan10 = true, + + // SOD变化百分比 + SODPercent = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.SODPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()), + + // SOD 百分比与基线期SOD相比减小≥30% bool + SODPercentBigger30 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.SODPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()) >= 30, + + // SOD 百分比 与基线期SOD相比减小<30% bool + SODPercentLess30 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.SODPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()) < 30, + + // SOD 百分比 整体访视期间SOD最低点SOD相比增加<20% + LowPercentLess20 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.LowPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()) < 20, + + // SOD 百分比 比整体访视期间SOD最低点SOD增加≥20% + LowPercentBigger20 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.LowPercent).Sum(x => x.Answer.IsNullOrEmptyReturn0()) >= 20, + + // SOD 变化值 比整体访视期间SOD最低点SOD绝对增加值<5 mm + LowChangeLess5 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.LowestIncrease).Sum(x => x.Answer.IsNullOrEmptyReturn0()) < 5, + + // 比整体访视期间SOD最低点SOD绝对增加值≥5 mm + LowChangeBigger5 = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.LowestIncrease).Sum(x => x.Answer.IsNullOrEmptyReturn0()) >= 5, + + // 被评估为NE的单个靶病灶 是否存在状态为不可评估的靶病灶 + ExixtsNETargetLesion = tableQuestion.SelectMany(x => x.TableQuestionList).Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(TargetState.UnableEvaluate)), + + //// 上次访视点整体肿瘤评估 + LastTargetLesionEvaluate = string.Empty, + + // 当前访视点非淋巴结病灶长径>0 + CurrentMajoreBigger0 = true, + + // 至少一个淋巴结靶病灶短径≥10 mm + CurrenShortBigger10 = true, + + // 该淋巴结靶病灶短径绝对增加值≥5 mm + IsAddFive = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.IsAddFive && x.Answer.EqEnum(YesOrNoOrNa.Yes)).Count() > 0, + }; + + + + + foreach (var item in tableQuestion) + { + if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && x.Answer.EqEnum(YesOrNoOrNa.Yes))) + { + // 淋巴结的短径 + resultData.DiameterLessThan10 = (item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault()).IsNullOrEmptyReturn0() < 10; + + // 至少一个淋巴结靶病灶短径≥10 mm + resultData.CurrenShortBigger10 = (item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.ShortAxis).Select(x => x.Answer).FirstOrDefault()).IsNullOrEmptyReturn0() >= 10; + } + + if (item.TableQuestionList.Any(x => x.QuestionMark == QuestionMark.IsLymph && !x.Answer.EqEnum(YesOrNoOrNa.Yes))) + { + // 当前访视点非淋巴结病灶 + resultData.CurrentMajoreBigger0 = (item.TableQuestionList.Where(x => x.QuestionMark == QuestionMark.MajorAxis).Select(x => x.Answer).FirstOrDefault()).IsNullOrEmptyReturn0() > 0; + } + } + + + var lastVisitTaskId = await GetLastVisitTaskId(inDto); + var questionId = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.Tumor).Select(x => x.QuestionId).FirstOrDefault(); + resultData.LastTargetLesionEvaluate = (await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == lastVisitTaskId && x.ReadingQuestionTrialId == questionId) + .Select(x => x.Answer).FirstOrDefaultAsync()) ?? string.Empty; + + + + + + TargetAssessment result = TargetAssessment.NA; + if (resultData.SumOfDiameter == 0 && resultData.DiameterLessThan10 && !resultData.ExixtsNETargetLesion) + { + result = TargetAssessment.CR; + } + else if ( + (resultData.SODPercentBigger30 && resultData.LowPercentLess20 && !resultData.ExixtsNETargetLesion) + || + (resultData.SODPercentBigger30 && resultData.LowChangeLess5 && !resultData.ExixtsNETargetLesion) + ) + { + result = TargetAssessment.PR; + } + else if ( + (resultData.SODPercentLess30 && resultData.LowPercentLess20 && !resultData.ExixtsNETargetLesion) + || + (resultData.SODPercentLess30 && resultData.LowChangeLess5 && !resultData.ExixtsNETargetLesion) + ) + { + result = TargetAssessment.SD; + } + else if (resultData.LowPercentBigger20 && resultData.LowChangeBigger5) + { + result = TargetAssessment.PD; + } + else if ( + (resultData.LowPercentLess20 && resultData.ExixtsNETargetLesion) + || + (resultData.LowPercentBigger20 && resultData.LowChangeLess5 && resultData.ExixtsNETargetLesion) + ) + { + result = TargetAssessment.NE; + } + + else if (!resultData.ExixtsNETargetLesion && resultData.SumOfDiameter == 0 && resultData.SODPercent == 0) + { + result = TargetAssessment.ND; + } + + else if ( + (resultData.LastTargetLesionEvaluate.EqEnum(TargetAssessment.CR) && resultData.CurrenShortBigger10 && resultData.IsAddFive) + || + (resultData.LastTargetLesionEvaluate.EqEnum(TargetAssessment.CR) && resultData.CurrentMajoreBigger0) + ) + { + result = TargetAssessment.PD; + } + + + return result.GetEnumInt(); + } + #endregion + + #region 获取非靶病灶评估 + + /// + /// 获取非靶病灶评估 + /// + /// + /// + public async Task GetNoTargetLesionEvaluate(ReadingCalculateDto inDto) + { + + NoTargetAssessment result = NoTargetAssessment.NA; + + if (inDto.IsBaseLine) + { + return result.GetEnumInt(); + } + + var tableRows = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.NonTargetLesions).SelectMany(x => x.TableRowInfoList).ToList(); + + var tableQuestions = tableRows.SelectMany(x => x.TableQuestionList).ToList(); + + //任意单个病灶 / 病灶组评估为“显著增大” + if (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NoTargetState.Increase))) + { + result = NoTargetAssessment.PD; + } + //所有单个病灶/病灶组状态评估状态为“消失” + else if (!tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NoTargetState.Loss))) + { + result = NoTargetAssessment.PD; + } + // 任意单个病灶/病灶组评估为“无法评估”并且没有“显著增大” + else if (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NoTargetState.Increase)) && + !tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && !x.Answer.EqEnum(NoTargetState.Increase)) + ) + { + result = NoTargetAssessment.NE; + } + // 基线时没有非靶病灶 + else if (tableQuestions.Count() == 0) + { + result = NoTargetAssessment.ND; + } + + // 所有单个病灶/病灶组评估为”存在”或者有些评估为“消失”有些评估为“存在”,且没有“显著增大”和“无法评估”的病灶 + + else if (!tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && !x.Answer.EqEnum(NoTargetState.Exist)) + || (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NoTargetState.Exist) || x.Answer.EqEnum(NoTargetState.Loss)) && !tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && (x.Answer != "显著增大" || x.Answer != "无法评估"))) + + ) + { + result = NoTargetAssessment.NN; + } + else + { + return string.Empty; + } + + return result.GetEnumInt(); + + } + + #endregion + + #region 获取新病灶评估 + /// + /// 获取新病灶评估 + /// + /// + /// + public async Task GetNewLesionEvaluate(ReadingCalculateDto inDto) + { + + NewLesionAssessment result = NewLesionAssessment.NA; + if (inDto.IsBaseLine) + { + return result.GetEnumInt(); + } + + var tableRows = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.NewLesions).SelectMany(x => x.TableRowInfoList).ToList(); + + var tableQuestions = tableRows.SelectMany(x => x.TableQuestionList).ToList(); + + + + // 当前访视存在至少一个明确新病灶 + if (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NewLesionState.Exist))) + { + result = NewLesionAssessment.Yes; + } + //当前访视不存在明确新病灶且存在至少一个疑似新病灶 + else if (!tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && !x.Answer.EqEnum(NewLesionState.Exist)) || + tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NewLesionState.Suspected)) + ) + { + result = NewLesionAssessment.Suspected; + } + + //只要有任何一个新病灶状态为“无法评估” + else if (tableQuestions.Any(x => x.QuestionMark == QuestionMark.State && x.Answer.EqEnum(NewLesionState.UnableEvaluate))) + { + result = NewLesionAssessment.NE; + } + else + { + result = NewLesionAssessment.No; + } + return result.GetEnumInt(); + + } + #endregion + + #endregion + + } + +} diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/ReadingCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/ReadingCalculateService.cs new file mode 100644 index 000000000..4fb76c6dd --- /dev/null +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/ReadingCalculateService.cs @@ -0,0 +1,144 @@ +using IRaCIS.Core.Application.Interfaces; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Infrastructure; +using Microsoft.AspNetCore.Mvc; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Core.Application.ViewModel; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.Service.ReadingCalculate +{ + [ApiExplorerSettings(GroupName = "Image")] + public class ReadingCalculateService: BaseService, IReadingCalculateService + { + + /// + /// 标准和服务对应 + /// + Dictionary CalculateServiceDic = new Dictionary() + { + {CriterionType.RECIST1Pointt1,typeof(RECIST1Point1CalculateService) } //RECIST1.1 + }; + + private readonly IEnumerable CriterionServices; + + private readonly IEnumerable _criterionServices; + private readonly IRepository _visitTaskRepository; + private readonly IRepository _readingQuestionCriterionTrialRepository; + private ICriterionCalculateService _useCriterion; + + + public ReadingCalculateService(IEnumerable criterionServices, + IRepository visitTaskRepository, + IRepository readingQuestionCriterionTrialRepository + + ) + { + + _criterionServices = criterionServices; + this._visitTaskRepository = visitTaskRepository; + this._readingQuestionCriterionTrialRepository = readingQuestionCriterionTrialRepository; + } + + /// + /// 获取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($"当前标准计算未开发好"); + } + + try + { + CriterionType thisCriterionType = criterionType.Value; + Type thisServiceType = CalculateServiceDic[thisCriterionType]; + _useCriterion = CriterionServices.FirstOrDefault(x => x.GetType().Name == nameof(thisServiceType) + "Proxy"); + + if (criterionType == null) + { + throw new BusinessValidationFailedException($"当前标准计算未开发好"); + } + + } + catch (Exception) + { + + throw new BusinessValidationFailedException($"当前标准计算未开发好"); + } + + return _useCriterion; + + + } + else + { + return _useCriterion; + } + } + /// + /// 自动计算 并修改值 + /// + /// + /// + public async Task CalculateTask(CalculateTaskInDto inDto) + { + var service = await this.GetService(inDto.VisitTaskId); + await service.CalculateTask(inDto); + } + + /// + /// 验证访视提交 + /// + /// + /// + public async Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto) + { + var service = await this.GetService(inDto.VisitTaskId); + await service.VerifyVisitTaskQuestions(inDto); + } + + /// + /// 将上一次的访视病灶添加到这一次 + /// + /// + /// + public async Task AddTaskLesionAnswerFromLastTask(AddTaskLesionAnswerFromLastTaskInDto inDto) + { + var service = await this.GetService(inDto.VisitTaskId); + return await service.AddTaskLesionAnswerFromLastTask(inDto); + } + + /// + /// 获取报告验证的信息(这里每个标准可能不一样 返回用object) + /// + /// + /// + public async Task GetReportVerify(GetReportVerifyInDto inDto) + { + var service = await this.GetService(inDto.VisitTaskId); + return await service.GetReportVerify(inDto); + } + } + + + +}