//-------------------------------------------------------------------- // 此代码由T4模板自动生成 byzhouhang 20210918 // 生成时间 2022-07-01 15:33:04 // 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。 //-------------------------------------------------------------------- using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Application.Interfaces; using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; using IRaCIS.Core.Infrastructure; using Medallion.Threading; using Microsoft.AspNetCore.Mvc; namespace IRaCIS.Core.Application.Service { /// /// 一致性分析配置表 /// [ApiExplorerSettings(GroupName = "Trial")] public class TaskConsistentRuleService(IRepository _taskConsistentRuleRepository, IRepository _visitTaskRepository, IRepository _trialReadingCriterionRepository, IReadingClinicalDataService _readingClinicalDataService, IRepository _subjectRepository, IDistributedLockProvider _distributedLockProvider, IRepository _trialRepository, IRepository _trialSiteRepository, IRepository _enrollRepository, IRepository _userRoleRepository, IRepository _trialVirtualSiteCodeUpdateRepository, IVisitTaskHelpeService _visitTaskCommonService, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ITaskConsistentRuleService { /// /// 设置一致性分析任务失效 /// /// /// [HttpPost] public async Task SetAnalysisTaskInvalid(List taskIdList) { await _visitTaskRepository.UpdatePartialFromQueryAsync(t => taskIdList.Contains(t.Id), u => new VisitTask() { TaskState = TaskState.Adbandon }, true); await _visitTaskRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } /// /// 一致性分析列表 (自身 组内 最后勾选 产生的任务) /// /// /// [HttpPost] public async Task>> GetAnalysisTaskList(VisitTaskQuery inQuery) { var visitTaskQueryable = _visitTaskRepository.Where(t => t.TrialId == inQuery.TrialId) .Where(t => t.IsAnalysisCreate) .WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId) .WhereIf(inQuery.TrialSiteId != null, t => t.Subject.TrialSiteId == inQuery.TrialSiteId) .WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId) .WhereIf(inQuery.TaskState != null, t => t.TaskState == inQuery.TaskState) .WhereIf(inQuery.IsUrgent != null, t => t.IsUrgent == inQuery.IsUrgent) .WhereIf(inQuery.DoctorUserId != null, t => t.DoctorUserId == inQuery.DoctorUserId) .WhereIf(inQuery.ReadingCategory != null, t => t.ReadingCategory == inQuery.ReadingCategory) .WhereIf(inQuery.ReadingTaskState != null, t => t.ReadingTaskState == inQuery.ReadingTaskState) .WhereIf(inQuery.TaskAllocationState != null, t => t.TaskAllocationState == inQuery.TaskAllocationState) .WhereIf(inQuery.IsSelfAnalysis != null, t => t.IsSelfAnalysis == inQuery.IsSelfAnalysis) .WhereIf(inQuery.ArmEnum != null, t => t.ArmEnum == inQuery.ArmEnum) .WhereIf(!string.IsNullOrEmpty(inQuery.TrialSiteCode), t => /*(t.BlindTrialSiteCode.Contains(queryVisitTask.TrialSiteCode!) && t.IsAnalysisCreate) ||*/ (t.Subject.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteCode!) /*&& t.IsAnalysisCreate == false*/)) .WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.TaskName.Contains(inQuery.TaskName) || t.TaskBlindName.Contains(inQuery.TaskName)) .WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => ((t.Subject.Code.Contains(inQuery.SubjectCode) || t.Subject.MedicalNo.Contains(inQuery.SubjectCode)) && t.IsAnalysisCreate == false) || (t.BlindSubjectCode.Contains(inQuery.SubjectCode) && t.IsAnalysisCreate)) .WhereIf(inQuery.BeginAllocateDate != null, t => t.AllocateTime >= inQuery.BeginAllocateDate) .WhereIf(inQuery.EndAllocateDate != null, t => t.AllocateTime <= inQuery.EndAllocateDate) .WhereIf(inQuery.BeginSignTime != null, t => t.SignTime >= inQuery.BeginSignTime) .WhereIf(inQuery.EndSignTime != null, t => t.SignTime <= inQuery.EndSignTime) .ProjectTo(_mapper.ConfigurationProvider); var defalutSortArray = new string[] { nameof(AnalysisTaskView.IsUrgent) + " desc", nameof(AnalysisTaskView.SubjectCode), nameof(AnalysisTaskView.VisitTaskNum) }; var pageList = await visitTaskQueryable.ToPagedListAsync(inQuery, defalutSortArray); #region 统计一致性分析临床数据数量 foreach (var item in pageList.CurrentPageData) { item.ConsistentClinicalDataCount = (await _readingClinicalDataService.GetClinicalDataList(new GetReadingOrTaskClinicalDataListInDto() { SubjectId = item.SubjectId, TrialId = item.TrialId, SelectIsSign = false, IsGetAllConsistencyAnalysis = false, VisitTaskId = item.Id, })).Count(); } #endregion var trialTaskConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => new { IsHaveDoubleReadCriterion = t.TrialReadingCriterionList.Any(t => t.IsSigned && t.IsConfirm && t.ReadingType == ReadingMethod.Double), t.VitrualSiteCode }).FirstOrDefault(); return ResponseOutput.Ok(pageList, trialTaskConfig); } /// /// 为自身一致性分析医生,选择Subejct 列表 /// /// /// [HttpPost] public async Task> GetDoctorSelfConsistentRuleSubjectList(ConsistentQuery inQuery) { var filterObj = await _taskConsistentRuleRepository.FirstOrDefaultAsync(t => t.Id == inQuery.TaskConsistentRuleId); var pagedList = await GetIQueryableDoctorSelfConsistentSubjectView(filterObj, inQuery.DoctorUserId).ToPagedListAsync(inQuery, nameof(DoctorSelfConsistentSubjectView.SubjectCode)); return pagedList; } /// /// 确认生成自身一致性分析任务 /// /// /// [HttpPost] [UnitOfWork] //[TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task ConfirmGenerateSelfConsistentTask(ConsistentConfirmGenerateCommand inCommand) { var filterObj = await _taskConsistentRuleRepository.Where(t => t.Id == inCommand.TaskConsistentRuleId).Include(t => t.TrialReadingCriterion).FirstOrDefaultAsync(); var doctorUserId = inCommand.DoctorUserId; var trialReadingCriterionId = filterObj.TrialReadingCriterionId; //随机分配 if (inCommand.IsAutoAllocateGenerateTask) { var subjectList = (await GetSelfConsistentRuleMatchSubjectIdListAsync(new SelfConsistentSimpleQuery() { TaskConsistentRuleId = inCommand.TaskConsistentRuleId, DoctorUserId = inCommand.DoctorUserId })).ToList(); if (subjectList.Any(t => t.IsHaveGeneratedTask)) { //已手动分配,不允许自动分配 throw new BusinessValidationFailedException(_localizer["TaskConsistent_NotAllowedGenerate"]); } if (subjectList.Count < 2 * filterObj.PlanSubjectCount) { throw new BusinessValidationFailedException(_localizer["TaskConsistent_NotAllowedGenerate1"]); } inCommand.SubejctIdList = subjectList.Select(t => t.SubjectId).ToList().GetRandomCountList(filterObj.PlanSubjectCount); } var list = await GetIQueryableDoctorSelfConsistentSubjectView(filterObj, doctorUserId, inCommand.SubejctIdList).ToListAsync(); var @lock = _distributedLockProvider.CreateLock($"VisitTaskCode"); using (await @lock.AcquireAsync()) { int maxCodeInt = 0; foreach (var subject in list) { //处理 Subject 编号 var blindSubjectCode = string.Empty; var subjectTask = _visitTaskRepository.Where(t => t.SubjectId == subject.SubjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsSelfAnalysis == true).OrderByDescending(t => t.BlindSubjectCode).FirstOrDefault(); if (subjectTask != null && subjectTask.BlindSubjectCode != String.Empty) { blindSubjectCode = subjectTask.BlindSubjectCode; } else { var maxCodeStr = _visitTaskRepository.Where(t => t.TrialId == subject.TrialId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsSelfAnalysis == true).OrderByDescending(t => t.BlindSubjectCode).Select(t => t.BlindSubjectCode).FirstOrDefault(); if (!string.IsNullOrEmpty(maxCodeStr)) { int.TryParse(maxCodeStr.Substring(maxCodeStr.Length - filterObj.BlindSubjectNumberOfPlaces), out maxCodeInt); } blindSubjectCode = filterObj.BlindTrialSiteCode + (maxCodeInt + 1).ToString($"D{filterObj.BlindSubjectNumberOfPlaces}"); } //有序阅片 if (filterObj.TrialReadingCriterion.IsReadingTaskViewInOrder == ReadingOrder.InOrder) { subject.VisitTaskList = subject.VisitTaskList.Take(filterObj.PlanVisitCount).ToList(); } else { //完全随机 和受试者随机,都是随机挑选访视 subject.VisitTaskList = subject.VisitTaskList.GetRandomCountList(filterObj.PlanVisitCount); } subject.VisitTaskList.ForEach(t => { t.DoctorUserId = doctorUserId; //t.TaskConsistentRuleId = filterObj.Id; t.BlindTrialSiteCode = filterObj.BlindTrialSiteCode; t.BlindSubjectCode = blindSubjectCode; }); //最后一个访视添加全局 if (filterObj.IsGenerateGlobalTask) { var lastTask = (subject.VisitTaskList.Take(filterObj.PlanVisitCount).Last()).Clone(); var existGlobal = _visitTaskRepository.Where(t => t.SubjectId == lastTask.SubjectId && t.ArmEnum==lastTask.ArmEnum && t.TrialReadingCriterionId == trialReadingCriterionId && t.TaskState == TaskState.Effect && t.ReadingCategory == ReadingCategory.Global && t.VisitTaskNum == lastTask.VisitTaskNum + ReadingCommon.TaskNumDic[ReadingCategory.Global]).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(); if (existGlobal == null) { existGlobal = new VisitTaskSimpleDTO() { SubjectId = lastTask.SubjectId, TrialId = lastTask.TrialId, ArmEnum = lastTask.ArmEnum, ReadingCategory = ReadingCategory.Global, TaskName = lastTask.TaskName + "_Global", TaskBlindName = lastTask.TaskBlindName + "_Global", TrialReadingCriterionId = trialReadingCriterionId, VisitTaskNum = lastTask.VisitTaskNum + ReadingCommon.TaskNumDic[ReadingCategory.Global] }; var afterGlobal = _visitTaskRepository.Where(t => t.SubjectId == lastTask.SubjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.TaskState == TaskState.Effect && t.ReadingCategory == ReadingCategory.Global && t.VisitTaskNum > lastTask.VisitTaskNum).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(); if (afterGlobal == null) { throw new BusinessValidationFailedException("联系后台排查数据,没找到后续全局"); } else { existGlobal.SouceReadModuleId = afterGlobal.SouceReadModuleId; } } existGlobal.DoctorUserId = doctorUserId; existGlobal.BlindSubjectCode = lastTask.BlindSubjectCode; existGlobal.BlindTrialSiteCode = lastTask.BlindTrialSiteCode; subject.VisitTaskList.Add(existGlobal); } await _visitTaskCommonService.AddTaskAsync(new GenerateTaskCommand() { TrialId = filterObj.TrialId, ReadingCategory = GenerateTaskCategory.SelfConsistent, //产生的过滤掉已经生成的 GenerataConsistentTaskList = subject.VisitTaskList.Where(t => t.IsHaveGeneratedTask == false).ToList() }); await _visitTaskRepository.SaveChangesAsync(); } } return ResponseOutput.Ok(); } /// /// 组间一致性分析 选择Subejct 列表 /// /// /// [HttpPost] public async Task>> GetGroupConsistentRuleSubjectList(GroupConsistentQuery inQuery) { var trialId = inQuery.TrialId; var filterObj = await _taskConsistentRuleRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.IsSelfAnalysis == false); if (filterObj == null) { object tt = null; return ResponseOutput.Ok(new PageOutput(), new { Rule = tt, IsAllowAutoAllocate = false }); } var query = await GetGroupConsistentQueryAsync(filterObj); var pagedList = await query.ToPagedListAsync(inQuery, nameof(DoctorSelfConsistentSubjectView.SubjectCode)); var rule = await _taskConsistentRuleRepository.Where(t => t.TrialId == inQuery.TrialId && t.IsSelfAnalysis == false && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync(); var list = await GetGroupConsistentRuleMatchSubjectIdListAsync(new GroupConsistentSimpleQuery() { TrialId = inQuery.TrialId, TrialReadingCriterionId = inQuery.TrialReadingCriterionId }); var isAllowAutoAllocate = !list.Any(t => t.IsHaveGeneratedTask) && list.Count() > 2 * (rule?.PlanSubjectCount ?? 0); return ResponseOutput.Ok(pagedList, new { Rule = rule, IsAllowAutoAllocate = isAllowAutoAllocate }); } /// /// 确认生成组间一致性分析任务 /// /// /// [HttpPost] [UnitOfWork] [TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task ConfirmGenerateGroupConsistentTask(GroupConsistentConfirmGenrateCommand inCommand) { var trialId = inCommand.TrialId; var filterObj = await _taskConsistentRuleRepository.Where(t => t.TrialId == trialId && t.TrialReadingCriterionId == inCommand.TrialReadingCriterionId && t.IsSelfAnalysis == false).Include(t => t.TrialReadingCriterion).FirstNotNullAsync(); var trialReadingCriterionId = filterObj.TrialReadingCriterionId; //随机分配 if (inCommand.IsAutoAllocateGenerateTask) { var subjectSelectList = (await GetGroupConsistentRuleMatchSubjectIdListAsync(new GroupConsistentSimpleQuery() { TrialId = inCommand.TrialId, TrialReadingCriterionId = inCommand.TrialReadingCriterionId })).ToList(); if (subjectSelectList.Any(t => t.IsHaveGeneratedTask)) { //已手动分配过,不允许自动分配 throw new BusinessValidationFailedException(_localizer["TaskConsistent_NotAllowedGenerate"]); } if (subjectSelectList.Count < 2 * filterObj.PlanSubjectCount) { throw new BusinessValidationFailedException(_localizer["TaskConsistent_NotAllowedGenerate1"]); } inCommand.SubejctIdList = subjectSelectList.Select(t => t.SubjectId).ToList().GetRandomCountList(filterObj.PlanSubjectCount); } var query = await GetGroupConsistentQueryAsync(filterObj, inCommand.SubejctIdList); var subjectList = query.ToList(); var doctorUserIdQuery = from enroll in _enrollRepository.Where(t => t.TrialId == trialId).Where(t => t.EnrollReadingCategoryList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId).Any(c => c.ReadingCategory == ReadingCategory.Global || c.ReadingCategory == ReadingCategory.Visit)) .Where(t => t.EnrollReadingCriteriaList.Any(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.IsJoinAnalysis == true)) join user in _userRoleRepository.Where() on enroll.DoctorId equals user.DoctorId select user.Id; var configDoctorUserIdList = await doctorUserIdQuery.ToListAsync(); var @lock = _distributedLockProvider.CreateLock($"VisitTaskCode"); using (await @lock.AcquireAsync()) { int maxCodeInt = 0; foreach (var subject in subjectList.Where(t => t.IsHaveGeneratedTask == false)) { //组间一致性分析 也用盲态SubjectCode //处理 Subject 编号 var blindSubjectCode = string.Empty; var subjectTask = _visitTaskRepository.Where(t => t.SubjectId == subject.SubjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsSelfAnalysis == false).OrderByDescending(t => t.BlindSubjectCode).FirstOrDefault(); if (subjectTask != null && subjectTask.BlindSubjectCode != String.Empty) { blindSubjectCode = subjectTask.BlindSubjectCode; } else { var maxCodeStr = _visitTaskRepository.Where(t => t.TrialId == subject.TrialId && t.TrialReadingCriterionId == trialReadingCriterionId && t.IsSelfAnalysis == false).OrderByDescending(t => t.BlindSubjectCode).Select(t => t.BlindSubjectCode).FirstOrDefault(); if (!string.IsNullOrEmpty(maxCodeStr)) { int.TryParse(maxCodeStr.Substring(maxCodeStr.Length - filterObj.BlindSubjectNumberOfPlaces), out maxCodeInt); } blindSubjectCode = filterObj.BlindTrialSiteCode + (maxCodeInt + 1).ToString($"D{filterObj.BlindSubjectNumberOfPlaces}"); } var subjectAddTaskList = new List(); //需要处理的医生 var needAddDoctorUserIdList = configDoctorUserIdList.Except(subject.VisitTaskList.Select(t => t.DoctorUserId!.Value)).ToList(); if (needAddDoctorUserIdList.Count == 0) { //"请配置一致性分析的医生" throw new BusinessValidationFailedException(_localizer["TaskConsistent_ConsistencyConfigExists"]); } foreach (var needAddDoctorUserId in needAddDoctorUserIdList) { //if(filterObj.TrialReadingCriterion.IsReadingTaskViewInOrder== ReadingOrder.InOrder) //{ //} //每个医生 都生成处理的任务 foreach (var task in subject.SubjectTaskVisitList.Take(filterObj.PlanVisitCount)) { subjectAddTaskList.Add(new VisitTaskGroupSimpleDTO() { ReadingCategory = task.ReadingCategory, ReadingTaskState = task.ReadingTaskState, TaskBlindName = task.TaskBlindName, TaskName = task.TaskName, TaskState = task.TaskState, SubjectId = task.SubjectId, VisitTaskNum = task.VisitTaskNum, TrialId = task.TrialId, DoctorUserId = needAddDoctorUserId, ArmEnum = Arm.GroupConsistentArm, SouceReadModuleId = task.SouceReadModuleId, SourceSubjectVisitId = task.SourceSubjectVisitId, TrialReadingCriterionId = task.TrialReadingCriterionId, BlindSubjectCode = blindSubjectCode, BlindTrialSiteCode = filterObj.BlindTrialSiteCode }); } //最后一个访视添加全局 if (filterObj.IsGenerateGlobalTask) { var lastTask = (subjectAddTaskList.Take(filterObj.PlanVisitCount).Last()).Clone(); var existGlobal = _visitTaskRepository.Where(t => t.SubjectId == lastTask.SubjectId && t.ArmEnum == lastTask.ArmEnum && t.TrialReadingCriterionId == trialReadingCriterionId && t.TaskState == TaskState.Effect && t.ReadingCategory == ReadingCategory.Global && t.VisitTaskNum == lastTask.VisitTaskNum + ReadingCommon.TaskNumDic[ReadingCategory.Global]).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(); if (existGlobal == null) { existGlobal = new VisitTaskSimpleDTO() { SubjectId = lastTask.SubjectId, TrialId = lastTask.TrialId, ReadingCategory = ReadingCategory.Global, TaskName = lastTask.TaskName + "_Global", TaskBlindName = lastTask.TaskBlindName + "_Global", TrialReadingCriterionId = trialReadingCriterionId, BlindSubjectCode = blindSubjectCode, BlindTrialSiteCode = filterObj.BlindTrialSiteCode, VisitTaskNum = lastTask.VisitTaskNum + ReadingCommon.TaskNumDic[ReadingCategory.Global] }; } existGlobal.BlindSubjectCode = blindSubjectCode; existGlobal.BlindTrialSiteCode = filterObj.BlindTrialSiteCode; existGlobal.ArmEnum = Arm.GroupConsistentArm; existGlobal.DoctorUserId = needAddDoctorUserId; subjectAddTaskList.Add(existGlobal); } } await _visitTaskCommonService.AddTaskAsync(new GenerateTaskCommand() { TrialId = filterObj.TrialId, ReadingCategory = GenerateTaskCategory.GroupConsistent, GenerataGroupConsistentTaskList = subjectAddTaskList }); await _taskConsistentRuleRepository.SaveChangesAsync(); } } return ResponseOutput.Ok(); } /// /// 仅仅自身一致性时使用( /// /// /// /// /// private IQueryable GetIQueryableDoctorSelfConsistentSubjectView(TaskConsistentRule filterObj, Guid doctorUserId, List? subejctIdList = null) { var trialId = filterObj.TrialId; var trialReadingCriterionId = filterObj.TrialReadingCriterionId; //防止生成sql生成GETDATE() 时区导致的问题 var appDateTimeNow = DateTime.Now; #region Subejct 维度 Expression> comonTaskFilter = u => u.TrialId == trialId && u.IsAnalysisCreate == false && u.TaskState == TaskState.Effect && u.ReadingTaskState == ReadingTaskState.HaveSigned && u.TrialReadingCriterionId == trialReadingCriterionId && u.SignTime!.Value.AddDays(filterObj.IntervalWeeks * 7) < appDateTimeNow && (u.ReReadingApplyState == ReReadingApplyState.Default || u.ReReadingApplyState == ReReadingApplyState.Reject) && u.DoctorUserId == doctorUserId; if (subejctIdList != null && subejctIdList?.Count > 0) { comonTaskFilter = comonTaskFilter.And(t => subejctIdList.Contains(t.SubjectId)); } Expression> visitTaskFilter = comonTaskFilter.And(t => t.ReadingCategory == ReadingCategory.Visit); ////所选访视数量 的访视 其中必有一个访视后有全局任务 //if (filterObj.IsHaveReadingPeriod == true) //{ // //这里的过滤条件 不能用 where(comonTaskFilter) 会报错,奇怪的问题 只能重新写一遍 // visitTaskFilter = visitTaskFilter.And(c => c.Subject.SubjectVisitTaskList.Any(t => t.VisitTaskNum == c.VisitTaskNum + ReadingCommon.TaskNumDic[ReadingCategory.Global] && t.ReadingCategory == ReadingCategory.Global && t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect && t.ReadingTaskState == ReadingTaskState.HaveSigned && // t.SignTime!.Value.AddDays(filterObj.IntervalWeeks * 7) < appDateTimeNow && (t.ReReadingApplyState == ReReadingApplyState.Default || t.ReReadingApplyState == ReReadingApplyState.Reject))); //} var subjectQuery = _subjectRepository.Where(t => t.TrialId == trialId && t.SubjectVisitTaskList.AsQueryable().Where(visitTaskFilter).Count() >= filterObj.PlanVisitCount) .WhereIf(filterObj.IsHaveReadingPeriod == true, u => u.SubjectVisitTaskList.AsQueryable().Where(comonTaskFilter) .Where(t => t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global).Any(t => t.ReadingCategory == ReadingCategory.Global && t.VisitTaskNum > filterObj.PlanVisitCount - 1)) ; var query = subjectQuery.Select(t => new DoctorSelfConsistentSubjectView() { TrialId = t.TrialId, TrialSiteId = t.TrialSiteId, SubjectCode = t.Code, TrialSiteCode = t.TrialSite.TrialSiteCode, SubjectId = t.Id, IsReReadingOrBackInfluenceAnalysis = t.IsReReadingOrBackInfluenceAnalysis, FirstGlobalVisitName = t.ReadModuleList.Where(c => c.TrialReadingCriterionId == trialReadingCriterionId && c.ModuleType == ModuleTypeEnum.Global).OrderBy(k => k.SubjectVisit.VisitNum).Select(u => u.SubjectVisit.VisitName).FirstOrDefault(), BlindSubjectCode = t.SubjectVisitTaskList.Where(t => t.IsAnalysisCreate && t.TrialReadingCriterionId == trialReadingCriterionId).OrderByDescending(t => t.BlindSubjectCode).Select(t => t.BlindSubjectCode).FirstOrDefault(), IsHaveGeneratedTask = t.SubjectVisitTaskList.Any(c => c.DoctorUserId == doctorUserId && c.IsSelfAnalysis == true && c.TrialReadingCriterionId == trialReadingCriterionId), ValidVisitCount = t.SubjectVisitTaskList.AsQueryable().Where(visitTaskFilter).Count(), VisitTaskList = t.SubjectVisitTaskList.AsQueryable().Where(visitTaskFilter).OrderBy(t => t.VisitTaskNum).Select(c => new VisitTaskSimpleDTO() { Id = c.Id, ReadingCategory = c.ReadingCategory, ReadingTaskState = c.ReadingTaskState, TaskBlindName = c.TaskBlindName, TaskCode = c.TaskCode, TaskName = c.TaskName, TaskState = c.TaskState, ArmEnum = c.ArmEnum, SubjectId = c.SubjectId, VisitTaskNum = c.VisitTaskNum, TrialId = c.TrialId, SourceSubjectVisitId = c.SourceSubjectVisitId, SouceReadModuleId = c.SouceReadModuleId, TrialReadingCriterionId = c.TrialReadingCriterionId, IsClinicalDataSign = c.IsClinicalDataSign, IsNeedClinicalDataSign = c.IsNeedClinicalDataSign, //GlobalVisitTaskList = c.Subject.SubjectVisitTaskList.AsQueryable().Where(comonTaskFilter).Where(t => t.VisitTaskNum == c.VisitTaskNum + ReadingCommon.TaskNumDic[ReadingCategory.Global]).Select(c => new VisitTaskSimpleDTO() //{ // Id = c.Id, // ReadingCategory = c.ReadingCategory, // ReadingTaskState = c.ReadingTaskState, // TaskBlindName = c.TaskBlindName, // TaskCode = c.TaskCode, // TaskName = c.TaskName, // TaskState = c.TaskState, // ArmEnum = c.ArmEnum, // SubjectId = c.SubjectId, // VisitTaskNum = c.VisitTaskNum, // TrialId = c.TrialId, // SourceSubjectVisitId = c.SourceSubjectVisitId, // SouceReadModuleId = c.SouceReadModuleId, // TrialReadingCriterionId = c.TrialReadingCriterionId, // IsClinicalDataSign = c.IsClinicalDataSign, // IsNeedClinicalDataSign = c.IsNeedClinicalDataSign, //}).ToList(), }).ToList() }); return query.OrderByDescending(t => t.IsHaveGeneratedTask); #endregion } /// /// 组间一致性分析 满足条件的subject 筛选 /// /// /// /// private async Task> GetGroupConsistentQueryAsync(TaskConsistentRule filterObj, List? subejctIdList = null) { //单重阅片没有组件一致性 var trialId = filterObj.TrialId; var trialReadingCriterionId = filterObj.TrialReadingCriterionId; Expression> comonTaskFilter = u => u.TrialId == trialId && u.IsAnalysisCreate == false && u.TaskState == TaskState.Effect && u.ReadingTaskState == ReadingTaskState.HaveSigned && u.TrialReadingCriterionId == trialReadingCriterionId && (u.ReReadingApplyState == ReReadingApplyState.Default || u.ReReadingApplyState == ReReadingApplyState.Reject); if (subejctIdList != null && subejctIdList?.Count > 0) { comonTaskFilter = comonTaskFilter.And(t => subejctIdList.Contains(t.SubjectId)); } Expression> visitTaskFilter = comonTaskFilter.And(t => t.ReadingCategory == ReadingCategory.Visit); IQueryable subjectQuery = default; //双重阅片,并且都阅片完成 subjectQuery = _subjectRepository.Where(t => t.TrialId == trialId && t.SubjectVisitTaskList.AsQueryable().Where(comonTaskFilter).Where(t => t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global).Select(t => t.DoctorUserId).Distinct().Count() == 2 && t.SubjectVisitTaskList.AsQueryable().Where(visitTaskFilter).GroupBy(t => new { t.SubjectId, t.VisitTaskNum }).Where(g => g.Count() == 2).Count() >= filterObj.PlanVisitCount ) //.WhereIf(filterObj.IsHaveReadingPeriod == true, u => u.SubjectVisitTaskList.AsQueryable().Where(comonTaskFilter).Where(t => t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global).OrderBy(t => t.VisitTaskNum).Take(filterObj.PlanVisitCount * 2 + 2).Any(t => t.ReadingCategory == ReadingCategory.Global)) .WhereIf(filterObj.IsHaveReadingPeriod == true, u => u.SubjectVisitTaskList.AsQueryable().Where(comonTaskFilter).Where(t => t.ReadingCategory == ReadingCategory.Global && t.VisitTaskNum > filterObj.PlanVisitCount - 1).Select(t => t.DoctorUserId).Distinct().Count() == 2) ; var query = subjectQuery.Select(t => new DoctorGroupConsistentSubjectView() { TrialId = t.TrialId, TrialSiteId = t.TrialSiteId, SubjectCode = t.Code, TrialSiteCode = t.TrialSite.TrialSiteCode, SubjectId = t.Id, IsReReadingOrBackInfluenceAnalysis = t.IsReReadingOrBackInfluenceAnalysis, IsHaveGeneratedTask = t.SubjectVisitTaskList.Any(c => c.IsSelfAnalysis == false && c.TrialReadingCriterionId == trialReadingCriterionId), DoctorUserList = t.SubjectDoctorList.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.IsConfirmed && t.ArmEnum <= Arm.DoubleReadingArm2).Select(t => new UserSimpleInfo() { UserId = t.Id, FullName = t.DoctorUser.FullName, UserCode = t.DoctorUser.UserCode, UserName = t.DoctorUser.UserName }).ToList(), ValidVisitCount = t.SubjectVisitTaskList.AsQueryable().Where(visitTaskFilter).GroupBy(t => new { t.SubjectId, t.VisitTaskNum }).Where(g => g.Count() == 2).Count(), VisitTaskList = t.SubjectVisitTaskList.AsQueryable().Where(visitTaskFilter) .Select(c => new VisitTaskGroupSimpleDTO() { ReadingCategory = c.ReadingCategory, ReadingTaskState = c.ReadingTaskState, TaskBlindName = c.TaskBlindName, TaskName = c.TaskName, TaskState = c.TaskState, SubjectId = c.SubjectId, VisitTaskNum = c.VisitTaskNum, TrialId = c.TrialId, DoctorUserId = c.DoctorUserId, SourceSubjectVisitId = c.SourceSubjectVisitId, SouceReadModuleId = c.SouceReadModuleId, TrialReadingCriterionId = c.TrialReadingCriterionId, IsClinicalDataSign = c.IsClinicalDataSign, IsNeedClinicalDataSign = c.IsNeedClinicalDataSign, }).ToList() // }); query = query.OrderByDescending(t => t.IsHaveGeneratedTask); return query; } [HttpPost] public async Task GetConsistentRule(TaskConsistentRuleQuery inQuery) { var IsReadingTaskViewInOrder = await _trialReadingCriterionRepository.Where(x => x.Id == inQuery.TrialReadingCriterionId).Select(x => x.IsReadingTaskViewInOrder).FirstNotNullAsync(); var result = await _taskConsistentRuleRepository.Where(t => t.TrialId == inQuery.TrialId && t.IsSelfAnalysis == inQuery.IsSelfAnalysis && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync(); return new GetConsistentRuleOut() { ConsistentRuleBasic = result, IsReadingTaskViewInOrder = IsReadingTaskViewInOrder }; } /// /// 自身一致性分配 配置+ 统计已经生成数量统计表 /// /// /// [HttpPost] public async Task>> GetSelfConsistentDoctorStatList(TaskConsistentRuleQuery inQuery) { var trialId = inQuery.TrialId; //防止生成sql生成GETDATE() 时区导致的问题 var appDateTimeNow = DateTime.Now; Expression> comonTaskFilter = u => u.TrialId == trialId && u.IsAnalysisCreate == false && u.TaskState == TaskState.Effect && u.ReadingTaskState == ReadingTaskState.HaveSigned && (u.ReReadingApplyState == ReReadingApplyState.Default || u.ReReadingApplyState == ReReadingApplyState.Reject); //&& u.TrialReadingCriterionId == trialReadingCriterionId &&u.SignTime!.Value.AddDays(filterObj.IntervalWeeks * 7) < appDateTimeNow && u.DoctorUserId == doctorUserId; Expression> visitTaskFilter = comonTaskFilter.And(t => t.ReadingCategory == ReadingCategory.Visit); var taskConsistentRuleQueryable = from enroll in _enrollRepository.Where(t => t.TrialId == trialId && t.EnrollStatus == EnrollStatus.ConfirmIntoGroup && t.EnrollReadingCriteriaList.Any(c => c.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && c.IsJoinAnalysis)) join user in _userRoleRepository.Where() on enroll.DoctorUserId equals user.Id join taskConsistentRule in _taskConsistentRuleRepository.Where(t => t.TrialId == trialId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.IsSelfAnalysis) on enroll.TrialId equals taskConsistentRule.TrialId select new TaskConsistentRuleView() { Id = taskConsistentRule.Id, CreateTime = taskConsistentRule.CreateTime, BlindTrialSiteCode = taskConsistentRule.BlindTrialSiteCode, BlindSubjectNumberOfPlaces = taskConsistentRule.BlindSubjectNumberOfPlaces, CreateUserId = taskConsistentRule.CreateUserId, IntervalWeeks = taskConsistentRule.IntervalWeeks, IsEnable = taskConsistentRule.IsEnable, PlanSubjectCount = taskConsistentRule.PlanSubjectCount, Note = taskConsistentRule.Note, TrialId = taskConsistentRule.TrialId, UpdateTime = taskConsistentRule.UpdateTime, UpdateUserId = taskConsistentRule.UpdateUserId, IsGenerateGlobalTask = taskConsistentRule.IsGenerateGlobalTask, IsHaveReadingPeriod = taskConsistentRule.IsHaveReadingPeriod, PlanVisitCount = taskConsistentRule.PlanVisitCount, GeneratedSubjectCount = taskConsistentRule.TrialReadingCriterion.VisitTaskList.Where(t => t.IsAnalysisCreate && t.IsSelfAnalysis == true && t.DoctorUserId == user.Id).Select(t => t.SubjectId).Distinct().Count(), MatchSubejctCount = taskConsistentRule.Trial.SubjectList.AsQueryable() .Where(t => taskConsistentRule.IsHaveReadingPeriod == false ? t.SubjectVisitTaskList.AsQueryable() .Where(visitTaskFilter).Where(t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SignTime!.Value.AddDays(taskConsistentRule.IntervalWeeks * 7) < appDateTimeNow && t.DoctorUserId == user.Id) .Count() >= taskConsistentRule.PlanVisitCount : //全局要>计划访视数量后面 t.SubjectVisitTaskList.AsQueryable().Where(comonTaskFilter) .Where(t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SignTime!.Value.AddDays(taskConsistentRule.IntervalWeeks * 7) < appDateTimeNow && t.DoctorUserId == user.Id) .Where(t => t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global).Any(t => t.ReadingCategory == ReadingCategory.Global && t.VisitTaskNum > taskConsistentRule.PlanVisitCount - 1) && t.SubjectVisitTaskList.AsQueryable().Where(visitTaskFilter) .Where(t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.SignTime!.Value.AddDays(taskConsistentRule.IntervalWeeks * 7) < appDateTimeNow && t.DoctorUserId == user.Id) .Count() >= taskConsistentRule.PlanVisitCount ) .Count(), AnalysisDoctorUser = new UserSimpleInfo() { UserId = user.Id, UserCode = user.UserCode, FullName = user.FullName, UserName = user.UserName } }; //if (await _taskConsistentRuleRepository.AnyAsync(t => t.TrialId == inQuery.TrialId)) //{ // var rule = await _taskConsistentRuleRepository.Where(t => t.TrialId == inQuery.TrialId).ProjectTo(_mapper.ConfigurationProvider).FirstAsync(); // rule.IsBatchAdd = true; // await BatchAddOrUpdateTaskConsistentRule(rule); //} //#endregion //var taskConsistentRuleQueryable = _taskConsistentRuleRepository.Where(t => t.TrialId == inQuery.TrialId) // .ProjectTo(_mapper.ConfigurationProvider); var list = await taskConsistentRuleQueryable.ToListAsync(); var rule = await _taskConsistentRuleRepository.Where(t => t.TrialId == inQuery.TrialId && t.IsSelfAnalysis == true && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync(); return ResponseOutput.Ok(list, rule); } [HttpPost] [UnitOfWork] [TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task UpdateTrialVirtualSiteCode(UpdateTrialSiteCodeCommand inCommand) { if (_trialSiteRepository.Where(t => t.TrialId == inCommand.TrialId, false, true).Any(t => t.TrialSiteCode == inCommand.VirtualSiteCode)) { return ResponseOutput.NotOk(_localizer["TaskConsistent_SiteCodeExists"]); } var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == inCommand.TrialId); var oldCode = trial.VitrualSiteCode; trial.VitrualSiteCode = inCommand.VirtualSiteCode; await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => t.TrialId == trial.Id, u => new VisitTask() { BlindTrialSiteCode = inCommand.VirtualSiteCode }); await _taskConsistentRuleRepository.BatchUpdateNoTrackingAsync(t => t.TrialId == trial.Id, u => new TaskConsistentRule() { BlindTrialSiteCode = inCommand.VirtualSiteCode }); await _visitTaskRepository.ExecuteUpdateAsync(t => t.TrialId == trial.Id, s => s.SetProperty(e => e.BlindSubjectCode, u => u.BlindSubjectCode.Replace(oldCode, inCommand.VirtualSiteCode))); await _trialVirtualSiteCodeUpdateRepository.AddAsync(new TrialVirtualSiteCodeUpdate() { VirturalSiteCode = inCommand.VirtualSiteCode, TrialId = inCommand.TrialId }); await _trialRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } public async Task> GetUpdateVirtualSiteCodeList(Guid trialId) { var list = await _trialVirtualSiteCodeUpdateRepository.Where(t => t.TrialId == trialId).Select(t => new UpdateTrialSiteCodeCommandView() { TrialId = trialId, VirtualSiteCode = t.VirturalSiteCode, Creatime = t.CreateTime }).OrderByDescending(t => t.Creatime).ToListAsync(); return list; } [TrialGlobalLimit( "AfterStopCannNotOpt" )] public async Task AddOrUpdateTaskConsistentRule(TaskConsistentRuleAddOrEdit addOrEditTaskConsistentRule) { var verifyExp1 = new EntityVerifyExp() { VerifyExp = t => t.TrialId == addOrEditTaskConsistentRule.TrialId && t.IsSelfAnalysis == addOrEditTaskConsistentRule.IsSelfAnalysis && t.TrialReadingCriterionId == addOrEditTaskConsistentRule.TrialReadingCriterionId, //"已有该项目配置,不允许继续增加" VerifyMsg = _localizer["TaskConsistent_TaskGenerated"] }; if (await _visitTaskRepository.AnyAsync(t => t.IsSelfAnalysis == addOrEditTaskConsistentRule.IsSelfAnalysis && t.TrialId == addOrEditTaskConsistentRule.TrialId && t.TrialReadingCriterionId == addOrEditTaskConsistentRule.TrialReadingCriterionId)) { //"该标准已有Subject 生成了任务,不允许修改配置" return ResponseOutput.NotOk(_localizer["TaskConsistent_MedicalAuditTaskExists"]); } if (_trialSiteRepository.Where(t => t.TrialId == addOrEditTaskConsistentRule.TrialId, false, true).Any(t => t.TrialSiteCode == addOrEditTaskConsistentRule.BlindTrialSiteCode)) { return ResponseOutput.NotOk(_localizer["TaskConsistent_SiteCodeExists"]); } var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == addOrEditTaskConsistentRule.TrialId); if (string.IsNullOrEmpty(trial.VitrualSiteCode)) { await _trialVirtualSiteCodeUpdateRepository.AddAsync(new TrialVirtualSiteCodeUpdate() { VirturalSiteCode = addOrEditTaskConsistentRule.BlindTrialSiteCode, TrialId = addOrEditTaskConsistentRule.TrialId }); } trial.VitrualSiteCode = addOrEditTaskConsistentRule.BlindTrialSiteCode; var entity = await _taskConsistentRuleRepository.InsertOrUpdateAsync(addOrEditTaskConsistentRule, true, verifyExp1); return ResponseOutput.Ok(entity.Id.ToString()); } [TrialGlobalLimit( "AfterStopCannNotOpt" )] [HttpDelete("{taskConsistentRuleId:guid}")] public async Task DeleteTaskConsistentRule(Guid taskConsistentRuleId) { var config = await _taskConsistentRuleRepository.FirstOrDefaultAsync(t => t.Id == taskConsistentRuleId); if (await _visitTaskRepository.AnyAsync(t => t.IsAnalysisCreate && t.TrialId == config.TrialId && t.IsSelfAnalysis == config.IsSelfAnalysis && t.TrialReadingCriterionId == config.TrialReadingCriterionId)) { //"该标准已产生一致性分析任务,不允许删除" throw new BusinessValidationFailedException(_localizer["TaskConsistent_SignedTaskCannotBeInvalidated"]); } var success = await _taskConsistentRuleRepository.DeleteFromQueryAsync(t => t.Id == taskConsistentRuleId, true); return ResponseOutput.Ok(); } /// /// 获取自身一致性分析 符合条件的subject 数组 /// /// /// public async Task> GetSelfConsistentRuleMatchSubjectIdListAsync(SelfConsistentSimpleQuery inQuery) { var filterObj = await _taskConsistentRuleRepository.FirstOrDefaultAsync(t => t.Id == inQuery.TaskConsistentRuleId); var subjectList = await GetIQueryableDoctorSelfConsistentSubjectView(filterObj, inQuery.DoctorUserId).Select(t => new SubjectGeneratedTask() { SubjectId = t.SubjectId, IsHaveGeneratedTask = t.IsHaveGeneratedTask }).ToListAsync(); return subjectList; } /// /// 获取组件一致性分析符合条件的subject 数组 /// /// /// public async Task> GetGroupConsistentRuleMatchSubjectIdListAsync(GroupConsistentSimpleQuery inQuery) { var filterObj = await _taskConsistentRuleRepository.FirstOrDefaultAsync(t => t.TrialId == inQuery.TrialId && t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId && t.IsSelfAnalysis == false); var subjectList = await (await GetGroupConsistentQueryAsync(filterObj)).Select(t => new SubjectGeneratedTask() { SubjectId = t.SubjectId, IsHaveGeneratedTask = t.IsHaveGeneratedTask }).ToListAsync(); return subjectList; } } }