670 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			670 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			C#
		
	
	
| using IRaCIS.Application.Contracts;
 | ||
| using IRaCIS.Application.Interfaces;
 | ||
| using IRaCIS.Core.Application.Filter;
 | ||
| using IRaCIS.Core.Application.Helper;
 | ||
| using IRaCIS.Core.Domain.Share;
 | ||
| using IRaCIS.Core.Infrastructure;
 | ||
| using Microsoft.AspNetCore.Authorization;
 | ||
| using Microsoft.AspNetCore.Mvc;
 | ||
| using Microsoft.Extensions.Options;
 | ||
| using Panda.DynamicWebApi.Attributes;
 | ||
| using ZiggyCreatures.Caching.Fusion;
 | ||
| 
 | ||
| namespace IRaCIS.Core.Application.Service
 | ||
| {
 | ||
| 
 | ||
|     [ApiExplorerSettings(GroupName = "Trial")]
 | ||
| 
 | ||
|     public class TrialService(IRepository<Trial> _trialRepository,
 | ||
|         IRepository<TrialUser> _trialUserRepository,
 | ||
|         IRepository<CRO> _croRepository,
 | ||
|         IRepository<EnrollDetail> _enrollDetailRepository,
 | ||
|         IRepository<Dictionary> _dictionaryRepository,
 | ||
|         IRepository<Enroll> _enrollRepository,
 | ||
|         IRepository<Workload> _workloadRepository,
 | ||
|         IRepository<Sponsor> _sponsorRepository,
 | ||
|         IRepository<VisitStage> _visitStageRepository,
 | ||
|         IRepository<TrialPaymentPrice> _trialPaymentPriceRepository,
 | ||
|         IRepository<TrialDictionary> _trialDictionaryRepository,
 | ||
|         IRepository<TrialBodyPart> _trialBodyPartRepository,
 | ||
|         IOptionsMonitor<ServiceVerifyConfigOption> _verifyConfig,
 | ||
|         IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, ITrialService
 | ||
|     {
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         public bool TrialExpeditedChange { get; set; } = false;
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 分页获取临床项目列表  默认后台加急状态为3 查所有的   
 | ||
|         /// </summary>
 | ||
|         /// <param name="inQuery"></param>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpPost]
 | ||
|         public async Task<PageOutput<TrialDetailDTO>> GetTrialList(TrialQueryDTO inQuery)
 | ||
|         {
 | ||
| 
 | ||
|             var multiModalityIdSelectCount = inQuery.ModalityIds.Count;
 | ||
|             var multiCriteriaSelectCount = inQuery.CriterionIds.Count;
 | ||
|             var multiReviewTypeSelectCount = inQuery.ReviewTypeIds.Count;
 | ||
| 
 | ||
|             Expression<Func<Trial, bool>> trialDeclarationTypeExpression = x => true;
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             foreach (var item in inQuery.DeclarationTypeEnumList)
 | ||
|             {
 | ||
|                 trialDeclarationTypeExpression = trialDeclarationTypeExpression.And(t => t.DeclarationTypes.Contains($"|{item}|"));
 | ||
|             }
 | ||
| 
 | ||
|             Expression<Func<Trial, bool>> trialAttendedReviewerTypeExpression = x => true;
 | ||
| 
 | ||
|             foreach (var item in inQuery.AttendedReviewerTypeEnumList)
 | ||
|             {
 | ||
|                 trialAttendedReviewerTypeExpression = trialAttendedReviewerTypeExpression.And(t => t.AttendedReviewerTypes.Contains($"|{item}|"));
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             var query = _trialRepository.AsQueryable()
 | ||
|                 .WhereIf(!string.IsNullOrEmpty(inQuery.TrialStatusStr), o => o.TrialStatusStr.Contains(inQuery.TrialStatusStr))
 | ||
|                 .WhereIf(inQuery.SponsorId != null, o => o.SponsorId == inQuery.SponsorId)
 | ||
|                 .WhereIf(inQuery.Expedited != null, o => o.Expedited == inQuery.Expedited)
 | ||
|                 .WhereIf(!string.IsNullOrEmpty(inQuery.Code), o => o.TrialCode.Contains(inQuery.Code))
 | ||
|                 .WhereIf(!string.IsNullOrWhiteSpace(inQuery.Indication), o => o.Indication.Contains(inQuery.Indication))
 | ||
|                 .WhereIf(!string.IsNullOrEmpty(inQuery.ResearchProgramNo), o => o.ResearchProgramNo.Contains(inQuery.ResearchProgramNo))
 | ||
|                 .WhereIf(!string.IsNullOrWhiteSpace(inQuery.ExperimentName), o => o.ExperimentName.Contains(inQuery.ExperimentName))
 | ||
|                 .WhereIf(inQuery.PhaseId != null, o => o.PhaseId == inQuery.PhaseId)
 | ||
| 
 | ||
|                 .WhereIf(inQuery.DeclarationTypeEnumList.Count > 0, trialDeclarationTypeExpression)
 | ||
|                 .WhereIf(inQuery.AttendedReviewerTypeEnumList.Count > 0, trialAttendedReviewerTypeExpression)
 | ||
| 
 | ||
|                 //.WhereIf(searchParam.AttendedReviewerType != null, o => o.AttendedReviewerType == searchParam.AttendedReviewerType)
 | ||
| 
 | ||
|                 .WhereIf(inQuery.IndicationTypeId != null, o => o.IndicationTypeId == inQuery.IndicationTypeId)
 | ||
|                 .WhereIf(inQuery.CROId != null, o => o.CROId == inQuery.CROId)
 | ||
|                 .WhereIf(inQuery.BeginDate != null, o => o.CreateTime >= inQuery.BeginDate)
 | ||
|                 .WhereIf(inQuery.EndDate != null, o => o.CreateTime <= inQuery.EndDate)
 | ||
| 
 | ||
|                 .WhereIf(multiModalityIdSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.Modality) == multiModalityIdSelectCount)
 | ||
|                 .WhereIf(multiCriteriaSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.Criterion) == multiCriteriaSelectCount)
 | ||
|                 .WhereIf(multiReviewTypeSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.ReviewType) == multiReviewTypeSelectCount)
 | ||
|                 .WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id && t.IsDeleted == false) && t.IsDeleted == false)
 | ||
