From f4e663d2288f5f2f7cad46e345f04513707dd5f6 Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Sun, 24 Apr 2022 08:44:36 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../IRaCIS.Core.Application.csproj | 4 - .../IRaCIS.Core.Application.xml | 12 +- .../Service/QC/QCOperationService.cs | 15 +- .../Service/Visit/SubjectService.cs | 158 +++++------ .../Service/Visit/SubjectVisitService.cs | 88 +++--- .../Service/Visit/VisitPlanService.cs | 254 ++++++++---------- .../Service/Visit/_MapConfig.cs | 3 +- .../Triggers/AddVisitPlanTrigger.cs | 56 ++++ .../Triggers/SubjectStateTrigger.cs | 65 +++++ .../Repository/ICommandRepository.cs | 2 +- .../Repository/Repository.cs | 3 +- 11 files changed, 379 insertions(+), 281 deletions(-) create mode 100644 IRaCIS.Core.Application/Triggers/AddVisitPlanTrigger.cs create mode 100644 IRaCIS.Core.Application/Triggers/SubjectStateTrigger.cs diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj index 7cb0fee49..1fe53bf75 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj @@ -100,8 +100,4 @@ - - - - diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index 8a1125c60..acb34b6fe 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -1660,6 +1660,16 @@ + + + 添加访视计划 要给改项目下的所有Subject 添加该访视 + + + + + + + 构造函数注入 @@ -2426,7 +2436,7 @@ 添加或更新访视计划某项[New] - 删除项目计划某一项[New] + 删除项目计划某一项 废弃 diff --git a/IRaCIS.Core.Application/Service/QC/QCOperationService.cs b/IRaCIS.Core.Application/Service/QC/QCOperationService.cs index 28db00460..f58a426c2 100644 --- a/IRaCIS.Core.Application/Service/QC/QCOperationService.cs +++ b/IRaCIS.Core.Application/Service/QC/QCOperationService.cs @@ -1058,13 +1058,6 @@ namespace IRaCIS.Core.Application.Image.QA #region 临床数据签名 领取、 设置紧急、RequestToQC QC通过、不通过 - //[HttpPut("{trialId:guid}/{subjectVisitId:guid}")] - //public async Task SignClinicalData(Guid trialId, Guid subjectVisitId) - //{ - // await _repository.UpdateFromQueryAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { ClinicalDataSignTime = DateTime.Now, ClinicalDataSignUserId = _userInfo.Id }); - - // return ResponseOutput.Ok(); - //} /// @@ -1097,8 +1090,14 @@ namespace IRaCIS.Core.Application.Image.QA } - if (await _subjectVisitRepository.AnyAsync(t => t.IsTake && t.SubjectId != dbSubjectVisit.SubjectId && t.CurrentActionUserId == _userInfo.Id && t.TrialId == dbSubjectVisit.TrialId)) + if (await _subjectVisitRepository.AnyAsync(t => t.IsTake && + t.SubjectId != dbSubjectVisit.SubjectId && + t.CurrentActionUserId == _userInfo.Id && + t.TrialId == dbSubjectVisit.TrialId + )) { + + return ResponseOutput.NotOk("您已经领取了其他受试者,完成后才允许领取新的受试者"); } diff --git a/IRaCIS.Core.Application/Service/Visit/SubjectService.cs b/IRaCIS.Core.Application/Service/Visit/SubjectService.cs index 64c91217d..c24d1717f 100644 --- a/IRaCIS.Core.Application/Service/Visit/SubjectService.cs +++ b/IRaCIS.Core.Application/Service/Visit/SubjectService.cs @@ -5,6 +5,7 @@ using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Domain.Share; using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Application.Service.Inspection.Interface; +using IRaCIS.Core.Infrastructure; using Newtonsoft.Json; namespace IRaCIS.Application.Services @@ -14,11 +15,13 @@ namespace IRaCIS.Application.Services { private readonly IRepository _subjectRepository; private readonly IInspectionService _inspectionService; + private readonly IRepository _subjectVisitRepository; - public SubjectService(IRepository subjectRepository, IInspectionService inspectionService) + public SubjectService(IRepository subjectRepository, IInspectionService inspectionService,IRepository subjectVisitRepository) { _subjectRepository = subjectRepository; - this._inspectionService = inspectionService; + _inspectionService = inspectionService; + _subjectVisitRepository = subjectVisitRepository; } /// @@ -31,7 +34,6 @@ namespace IRaCIS.Application.Services [TypeFilter(typeof(TrialResourceFilter))] public async Task> AddOrUpdateSubject([FromBody] SubjectCommand subjectCommand) { - bool isadd = false; if (await _repository.AnyAsync(t => t.Id == subjectCommand.TrialId && !t.VisitPlanConfirmed)) { return ResponseOutput.NotOk("The trial visit plan has not been confirmed yet.Please contact the project manager to confirm the visit plan before adding subject."); @@ -43,18 +45,25 @@ namespace IRaCIS.Application.Services VerifyMsg = "A subjects with the same subject ID already existed in this trial." }; - var mapedSubject = await _subjectRepository.InsertOrUpdateAsync(subjectCommand, false, verifyExp1/*, verifyExp2*/); + + bool isadd = false; + + Subject mapedSubject = null; if (subjectCommand.Id == null) //insert { isadd = true; - var IsEnrollementQualificationConfirm = await _repository.Where(t => t.Id == mapedSubject.TrialId).Select(u => u.IsEnrollementQualificationConfirm).FirstOrDefaultAsync(); + + mapedSubject= await _subjectRepository.InsertFromDTOAsync(subjectCommand, false, verifyExp1); + //添加受试者的时候,获取访视计划列表,添加到受试者访视表。 var visitPlan = await _repository.Where(t => t.TrialId == subjectCommand.TrialId).ToListAsync(); var svlist = _mapper.Map>(visitPlan); + var IsEnrollementQualificationConfirm = await _repository.Where(t => t.Id == mapedSubject.TrialId).Select(u => u.IsEnrollementQualificationConfirm).FirstOrDefaultAsync(); + svlist.ForEach(t => { t.TrialId = subjectCommand.TrialId; @@ -66,35 +75,16 @@ namespace IRaCIS.Application.Services } else //update { - //变更site - if (mapedSubject.SiteId != subjectCommand.SiteId) - { - - await _repository.BatchUpdateAsync(t => t.SubjectId == mapedSubject.Id, - u => new SubjectVisit() { SiteId = mapedSubject.SiteId }); - - await _repository.BatchUpdateAsync(t => t.SubjectId == mapedSubject.Id, - u => new DicomStudy() { SiteId = mapedSubject.SiteId }); - - - }; - ////如果访视结束了 需要删除计划外未执行的访视 - //if (mapedSubject.Status == SubjectStatus.EndOfVisit) - //{ - // await _repository.DeleteFromQueryAsync(t => t.VisitExecuted == VisitExecutedEnum.UnExecuted && t.SubjectId == mapedSubject.Id && t.InPlan == false); - //} - - ////如果是出组了 将受试者未执行的 设置为不可用 - //if (mapedSubject.Status == SubjectStatus.OutOfEnrollment) - //{ - // await _repository.UpdateFromQueryAsync(t => t.SubjectId == mapedSubject.Id && t.VisitExecuted == VisitExecutedEnum.UnExecuted, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable }); - //} + mapedSubject = await _subjectRepository.UpdateFromDTOAsync(subjectCommand, false,false, verifyExp1/*, verifyExp2*/); + } await _repository.SaveChangesAsync(); + + var createtime = DateTime.Now.AddSeconds(1); // 添加稽查记录 if (isadd) @@ -102,7 +92,7 @@ namespace IRaCIS.Application.Services List datas = new List(); // 移到仓储了 - + //datas.Add(new DataInspection() //{ // TrialId = subjectCommand.TrialId, @@ -127,24 +117,24 @@ namespace IRaCIS.Application.Services SiteId = subjectCommand.SiteId, SubjectId = mapedSubject.Id, SubjectCode = subjectCommand.Code, - SubjectVisitId= item.Id, - SubjectVisitName=item.VisitName, - BlindName=item.BlindName, + SubjectVisitId = item.Id, + SubjectVisitName = item.VisitName, + BlindName = item.BlindName, IsSign = false, CreateTime = visittime, Identification = "Add|Visit|Info|Visit-Image Upload", JsonDetail = JsonConvert.SerializeObject(new { - BlindName=item.BlindName, + BlindName = item.BlindName, VisitName = item.VisitName, VisitNum = item.VisitNum, - IsBaseLine=item.IsBaseLine ? "是" : "否", - VisitExecuted= "否", - IsFinalVisit=item.IsFinalVisit ? "是" : "否", - PDState=item.PDState== PDStateEnum.PDProgress?"是":"否", - InPlan=item.InPlan, - IsUrgent=item.IsUrgent, - IsLostVisit =item.IsLostVisit?"是":"否", + IsBaseLine = item.IsBaseLine ? "是" : "否", + VisitExecuted = "否", + IsFinalVisit = item.IsFinalVisit ? "是" : "否", + PDState = item.PDState == PDStateEnum.PDProgress ? "是" : "否", + InPlan = item.InPlan, + IsUrgent = item.IsUrgent, + IsLostVisit = item.IsLostVisit ? "是" : "否", }) }); @@ -157,7 +147,7 @@ namespace IRaCIS.Application.Services SubjectId = mapedSubject.Id, SubjectCode = subjectCommand.Code, SubjectVisitId = item.Id, - + BlindName = item.BlindName, SubjectVisitName = item.VisitName, IsSign = false, @@ -174,9 +164,9 @@ namespace IRaCIS.Application.Services }) }); } - - await _inspectionService.AddListInspectionRecordAsync(datas); + + await _inspectionService.AddListInspectionRecordAsync(datas); } return ResponseOutput.Ok(mapedSubject.Id.ToString()); @@ -184,19 +174,11 @@ namespace IRaCIS.Application.Services } [HttpPut("{trialId:guid}")] + [UnitOfWork] public async Task UpdateSubjectStatus(SubjectStatusChangeCommand subjectStatusChangeCommand) { - var subject = await _subjectRepository.FirstOrDefaultAsync(t => t.Id == subjectStatusChangeCommand.SubjectId); - if (subject == null) return Null404NotFound(subject); - - _mapper.Map(subjectStatusChangeCommand, subject); - - ////如果访视结束了 需要删除计划外未执行的访视 - //if (subjectStatusChangeCommand.Status == SubjectStatus.EndOfVisit) - //{ - // await _repository.DeleteFromQueryAsync(t => t.VisitExecuted == VisitExecutedEnum.UnExecuted && t.SubjectId == subject.Id && t.InPlan == false); - //} + var dbBeforeSubject = await _subjectRepository.UpdateFromDTOAsync(subjectStatusChangeCommand, true); //如果是出组了 if (subjectStatusChangeCommand.Status == SubjectStatus.OutOfVisit) @@ -205,32 +187,33 @@ namespace IRaCIS.Application.Services if (subjectStatusChangeCommand.FinalSubjectVisitId != null) { - if (await _repository.AnyAsync(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.IsFinalVisit && t.Id != subjectStatusChangeCommand.FinalSubjectVisitId)) + if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.IsFinalVisit && t.Id != subjectStatusChangeCommand.FinalSubjectVisitId)) { - return ResponseOutput.NotOk("该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视"); + + throw new BusinessValidationFailedException( + "该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视"); } - var sv = await _repository.FirstOrDefaultAsync(t => t.Id == subjectStatusChangeCommand.FinalSubjectVisitId).IfNullThrowException(); + var sv = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectStatusChangeCommand.FinalSubjectVisitId).IfNullThrowException(); - if (await _repository.AnyAsync(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.VisitNum > sv.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit)) + if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.VisitNum > sv.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit)) { - return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视"); + + throw new BusinessValidationFailedException( + "该受试者此访视后有影像上传,该访视不允许设置为末次访视"); + } sv.IsFinalVisit = true; //末次访视后的 访视设置为不可用 - await _repository.BatchUpdateAsync(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.VisitNum > sv.VisitNum, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable }); + await _subjectVisitRepository.BatchUpdateAsync(t => t.SubjectId == subjectStatusChangeCommand.SubjectId && t.VisitNum > sv.VisitNum, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable }); } //将受试者未执行的 设置为不可用 - await _repository.BatchUpdateAsync(t => t.SubjectId == subject.Id && t.VisitExecuted == VisitExecutedEnum.UnExecuted, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable }); - } - else - { - + await _subjectVisitRepository.BatchUpdateAsync(t => t.SubjectId == dbBeforeSubject.Id && t.VisitExecuted == VisitExecutedEnum.UnExecuted, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable }); } await _repository.SaveChangesAsync(); @@ -240,25 +223,7 @@ namespace IRaCIS.Application.Services } - [Obsolete] - [HttpGet("{trialId:guid}/{subjectId:guid}/{finalSubjectVisitId:guid}")] - public async Task VerifySubjectFinalVisit(Guid subjectId, Guid finalSubjectVisitId) - { - if (await _repository.AnyAsync(t => t.SubjectId == subjectId && t.IsFinalVisit)) - { - return ResponseOutput.NotOk("该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视"); - } - - var sv = (await _repository.FirstOrDefaultAsync(t => t.Id == finalSubjectVisitId)).IfNullThrowException(); - - if (await _repository.AnyAsync(t => t.SubjectId == subjectId && t.VisitNum > sv.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit)) - { - return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视"); - } - - return ResponseOutput.Ok(); - } [HttpDelete("{id:guid}/{trialId:guid}")] @@ -268,14 +233,16 @@ namespace IRaCIS.Application.Services public async Task DeleteSubject(Guid id) { - if (await _repository.AnyAsync(u => u.SubjectId == id && u.VisitExecuted == VisitExecutedEnum.Executed)) + if (await _subjectVisitRepository.AnyAsync(u => u.SubjectId == id && u.VisitExecuted == VisitExecutedEnum.Executed)) { return ResponseOutput.NotOk("This subject has executed a visit with uploading study images,and couldn't be deleted."); } var isSuccess = await _subjectRepository.BatchDeleteAsync(u => u.Id == id); - await _repository.BatchDeleteAsync(u => u.SubjectId == id); - var subvisit = await _repository.GetQueryable().Where(x=>x.SubjectId==id).ToListAsync(); + await _subjectVisitRepository.BatchDeleteAsync(u => u.SubjectId == id); + + + var subvisit = await _subjectVisitRepository.Where(x => x.SubjectId == id).ToListAsync(); List datas = new List(); @@ -292,7 +259,7 @@ namespace IRaCIS.Application.Services }); }; - + await _inspectionService.AddListInspectionRecordAsync(datas); return ResponseOutput.Result(isSuccess); @@ -348,6 +315,25 @@ namespace IRaCIS.Application.Services return query.ToList(); } + [Obsolete] + [HttpGet("{trialId:guid}/{subjectId:guid}/{finalSubjectVisitId:guid}")] + public async Task VerifySubjectFinalVisit(Guid subjectId, Guid finalSubjectVisitId) + { + + if (await _repository.AnyAsync(t => t.SubjectId == subjectId && t.IsFinalVisit)) + { + return ResponseOutput.NotOk("该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视"); + } + + var sv = (await _repository.FirstOrDefaultAsync(t => t.Id == finalSubjectVisitId)).IfNullThrowException(); + + if (await _repository.AnyAsync(t => t.SubjectId == subjectId && t.VisitNum > sv.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit)) + { + return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视"); + } + + return ResponseOutput.Ok(); + } } } diff --git a/IRaCIS.Core.Application/Service/Visit/SubjectVisitService.cs b/IRaCIS.Core.Application/Service/Visit/SubjectVisitService.cs index 3d5205019..aa3e7ee55 100644 --- a/IRaCIS.Core.Application/Service/Visit/SubjectVisitService.cs +++ b/IRaCIS.Core.Application/Service/Visit/SubjectVisitService.cs @@ -9,6 +9,7 @@ using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Interfaces; using IRaCIS.Core.Application.Service.Inspection.Interface; using Newtonsoft.Json; +using IRaCIS.Core.Infrastructure; namespace IRaCIS.Core.Application.Services { @@ -31,13 +32,7 @@ namespace IRaCIS.Core.Application.Services [UnitOfWork] public async Task> AddOrUpdateSV(SubjectVisitCommand svCommand) { - bool isadd=false; - - if (svCommand.Id == null) - { - isadd=true; - } - + var verifyExp1 = new EntityVerifyExp() { VerifyExp = t => t.VisitNum == svCommand.VisitNum && t.SubjectId == svCommand.SubjectId, @@ -53,43 +48,60 @@ namespace IRaCIS.Core.Application.Services svCommand.BlindName = "B" + ((int)(svCommand.VisitNum * 10)).ToString("D3"); - - var subject = (await _subjectRepository.FirstOrDefaultAsync(t => t.Id == svCommand.SubjectId)).IfNullThrowException(); - - - - svCommand.VisitExecuted = svCommand.IsLostVisit ? VisitExecutedEnum.Executed : svCommand.VisitExecuted; - //设置末次评估后,不允许添加计划外访视 - if (svCommand.InPlan == false && svCommand.Id == null) + + SubjectVisit dbBeforeEntity = null; + //Add + if (svCommand.Id == null) { - if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit)) + + //设置末次评估后,不允许添加计划外访视 + if (svCommand.InPlan == false) { - return ResponseOutput.NotOk("设置末次评估后,不允许添加计划外访视"); + if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit)) + { + throw new BusinessValidationFailedException("设置末次评估后,不允许添加计划外访视"); + } + } + + dbBeforeEntity = await _subjectVisitRepository.InsertFromDTOAsync(svCommand, false, verifyExp1, verifyExp2); + } + + else + { + dbBeforeEntity = await _subjectVisitRepository.UpdateFromDTOAsync(svCommand, false,false, verifyExp1, verifyExp2); + + if (svCommand.PDState != dbBeforeEntity.PDState && dbBeforeEntity.SubmitState == SubmitStateEnum.Submitted) + { + throw new BusinessValidationFailedException("CRC提交后,不允许修改PD确认状态"); + } + + if (svCommand.PDState != dbBeforeEntity.PDState && dbBeforeEntity.RequestBackState == RequestBackStateEnum.PM_AgressBack) + { + throw new BusinessValidationFailedException("回退的访视,不允许修改PD确认状态"); + } + + if (svCommand.IsLostVisit ) + { + if (await _subjectVisitRepository.AnyAsync(t => t.Id == svCommand.Id && t.SubmitState == SubmitStateEnum.ToSubmit)) + { + throw new BusinessValidationFailedException("该受试者此访视有影像上传,不允许设置为失访"); + } } } - //更新的时候,返回的是数据库此时的实体数据 - var needDealEntity = await _subjectVisitRepository.InsertOrUpdateAsync(svCommand, false, verifyExp1, verifyExp2); - - if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.SubmitState == SubmitStateEnum.Submitted) - { - return ResponseOutput.NotOk("CRC提交后,不允许修改PD确认状态"); - } - if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.RequestBackState == RequestBackStateEnum.PM_AgressBack) - { - return ResponseOutput.NotOk("回退的访视,不允许修改PD确认状态"); - } + var subject = (await _subjectRepository.FirstOrDefaultAsync(t => t.Id == svCommand.SubjectId)).IfNullThrowException(); + if (svCommand.IsFinalVisit) { if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitNum > svCommand.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit)) { - return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视"); + throw new BusinessValidationFailedException("该受试者此访视后有影像上传,该访视不允许设置为末次访视"); } @@ -107,13 +119,7 @@ namespace IRaCIS.Core.Application.Services await _subjectVisitRepository.BatchUpdateAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitExecuted == VisitExecutedEnum.Unavailable, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.UnExecuted }); } - if (svCommand.IsLostVisit && svCommand.Id == null) - { - if (await _subjectVisitRepository.AnyAsync(t => t.Id==svCommand.Id && t.SubmitState == SubmitStateEnum.ToSubmit)) - { - return ResponseOutput.NotOk("该受试者此访视有影像上传,不允许设置为失访"); - } - } + //更新受试者 首次给药日期 是否入组确认 if (svCommand.SubjectFirstGiveMedicineTime != null) @@ -154,6 +160,14 @@ namespace IRaCIS.Core.Application.Services await _repository.SaveChangesAsync(); + bool isadd = false; + + if (svCommand.Id == null) + { + isadd = true; + } + + if (isadd) { List dataInspection=new List(); @@ -198,7 +212,7 @@ namespace IRaCIS.Core.Application.Services - return ResponseOutput.Ok(needDealEntity.Id.ToString()); + return ResponseOutput.Ok(dbBeforeEntity.Id.ToString()); } diff --git a/IRaCIS.Core.Application/Service/Visit/VisitPlanService.cs b/IRaCIS.Core.Application/Service/Visit/VisitPlanService.cs index e67390bae..b4be96fa4 100644 --- a/IRaCIS.Core.Application/Service/Visit/VisitPlanService.cs +++ b/IRaCIS.Core.Application/Service/Visit/VisitPlanService.cs @@ -26,7 +26,7 @@ namespace IRaCIS.Application.Services private readonly IRepository _influnceRepository; private readonly IInspectionService _inspectionService; - public VisitPlanService(IRepository visitStageRepository,IRepository trialRepository, IRepository subjectVisitRepository, + public VisitPlanService(IRepository visitStageRepository, IRepository trialRepository, IRepository subjectVisitRepository, IRepository influnceStatRepository, IRepository visitPlanInfluenceStudy, @@ -61,7 +61,7 @@ namespace IRaCIS.Application.Services var query = _visitStageRepository.AsQueryable(true).Where(u => u.TrialId == trialId) .ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum); var list = await query.ToListAsync(); - var trial = await _repository.FirstOrDefaultAsync(t => t.Id == trialId).IfNullThrowException(); + var trial = (await _repository.FirstOrDefaultAsync(t => t.Id == trialId)).IfNullThrowException(); return new VisitPlanView() { @@ -93,15 +93,14 @@ namespace IRaCIS.Application.Services [UnitOfWork] public async Task> AddOrUpdateVisitStage(VisitPlanCommand visitPlan) { - DateTime createtime = DateTime.Now; - + if (!await _trialRepository.Where(t => t.Id == visitPlan.TrialId).IgnoreQueryFilters().AnyAsync(t => t.TrialStatusStr == StaticData.TrialOngoing || t.TrialStatusStr == StaticData.TrialInitializing)) { throw new BusinessValidationFailedException(" only in Initializing or Ongoing State can operate "); - + } - var visitPlanList = await _visitStageRepository.Where(t => t.TrialId == visitPlan.TrialId,ignoreQueryFilters:true) + var visitPlanList = await _visitStageRepository.Where(t => t.TrialId == visitPlan.TrialId, ignoreQueryFilters: true) .Select(t => new { t.Id, t.VisitNum, t.VisitDay }).OrderBy(t => t.VisitNum).ToListAsync(); //更新的时候,需要排除自己 @@ -116,7 +115,7 @@ namespace IRaCIS.Application.Services if (visitPlan.VisitDay <= visitPlanList.Where(t => t.VisitNum < visitPlan.VisitNum).Select(t => t.VisitDay).Max()) { throw new BusinessValidationFailedException(" For the visit plan, the VisitDay with a larger VisitNum should be larger than the VisitDay with a smaller VisitNum."); - + } } @@ -141,50 +140,20 @@ namespace IRaCIS.Application.Services throw new BusinessValidationFailedException("A visit already is baseline in the current visit plan."); } - //已添加受试者 都不存在该新增的计划名称 那么该项目所有受试者都增加一个访视记录 - if (!await _subjectVisitRepository.AnyAsync(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId)) - { - var subjectSVS = await _subjectVisitRepository.Where(t => t.TrialId == visitPlan.TrialId).Select(t => new { t.SubjectId, t.SiteId,t.IsFinalVisit }).Distinct().ToListAsync(); + //不用前端传递的值 + visitPlan.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3"); - var subjects = subjectSVS.Select(t => new { t.SubjectId, t.SiteId }).Distinct().ToList(); + var visitPlanItem = await _visitStageRepository.InsertFromDTOAsync(visitPlan,true); - foreach (var subject in subjects) - { - var svItem = _mapper.Map(visitPlan); + #region 废弃前 - svItem.SiteId = subject.SiteId; + // var visitPlanItem = _mapper.Map(visitPlan); - svItem.SubjectId = subject.SubjectId; - svItem.Id = NewId.NextGuid(); + //visitPlanItem.BlindName = "B" + ((int)visitPlanItem.VisitNum * 10).ToString("D3"); - //设置了末次访视,那么加访视计划的时候,设置为不可用 - if (subjectSVS.Any(t => t.SubjectId == svItem.SubjectId && t.IsFinalVisit)) - { - svItem.VisitExecuted = VisitExecutedEnum.Unavailable; - } - + //var result = await _visitStageRepository.AddAsync(visitPlanItem,true); + #endregion - - await _repository.AddAsync(svItem); - } - } - - - var visitPlanItem = _mapper.Map(visitPlan); - - visitPlanItem.BlindName = "B" + ((int)visitPlanItem.VisitNum * 10).ToString("D3"); - - //var result = await _visitStageRepository.AddAsync(visitPlanItem); - - var result = await _repository.AddAsync(visitPlanItem); - - - //更新项目访视计划状态为未确认 - await _trialRepository.BatchUpdateAsync(u => u.Id == visitPlan.TrialId, t => new Trial() { VisitPlanConfirmed = false }); - - await _repository.SaveChangesAsync(); - - //return ResponseOutput.Ok(result.Id.ToString()); return ResponseOutput.Ok(visitPlanItem); } @@ -193,22 +162,42 @@ namespace IRaCIS.Application.Services { - if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum) && t.Id != visitPlan.Id,true)) + if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum) && t.Id != visitPlan.Id, true)) { throw new BusinessValidationFailedException("A visit with the same VisitName/VisitNum already existed in the current visit plan."); } - if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine && t.Id != visitPlan.Id,true) && visitPlan.IsBaseLine) + if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine && t.Id != visitPlan.Id, true) && visitPlan.IsBaseLine) { throw new BusinessValidationFailedException("A visit already is baseline in the current visit plan."); } + #region 废弃前 + //var stage = (await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == visitPlan.Id, true)).IfNullThrowException(); - var stage = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == visitPlan.Id,true); - if (stage == null) throw new BusinessValidationFailedException("None"); + ////修改是否是基线 + //if (stage.IsBaseLine && stage.IsBaseLine != visitPlan.IsBaseLine) + //{ + // if (await _repository.Where(t => t.TrialId == visitPlan.TrialId).AnyAsync(v => v.IsBaseLine && v.SubmitState >= SubmitStateEnum.ToSubmit)) + // { + // throw new BusinessValidationFailedException("有CRC已经为基线上传了影像数据,不允许修改基线"); + // } + //} + + //_mapper.Map(visitPlan, stage); + + //stage.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3"); + + //await _visitStageRepository.SaveChangesAsync(); + + #endregion + + //不用前端传递的值 + visitPlan.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3"); + //返回的是数据库查询的数据 + var stage = await _visitStageRepository.UpdateFromDTOAsync(visitPlan,true); - //修改是否是基线 if (stage.IsBaseLine && stage.IsBaseLine != visitPlan.IsBaseLine) { if (await _repository.Where(t => t.TrialId == visitPlan.TrialId).AnyAsync(v => v.IsBaseLine && v.SubmitState >= SubmitStateEnum.ToSubmit)) @@ -217,71 +206,15 @@ namespace IRaCIS.Application.Services } } - _mapper.Map(visitPlan, stage); - stage.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3"); - - //更新项目访视计划状态为未确认 - //await _trialRepository.UpdateFromQueryAsync(u => u.Id == visitPlan.TrialId, t => new Trial() { VisitPlanConfirmed = false }); - - await _repository.SaveChangesAsync(); return ResponseOutput.Ok(stage); - //return ResponseOutput.Ok(); } - - + + } - /// 删除项目计划某一项[New] - [HttpDelete("{id:guid}/{trialId:guid}")] - [TrialAudit(AuditType.TrialAudit, AuditOptType.DeleteTrialVisitPlanItem)] - - [TypeFilter(typeof(TrialResourceFilter))] - public async Task DeleteVisitStage(Guid id) - { - - var visitPlan = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == id); - - if (visitPlan == null) return Null404NotFound(visitPlan); - - if (await _repository.AnyAsync(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId && t.VisitExecuted == VisitExecutedEnum.Executed)) - { - return ResponseOutput.NotOk("The visit plan has been assigned to the subjects and executed."); - } - - - var list = await _subjectVisitRepository.Where(t => t.TrialId == visitPlan.TrialId && t.VisitName == visitPlan.VisitName).ToListAsync(); - - - List datas = new List(); - var createtime = DateTime.Now.AddSeconds(1); - list.ForEach(x => - { - datas.Add(new DataInspection() - { - BlindName = x.BlindName, - IsSign = false, - SiteId = x.SiteId, - SubjectId = x.SubjectId, - SubjectVisitId = x.Id, - CreateTime = createtime, - SubjectVisitName = x.VisitName, - TrialId = x.TrialId, - JsonDetail = JsonConvert.SerializeObject(x), - Identification = "Delete|Visit|Data|Visit-Image Upload" - }); - }); - - - await _inspectionService.AddListInspectionRecordAsync(datas); - await _repository.BatchDeleteAsync(t => t.TrialId == visitPlan.TrialId && t.VisitName == visitPlan.VisitName); - - var result = await _visitStageRepository.BatchDeleteAsync(u => u.Id == id); - - return ResponseOutput.Result(result); - } [UnitOfWork] @@ -290,7 +223,7 @@ namespace IRaCIS.Application.Services public async Task ConfirmTrialVisitPlan(Guid trialId) { - if (!await _trialRepository.AnyAsync(t => t.Id == trialId &&( t.TrialStatusStr==StaticData.TrialInitializing || t.TrialStatusStr == StaticData.TrialOngoing))) + if (!await _trialRepository.AnyAsync(t => t.Id == trialId && (t.TrialStatusStr == StaticData.TrialInitializing || t.TrialStatusStr == StaticData.TrialOngoing))) { return ResponseOutput.NotOk("仅仅在项目初始化或者进行中时,才允许修改确认"); } @@ -314,23 +247,34 @@ namespace IRaCIS.Application.Services List datas = new List(); - var addvisitStages = await _visitStageRepository.Where(x => !x.IsHaveFirstConfirmed&&x.TrialId== trialId).ToListAsync(); + var addvisitStages = await _visitStageRepository.Where(x => !x.IsHaveFirstConfirmed && x.TrialId == trialId).ToListAsync(); //更新项目访视计划状态为已确认 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) - .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, + .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 createtime = DateTime.Now.AddSeconds(1); changedList.ForEach(x => { - + datas.Add(new DataInspection() { IsSign = false, @@ -341,16 +285,16 @@ namespace IRaCIS.Application.Services TrialId = x.TrialId, JsonDetail = JsonConvert.SerializeObject(x), Identification = "Confirm|Visit Plan Template|Data|Trial Setting-Visit Plan", - + }); }); //访视计划 整体状态变更为 确认 - await _visitStageRepository.BatchUpdateAsync(u => u.TrialId == trialId, t => new VisitStage() { IsConfirmed = true ,IsHaveFirstConfirmed = true}); + 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) { //找到该项目 访视已经执行,并且配置了有首次给药日期 并且更新后超窗的访视,要把超窗之前的值也要查询出来 @@ -463,8 +407,8 @@ namespace IRaCIS.Application.Services } - - + + var list = await _subjectVisitRepository.Where(t => t.TrialId == trialId && t.VisitStageId == changedItem.Id).ToListAsync(); list.ForEach(x => @@ -479,8 +423,9 @@ namespace IRaCIS.Application.Services CreateTime = createtime, SubjectVisitName = x.VisitName, TrialId = x.TrialId, - Reason="确认访视修改状态", - JsonDetail = JsonConvert.SerializeObject(new { + Reason = "确认访视修改状态", + JsonDetail = JsonConvert.SerializeObject(new + { IsBaseLine = changedItem.IsBaseLine, VisitName = changedItem.VisitName, VisitNum = changedItem.VisitNum, @@ -514,14 +459,14 @@ namespace IRaCIS.Application.Services x.IsUrgent }); - + List subjectVisits = new List(); - var trial =await _repository.GetQueryable().FirstOrDefaultAsync(x => x.Id == trialId); - - + var trial = await _repository.GetQueryable().FirstOrDefaultAsync(x => x.Id == trialId); + + addvisitStages.ForEach(x => { subjectsids.ForEach(y => @@ -531,7 +476,7 @@ namespace IRaCIS.Application.Services // datas.Add(new DataInspection() { - Id= dataindtid, + Id = dataindtid, BlindName = x.BlindName, IsSign = false, SiteId = y.SiteId, @@ -547,14 +492,14 @@ namespace IRaCIS.Application.Services VisitName = x.VisitName, VisitNum = x.VisitNum, VisitDay = x.VisitDay, - VisitExecuted=false, - BlindName=x.BlindName, + VisitExecuted = false, + BlindName = x.BlindName, VisitWindowLeft = x.VisitWindowLeft, VisitWindowRight = x.VisitWindowRight, - IsEnrollment=y.IsEnrollment, + IsEnrollment = y.IsEnrollment, IsUrgent = trial.IsSubjectExpeditedView, - IsFinalVisit=false, - IsLostVisit= false, + IsFinalVisit = false, + IsLostVisit = false, PDState = trial.IsPDProgressView, }), }); @@ -570,7 +515,7 @@ namespace IRaCIS.Application.Services ParentId = dataindtid, SubjectVisitName = x.VisitName, IsSign = false, - TrialId=x.TrialId, + TrialId = x.TrialId, CreateTime = createtime.AddMilliseconds(500), Identification = "Init|Visit|Status|Visit-Image Upload", JsonDetail = JsonConvert.SerializeObject(new @@ -595,18 +540,18 @@ namespace IRaCIS.Application.Services subjectVisits.Add(new SubjectVisit() { - + SiteId = y.SiteId, SubjectId = y.Id, Id = guid, - VisitName=x.VisitName, - - BlindName=x.BlindName, - IsBaseLine=x.IsBaseLine, - IsCheckBack=x.IsBaseLine, - IsUrgent= trial.IsSubjectExpeditedView, - - + VisitName = x.VisitName, + + BlindName = x.BlindName, + IsBaseLine = x.IsBaseLine, + IsCheckBack = x.IsBaseLine, + IsUrgent = trial.IsSubjectExpeditedView, + + }); }); @@ -621,7 +566,7 @@ namespace IRaCIS.Application.Services } - + [HttpGet("{trialId:guid}")] public async Task> GetInfluenceHistoryList(Guid trialId, [FromServices] IRepository _influnceStatRepository) @@ -649,5 +594,30 @@ namespace IRaCIS.Application.Services } + /// 删除项目计划某一项 废弃 + [HttpDelete("{id:guid}/{trialId:guid}")] + [TrialAudit(AuditType.TrialAudit, AuditOptType.DeleteTrialVisitPlanItem)] + [TypeFilter(typeof(TrialResourceFilter))] + [Obsolete] + public async Task DeleteVisitStage(Guid id) + { + + var visitPlan = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == id); + + if (visitPlan == null) return Null404NotFound(visitPlan); + + if (await _repository.AnyAsync(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId && t.VisitExecuted == VisitExecutedEnum.Executed)) + { + return ResponseOutput.NotOk("The visit plan has been assigned to the subjects and executed."); + } + + await _repository.BatchDeleteAsync(t => t.TrialId == visitPlan.TrialId && t.VisitName == visitPlan.VisitName); + + var result = await _visitStageRepository.BatchDeleteAsync(u => u.Id == id); + + return ResponseOutput.Result(result); + } + + } } \ No newline at end of file diff --git a/IRaCIS.Core.Application/Service/Visit/_MapConfig.cs b/IRaCIS.Core.Application/Service/Visit/_MapConfig.cs index 0e885dead..51cbcc824 100644 --- a/IRaCIS.Core.Application/Service/Visit/_MapConfig.cs +++ b/IRaCIS.Core.Application/Service/Visit/_MapConfig.cs @@ -30,7 +30,8 @@ namespace IRaCIS.Core.Application.Service - CreateMap(); + CreateMap() + .ForMember(d => d.Id, t => t.MapFrom(u=>u.SubjectId)); CreateMap(); CreateMap() diff --git a/IRaCIS.Core.Application/Triggers/AddVisitPlanTrigger.cs b/IRaCIS.Core.Application/Triggers/AddVisitPlanTrigger.cs new file mode 100644 index 000000000..7cb2ef195 --- /dev/null +++ b/IRaCIS.Core.Application/Triggers/AddVisitPlanTrigger.cs @@ -0,0 +1,56 @@ +using AutoMapper; +using EntityFrameworkCore.Triggered; +using IRaCIS.Core.Domain.Share; +using MassTransit; + +namespace IRaCIS.Core.Application.Triggers +{ + /// + /// 添加访视计划 要给改项目下的所有Subject 添加该访视 + /// + public class AddVisitPlanTrigger : IAfterSaveTrigger + { + private readonly IRepository _subjectVisitRepository; + private readonly IMapper _mapper; + + public AddVisitPlanTrigger(IRepository subjectVisitRepository,IMapper mapper) + { + _subjectVisitRepository = subjectVisitRepository; + _mapper = mapper; + } + + public async Task AfterSave(ITriggerContext context, CancellationToken cancellationToken) + { + var visitPlan = context.Entity; + + if (context.ChangeType == ChangeType.Added) + { + //已添加受试者 都不存在该新增的计划名称 那么该项目所有受试者都增加一个访视记录 + if (!await _subjectVisitRepository.AnyAsync(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId)) + { + var subjectSVS = await _subjectVisitRepository.Where(t => t.TrialId == visitPlan.TrialId).Select(t => new { t.SubjectId, t.SiteId, t.IsFinalVisit }).Distinct().ToListAsync(); + + var subjects = subjectSVS.Select(t => new { t.SubjectId, t.SiteId }).Distinct().ToList(); + + foreach (var subject in subjects) + { + + var svItem = _mapper.Map(visitPlan); + svItem.SiteId = subject.SiteId; + svItem.SubjectId = subject.SubjectId; + svItem.Id = NewId.NextGuid(); + + //设置了末次访视,那么加访视计划的时候,设置为不可用 + if (subjectSVS.Any(t => t.SubjectId == svItem.SubjectId && t.IsFinalVisit)) + { + svItem.VisitExecuted = VisitExecutedEnum.Unavailable; + } + + await _subjectVisitRepository.AddAsync(svItem); + } + } + + } + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Triggers/SubjectStateTrigger.cs b/IRaCIS.Core.Application/Triggers/SubjectStateTrigger.cs new file mode 100644 index 000000000..1acf41545 --- /dev/null +++ b/IRaCIS.Core.Application/Triggers/SubjectStateTrigger.cs @@ -0,0 +1,65 @@ +using AutoMapper; +using EntityFrameworkCore.Triggered; +using IRaCIS.Core.Domain.Share; +using MassTransit; + +namespace IRaCIS.Core.Application.Triggers +{ + /// + /// + /// + public class SubjectStateTrigger : IAfterSaveTrigger + { + private readonly IRepository _subjectVisitRepository; + private readonly IRepository _repository; + private readonly IMapper _mapper; + + public SubjectStateTrigger(IRepository subjectVisitRepository, IRepository repository, IMapper mapper) + { + _subjectVisitRepository = subjectVisitRepository; + _repository = repository; + _mapper = mapper; + } + + public async Task AfterSave(ITriggerContext context, CancellationToken cancellationToken) + { + + if (context.ChangeType == ChangeType.Modified ) + { + //Site变更 + + if ( context.Entity.SiteId != context.UnmodifiedEntity.SiteId) + { + var subjectId = context.Entity.Id; + var siteId = context.Entity.SiteId; + + + await _repository.BatchUpdateAsync(t => t.SubjectId == subjectId, u => new SubjectVisit() { SiteId = siteId }); + + await _repository.BatchUpdateAsync(t => t.SubjectId == subjectId, u => new DicomStudy() { SiteId = siteId }); + + + #region 废弃 + ////如果访视结束了 需要删除计划外未执行的访视 + //if (mapedSubject.Status == SubjectStatus.EndOfVisit) + //{ + // await _repository.DeleteFromQueryAsync(t => t.VisitExecuted == VisitExecutedEnum.UnExecuted && t.SubjectId == mapedSubject.Id && t.InPlan == false); + //} + + ////如果是出组了 将受试者未执行的 设置为不可用 + //if (mapedSubject.Status == SubjectStatus.OutOfEnrollment) + //{ + // await _repository.UpdateFromQueryAsync(t => t.SubjectId == mapedSubject.Id && t.VisitExecuted == VisitExecutedEnum.UnExecuted, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable }); + //} + #endregion + } + + + + + } + + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs b/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs index 29e2f174a..339b8c31b 100644 --- a/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs +++ b/IRaCIS.Core.Infra.EFCore/Repository/ICommandRepository.cs @@ -35,7 +35,7 @@ namespace IRaCIS.Core.Infra.EFCore /// 批量删除,EF跟踪方式(所有查询出来,再删除 浪费性能,但是稽查 或者触发某些操作时,需要知道数据库实体信息 不可避免用这种) - Task TrackingBatchDeleteAsync(Expression> deleteFilter); + Task> TrackingBatchDeleteAsync(Expression> deleteFilter); } diff --git a/IRaCIS.Core.Infra.EFCore/Repository/Repository.cs b/IRaCIS.Core.Infra.EFCore/Repository/Repository.cs index d8a001307..79a1e897a 100644 --- a/IRaCIS.Core.Infra.EFCore/Repository/Repository.cs +++ b/IRaCIS.Core.Infra.EFCore/Repository/Repository.cs @@ -242,7 +242,7 @@ namespace IRaCIS.Core.Infra.EFCore /// 批量删除,EF跟踪方式(所有查询出来,再删除 浪费性能,但是稽查 或者触发某些操作时,需要知道数据库实体信息 不可避免用这种) - public async Task TrackingBatchDeleteAsync(Expression> deleteFilter) + public async Task> TrackingBatchDeleteAsync(Expression> deleteFilter) { var waitDeleteList = await _dbSet.IgnoreQueryFilters().Where(deleteFilter).ToListAsync(); @@ -250,6 +250,7 @@ namespace IRaCIS.Core.Infra.EFCore { await DeleteAsync(deleteItem, false); } + return waitDeleteList; }