评估统计初步增加

Test_IRC_Net8
hang 2025-10-27 10:48:31 +08:00
parent b581afebe6
commit 998b92aa79
3 changed files with 341 additions and 24 deletions

View File

@ -9438,6 +9438,11 @@
融合的CTSeriesId 融合的CTSeriesId
</summary> </summary>
</member> </member>
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.AddNoneDicomMarkInDto.Proportion">
<summary>
比例
</summary>
</member>
<member name="T:IRaCIS.Core.Application.Service.Reading.Dto.SubmitVisitTaskQuestionsInDto"> <member name="T:IRaCIS.Core.Application.Service.Reading.Dto.SubmitVisitTaskQuestionsInDto">
<summary> <summary>
@ -13675,6 +13680,14 @@
<param name="inDto"></param> <param name="inDto"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.ChangePlottingScale(System.Nullable{System.Guid},System.Decimal)">
<summary>
修改比例修改答案
</summary>
<param name="id"></param>
<param name="proportion"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.DeleteBinding(IRaCIS.Core.Application.Service.Reading.Dto.DeleteBindingInDto)"> <member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.DeleteBinding(IRaCIS.Core.Application.Service.Reading.Dto.DeleteBindingInDto)">
<summary> <summary>
删除绑定关系 删除绑定关系

View File

@ -87,7 +87,7 @@ namespace IRaCIS.Core.Application.ViewModel
public class EfficacyEvaluationStatViewModel public class EfficacyEvaluationStatViewModel
{ {
public int OverallTumorEvaluation { get; set; } public string OverallTumorEvaluation { get; set; }
public int SubjectCount { get; set; } public int SubjectCount { get; set; }
} }
@ -135,26 +135,24 @@ namespace IRaCIS.Core.Application.ViewModel
public string JudgeNote { get; set; } = string.Empty; public string JudgeNote { get; set; } = string.Empty;
public string VisitNote { get; set; }
public Guid? DoctorUserId { get; set; }
public string UserName { get; set; }
public List<CommonQuesionInfo> QuestionAnswerList { get; set; }
public List<decimal> SubjectCriterionReadingPeriodVisitNumList { get; set; } public List<decimal> SubjectCriterionReadingPeriodVisitNumList { get; set; }
public String TrialSiteCode { get; set; } = String.Empty;
public string OverallTumorEvaluation { get; set; }
//public string VisitNote { get; set; }
//public Guid? DoctorUserId { get; set; }
//public string UserName { get; set; }
//public List<CommonQuesionInfo> QuestionAnswerList { get; set; }
//public String TrialSiteCode { get; set; } = String.Empty;
} }
} }

View File