|                 .ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id, isEn_Us = _userInfo.IsEn_Us });
 | ||
| 
 | ||
|             return await query.ToPagedListAsync(inQuery);
 | ||
| 
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
|         //过滤废除的项目
 | ||
|         public async Task<List<TrialSelectDTO>> GetTrialSelect()
 | ||
|         {
 | ||
|             return await _trialRepository.AsQueryable()
 | ||
|                 .WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.Admin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.OP, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id) && t.IsDeleted == false)
 | ||
| 
 | ||
|                 .ProjectTo<TrialSelectDTO>(_mapper.ConfigurationProvider).ToListAsync();
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取项目基本信息
 | ||
|         /// </summary>
 | ||
|         /// <param name="projectId"></param>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpGet("{projectId:guid}")]
 | ||
|         public async Task<TrialDetailDTO> GetTrialInfoAndLockState(Guid projectId)
 | ||
|         {
 | ||
|             return (await _trialRepository.Where(o => o.Id == projectId).ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { isEn_Us = _userInfo.IsEn_Us }).FirstOrDefaultAsync()).IfNullThrowException();
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         [NonDynamicMethod]
 | ||
|         public async Task<int> GetTrialMaxState(Guid trialId)
 | ||
|         {
 | ||
|             return await _enrollDetailRepository.Where(t => t.TrialId == trialId).MaxAsync(u => (int?)u.EnrollStatus) ?? 0;
 | ||
|         }
 | ||
| 
 | ||
|         [HttpGet("{trialId:guid}")]
 | ||
|         public async Task<TrialAndTrialStateVieModel> GetTrialInfoAndMaxTrialState(Guid trialId)
 | ||
