diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index 29143502f..62f4d7d26 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -1726,6 +1726,11 @@ 处理拍片日期 + + + 处理 访视 末次评估 会影响Subject 状态 + + 构造函数注入 diff --git a/IRaCIS.Core.Application/Service/Visit/VisitPlanService.cs b/IRaCIS.Core.Application/Service/Visit/VisitPlanService.cs index da9df6202..c82a0300d 100644 --- a/IRaCIS.Core.Application/Service/Visit/VisitPlanService.cs +++ b/IRaCIS.Core.Application/Service/Visit/VisitPlanService.cs @@ -246,12 +246,10 @@ namespace IRaCIS.Application.Services return ResponseOutput.NotOk("基线VisitDay 不是最小的, 不允许确认"); } - List datas = new List(); - var addvisitStages = await _visitStageRepository.Where(x => !x.IsHaveFirstConfirmed && x.TrialId == trialId).ToListAsync(); + //更新项目访视计划状态为已确认 必定生成更新的sql 通过状态改变 触发操作 + await _trialRepository.UpdatePartialFieldsNowAsync(trialId, t => new Trial() { VisitPlanConfirmed = true }); - //更新项目访视计划状态为已确认 - await _trialRepository.BatchUpdateAsync(u => u.Id == trialId, t => new Trial() { VisitPlanConfirmed = true }); //找到访视计划修改的Item var changedList = await _visitStageRepository.Where(t => t.TrialId == trialId && t.IsConfirmed == false) @@ -271,6 +269,10 @@ namespace IRaCIS.Application.Services t.Description, IsConfirmed = true, }).ToListAsync(); + + + List datas = new List(); + var createtime = DateTime.Now.AddSeconds(1); @@ -292,126 +294,12 @@ namespace IRaCIS.Application.Services }); - //访视计划 整体状态变更为 确认 - await _visitStageRepository.BatchUpdateAsync(u => u.TrialId == trialId, t => new VisitStage() { IsConfirmed = true, IsHaveFirstConfirmed = true }); + - var stat = new VisitPlanInfluenceStat() { TrialId = trialId }; foreach (var changedItem in changedList) { - //找到该项目 访视已经执行,并且配置了有首次给药日期 并且更新后超窗的访视,要把超窗之前的值也要查询出来 - var qcPassedVisitList = await _repository.Where(t => t.TrialId == trialId - && t.VisitExecuted == VisitExecutedEnum.Executed - && t.AuditState == AuditStateEnum.QCPassed - && t.Trial.IsHaveFirstGiveMedicineDate == true - && t.VisitStageId == changedItem.Id - && t.Subject.FirstGiveMedicineTime != null - ).Select(k => new - { - SubjectVisitId = k.Id, - SelfWindowLeft = k.Subject.FirstGiveMedicineTime!.Value.AddDays(k.VisitDay + k.VisitWindowLeft), - SelfWindowRight = k.Subject.FirstGiveMedicineTime!.Value.AddDays(k.VisitDay + k.VisitWindowRight + 1).AddSeconds(-1), - - NowWindowLeft = k.Subject.FirstGiveMedicineTime!.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowLeft), - NowWindowRight = k.Subject.FirstGiveMedicineTime!.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight + 1).AddSeconds(-1), - - NoneDicomStudyList = - k.NoneDicomStudyList //之前是查询调整之后超窗的 现在调整前超窗 调整后 没超窗的也要记录 - //.Where(study => study.ImageDate k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight??0 + 1).AddSeconds(-1)) - .Select(t => new { NoneDicomStudyId = t.Id, t.Modality, StudyTime = t.ImageDate }), - - - DicomStudyList = k.StudyList - //.Where(study => study.StudyTime k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight??0 + 1).AddSeconds(-1)) - .Select(t => new { StudyId = t.Id, Modality = t.Modalities, t.StudyTime }) - - }).ToListAsync(); - - - foreach (var visit in qcPassedVisitList) - { - //找到本身没有超窗的数据 修改后超窗的 - visit.DicomStudyList.Where(t => (t.StudyTime > visit.SelfWindowLeft && t.StudyTime < visit.SelfWindowRight) && (t.StudyTime < visit.NowWindowLeft || t.StudyTime > visit.NowWindowRight)).ForEach(t => - { - stat.InconsistentCount++; - stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() - { - IsOverWindowNowNotOverWindow = false, - Modality = t.Modality, - SubjectVisitId = visit.SubjectVisitId, - StudyId = t.StudyId, - IsDicomStudy = true, - StudyTime = t.StudyTime, - TrialId = trialId, - HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), - NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") - - }); - - }); - - visit.NoneDicomStudyList.Where(t => (t.StudyTime > visit.SelfWindowLeft && t.StudyTime < visit.SelfWindowRight) && (t.StudyTime < visit.NowWindowLeft || t.StudyTime > visit.NowWindowRight)).ForEach(t => - { - stat.InconsistentCount++; - stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() - { - IsOverWindowNowNotOverWindow = false, - Modality = t.Modality, - SubjectVisitId = visit.SubjectVisitId, - StudyId = t.NoneDicomStudyId, - IsDicomStudy = false, - StudyTime = t.StudyTime, - TrialId = trialId, - HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), - NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") - - }); - }); - - //本身超窗 修改后没超窗的 - visit.DicomStudyList.Where(t => (t.StudyTime < visit.SelfWindowLeft || t.StudyTime > visit.SelfWindowRight) && (t.StudyTime > visit.NowWindowLeft && t.StudyTime < visit.NowWindowRight)).ForEach(t => - { - stat.InconsistentCount++; - stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() - { - IsOverWindowNowNotOverWindow = true, - Modality = t.Modality, - SubjectVisitId = visit.SubjectVisitId, - StudyId = t.StudyId, - IsDicomStudy = true, - StudyTime = t.StudyTime, - TrialId = trialId, - HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), - NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") - - }); - }); - - visit.NoneDicomStudyList.Where(t => (t.StudyTime < visit.SelfWindowLeft || t.StudyTime > visit.SelfWindowRight) && (t.StudyTime > visit.NowWindowLeft && t.StudyTime < visit.NowWindowRight)).ForEach(t => - { - stat.InconsistentCount++; - stat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() - { - IsOverWindowNowNotOverWindow = true, - Modality = t.Modality, - SubjectVisitId = visit.SubjectVisitId, - StudyId = t.NoneDicomStudyId, - IsDicomStudy = false, - StudyTime = t.StudyTime, - TrialId = trialId, - HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), - NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") - - }); - }); - } - - - - - + var list = await _subjectVisitRepository.Where(t => t.TrialId == trialId && t.VisitStageId == changedItem.Id).ToListAsync(); list.ForEach(x => { @@ -440,18 +328,8 @@ namespace IRaCIS.Application.Services }); }); - //变更某一访视计划Item 受试者访视相关字段 - await _repository.BatchUpdateAsync(t => t.TrialId == trialId && t.VisitStageId == changedItem.Id, k => new SubjectVisit() - { - IsBaseLine = changedItem.IsBaseLine, - VisitName = changedItem.VisitName, - VisitNum = changedItem.VisitNum, - VisitDay = changedItem.VisitDay, - VisitWindowLeft = changedItem.VisitWindowLeft, - VisitWindowRight = changedItem.VisitWindowRight - }); - } + var subjectsids = _repository.GetQueryable().Where(x => x.TrialId == trialId).Select(x => new { x.Code, @@ -459,8 +337,7 @@ namespace IRaCIS.Application.Services x.Id, x.IsEnrollment, x.IsUrgent, - - + }); List subjectVisits = new List(); @@ -469,6 +346,8 @@ namespace IRaCIS.Application.Services var trial = await _repository.GetQueryable().FirstOrDefaultAsync(x => x.Id == trialId); + var addvisitStages = await _visitStageRepository.Where(x => !x.IsHaveFirstConfirmed && x.TrialId == trialId).ToListAsync(); + addvisitStages.ForEach(x => { @@ -565,9 +444,12 @@ namespace IRaCIS.Application.Services }); await _inspectionService.AddListInspectionRecordAsync(datas); - await _repository.AddAsync(stat); //await _subjectVisitRepository.AddRangeAsync() await _repository.AddRangeAsync(subjectVisits); + + //访视计划 整体状态变更为 确认 + await _visitStageRepository.BatchUpdateAsync(u => u.TrialId == trialId, t => new VisitStage() { IsConfirmed = true, IsHaveFirstConfirmed = true }); + await _repository.SaveChangesAsync(); return ResponseOutput.Ok(); diff --git a/IRaCIS.Core.Application/Triggers/TrialVisitPlanConfirmTrigger.cs b/IRaCIS.Core.Application/Triggers/TrialVisitPlanConfirmTrigger.cs index bc90253c5..d30616e57 100644 --- a/IRaCIS.Core.Application/Triggers/TrialVisitPlanConfirmTrigger.cs +++ b/IRaCIS.Core.Application/Triggers/TrialVisitPlanConfirmTrigger.cs @@ -5,17 +5,23 @@ using IRaCIS.Core.Infrastructure; namespace IRaCIS.Core.Application.Triggers { /// - /// 处理 访视 末次评估 会影响Subject 状态 + /// 处理 项目访视计划确认,记录影像的检查,另外批量插入访视数据 /// public class TrialVisitPlanConfirmTrigger : IAfterSaveTrigger { private readonly IRepository _subjectVisitRepository; private readonly IRepository _subjectRepository; + private readonly IRepository _visitStageRepository; + private readonly IRepository _visitPlanInfluenceStatRepository; - public TrialVisitPlanConfirmTrigger(IRepository subjectVisitRepository, IRepository subjectRepository) + public TrialVisitPlanConfirmTrigger(IRepository subjectVisitRepository, + IRepository subjectRepository,IRepository visitStageRepository, + IRepository visitPlanInfluenceStatRepository) { _subjectVisitRepository = subjectVisitRepository; _subjectRepository = subjectRepository; + _visitStageRepository = visitStageRepository; + _visitPlanInfluenceStatRepository = visitPlanInfluenceStatRepository; } public async Task AfterSave(ITriggerContext context, CancellationToken cancellationToken) @@ -23,11 +29,163 @@ namespace IRaCIS.Core.Application.Triggers var trial = context.Entity; + var trialId = context.Entity.Id; + if (context.ChangeType == ChangeType.Modified) { - + //项目访视计划确认 状态改变触发 + if (trial.VisitPlanConfirmed && trial.VisitPlanConfirmed != context.UnmodifiedEntity.VisitPlanConfirmed) + { + //找到访视计划修改的Item + var changedList = await _visitStageRepository.Where(t => t.TrialId == trial.Id && t.IsConfirmed == false) + .Select(t => new + { + t.Trial.IsHaveFirstGiveMedicineDate, + t.Id, + t.VisitName, + t.TrialId, + t.VisitWindowLeft, + t.VisitWindowRight, + t.VisitDay, + t.VisitNum, + t.IsBaseLine, + t.BlindName, + + t.Description, + IsConfirmed = true, + }).ToListAsync(); + + var visitPlanInfluenceStat = new VisitPlanInfluenceStat() { TrialId = trial.Id }; + + foreach (var changedItem in changedList) + { + //找到该项目 访视已经执行,并且配置了有首次给药日期 并且更新后超窗的访视,要把超窗之前的值也要查询出来 + var qcPassedVisitList = await _subjectVisitRepository.Where(t => t.TrialId == trialId + && t.VisitExecuted == VisitExecutedEnum.Executed + && t.AuditState == AuditStateEnum.QCPassed + && t.Trial.IsHaveFirstGiveMedicineDate == true + && t.VisitStageId == changedItem.Id + && t.Subject.FirstGiveMedicineTime != null + ).Select(k => new + { + SubjectVisitId = k.Id, + SelfWindowLeft = k.Subject.FirstGiveMedicineTime!.Value.AddDays(k.VisitDay + k.VisitWindowLeft), + SelfWindowRight = k.Subject.FirstGiveMedicineTime!.Value.AddDays(k.VisitDay + k.VisitWindowRight + 1).AddSeconds(-1), + + NowWindowLeft = k.Subject.FirstGiveMedicineTime!.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowLeft), + NowWindowRight = k.Subject.FirstGiveMedicineTime!.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight + 1).AddSeconds(-1), + + NoneDicomStudyList = + k.NoneDicomStudyList //之前是查询调整之后超窗的 现在调整前超窗 调整后 没超窗的也要记录 + //.Where(study => study.ImageDate k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight??0 + 1).AddSeconds(-1)) + .Select(t => new { NoneDicomStudyId = t.Id, t.Modality, StudyTime = t.ImageDate }), + + + DicomStudyList = k.StudyList + //.Where(study => study.StudyTime k.Subject.FirstGiveMedicineTime.Value.AddDays(changedItem.VisitDay + changedItem.VisitWindowRight??0 + 1).AddSeconds(-1)) + .Select(t => new { StudyId = t.Id, Modality = t.Modalities, t.StudyTime }) + + }).ToListAsync(); + + + foreach (var visit in qcPassedVisitList) + { + //找到本身没有超窗的数据 修改后超窗的 + visit.DicomStudyList.Where(t => (t.StudyTime > visit.SelfWindowLeft && t.StudyTime < visit.SelfWindowRight) && (t.StudyTime < visit.NowWindowLeft || t.StudyTime > visit.NowWindowRight)).ForEach(t => + { + visitPlanInfluenceStat.InconsistentCount++; + visitPlanInfluenceStat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() + { + IsOverWindowNowNotOverWindow = false, + Modality = t.Modality, + SubjectVisitId = visit.SubjectVisitId, + StudyId = t.StudyId, + IsDicomStudy = true, + StudyTime = t.StudyTime, + TrialId = trialId, + HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), + NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") + + }); + + }); + + visit.NoneDicomStudyList.Where(t => (t.StudyTime > visit.SelfWindowLeft && t.StudyTime < visit.SelfWindowRight) && (t.StudyTime < visit.NowWindowLeft || t.StudyTime > visit.NowWindowRight)).ForEach(t => + { + visitPlanInfluenceStat.InconsistentCount++; + visitPlanInfluenceStat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() + { + IsOverWindowNowNotOverWindow = false, + Modality = t.Modality, + SubjectVisitId = visit.SubjectVisitId, + StudyId = t.NoneDicomStudyId, + IsDicomStudy = false, + StudyTime = t.StudyTime, + TrialId = trialId, + HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), + NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") + + }); + }); + + //本身超窗 修改后没超窗的 + visit.DicomStudyList.Where(t => (t.StudyTime < visit.SelfWindowLeft || t.StudyTime > visit.SelfWindowRight) && (t.StudyTime > visit.NowWindowLeft && t.StudyTime < visit.NowWindowRight)).ForEach(t => + { + visitPlanInfluenceStat.InconsistentCount++; + visitPlanInfluenceStat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() + { + IsOverWindowNowNotOverWindow = true, + Modality = t.Modality, + SubjectVisitId = visit.SubjectVisitId, + StudyId = t.StudyId, + IsDicomStudy = true, + StudyTime = t.StudyTime, + TrialId = trialId, + HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), + NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") + + }); + }); + + visit.NoneDicomStudyList.Where(t => (t.StudyTime < visit.SelfWindowLeft || t.StudyTime > visit.SelfWindowRight) && (t.StudyTime > visit.NowWindowLeft && t.StudyTime < visit.NowWindowRight)).ForEach(t => + { + visitPlanInfluenceStat.InconsistentCount++; + visitPlanInfluenceStat.InfluenceStudyList.Add(new VisitPlanInfluenceStudy() + { + IsOverWindowNowNotOverWindow = true, + Modality = t.Modality, + SubjectVisitId = visit.SubjectVisitId, + StudyId = t.NoneDicomStudyId, + IsDicomStudy = false, + StudyTime = t.StudyTime, + TrialId = trialId, + HistoryWindow = visit.SelfWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.SelfWindowRight.ToString("yyyy-MM-dd"), + NowWindow = visit.NowWindowLeft.ToString("yyyy-MM-dd") + " ~ " + visit.NowWindowRight.ToString("yyyy-MM-dd") + + }); + }); + + //变更某一访视计划Item 受试者访视相关字段 + await _subjectVisitRepository.BatchUpdateAsync(t => t.TrialId == trialId && t.VisitStageId == changedItem.Id, k => new SubjectVisit() + { + IsBaseLine = changedItem.IsBaseLine, + VisitName = changedItem.VisitName, + VisitNum = changedItem.VisitNum, + VisitDay = changedItem.VisitDay, + VisitWindowLeft = changedItem.VisitWindowLeft, + VisitWindowRight = changedItem.VisitWindowRight + }); + } + + } + + + await _visitPlanInfluenceStatRepository.AddAsync(visitPlanInfluenceStat,true); + } } diff --git a/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs b/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs index 07f5d8385..607b6a3fa 100644 --- a/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs +++ b/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs @@ -17,14 +17,14 @@ namespace IRaCIS.Core.Infra.EFCore Task UpdateFromDTOAsync(TFrom from, bool autoSave = false, bool ignoreDtoNullProperty = true, params EntityVerifyExp[] verify); - + /// EF跟踪方式 生成 部分字段更新 (只更新传递的字段名 new[] {nameof(User.Name), nameof(User.Age)) Task UpdatePartialFieldsAsync(TEntity entity, string[] propertyNames, bool autoSave = false, bool ignoreEntityNullProperty = true, params EntityVerifyExp[] verify); - /// 更新字段,立即提交事务 + /// EF跟踪方式 生成 部分字段立即更新,默认会去处理更新更新人 更新时间 Task UpdatePartialFieldsNowAsync(Guid id, Expression> updateFactory, params EntityVerifyExp[] verify); - /// 更新字段,默认不提交事务,一般用于服务里面 和别的操作 一起提交事务 + /// EF跟踪方式 生成 部分字段更新, 通过主键id 和表达式树 更新部分字段,默认不提交事务,一般用于服务里面 和别的操作 一起提交事务 Task UpdatePartialFieldsAsync(Guid id, Expression> updateFactory, bool autoSave = false, params EntityVerifyExp[] verify); /// 批量删除,相当于原生sql, 没用EF跟踪方式(所有查询出来,再删除 浪费性能) @@ -37,9 +37,11 @@ namespace IRaCIS.Core.Infra.EFCore /// 批量删除,EF跟踪方式(所有查询出来,再删除 浪费性能,但是稽查 或者触发某些操作时,需要知道数据库实体信息 不可避免用这种) Task> TrackingBatchDeleteAsync(Expression> deleteFilter); + /// EF跟踪方式 先查询出来,再更新部分字段 稽查的时候需要完整的实体信息 Task UpdatePartialAsync(TEntity entity, Expression> updateFactory, bool autoSave = false, CancellationToken cancellationToken = default); + /// EF跟踪方式 先查询出来,再更新部分字段 稽查的时候需要完整的实体信息 Task UpdatePartialSearchFirstAsync(Guid id, Expression> updateFactory, bool autoSave = false, CancellationToken cancellationToken = default);