@ -1,21 +1,26 @@
using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore.Common;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using static IRaCIS.Core.Application.Service.ExcelExportHelper;
namespace IRaCIS.Core.Application; namespace IRaCIS.Core.Application;
[ApiExplorerSettings(GroupName = "Trial")] [ApiExplorerSettings(GroupName = "Trial")]
public class TrialStatService( public class TrialStatService(
IRepository<Trial> _trialRepository, IRepository<Trial> _trialRepository,
IRepository<SubjectVisit> _subjectVisitRepository, IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<TrialDocument> _trialDocumentRepository, IRepository<TrialDocument> _trialDocumentRepository,
IRepository<SystemDocument> _systemDocumentRepository, IRepository<SystemDocument> _systemDocumentRepository,
IRepository<SystemNotice> _systemNoticeRepository, IRepository<SystemNotice> _systemNoticeRepository,
IRepository<VisitTask> _visitTaskRepository, IRepository<VisitTask> _visitTaskRepository,
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService
{ {
@ -94,8 +99,38 @@ public class TrialStatService(
public async Task<List<EfficacyEvaluationStatViewModel>> GetTrialEfficacyEvaluationStatList(EfficacyEvaluationQuery inQuery) public async Task<List<EfficacyEvaluationStatViewModel>> GetTrialEfficacyEvaluationStatList(EfficacyEvaluationQuery inQuery)
{ {
var trialReadingCriterionId = inQuery.TrialReadingCriterionId;
//每次查询必须是单标准的
var criterion = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == trialReadingCriterionId).Select(t => new { t.CriterionType, t.CriterionGroup, t.IsGlobalReading, t.IsArbitrationReading, t.IsOncologyReading, t.CriterionName, t.ArbitrationRule }).FirstNotNullAsync();
if (criterion.CriterionGroup == CriterionGroup.Nontumorous)
{
return new List<EfficacyEvaluationStatViewModel>();
}
var questionType = QuestionType.Tumor;
if (criterion.CriterionType == CriterionType.RECIST1Point1 || criterion.CriterionType == CriterionType.RECIST1Pointt1_MB
|| criterion.CriterionType == CriterionType.IRECIST1Point1 || criterion.CriterionType == CriterionType.mRECISTHCC)
{
questionType = QuestionType.Tumor;
}
else if (criterion.CriterionType == CriterionType.Lugano2014 || criterion.CriterionType == CriterionType.Lugano2014WithoutPET)
{
questionType = QuestionType.ImgOncology;
}
else if (criterion.CriterionType == CriterionType.PCWG3)
{
}
var query = _visitTaskRepository var query = _visitTaskRepository
.Where(t => t.TrialId == inQuery.TrialId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.IsAnalysisCreate == false && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze)) .Where(t => t.TrialId == inQuery.TrialId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze))
//访视和全局查询已签名完成的,裁判可以是未签名,未完成的 //访视和全局查询已签名完成的,裁判可以是未签名,未完成的
.Where(t => (t.ReadingTaskState == ReadingTaskState.HaveSigned && (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global)) || t.ReadingCategory == ReadingCategory.Judge) .Where(t => (t.ReadingTaskState == ReadingTaskState.HaveSigned && (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global)) || t.ReadingCategory == ReadingCategory.Judge)
@ -109,12 +144,283 @@ public class TrialStatService(
TaskBlindName = t.TaskBlindName, TaskBlindName = t.TaskBlindName,
ReadingTaskState = t.ReadingTaskState, ReadingTaskState = t.ReadingTaskState,
ReadingCategory = t.ReadingCategory, ReadingCategory = t.ReadingCategory,
ArmEnum = t.ArmEnum,
JudgeArmEnum = t.JudgeResultTask.ArmEnum,
IsTrigerJudge = criterion.ArbitrationRule == ArbitrationRule.Visit ? t.JudgeVisitTaskId != null :
(criterion.ArbitrationRule == ArbitrationRule.Reading ?
t.Subject.SubjectVisitTaskList.Any(c => c.TaskState == TaskState.Effect && c.IsAnalysisCreate == false && c.ReadingCategory == ReadingCategory.Judge && c.TrialReadingCriterionId == trialReadingCriterionId
&& t.VisitTaskNum < c.VisitTaskNum) :
false),
JudgeNote = t.ReadingCategory == ReadingCategory.Judge ? t.JudgeResultRemark : "",
SubjectCriterionReadingPeriodVisitNumList = t.Subject.ReadModuleList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.ReadingSetType == ReadingSetType.ImageReading).Select(c => c.SubjectVisit.VisitNum).ToList(),
//整体肿瘤评估答案
OverallTumorEvaluation = t.ReadingTaskQuestionAnswerList.Where(c => c.ReadingQuestionTrial.QuestionType == questionType).FirstOrDefault()!.Answer
}); });
return new List<EfficacyEvaluationStatViewModel> { };
var list = await query.ToListAsync();
if (criterion.IsArbitrationReading)
{
//找到只有一个人阅片的受试者 和访视
var exceptVisit = list.Where(t => t.ReadingCategory == ReadingCategory.Visit)
.GroupBy(t => new { t.SubjectCode, t.TaskName }).Where(g => g.Count() == 1).Select(g => new { g.Key.SubjectCode, g.Key.TaskName }).ToList();
list = list.Where(t => !exceptVisit.Any(ev => ev.SubjectCode == t.SubjectCode && ev.TaskName == t.TaskName)).ToList();
}
list = list.OrderBy(t => t.SubjectCode).ThenBy(t => t.ArmEnum).ThenBy(t => t.VisitTaskNum).ToList();
//处理裁判标记
list = DealJudgeMark(criterion.ArbitrationRule, criterion.IsGlobalReading, list);
//判断subject的逻辑需要确认这么多次访视任务有的符合有的不符合准则是什么
return list.GroupBy(t => t.OverallTumorEvaluation).Select(g => new EfficacyEvaluationStatViewModel()
{
OverallTumorEvaluation = g.Key,
SubjectCount = g.Select(t => t.SubjectId).Distinct().Count()
}).ToList();
} }
public List<T> DealJudgeMark<T>(ArbitrationRule arbitrationRule, bool isGlobalReading, IEnumerable<T> list) where T : EfficacyEvaluationExport
{
//处理访视任务的裁判标记
var resultExceptJudgeList = list.Where(t => t.ReadingCategory != ReadingCategory.Judge).ToList();
var judegeList = list.Where(t => t.ReadingCategory == ReadingCategory.Judge).ToList();
if (arbitrationRule == ArbitrationRule.Visit)
{
foreach (var item in resultExceptJudgeList)
{
var findJudge = judegeList.FirstOrDefault(t => t.SubjectCode == item.SubjectCode
&& (t.VisitTaskNum - ReadingCommon.TaskNumDic[ReadingCategory.Judge]) == item.VisitTaskNum);
if (findJudge != null)
{
if (findJudge.ReadingTaskState == ReadingTaskState.HaveSigned)
{
item.IsJudgeSelect = findJudge.JudgeArmEnum == item.ArmEnum ? true : false;
item.JudgeNote = findJudge.JudgeArmEnum == item.ArmEnum ? findJudge.JudgeNote : string.Empty;
}
else
{
//默认也是null 其实不用赋值
item.IsJudgeSelect = null;
}
}
else
{
//两个人都做了
if (resultExceptJudgeList.Where(t => t.VisitTaskNum == item.VisitTaskNum && t.SubjectCode == item.SubjectCode).Select(t => t.ArmEnum).Distinct().Count() == 2)
{
//如果没有产生裁判默认选择R1
if (item.ArmEnum == Arm.DoubleReadingArm1)
{
item.IsJudgeSelect = true;
}
else
{
item.IsJudgeSelect = false;
}
}
else
{
item.IsJudgeSelect = null;
item.IsTrigerJudge = null;
}
}
}
}
else if (arbitrationRule == ArbitrationRule.Reading)
{
//处理访视裁判标记
foreach (var visitItem in resultExceptJudgeList.Where(t => t.ReadingCategory == ReadingCategory.Visit))
{
////默认设置为false 只处理为true 和 空的情况
//visitItem.IsJudgeSelect = false;
var subjectJudgeList = judegeList.Where(t => t.SubjectCode == visitItem.SubjectCode).ToList();
//阅片期访视号
var subjectReadingPeriondVisitNumList = resultExceptJudgeList.Where(t => t.SubjectCode == visitItem.SubjectCode).FirstOrDefault()?.SubjectCriterionReadingPeriodVisitNumList;
//两个人完成最大得任务号(访视+全局)
var subjectMaxFinishedTaskNum = resultExceptJudgeList.Where(t => t.SubjectCode == visitItem.SubjectCode)
.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).DefaultIfEmpty().Max();
var addReadingPeriodNum = isGlobalReading ? ReadingCommon.TaskNumDic[ReadingCategory.Global] : 0;
var finishedGlobalCount = 0;
//没有配置阅片期
if (subjectReadingPeriondVisitNumList == null)
{
finishedGlobalCount = 0;
}
else
{
//已完成的全局数量
finishedGlobalCount = resultExceptJudgeList.Where(t => t.SubjectCode == visitItem.SubjectCode && subjectReadingPeriondVisitNumList.Any(c => (c + addReadingPeriodNum) == t.VisitTaskNum)
/*&& t.ReadingCategory == ReadingCategory.Global*/)
.Select(t => new { t.VisitTaskNum, t.ArmEnum }).Distinct()
.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).Count();
}
visitItem.IsJudgeSelect = null;
visitItem.IsTrigerJudge = null;
if (finishedGlobalCount != 0)
{
//最大的全局是否产生裁判
var subjectMaxFinishedGlobalTaskNum = resultExceptJudgeList.Where(t => t.SubjectCode == visitItem.SubjectCode && subjectReadingPeriondVisitNumList.Any(c => (c + addReadingPeriodNum) == t.VisitTaskNum)
/*&& t.ReadingCategory == ReadingCategory.Global*/)
.Select(t => new { t.VisitTaskNum, t.ArmEnum }).Distinct()
.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).DefaultIfEmpty().Max();
//最大的完成的全局是否产生裁判
if (subjectJudgeList.Any(t => t.VisitTaskNum == (subjectMaxFinishedGlobalTaskNum + ReadingCommon.TaskNumDic[ReadingCategory.Judge])))
{
var maxJudge = subjectJudgeList.FirstOrDefault(t => t.VisitTaskNum == (subjectMaxFinishedGlobalTaskNum + ReadingCommon.TaskNumDic[ReadingCategory.Judge]));
//最大裁判完成了
if (maxJudge.ReadingTaskState == ReadingTaskState.HaveSigned)
{
if (visitItem.VisitTaskNum < maxJudge.VisitTaskNum)
{
//触发裁判
visitItem.IsTrigerJudge = true;
if (visitItem.ArmEnum == maxJudge.JudgeArmEnum)
{
visitItem.IsJudgeSelect = true;
visitItem.JudgeNote = maxJudge.JudgeNote;
}
//裁判没选择的人设置为false
else
{
visitItem.IsJudgeSelect = false;
}
}
else
{
//后续访视 未知 默认都是null
}
}
else
{
//找到当前未阅最大裁判之前的已完成的最大裁判任务
var maxFinishedJudge = subjectJudgeList.Where(t => t.ReadingTaskState == ReadingTaskState.HaveSigned).OrderByDescending(t => t.VisitTaskNum).FirstOrDefault();
if (maxFinishedJudge == null)
{
// 为空 裁判选择标记默认就是null 不用处理
if (visitItem.VisitTaskNum < maxJudge.VisitTaskNum)
{
visitItem.IsTrigerJudge = true;
}
}
else
{
if (visitItem.VisitTaskNum < maxFinishedJudge.VisitTaskNum)
{
visitItem.IsTrigerJudge = true;
if (visitItem.ArmEnum == maxFinishedJudge.JudgeArmEnum)
{
visitItem.IsJudgeSelect = true;
visitItem.JudgeNote = maxFinishedJudge.JudgeNote;
}
//裁判没选择的人设置为false
else
{
visitItem.IsJudgeSelect = false;
}
}
else if (visitItem.VisitTaskNum > maxFinishedJudge.VisitTaskNum && visitItem.VisitTaskNum < maxJudge.VisitTaskNum)
{
//完成裁判 和未完成裁判之间的 裁判选择标记默认是null
visitItem.IsTrigerJudge = true;
}
else
{
//在未完成全局裁判之后的访视 未知 默认都是null
}
}
}
}
else
{
//最大的完成的全局未产生裁判
if (visitItem.VisitTaskNum <= subjectMaxFinishedGlobalTaskNum)
{
visitItem.IsTrigerJudge = false;
if (visitItem.ArmEnum == Arm.DoubleReadingArm1)
{
visitItem.IsJudgeSelect = true;
}
else
{
visitItem.IsJudgeSelect = false;
}
}
else
{
//未产生裁判的全局之后的访视 两个标记都是null (后续可能还有全局,但是全局两个人没做完)
}
}
}
}
}
else
{
foreach (var visitItem in resultExceptJudgeList.Where(t => t.ReadingCategory == ReadingCategory.Visit))
{
visitItem.IsJudgeSelect = null;
visitItem.IsTrigerJudge = null;
}
}
return resultExceptJudgeList;
}
} }