|         {
 | ||
|             return new TrialAndTrialStateVieModel()
 | ||
|             {
 | ||
|                 TrialView = await GetTrialInfoAndLockState(trialId),
 | ||
|                 TrialMaxState = await GetTrialMaxState(trialId)
 | ||
|             };
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         [HttpGet("{trialId:guid}")]
 | ||
|         public async Task<int> GetTrialExpeditedState(Guid trialId)
 | ||
|         {
 | ||
|             var trial = (await _trialRepository.FirstOrDefaultAsync(u => u.Id == trialId)).IfNullThrowException();
 | ||
| 
 | ||
|             return trial.Expedited;
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 添加项目
 | ||
|         /// </summary>
 | ||
|         /// <param name="trialAddModel"></param>
 | ||
|         /// <returns></returns>
 | ||
|         [NonDynamicMethod]
 | ||
|         public virtual async Task<IResponseOutput<Trial>> AddOrUpdateTrial(TrialCommand trialAddModel)
 | ||
|         {
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             //测试用户 只能创建非正式项目
 | ||
|             if (_userInfo.IsTestUser && trialAddModel.TrialType != TrialType.NoneOfficial)
 | ||
|             {
 | ||
|                 //---测试用户 只能创建非正式项目
 | ||
|                 throw new BusinessValidationFailedException(_localizer["Trial_TestUserCreateOnlyNonFormal"]);
 | ||
|             }
 | ||
| 
 | ||
|             if (trialAddModel.Id == Guid.Empty || trialAddModel.Id == null)
 | ||
|             {
 | ||
|                 if (await _trialRepository.AnyAsync(u => u.TrialCode == trialAddModel.TrialCode))
 | ||
|                 {
 | ||
|                     //---已经存在相同的项目编号。
 | ||
|                     throw new BusinessValidationFailedException(_localizer["Trial_DuplicateProjectNumber"]);
 | ||
|                 }
 | ||
| 
 | ||
|                 var dbMaxCode = await _trialRepository.Where(t => t.CreateTime.Year == DateTime.Now.Year && t.TrialType == trialAddModel.TrialType).Select(t => t.Code).DefaultIfEmpty().MaxAsync();
 | ||
| 
 | ||
|                 var currentYearMaxCodeNext = dbMaxCode + 1;
 | ||
| 
 | ||
|                 //var test = _trialRepository.Where(t => t.CreateTime.Year == DateTime.Now.Year + 1).Select(t => t.Code).DefaultIfEmpty(1).ToList();
 | ||
| 
 | ||
|                 var trial = _mapper.Map<Trial>(trialAddModel);
 | ||
|                 //trial.Id = NewId.NextGuid();
 | ||
|                 var yearStr = DateTime.Now.Year.ToString();
 | ||
| 
 | ||
|                 trial.Code = currentYearMaxCodeNext;
 | ||
|                 trial.TrialCode = (trial.TrialType == TrialType.NoneOfficial ? "T0" : yearStr.Substring(yearStr.Length - 2)) + trial.TrialCode + currentYearMaxCodeNext.ToString("D3");
 | ||
| 
 | ||
| 
 | ||
|                 trial.DeclarationTypes = $"|{string.Join('|', trialAddModel.DeclarationTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
 | ||
|                 trial.AttendedReviewerTypes = $"|{string.Join('|', trialAddModel.AttendedReviewerTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
 | ||
| 
 | ||
|                 //多选信息
 | ||
|                 trialAddModel.ModalityIds.ForEach(modalityId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = modalityId, KeyName = StaticData.Modality, TrialId = trial.Id }));
 | ||
|                 trialAddModel.CriterionIds.ForEach(criterionId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = criterionId, KeyName = StaticData.Criterion, TrialId = trial.Id }));
 | ||
|                 trialAddModel.ReviewTypeIds.ForEach(ReviewTypeId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = ReviewTypeId, KeyName = StaticData.ReviewType, TrialId = trial.Id }));
 | ||
| 
 | ||
|                 //添加项目后 项目状态变更为申请下载简历
 | ||
|                 trial.TrialEnrollStatus = (int)TrialEnrollStatus.ChooseDoctor;
 | ||
|                 //trial.TrialStatusStr = StaticData.TrialInitializing;
 | ||
| 
 | ||
|                 //状态变更详细表
 | ||
|                 trial.ClinicalTrialProjectDetails.Add(new TrialStatusDetail() { TrialId = trial.Id, TrialStatus = (int)TrialEnrollStatus.ChooseDoctor });
 | ||
| 
 | ||
|                 trial = await _trialRepository.AddAsync(trial);
 | ||
| 
 | ||
|                 //如果是PM, 则需要将该人员添加到 运维人员表
 | ||
|                 //添加运维人员PM 
 | ||
