irc-netcore-api/IRaCIS.Core.Application/Service/ReadingCalculate/PCWG3CalculateService.cs

1274 lines
56 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using IRaCIS.Core.Application.Service.Reading.Dto;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore.Common;
using IRaCIS.Core.Infrastructure;
using MassTransit;
using Microsoft.AspNetCore.Mvc;
namespace IRaCIS.Core.Application.Service.ReadingCalculate
{
[ApiExplorerSettings(GroupName = "Reading")]
public class PCWG3CalculateService(IRepository<ReadingTableQuestionAnswer> _readingTableQuestionAnswerRepository,
IRepository<VisitTask> _visitTaskRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository,
IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
IRepository<ReadingQuestionTrial> _readingQuestionTrialRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<OrganInfo> _organInfoRepository,
IRepository<DicomStudy> _dicomStudyRepository,
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
IRepository<TumorAssessment_RECIST1Point1> _tumorAssessmentRepository,
IGeneralCalculateService _generalCalculateService,
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService
{
private List<SiteVisitForTumor> siteVisitForTumorList;
/// <summary>
/// 阅片导入
/// </summary>
/// <returns></returns>
public async Task ReadingImport()
{
}
/// <summary>
/// 获取阅片的计算数据
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<object> GetReadingCalculationData(GetReadingCalculationDataInDto inDto)
{
return new
{
};
}
#region 删除病灶获取起始病灶序号
/// <summary>
/// 删除病灶获取起始病灶序号
/// </summary>
/// <returns></returns>
public async Task<int> GetDeleteLesionStatrIndex(DeleteReadingRowAnswerInDto inDto)
{
var rowInfo = await _readingTableAnswerRowInfoRepository.Where(x => x.Id == inDto.RowId).Include(x => x.ReadingQuestionTrial).FirstNotNullAsync();
if (rowInfo.ReadingQuestionTrial.LesionType == LesionType.NewLesions)
{
var minIndex = await _readingTableAnswerRowInfoRepository.Where(x => x.QuestionId == rowInfo.QuestionId && x.VisitTaskId == inDto.VisitTaskId).OrderBy(x => x.RowIndex).Select(x => x.RowIndex).FirstOrDefaultAsync();
return (int)minIndex;
}
else
{
return 1;
}
}
#endregion
#region 获取阅片报告
/// <summary>
/// 获取阅片报告
/// </summary>
/// <param name="indto"></param>
/// <returns></returns>
[HttpPost]
public async Task<GetReadingReportEvaluationOutDto> GetReadingReportEvaluation(GetReadingReportEvaluationInDto indto)
{
GetReadingReportEvaluationOutDto result = new GetReadingReportEvaluationOutDto();
result.CalculateResult = await this.GetReportVerify(new GetReportVerifyInDto()
{
VisitTaskId = indto.VisitTaskId
});
var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == indto.VisitTaskId).FirstNotNullAsync();
result.ReadingTaskState = visitTaskInfo.ReadingTaskState;
var taskInfoList = await _generalCalculateService.GetReadingReportTaskList(indto.VisitTaskId);
taskInfoList = taskInfoList.Where(x => x.VisitTaskNum <= visitTaskInfo.VisitTaskNum).ToList();
result.VisitTaskList = taskInfoList;
var visitTaskIds = taskInfoList.Select(x => x.VisitTaskId).ToList();
var criterionId = visitTaskInfo.TrialReadingCriterionId;
var questionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == criterionId && x.ShowQuestion != ShowQuestion.Hide)
//.Where(x => x.LesionType != LesionType.BaselineLesions)
.Where(x => x.QuestionType != QuestionType.TherapeuticEffectEvaluationGroup)
.ToListAsync();
// 新病灶
var questionNewLesions = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == visitTaskInfo.TrialReadingCriterionId && x.LesionType == LesionType.NewLesions).FirstNotNullAsync();
var tableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == criterionId).OrderBy(x => x.ShowOrder).ToListAsync();
var tableAnsweRowInfos = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == indto.VisitTaskId).ProjectTo<TableAnsweRowInfo>(_mapper.ConfigurationProvider).ToListAsync();
var answers = await _readingTaskQuestionAnswerRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId))
.Where(x => x.ReadingQuestionTrialId != questionNewLesions.Id || x.VisitTaskId == visitTaskInfo.Id)
.ToListAsync();
if (visitTaskInfo.ReadingTaskState != ReadingTaskState.HaveSigned)
{
foreach (var item in answers)
{
item.Answer = item.PCWGInterimAnswer == null ? item.Answer : item.PCWGInterimAnswer;
}
}
var tableAnswers = await _readingTableQuestionAnswerRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId))
.Where(x => x.QuestionId != questionNewLesions.Id || x.VisitTaskId == visitTaskInfo.Id)
.ToListAsync();
var alltableAnsweRowInfos = await _readingTableAnswerRowInfoRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId)).ToListAsync();
var organIds = alltableAnsweRowInfos.Where(x => x.OrganInfoId != null).Select(x => x.OrganInfoId).Distinct().ToList();
var organInfos = await _organInfoRepository.Where(x => organIds.Contains(x.Id)).ToListAsync();
var needChangeType = new List<QuestionMark?>() {
QuestionMark.Organ,
QuestionMark.Location,
QuestionMark.Part,
};
// 第一级 分组
#region 构造问题
List<ReadingReportDto> questions = questionList.Where(x => x.Type == ReadingQestionType.Group).OrderBy(x => x.ShowOrder).Select(x => new ReadingReportDto()
{
QuestionId = x.Id,
GroupName = x.GroupName,
GroupEnName = x.GroupEnName,
IsShowInDicom = x.IsShowInDicom,
Type = x.Type,
GroupId = x.GroupId,
QuestionType = x.QuestionType,
LesionType = x.LesionType,
QuestionGenre = x.QuestionGenre,
DataSource = x.DataSource,
DictionaryCode = x.DictionaryCode,
TypeValue = x.TypeValue,
QuestionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us),
ShowOrder = x.ShowOrder,
ValueType = x.ValueType,
CustomUnit = x.CustomUnit,
Unit = x.Unit,
ReportLayType = ReportLayType.Group,
HighlightAnswer = x.HighlightAnswer,
HighlightAnswerList = x.HighlightAnswerList,
}).ToList();
// 分组
foreach (var item in questions)
{
// 问题
item.Childrens = questionList.Where(x => x.GroupId == item.QuestionId).OrderBy(x => x.ShowOrder).Select(x => new ReadingReportDto()
{
GroupName = x.GroupName,
GroupEnName = x.GroupEnName,
QuestionId = x.Id,
IsShowInDicom = x.IsShowInDicom,
QuestionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us),
LesionType = x.LesionType,
QuestionGenre = x.QuestionGenre,
DataSource = x.DataSource,
DictionaryCode = x.DictionaryCode,
Type = x.Type,
QuestionType = x.QuestionType,
TypeValue = x.TypeValue,
ShowOrder = x.ShowOrder,
OrderMark = x.OrderMark,
ValueType = x.ValueType,
Unit = x.Unit,
CustomUnit = x.CustomUnit,
ReportLayType = ReportLayType.Question,
HighlightAnswer = x.HighlightAnswer,
HighlightAnswerList = x.HighlightAnswerList,
}).ToList();
// 问题
foreach (var question in item.Childrens)
{
foreach (var task in taskInfoList)
{
var answer = answers.Where(x => x.VisitTaskId == task.VisitTaskId && x.ReadingQuestionTrialId == question.QuestionId).FirstOrDefault();
question.Answer.Add(new TaskQuestionAnswer()
{
Answer = answer == null ? string.Empty : answer.Answer,
IsGlobalChange = answer == null ? false : answer.IsGlobalChange,
GlobalChangeAnswer = answer == null ? string.Empty : answer.GlobalChangeAnswer,
TaskName = task.TaskName,
VisitTaskId = task.VisitTaskId,
});
}
// 构造表格行数据
var rowlist = tableAnsweRowInfos.Where(x => x.QuestionId == question.QuestionId).OrderBy(x => x.RowIndex).ToList();
question.Childrens = rowlist.OrderBy(x => x.RowIndex).Select(x => new ReadingReportDto()
{
QuestionName = question.OrderMark + x.RowIndex.GetLesionMark(),
SplitOrMergeLesionName = x.MergeName.IsNullOrEmpty() ? x.SplitName : x.MergeName,
SplitOrMergeType = x.SplitOrMergeType,
LesionType = question.LesionType,
IsCanEditPosition = x.IsCanEditPosition,
RowIndex = x.RowIndex,
BlindName = x.BlindName,
RowId = x.Id,
ReportLayType = ReportLayType.Lesions,
FristAddTaskNum = x.FristAddTaskNum,
}).ToList();
foreach (var row in question.Childrens)
{
// tableQuestion
row.Childrens = tableQuestionList.Where(x => x.ReadingQuestionId == question.QuestionId).Select(x => new ReadingReportDto()
{
QuestionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us),
QuestionId = x.ReadingQuestionId,
TableQuestionId = x.Id,
Type = x.Type,
LesionType = question.LesionType,
TableQuestionType = x.TableQuestionType,
DataSource = x.DataSource,
DictionaryCode = x.DictionaryCode,
QuestionMark = x.QuestionMark,
TypeValue = x.TypeValue,
RowIndex = row.RowIndex,
ShowOrder = x.ShowOrder,
ValueType = x.ValueType,
RowId = row.RowId,
Unit = x.Unit,
ReportLayType = ReportLayType.TableQuestion,
FristAddTaskNum = row.FristAddTaskNum,
}).ToList();
foreach (var tableQuestion in row.Childrens)
{
foreach (var task in taskInfoList)
{
var rowinfo = alltableAnsweRowInfos.Where(x => x.VisitTaskId == task.VisitTaskId && x.QuestionId == tableQuestion.QuestionId && x.RowIndex == tableQuestion.RowIndex).FirstOrDefault();
var taskQuestionAnswer = new TaskQuestionAnswer()
{
Answer = tableAnswers.Where(x => x.VisitTaskId == task.VisitTaskId && x.QuestionId == tableQuestion.QuestionId && x.RowIndex == tableQuestion.RowIndex && x.TableQuestionId == tableQuestion.TableQuestionId).Select(x => x.Answer).FirstIsNullReturnEmpty(),
TaskName = task.TaskName,
VisitTaskId = task.VisitTaskId,
};
if (rowinfo != null && rowinfo.OrganInfoId != null)
{
var organInfo = organInfos.Where(x => x.Id == rowinfo.OrganInfoId).FirstOrDefault();
if (organInfo != null && needChangeType.Contains(tableQuestion.QuestionMark))
{
if (_userInfo.IsEn_Us)
{
switch (tableQuestion.QuestionMark)
{
case QuestionMark.Organ:
taskQuestionAnswer.Answer = organInfo.TULOCEN;
break;
case QuestionMark.Location:
if (organInfo.IsCanEditPosition)
{
}
else
{
taskQuestionAnswer.Answer = organInfo.TULATEN;
}
break;
case QuestionMark.Part:
taskQuestionAnswer.Answer = organInfo.PartEN;
break;
}
}
else
{
switch (tableQuestion.QuestionMark)
{
case QuestionMark.Organ:
taskQuestionAnswer.Answer = organInfo.TULOC;
break;
case QuestionMark.Location:
if (organInfo.IsCanEditPosition)
{
}
else
{
taskQuestionAnswer.Answer = organInfo.TULAT;
}
break;
case QuestionMark.Part:
taskQuestionAnswer.Answer = organInfo.Part;
break;
}
}
}
}
tableQuestion.Answer.Add(taskQuestionAnswer);
}
}
}
};
}
#endregion
result.TaskQuestions = questions;
return result;
}
#endregion
/// <summary>
/// 将上一次的病灶信息添加到这一次
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<AddTaskLesionAnswerFromLastTaskOutDto> 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.TrialReadingCriterionId == taskinfo.TrialReadingCriterionId &&
x.IsAnalysisCreate == taskinfo.IsAnalysisCreate &&
x.DoctorUserId == taskinfo.DoctorUserId &&
x.IsSelfAnalysis == taskinfo.IsSelfAnalysis &&
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<CopyTableAnswerRowInfo>(_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;
x.PicturePath = 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<QuestionMark?> notNeedCopyMarks = new List<QuestionMark?>()
{
QuestionMark.State,
QuestionMark.LesionNumber,
};
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,
}).ToList();
try
{
// 新病灶外层问题
var newLesionQuestion = await _readingQuestionTrialRepository.Where(x => x.LesionType == LesionType.NewLesions && x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).FirstNotNullAsync();
// 既往病灶外层问题
var alwaysNewLesionsQuestion = await _readingQuestionTrialRepository.Where(x => x.LesionType == LesionType.AlwaysNewLesions && x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).FirstNotNullAsync();
// 新病灶表格问题
var newLesionTableQuestions = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionId == newLesionQuestion.Id).ToListAsync();
// 既往病灶表格问题
var alwaysNewLesionsTableQuestions = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionId == alwaysNewLesionsQuestion.Id).ToListAsync();
Dictionary<Guid, Guid> alwaysTableQuestionIdDic = new Dictionary<Guid, Guid>();
newLesionTableQuestions.ForEach(x =>
{
alwaysTableQuestionIdDic.Add(
x.Id,
alwaysNewLesionsTableQuestions.Where(y => y.QuestionName == x.QuestionName).Select(y => y.Id).FirstOrDefault()
);
});
foreach (var item in tableRowAnswers.Where(x => x.QuestionId == newLesionQuestion.Id).OrderBy(x => x.RowIndex))
{
item.QuestionId = alwaysNewLesionsQuestion.Id;
foreach (var tableAnswer in tableAnswers.Where(y => y.RowId == item.Id))
{
tableAnswer.QuestionId = alwaysNewLesionsQuestion.Id;
tableAnswer.TableQuestionId = alwaysTableQuestionIdDic[tableAnswer.TableQuestionId];
}
}
}
catch (Exception)
{
throw new BusinessValidationFailedException(_localizer["ReadingCalculate_Abnormal"]);
}
var addList = _mapper.Map<List<ReadingTableAnswerRowInfo>>(tableRowAnswers);
await _readingTableAnswerRowInfoRepository.AddRangeAsync(addList);
await _readingTableQuestionAnswerRepository.AddRangeAsync(tableAnswers);
await _readingTableQuestionAnswerRepository.SaveChangesAsync();
}
}
return new AddTaskLesionAnswerFromLastTaskOutDto()
{
IsBaseLine = taskinfo.SourceSubjectVisitId == baseLineVisitId,
};
}
/// <summary>
/// 测试计算
/// </summary>
/// <param name="visitTaskId"></param>
/// <param name="type"></param>
/// <returns></returns>
[HttpPost]
public async Task TestCalculate(Guid visitTaskId, QuestionType type)
{
ReadingCalculateDto readingData = await _generalCalculateService.GetReadingCalculateDto(visitTaskId);
// 只获取当前的 不会获取上一次临时修改的结果
foreach (var item in readingData.QuestionInfo)
{
if (item.PCWGInterimAnswer != null)
{
item.Answer = item.PCWGInterimAnswer;
}
}
await ReadingCalculate(readingData, new List<QuestionType>() { type });
}
/// <summary>
/// 计算任务
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
[HttpPost]
public async Task CalculateTask(CalculateTaskInDto inDto)
{
ReadingCalculateDto readingData = await _generalCalculateService.GetReadingCalculateDto(inDto.VisitTaskId);
// 只获取当前的 不会获取上一次临时修改的结果
foreach (var item in readingData.QuestionInfo)
{
if (item.PCWGInterimAnswer != null)
{
item.Answer = item.PCWGInterimAnswer;
}
}
readingData.IsChangeOtherTask = inDto.IsChangeOtherTask;
await ReadingCalculate(readingData);
}
/// <summary>
/// 自动计算
/// </summary>
/// <param name="inDto"></param>
/// <param name="calculateType"></param>
/// <returns></returns>
public async Task ReadingCalculate(ReadingCalculateDto inDto, List<QuestionType>? calculateType = null)
{
#region 计算 这里顺序非常重要 后面计算的值要依赖前面计算的结果
var needAddList = new List<ReadingTaskQuestionAnswer>();
List<ReadingCalculateData> calculateList = new List<ReadingCalculateData>()
{
// 基线病灶计数
new ReadingCalculateData (){QuestionType=QuestionType.BaseLineLesionsCount,GetIntFun=GetBaseLineLesionsCount},
// 新病灶计数
new ReadingCalculateData (){QuestionType=QuestionType.NewLesionsCount,GetIntFun=GetNewLesionsCount},
// 既往新病灶
new ReadingCalculateData (){QuestionType=QuestionType.AlwaysNewLesionsCount,GetIntFun=GetAlwaysNewLesionsCount},
// 自治疗后第二个访视点以来持续的新骨病变数量
new ReadingCalculateData (){QuestionType=QuestionType.NewBoneLesionsCount,GetIntFun=GetNewBoneLesionCount},
// 间隔天数
new ReadingCalculateData (){QuestionType=QuestionType.DaysBetween,GetIntFun=GetNumberOfDaysBetween},
// 访视点肿瘤评估
new ReadingCalculateData (){QuestionType=QuestionType.SiteVisitForTumorEvaluation,GetStringFun=GetSiteVisitForTumorEvaluation},
};
if (calculateType != null)
{
calculateList = calculateList.Where(x => calculateType.Contains(x.QuestionType)).ToList();
}
foreach (var calculate in calculateList)
{
var item = inDto.QuestionInfo.FirstOrDefault(x => x.QuestionType == calculate.QuestionType);
if (item != null)
{
//计算答案
if (inDto.IsOnlyChangeAllTask == false)
{
#region 计算答案
switch (calculate.QuestionType)
{
case QuestionType.BaseLineLesionsCount:
item.Answer = (await calculate.GetIntFun(inDto)).ToString();
break;
case QuestionType.NewLesionsCount:
if (inDto.VisitTaskNum >= 1)
{
item.Answer = (await calculate.GetIntFun(inDto)).ToString();
}
else
{
item.Answer = nameof(YesOrNoOrNa.NA);
}
break;
case QuestionType.AlwaysNewLesionsCount:
if (inDto.VisitTaskNum > 1)
{
item.Answer = (await calculate.GetIntFun(inDto)).ToString();
}
else
{
item.Answer = nameof(YesOrNoOrNa.NA);
}
break;
case QuestionType.NewBoneLesionsCount:
item.Answer = (await calculate.GetIntFun(inDto)).ToString();
if (item.Answer == "-1")
{
item.Answer = nameof(YesOrNoOrNa.NA);
}
break;
case QuestionType.DaysBetween:
item.Answer = (await calculate.GetIntFun(inDto)).ToString();
break;
case QuestionType.SiteVisitForTumorEvaluation:
item.Answer = await calculate.GetStringFun(inDto);
break;
default:
item.Answer = string.Empty;
break;
}
#endregion
// 修改修约小数位数
try
{
List<ValueOfType?> valueOfTypes = new List<ValueOfType?>() {
ValueOfType.Decimals,
ValueOfType.Percentage
};
if (valueOfTypes.Contains(item.ValueType))
{
item.Answer = decimal.Round(decimal.Parse(item.Answer.IsNullOrEmpty() ? "0" : item.Answer), inDto.DigitPlaces).ToString("F" + inDto.DigitPlaces.ToString());
}
}
catch (Exception)
{
}
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
}
#region 基线病灶计数
/// <summary>
/// 基线病灶计数
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<int> GetBaseLineLesionsCount(ReadingCalculateDto inDto)
{
try
{
return (int)(inDto.QuestionInfo.Where(x => x.LesionType == LesionType.BaselineLesions).SelectMany(x => x.TableRowInfoList)
.Sum(x => x.TableQuestionList.Where(y => y.QuestionMark == QuestionMark.LesionNumber).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0()));
}
catch
{
return 0;
}
}
#endregion
#region 新病灶计数
/// <summary>
/// 获取新病灶计数
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<int> GetNewLesionsCount(ReadingCalculateDto inDto)
{
return inDto.QuestionInfo.Where(x => x.LesionType == LesionType.NewLesions).SelectMany(x => x.TableRowInfoList)
.Where(x => x.TableQuestionList.Any(y => y.QuestionMark == QuestionMark.State && y.Answer == EvaluationOfState.Exists.GetEnumInt()))
.Count();
}
#endregion
#region 既往新病灶计数
/// <summary>
/// 既往新病灶计数
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<int> GetAlwaysNewLesionsCount(ReadingCalculateDto inDto)
{
return inDto.QuestionInfo.Where(x => x.LesionType == LesionType.AlwaysNewLesions).SelectMany(x => x.TableRowInfoList)
.Where(x => x.TableQuestionList.Any(y => y.QuestionMark == QuestionMark.State && y.Answer == EvaluationOfState.Exists.GetEnumInt()))
.Count();
}
#endregion
#region 自治疗后第二个访视点以来持续的新骨病变数量
/// <summary>
/// 自治疗后第二个访视点以来持续的新骨病变数量
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<int> GetNewBoneLesionCount(ReadingCalculateDto inDto)
{
var taskList = await GetSiteVisitForTumorList(inDto);
var result = 0;
var findindex = taskList.OrderBy(x => x.VisitTaskNum).ToList().FindIndex(x => x.VisitTaskId == inDto.VisitTaskId);
if (findindex < 3)
{
return -1;
}
else
{
var twoindex = taskList.OrderBy(x => x.VisitTaskNum).ToList()[2];
result = inDto.QuestionInfo.Where(x => x.LesionType == LesionType.AlwaysNewLesions).SelectMany(x => x.TableRowInfoList)
.Where(x => x.FristAddTaskNum >= twoindex.VisitTaskNum && x.TableQuestionList.Any(y => y.QuestionMark == QuestionMark.State && y.Answer == EvaluationOfState.Exists.GetEnumInt())).Count();
//+ inDto.QuestionInfo.Where(x => x.LesionType == LesionType.NewLesions).SelectMany(x => x.TableRowInfoList)
// .Where(x => x.TableQuestionList.Any(y => y.QuestionMark == QuestionMark.State && y.Answer == EvaluationOfState.Exists.GetEnumInt()))
// .Count();
}
return result;
}
#endregion
#region 间隔天数
/// <summary>
/// 获取
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<int> GetNumberOfDaysBetween(ReadingCalculateDto inDto)
{
if (inDto.IsBaseLine)
{
return -1;
}
var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync();
var taskList = await GetSiteVisitForTumorList(inDto);
var lastTask = taskList.Where(x => x.VisitTaskNum < taskinfo.VisitTaskNum && x.VisitTaskId != inDto.VisitTaskId).OrderByDescending(x => x.VisitTaskNum).FirstOrDefault();
if (lastTask != null)
{
var thisTask = taskList.FirstOrDefault();
if (thisTask != null && thisTask.StudyTime != null && lastTask.StudyTime != null)
{
return (int)Math.Floor((thisTask.StudyTime.Value - lastTask.StudyTime.Value).TotalDays);
}
else
{
return -1;
}
}
else
{
return -1;
}
}
#endregion
#region 访视点肿瘤评估
/// <summary>
/// 访视点肿瘤评估
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<string> GetSiteVisitForTumorEvaluation(ReadingCalculateDto inDto)
{
return (await GetSiteVisitForTumorEvaluationByDay(inDto)).Result;
}
/// <summary>
/// 获取肿瘤评估 逻辑抽离 这里还要返回上一次的结果
/// </summary>
/// <param name="inDto"></param>
/// <param name="daysBetween"></param>
/// <returns></returns>
public async Task<SiteVisitForTumorEvaluationByDayOutDto> GetSiteVisitForTumorEvaluationByDay(ReadingCalculateDto inDto, int? daysBetween = null)
{
SiteVisitForTumorEvaluationByDayOutDto result = new SiteVisitForTumorEvaluationByDayOutDto();
if (inDto.IsBaseLine)
{
result.Result = VisitTumorEvaluation.NA.GetEnumInt();
return result;
}
//如果日期未知,不需要计算肿瘤评估结果;
if (await GetNumberOfDaysBetween(inDto) == -1)
{
result.Result = string.Empty;
return result;
}
if (inDto.QuestionInfo.Any(x => x.QuestionType == QuestionType.ImageQualityAssessment && x.Answer == ImageQualityEvaluation.Abnormal.GetEnumInt()))
{
//影像质量不正常
result.Result = VisitTumorEvaluation.NE.GetEnumInt();
return result;
}
var pdResult = await ChangeLastTaskSiteVisitForTumorEvaluation(inDto, daysBetween);
// 这里为什么要这样写 因为要把上一次的也返回前端去 前端要修改
result.LastTaskResult = pdResult.LastTaskResult;
result.LastTaskId = pdResult.LastTaskId;
var newLesionsCount = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.NewLesionsCount).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0();
var baseLineLesionsCount = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.BaseLineLesionsCount).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0();
var alwaysNewLesionsCount = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.AlwaysNewLesionsCount).Select(x => x.Answer).FirstOrDefault().IsNullOrEmptyReturn0();
if (pdResult.IsPD)
{
result.Result = VisitTumorEvaluation.PD.GetEnumInt();
}
else if (newLesionsCount == 0 &&
baseLineLesionsCount == 0 &&
alwaysNewLesionsCount == 0)
{
result.Result = VisitTumorEvaluation.ND.GetEnumInt();
}
else
{
result.Result = VisitTumorEvaluation.NoPD.GetEnumInt();
}
return result;
}
/// <summary>
/// 前端获取访视点肿瘤评估
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<FrontGetSiteVisitForTumorEvaluationOutDto> FrontGetSiteVisitForTumorEvaluation(FrontGetSiteVisitForTumorEvaluationInDto inDto)
{
ReadingCalculateDto readingData = await _generalCalculateService.GetReadingCalculateDto(inDto.VisitTaskId);
// 只获取当前的 不会获取上一次临时修改的结果
foreach (var item in readingData.QuestionInfo)
{
if (item.PCWGInterimAnswer != null)
{
item.Answer = item.PCWGInterimAnswer;
}
if (item.QuestionType == QuestionType.DaysBetween)
{
item.Answer = inDto.NumberOfDaysBetween.ToString();
}
}
FrontGetSiteVisitForTumorEvaluationOutDto result = new FrontGetSiteVisitForTumorEvaluationOutDto();
var tumorEvaluation = await GetSiteVisitForTumorEvaluationByDay(readingData, inDto.NumberOfDaysBetween);
result.ResultList = new List<FrontGetSiteVisitForTumor>() {
new FrontGetSiteVisitForTumor(){
VisitTaskId=inDto.VisitTaskId,
TumorEvaluationResult=tumorEvaluation.Result,
}
};
if (tumorEvaluation.LastTaskResult != null && tumorEvaluation.LastTaskId != null)
{
result.ResultList.Add(new FrontGetSiteVisitForTumor()
{
VisitTaskId = tumorEvaluation.LastTaskId.Value,
TumorEvaluationResult = tumorEvaluation.LastTaskResult,
});
}
return result;
}
/// <summary>
/// 修改上一次访视结果 并且计算是不是PD
/// </summary>
/// <param name="inDto"></param>
/// <param name="numOfDaysBetween"></param>
/// <returns></returns>
public async Task<PCWGSiteVisitForTumor> ChangeLastTaskSiteVisitForTumorEvaluation(ReadingCalculateDto inDto, int? numOfDaysBetween)
{
PCWGSiteVisitForTumor result = new PCWGSiteVisitForTumor()
{
IsPD = false,
};
var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync();
var taskList = await GetSiteVisitForTumorList(inDto);
var lastTask = taskList.Where(x => x.VisitTaskNum < taskinfo.VisitTaskNum && x.VisitTaskId != inDto.VisitTaskId).OrderByDescending(x => x.VisitTaskNum).FirstOrDefault();
var baseLineTask = taskList.OrderBy(x => x.VisitTaskNum).FirstOrDefault();
// 先判断有没有上一个任务
if (lastTask != null)
{
// 查看历史有没有PD
var taskIdList = taskList.Select(x => x.VisitTaskId).ToList();
// pd的任务列表
var pdTaskList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId != inDto.VisitTaskId && taskIdList.Contains(x.VisitTaskId) && x.ReadingQuestionTrial.QuestionType == QuestionType.SiteVisitForTumorEvaluation && x.Answer == VisitTumorEvaluation.PD.GetEnumInt()).OrderByDescending(x => x.VisitTask.VisitTaskNum).ToListAsync();
// 自治疗后第二个访视点以来持续的新骨变数量
var thisNewBoneLesionsCount = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.NewBoneLesionsCount).Select(x => x.Answer).FirstIsNullReturnEmpty().IsNullOrEmptyReturn0();
// 当前任务的BL-BTN
var thisBTN = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.BaseLineLesionsCount).Select(x => x.Answer).FirstIsNullReturnEmpty().IsNullOrEmptyReturn0();
// 当前访视新病灶数量
var thisNewLesionsCount = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.NewLesionsCount).Select(x => x.Answer).FirstIsNullReturnEmpty().IsNullOrEmptyReturn0();
// 其他访视的BTN
var otherBTNStrList = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId != inDto.VisitTaskId && taskIdList.Contains(x.VisitTaskId) && x.ReadingQuestionTrial.QuestionType == QuestionType.BaseLineLesionsCount).Select(x => new {
x.VisitTask.VisitTaskNum,
x.Answer,
}).ToListAsync();
// 最小的BTN 这个时候再转为int 避免查询报错
var otherMinBTNCount = otherBTNStrList.Select(x => x.Answer.IsNullOrEmptyReturn0()).Min();
// [(V3 - BTN - MinV2 - BTN、V1 - BTN、BL - BTN] 小于当0计算
var btnValue = thisBTN - otherMinBTNCount;
if (btnValue < 0)
{
btnValue = 0;
}
// 历史有PD
if (pdTaskList.Count() > 0)
{
// 当前访视:自治疗后第二个访视点以来持续的新骨变数量 + [(V3 - BTN - MinV2 - BTN、V1 - BTN、BL - BTN] + 新病灶 >= 2
if (thisNewBoneLesionsCount + btnValue + thisNewLesionsCount >= 2)
{
result.IsPD = true;
}
}
else
{
// 间隔天数
var daysBetween = numOfDaysBetween != null ? numOfDaysBetween.Value : await GetNumberOfDaysBetween(inDto);
// 上一次访视的新病灶数量
var lastNewLesionsCount = (await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == lastTask.VisitTaskId && x.ReadingQuestionTrial.QuestionType == QuestionType.NewLesionsCount).Select(x => x.Answer).FirstOrDefaultAsync()).IsNullOrEmptyReturn0();
// 之前不存在pd 又分为两种情况 在访视2 和 访视2以后
if (inDto.VisitTaskNum == 2)
{
var alwaysNewLesionsCount = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.AlwaysNewLesionsCount).Select(x => x.Answer).FirstIsNullReturnEmpty().IsNullOrEmptyReturn0();
// V1新病灶计数>=2; V2新病灶计数>=2且既往新病灶计数>=2;; V2与V1的间隔 >= 6周
if (lastNewLesionsCount >= 2 && thisNewLesionsCount >= 2 && alwaysNewLesionsCount >= 2 && daysBetween >= 42)
{
result.IsPD = true;
}
}
else if (inDto.VisitTaskNum > 2)
{
// 上一个访视的BTN
var lastBTN = (await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == lastTask.VisitTaskId && x.ReadingQuestionTrial.QuestionType == QuestionType.BaseLineLesionsCount).Select(x => x.Answer).FirstOrDefaultAsync()).IsNullOrEmptyReturn0();
// 上上个访视的 最小BTN
var lastTwoBTN = otherBTNStrList.Where(x => x.VisitTaskNum < lastTask.VisitTaskNum).Select(x => x.Answer.IsNullOrEmptyReturn0()).Min();
// V2新病灶计数+[(V2-BTN- MinV1-BTN、BL-BTN]>=2
// V3自治疗后第二个访视点以来持续的新骨变数量 + [(V3 - BTN - MinV2 - BTN、V1 - BTN、BL - BTN] + 新病灶 >= 2
// V3与V2的间隔 >= 6周
// 按上面条件写三个if看着清晰点
var lastBtnSubMin = lastBTN - lastTwoBTN;
if (lastBtnSubMin < 0)
{
lastBtnSubMin = 0;
}
if (lastNewLesionsCount + lastBtnSubMin >= 2)
{
if (thisNewBoneLesionsCount + btnValue + thisNewLesionsCount >= 2)
{
if (daysBetween >= 42)
{
result.IsPD = true;
}
}
}
}
if (result.IsPD)
{
// 为 null 说明不是前端传的
if (numOfDaysBetween == null)
{
var visitForTumorEvaluationQuestionId = inDto.QuestionInfo.Where(x => x.QuestionType == QuestionType.SiteVisitForTumorEvaluation).Select(x => x.QuestionId).FirstOrDefault();
await _readingTaskQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => x.VisitTaskId == lastTask.VisitTaskId && x.ReadingQuestionTrialId == visitForTumorEvaluationQuestionId, x => new ReadingTaskQuestionAnswer
{
PCWGInterimAnswer = VisitTumorEvaluation.PD.GetEnumInt(),
});
}
result.LastTaskResult = VisitTumorEvaluation.PD.GetEnumInt();
result.LastTaskId = lastTask.VisitTaskId;
}
else
{
if (lastTask != null)
{
if (numOfDaysBetween == null)
{
// 如果不是PD 需要把上一次的PD改为NoPD 这里去掉临时答案就是原始答案
await _readingTaskQuestionAnswerRepository.BatchUpdateNoTrackingAsync(x => x.VisitTaskId == lastTask.VisitTaskId && x.ReadingQuestionTrial.QuestionType == QuestionType.SiteVisitForTumorEvaluation, x => new ReadingTaskQuestionAnswer
{
PCWGInterimAnswer = null,
});
}
var lastTaskResult = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == lastTask.VisitTaskId && x.ReadingQuestionTrial.QuestionType == QuestionType.SiteVisitForTumorEvaluation).Select(x => x.Answer).FirstOrDefaultAsync();
result.LastTaskResult = lastTaskResult;
result.LastTaskId = lastTask.VisitTaskId;
}
}
}
}
return result;
}
#endregion
/// <summary>
/// 获取访视日期信息
/// </summary>
/// <param name="inDto"></param>
/// <returns></returns>
public async Task<List<SiteVisitForTumor>> GetSiteVisitForTumorList(ReadingCalculateDto inDto)
{
if (siteVisitForTumorList == null)
{
var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync();
siteVisitForTumorList = await _visitTaskRepository.Where(x => (x.ReadingCategory == ReadingCategory.Visit &&
x.TrialReadingCriterionId == taskinfo.TrialReadingCriterionId &&
x.DoctorUserId == taskinfo.DoctorUserId &&
x.IsAnalysisCreate == inDto.IsAnalysisCreate &&
x.SubjectId == taskinfo.SubjectId && x.ReadingTaskState == ReadingTaskState.HaveSigned && x.VisitTaskNum <= taskinfo.VisitTaskNum && x.TaskState == TaskState.Effect && x.ArmEnum == taskinfo.ArmEnum
) || x.Id == inDto.VisitTaskId).OrderByDescending(x => x.VisitTaskNum).Select(x => new SiteVisitForTumor()
{
VisitTaskId = x.Id,
VisitTaskNum = x.VisitTaskNum,
SubjectVisitId = x.SourceSubjectVisitId,
}).ToListAsync();
var visitIds = siteVisitForTumorList.Select(x => x.SubjectVisitId).ToList();
// Dicom 用NM 非dicom 用骨扫描 (BoneScan)
List<VisitStudyTime> visitStudies = await _dicomStudyRepository.Where(x => visitIds.Contains(x.SubjectVisitId) && x.ModalityForEdit == "BoneScan").Select(x => new VisitStudyTime()
{
SubjectVisitId = x.SubjectVisitId,
StudyTime = x.StudyTime
}).ToListAsync();
visitStudies.AddRange(
await _noneDicomStudyRepository.Where(x => visitIds.Contains(x.SubjectVisitId) && x.Modality == "BoneScan").Select(x => new VisitStudyTime()
{
SubjectVisitId = x.SubjectVisitId,
StudyTime = x.ImageDate
}).ToListAsync()
);
visitStudies = visitStudies.Where(x => x.StudyTime != null).ToList();
foreach (var item in siteVisitForTumorList)
{
item.StudyTime = visitStudies.Where(x => x.SubjectVisitId == item.SubjectVisitId).Max(x => x.StudyTime);
}
}
return siteVisitForTumorList;
}
public async Task<GetReportVerifyOutDto> GetReportVerify(GetReportVerifyInDto inDto)
{
return new GetReportVerifyOutDto()
{
};
}
public async Task VerifyVisitTaskQuestions(VerifyVisitTaskQuestionsInDto inDto)
{
if (await _readingTaskQuestionAnswerRepository.AnyAsync(x => x.ReadingQuestionTrial.QuestionType == QuestionType.ImageQualityAssessment && x.VisitTaskId == inDto.VisitTaskId && x.Answer == ImageQualityEvaluation.Abnormal.GetEnumInt()))
{
return;
}
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.ReadingQuestionTrial.LesionType != LesionType.BaselineLesions && (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 == EvaluationOfState.UnableEvaluate.GetEnumInt()
&& x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State
)
.Select(x => x.RowId).Distinct().ToListAsync();
List<string> measureDataList = rowAnswerList.Where(x => !unableEvaluateRowIds.Contains(x.Id)).Select(x => x.OrderMark + x.RowIndex.GetLesionMark()).ToList();
List<string> stateIsNullList = tableAnswerList.Select(x => x.OrderMark + x.RowIndex.GetLesionMark()).ToList();
List<string> allExists = measureDataList.Intersect(stateIsNullList).ToList();
measureDataList = measureDataList.Except(allExists).ToList();
stateIsNullList = stateIsNullList.Except(allExists).ToList();
if (measureDataList.Count() > 0)
{
errorMassage += _localizer["ReadingCalculate_NoMarker", string.Join(',', measureDataList)] + ",";
}
if (tableAnswerList.Count > 0)
{
errorMassage += _localizer["ReadingCalculate_StatusIsEmpty", string.Join(',', stateIsNullList)] + ",";
}
if (allExists.Count > 0)
{
errorMassage += _localizer["ReadingCalculate_NoMarkerEmpty", string.Join(',', stateIsNullList)] + ",";
}
if (errorMassage != string.Empty)
{
errorMassage = _localizer["ReadingCalculate_questionable"] + errorMassage;
throw new BusinessValidationFailedException(errorMassage);
}
}
}
}