|                 await _trialUserRepository.AddAsync(new TrialUser() { TrialId = trial.Id, UserId = _userInfo.Id, JoinTime = DateTime.Now });
 | ||
| 
 | ||
|                 // 添加扩展信息表记录
 | ||
|                 await _trialPaymentPriceRepository.AddAsync(new TrialPaymentPrice() { TrialId = trial.Id });
 | ||
| 
 | ||
|                 //添加访视
 | ||
|                 await _visitStageRepository.AddAsync(new VisitStage { TrialId = trial.Id, VisitNum = 0, BlindName = "B" + 0.ToString("D3"), VisitDay = 0, VisitName = "Baseline", IsBaseLine = true, VisitWindowLeft = -28, VisitWindowRight = 0 });
 | ||
|                 await _visitStageRepository.AddAsync(new VisitStage { TrialId = trial.Id, VisitNum = 1, BlindName = "B" + 10.ToString("D3"), VisitDay = 30, VisitName = "Visit 1", VisitWindowLeft = -5, VisitWindowRight = 5 });
 | ||
| 
 | ||
| 
 | ||
|                 var success = await _trialRepository.SaveChangesAsync();
 | ||
| 
 | ||
|                 //维护CRO Sponsor
 | ||
|                 await DealSponsorAndCROAsync(trial);
 | ||
| 
 | ||
|                 //维护部位到项目表
 | ||
|                 var searchList = await _dictionaryRepository.Where(t => t.Parent.Code == "BodyPart" && t.ParentId != null && t.IsEnable).ProjectTo<BasicDicSelect>(_mapper.ConfigurationProvider).ToListAsync();
 | ||
| 
 | ||
|                 var needAddBodyPartList = searchList.Select(t => new TrialBodyPart() { Code = t.Code, Name = t.Value, NameCN = t.ValueCN }).ToList();
 | ||
| 
 | ||
|                 foreach (var item in needAddBodyPartList)
 | ||
|                 {
 | ||
|                     item.TrialId = trial.Id;
 | ||
|                 }
 | ||
| 
 | ||
| 
 | ||
|                 await _trialBodyPartRepository.AddRangeAsync(needAddBodyPartList, true);
 | ||
| 
 | ||
|                 await _fusionCache.SetAsync(CacheKeys.Trial(trial.Id.ToString()), StaticData.TrialState.TrialInitializing, TimeSpan.FromDays(7));
 | ||
| 
 | ||
|                 return ResponseOutput.Ok(trial);
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 var updateModel = trialAddModel;
 | ||
| 
 | ||
|                 if (!await _trialRepository.AnyAsync(u => u.Id == trialAddModel.Id && (u.TrialStatusStr == StaticData.TrialState.TrialInitializing || u.TrialStatusStr == StaticData.TrialState.TrialOngoing)))
 | ||
|                 {
 | ||
|                     //---项目状态只有处于:初始化或者进行中时,才允许操作。
 | ||
|                     throw new BusinessValidationFailedException(_localizer["Trial_InvalidProjectStatus"]);
 | ||
| 
 | ||
|                 }
 | ||
|                 // 判断项目Id 是否已经存在
 | ||
|                 if (await _trialRepository.AnyAsync(u => u.TrialCode == updateModel.TrialCode && u.Id != updateModel.Id))
 | ||
|                 {
 | ||
|                     //---已经存在相同的项目编号。
 | ||
|                     throw new BusinessValidationFailedException(_localizer["Trial_DuplicateProjectNumber"]);
 | ||
|                 }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|                 var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == updateModel.Id);
 | ||
| 
 | ||
| 
 | ||
|                 //删除中间表  Title对应的记录
 | ||
|                 await _trialDictionaryRepository.BatchDeleteNoTrackingAsync(t => t.TrialId == updateModel.Id);
 | ||
| 
 | ||
|                 //重新插入新的 Title记录
 | ||
| 
 | ||
|                 updateModel.ModalityIds.ForEach(modalityId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = modalityId, KeyName = StaticData.Modality, TrialId = trial.Id }));
 | ||
|                 updateModel.CriterionIds.ForEach(criterionId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = criterionId, KeyName = StaticData.Criterion, TrialId = trial.Id }));
 | ||
|                 updateModel.ReviewTypeIds.ForEach(ReviewTypeId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = ReviewTypeId, KeyName = StaticData.ReviewType, TrialId = trial.Id }));
 | ||
| 
 | ||
| 
 | ||
|                 if (updateModel.Expedited != trial.Expedited && updateModel.Expedited != null)
 | ||
|                 {
 | ||
|                     TrialExpeditedChange = true;
 | ||
|                     await TrialExpeditedStatusChange(trial.Id, trial.Expedited, (int)updateModel.Expedited);
 | ||
|                 }
 | ||
|                 _mapper.Map(updateModel, trial);
 | ||
| 
 | ||
|                 trial.DeclarationTypes = $"|{string.Join('|', updateModel.DeclarationTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
 | ||
|                 trial.AttendedReviewerTypes = $"|{string.Join('|', updateModel.AttendedReviewerTypeEnumList.Select(x => ((int)x).ToString()).ToList())}|";
 | ||
| 
 | ||
|                 var success = await _trialRepository.SaveChangesAsync();
 | ||
| 
 | ||
|                 //维护CRO Sponsor
 | ||
|                 await DealSponsorAndCROAsync(trial);
 | ||
| 
 | ||
|                 return ResponseOutput.Ok(trial);
 | ||
| 
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         private async Task DealSponsorAndCROAsync(Trial trial)
 | ||
|         {
 | ||
|             if (trial.SponsorId != null)
 | ||
|             {
 | ||
|                 if (await _sponsorRepository.AnyAsync(t => t.Id == trial.SponsorId && t.IsTrialLevel))
 | ||
|                 {
 | ||
|                     await _sponsorRepository.BatchUpdateNoTrackingAsync(t => t.Id == trial.SponsorId, u => new Sponsor() { TrialId = trial.Id });
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
|             if (trial.CROId != null)
 | ||
|             {
 | ||
|                 if (await _croRepository.AnyAsync(t => t.Id == trial.CROId && t.IsTrialLevel))
 | ||
|                 {
 | ||
|                     await _croRepository.BatchUpdateNoTrackingAsync(t => t.Id == trial.CROId, u => new CRO() { TrialId = trial.Id });
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         // TODO: 需要优化,嵌套两层 switch case ?
 | ||
|         [NonDynamicMethod]
 | ||
|         private async Task TrialExpeditedStatusChange(Guid trialId, int oldState, int newState)
 | ||
|         {
 | ||
|             switch (oldState)
 | ||
|             {
 | ||
|                 case (int)TrialExpedited.None:
 | ||
|                     switch (newState)
 | ||
|                     {
 | ||
|                         case (int)TrialExpedited.ExpeditedIn24H:
 | ||
|                             await _workloadRepository.BatchUpdateNoTrackingAsync(t => t.IsLock == false && t.TrialId == trialId, u => new Workload()
 | ||
|                             {
 | ||
|                                 TimepointIn24H = u.Timepoint,
 | ||
|                                 AdjudicationIn24H = u.Adjudication,
 | ||
|                                 Timepoint = 0,
 | ||
|                                 Adjudication = 0
 | ||
|                             });
 | ||
|                             break;
 | ||
|                         case (int)TrialExpedited.ExpeditedIn48H:
 | ||
|                             await _workloadRepository.BatchUpdateNoTrackingAsync(t => t.IsLock == false && t.TrialId == trialId, u => new Workload()
 | ||
|                             {
 | ||
|                                 TimepointIn48H = u.Timepoint,
 | ||
|                                 AdjudicationIn48H = u.Adjudication,
 | ||
|                                 Timepoint = 0,
 | ||
|                                 Adjudication = 0
 | ||
|                             });
 | ||
|                             break;
 | ||
|                     }
 | ||
|                     //_workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload()
 | ||
|                     //{
 | ||
|                     //    Timepoint = 0,
 | ||
|                     //    Adjudication = 0
 | ||
|                     //});
 | ||
| 
 | ||
|                     break;
 | ||
|                 case (int)TrialExpedited.ExpeditedIn24H:
 | ||
| 
 | ||
|                     switch (newState)
 | ||
|                     {
 | ||
|                         case (int)TrialExpedited.None:
 | ||
|                             await _workloadRepository.BatchUpdateNoTrackingAsync(t => t.IsLock == false && t.TrialId == trialId, u => new Workload()
 | ||
|                             {
 | ||
|                                 Timepoint = u.TimepointIn24H,
 | ||
|                                 Adjudication = u.AdjudicationIn24H,
 | ||
|                                 TimepointIn24H = 0,
 | ||
|                                 AdjudicationIn24H = 0
 | ||
|                             });
 | ||
|                             break;
 | ||
|                         case (int)TrialExpedited.ExpeditedIn48H:
 | ||
|                             await _workloadRepository.BatchUpdateNoTrackingAsync(t => t.IsLock == false && t.TrialId == trialId, u => new Workload()
 | ||
|                             {
 | ||
|                                 TimepointIn48H = u.TimepointIn24H,
 | ||
|                                 AdjudicationIn48H = u.AdjudicationIn24H,
 | ||
|                                 TimepointIn24H = 0,
 | ||
|                                 AdjudicationIn24H = 0
 | ||
|                             });
 | ||
| 
 | ||
|                             break;
 | ||
|                     }
 | ||
| 
 | ||
|                     //_workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload()
 | ||
|                     //{
 | ||
|                     //    TimepointIn24H = 0,
 | ||
|                     //    AdjudicationIn24H = 0
 | ||
|                     //});
 | ||
| 
 | ||
|                     break;
 | ||
|                 case (int)TrialExpedited.ExpeditedIn48H:
 | ||
|                     switch (newState)
 | ||
|                     {
 | ||
|                         case (int)TrialExpedited.None:
 | ||
|                             await _workloadRepository.BatchUpdateNoTrackingAsync(t => t.IsLock == false && t.TrialId == trialId, u => new Workload()
 | ||
|                             {
 | ||
|                                 Timepoint = u.TimepointIn48H,
 | ||
|                                 Adjudication = u.AdjudicationIn48H,
 | ||
|                                 TimepointIn48H = 0,
 | ||
|                                 AdjudicationIn48H = 0
 | ||
|                             });
 | ||
|                             break;
 | ||
|                         case (int)TrialExpedited.ExpeditedIn24H:
 | ||
|                             await _workloadRepository.BatchUpdateNoTrackingAsync(t => t.IsLock == false && t.TrialId == trialId, u => new Workload()
 | ||
|                             {
 | ||
|                                 TimepointIn24H = u.TimepointIn48H,
 | ||
|                                 AdjudicationIn24H = u.AdjudicationIn48H,
 | ||
|                                 TimepointIn48H = 0,
 | ||
|                                 AdjudicationIn48H = 0
 | ||
|                             });
 | ||
|                             break;
 | ||
|                     }
 | ||
| 
 | ||
|                     //_workloadRepository.Update(t => t.IsLock == false && t.TrialId == trialId, u => new Workload()
 | ||
|                     //{
 | ||
|                     //    TimepointIn48H = 0,
 | ||
|                     //    AdjudicationIn48H = 0
 | ||
|                     //});
 | ||
|                     break;
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 标记项目删除
 | ||
|         /// </summary>
 | ||
|         /// <param name="trialId"></param>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpDelete, Route("{trialId:guid}")]
 | ||
|         public async Task<IResponseOutput> MarkTrialDelete(Guid trialId)
 | ||
|         {
 | ||
|             await _trialRepository.BatchUpdateNoTrackingAsync(t => t.Id == trialId, u => new Trial() { IsDeleted = true });
 | ||
| 
 | ||
|             return ResponseOutput.Ok();
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary> 真删除项目  方便清理测试数据 </summary>
 | ||
|         /// <param name="trialId">临床试验项目Id</param>
 | ||
|         [AllowAnonymous]
 | ||
|         [HttpDelete, Route("{trialId:guid}")]
 | ||
|         public async Task<IResponseOutput> DeleteTrial(Guid trialId, [FromServices] IRepository _repository)
 | ||
|         {
 | ||
| 
 | ||
| 
 | ||
|             var trial = (await _trialRepository.FirstOrDefaultAsync(u => u.Id == trialId, true)).IfNullThrowException();
 | ||
| 
 | ||
| 
 | ||
|             if (_verifyConfig.CurrentValue.OpenTrialRelationDelete)
 | ||
|             {
 | ||
| 
 | ||
| 
 | ||
|                 #region 真项目删除
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<CheckChallengeDialog>(o => o.SubjectVisit.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ClinicalDataTrialSet>(o => o.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<InspectionFile>(o => o.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<CriterionNidusSystem>(o => o.TrialReadingCriterion.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<DataInspection>(o => o.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<DicomStudy>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<StudyMonitor>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<DicomSeries>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<DicomInstance>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<EnrollReadingCategory>(t => t.Enroll.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<Enroll>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<EnrollDetail>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<NoneDicomStudyFile>(t => t.NoneDicomStudy.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<NoneDicomStudy>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<OrganTrialInfo>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<PaymentAdjustment>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<PaymentDetail>(t => t.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<PreviousHistory>(t => t.SubjectVisit.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<PreviousOther>(t => t.SubjectVisit.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<PreviousPDF>(t => t.SubjectVisit.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<QCChallengeDialog>(t => t.QCChallenge.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<QCChallenge>(t => t.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingClinicalDataPDF>(t => t.ReadingClinicalData.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingClinicalData>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingGlobalTaskInfo>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingJudgeInfo>(t => t.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingMedicalReviewDialog>(t => t.TaskMedicalReview.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingMedicineQuestionAnswer>(t => t.TaskMedicalReview.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingMedicineTrialQuestion>(t => t.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingOncologyTaskInfo>(t => t.VisitTask.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingPeriodPlan>(t => t.ReadingPeriodSet.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingPeriodSet>(t => t.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingQuestionTrial>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingTableAnswerRowInfo>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingTableQuestionAnswer>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingTableQuestionTrial>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingTaskQuestionAnswer>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingTaskRelation>(t => t.VisitTask.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadModule>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingTaskQuestionAnswer>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<SubjectCanceDoctor>(t => t.Subject.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<SubjectUser>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<Subject>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<SubjectVisit>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TaskAllocationRule>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TaskConsistentRule>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TaskInfluence>(t => t.InfluenceTask.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TaskMedicalReview>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TaskMedicalReviewRule>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialStateChange>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialPaymentPrice>(t => t.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<Trial>(o => o.Id == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialClinicalDataSetCriterion>(t => t.TrialReadingCriterion.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialCriterionDictionaryCode>(t => t.TrialReadingCriterion.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<ReadingQuestionCriterionTrial>(t => t.TrialId == trialId);
 | ||
|                 await _trialDictionaryRepository.BatchDeleteNoTrackingAsync(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialDocConfirmedUser>(t => t.TrialDocument.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialDocument>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialDocNeedConfirmedUserType>(t => t.TrialDocument.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialEmailNoticeUser>(t => t.TrialEmailNoticeConfig.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialEmailNoticeConfig>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialExternalUser>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialPaymentPrice>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialQCQuestion>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialQCQuestionAnswer>(t => t.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialRevenuesPrice>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialRevenuesPriceVerification>(t => t.TrialId == trialId);
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialSign>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialSite>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialSiteSurvey>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialSiteUserSurvey>(t => t.TrialSiteSurvey.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialSiteEquipmentSurvey>(t => t.TrialSiteSurvey.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialUser>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialSiteUser>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<VisitStage>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<VisitPlanInfluenceStat>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<VisitPlanInfluenceStudy>(t => t.TrialId == trialId);
 | ||
| 
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<VisitTaskReReading>(t => t.OriginalReReadingTask.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<VisitTask>(t => t.TrialId == trialId);
 | ||
|                 await _repository.BatchDeleteNoTrackingAsync<TrialStateChange>(t => t.TrialId == trialId);
 | ||
|                 #endregion
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|                 return ResponseOutput.Ok();
 | ||
| 
 | ||
|             }
 | ||
| 
 | ||
|             else
 | ||
|             {
 | ||
|                 //---当前运行环境下,不允许删除项目数据。
 | ||
|                 return ResponseOutput.NotOk(_localizer["Trial_CannotDeleteProject"]);
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         [HttpPost]
 | ||
|         public async Task<PageOutput<TrialDetailDTO>> GetReviewerTrialListByEnrollmentStatus(TrialByStatusQueryDTO inQuery)
 | ||
|         {
 | ||
| 
 | ||
|             var query = _trialRepository.AsQueryable()
 | ||
|                 .WhereIf(inQuery.Status == 5, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.HasCommittedToCRO))
 | ||
|                 .WhereIf(inQuery.Status == 8, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.InviteIntoGroup))
 | ||
|                 .WhereIf(inQuery.Status == 10, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.DoctorReading))
 | ||
|                 .WhereIf(inQuery.Status == 14, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.Finished))
 | ||
|                .ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id, isEn_Us = _userInfo.IsEn_Us });
 | ||
| 
 | ||
|             return await query.ToPagedListAsync(inQuery, nameof(TrialDetailDTO.CreateTime));
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 根据项目Id 获取医生Id,用于触发计算费用
 | ||
|         /// </summary>
 | ||
|         public async Task<List<Guid>> GetTrialEnrollmentReviewerIds(Guid trialId)
 | ||
|         {
 | ||
|             return await _enrollRepository.Where(u => u.TrialId == trialId &&
 | ||
|             u.EnrollStatus >= EnrollStatus.DoctorReading).Select(u => u.DoctorId).Distinct().ToListAsync();
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         #region 医生用户接口
 | ||
| 
 | ||
|         /// <summary> 分页获取医生参与的临床实验项目列表(查询条件)</summary>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpPost]
 | ||
|         public async Task<PageOutput<TrialDetailDTO>> GetTrialListByReviewer(ReviewerTrialQueryDTO inQuery)
 | ||
|         {
 | ||
|             var query = _trialRepository
 | ||
|                .WhereIf(inQuery.EnrollStatus != null, o => (int)inQuery.EnrollStatus! == 10 ?
 | ||
|                o.EnrollList.Any(o => o.EnrollStatus >= EnrollStatus.ConfirmIntoGroup && o.EnrollStatus <= EnrollStatus.DoctorReading && o.DoctorId == _userInfo.Id) :
 | ||
|                o.EnrollList.Any(o => o.EnrollStatus == inQuery.EnrollStatus && o.DoctorId == _userInfo.Id))
 | ||
|                .WhereIf(inQuery.Expedited != null, o => o.Expedited == inQuery.Expedited)
 | ||
|                .WhereIf(!string.IsNullOrEmpty(inQuery.Code), o => o.TrialCode.Contains(inQuery.Code))
 | ||
|                .WhereIf(!string.IsNullOrWhiteSpace(inQuery.Indication), o => o.Indication.Contains(inQuery.Indication))
 | ||
|                .WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id))
 | ||
|                .ProjectTo<TrialDetailDTO>(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id, isEn_Us = _userInfo.IsEn_Us });
 | ||
| 
 | ||
| 
 | ||
|             return await query.ToPagedListAsync(inQuery, nameof(TrialDetailDTO.CreateTime));
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 医生确认入组或拒绝入组
 | ||
|         /// </summary>
 | ||
|         /// <param name="trialId">项目Id</param>
 | ||
|         /// <param name="status">9-拒绝入组,10-确认入组</param>
 | ||
|         /// <returns></returns>
 | ||
|         [HttpPost("{trialId:guid}/{status:int}")]
 | ||
| 
 | ||
|         [TrialGlobalLimit("AfterStopCannNotOpt")]
 | ||
|         public async Task<IResponseOutput> UpdateEnrollStatus(Guid trialId, EnrollStatus status)
 | ||
|         {
 | ||
|             await _enrollDetailRepository.AddAsync(new EnrollDetail()
 | ||
|             {
 | ||
|                 DoctorId = _userInfo.Id,
 | ||
|                 TrialId = trialId,
 | ||
|                 EnrollStatus = status,
 | ||
|                 OptUserType = (int)SystemUserType.DoctorUser,
 | ||
|             });
 | ||
|             return ResponseOutput.Result(await _enrollRepository.BatchUpdateNoTrackingAsync(u => u.TrialId == trialId && u.DoctorId == _userInfo.Id, e => new Enroll
 | ||
|             {
 | ||
|                 EnrollStatus = status
 | ||
|             }));
 | ||
|         }
 | ||
| 
 | ||
|         #endregion
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|     }
 | ||
| 
 | ||
| }
 |