using IRaCIS.Application.Interfaces; using IRaCIS.Core.Application.Contracts; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using IRaCIS.Core.Domain.Share; using EasyCaching.Core; using IRaCIS.Core.Infrastructure; using Microsoft.AspNetCore.Authorization; using IRaCIS.Core.Application.Auth; using Panda.DynamicWebApi.Attributes; using IRaCIS.Core.Infra.EFCore.Common; using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.Interfaces; using IRaCIS.Core.Application.ViewModel; using MassTransit; using IRaCIS.Core.Application.Filter; using static IRaCIS.Core.Domain.Share.StaticData; namespace IRaCIS.Core.Application { [ApiExplorerSettings(GroupName = "Trial")] public class TrialConfigService : BaseService, ITrialConfigService { private readonly IRepository _trialRepository; private readonly IRepository _trialQCQuestionRepository; private readonly IRepository _readingQuestionCriterionTrialRepository; private readonly IRepository _readingQuestionTrialRepository; private readonly IRepository _readingQuestionCriterionSystemRepository; private readonly IRepository _clinicalDataTrialSetRepository; private readonly IRepository _readingCriterionPageRepository; private readonly IEasyCachingProvider _provider; private readonly IOrganInfoService _iOrganInfoService; private readonly IRepository _taskAllocationRuleRepository; private readonly IRepository _readingCriterionDictionaryRepository; private readonly IReadingQuestionService iReadingQuestionService; public TrialConfigService(IRepository trialRepository, IRepository trialQCQuestionRepository, IRepository readingQuestionCriterionTrialRepository, IRepository readingQuestionTrialRepository, IRepository readingQuestionCriterionSystemRepository, IRepository clinicalDataTrialSetRepository, IRepository readingCriterionPageRepository, IRepository taskAllocationRuleRepository, IRepository readingCriterionDictionaryRepository, IReadingQuestionService iReadingQuestionService, IEasyCachingProvider provider, IOrganInfoService iOrganInfoService ) { _trialRepository = trialRepository; _taskAllocationRuleRepository = taskAllocationRuleRepository; this._readingCriterionDictionaryRepository = readingCriterionDictionaryRepository; this.iReadingQuestionService = iReadingQuestionService; this._trialQCQuestionRepository = trialQCQuestionRepository; this._readingQuestionCriterionTrialRepository = readingQuestionCriterionTrialRepository; this._readingQuestionTrialRepository = readingQuestionTrialRepository; this._readingQuestionCriterionSystemRepository = readingQuestionCriterionSystemRepository; this._clinicalDataTrialSetRepository = clinicalDataTrialSetRepository; this._readingCriterionPageRepository = readingCriterionPageRepository; this._provider = provider; this._iOrganInfoService = iOrganInfoService; } /// /// 阅片信息签名验证接口 /// /// /// /// [HttpPost] public async Task TrialReadingInfoSignVerify(TrialReadingInfoSignInDto inDto) { var trialCriterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).FirstOrDefaultAsync(); var existsJudge = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == trialCriterion.Id && x.IsJudgeQuestion && x.JudgeType == JudgeTypeEnum.None) .WhereIf(trialCriterion.FormType == FormType.SinglePage, x => x.ReadingCriterionPageId == null) .WhereIf(trialCriterion.FormType == FormType.MultiplePage, x => x.ReadingCriterionPageId != null) .AnyAsync(); if (existsJudge&& trialCriterion.IsArbitrationReading) { throw new BusinessValidationFailedException("有裁判问题未配置产生裁判阅片任务的条件,操作失败!"); } return ResponseOutput.Ok(true); } /// /// 获取项目已经确认的标准 /// /// [HttpPost] public async Task> GetTrialConfirmCriterionList(GetTrialConfirmCriterionListInDto inDto) { List result = await _readingQuestionCriterionTrialRepository.Where(x => x.TrialId == inDto.TrialId && x.IsConfirm) .Select(x => new GetTrialConfirmCriterionOutDto() { TrialCriterionId = x.Id, CriterionName = x.CriterionName }).ToListAsync(); return result; } /// /// 阅片信息签名 /// /// /// [NonDynamicMethod] public async Task TrialReadingInfoSign(TrialReadingInfoSignInDto inDto) { var trialCriterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id==inDto.TrialReadingCriterionId).FirstOrDefaultAsync(); var existsJudge = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == trialCriterion.Id && x.IsJudgeQuestion && x.JudgeType == JudgeTypeEnum.None) .WhereIf(trialCriterion.FormType == FormType.SinglePage, x => x.ReadingCriterionPageId == null) .WhereIf(trialCriterion.FormType == FormType.MultiplePage, x => x.ReadingCriterionPageId != null) .AnyAsync(); if (existsJudge&& trialCriterion.IsArbitrationReading) { throw new BusinessValidationFailedException("有裁判问题未配置产生裁判阅片任务的条件,操作失败!"); } await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(x => x.Id == inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial() { ReadingInfoSignTime = DateTime.Now }); var result = await _trialRepository.SaveChangesAsync(); return ResponseOutput.Ok(result); } /// /// 获取项目阅片信息 /// /// /// [HttpPost] public async Task GetCriterionReadingInfo(GetTrialReadingInfoInDto inDto) { GetTrialReadingInfoOutDto trialInfo= await _readingQuestionCriterionTrialRepository.Where(x=>x.Id==inDto.TrialReadingCriterionId).ProjectTo(_mapper.ConfigurationProvider).FirstNotNullAsync(); if (trialInfo.ReadingTool == null) { trialInfo.ReadingTool = ReadingTool.Dicom; } return trialInfo; } /// /// 同步项目标准字典信息 /// /// /// [HttpPost] public async Task AsyncTrialCriterionDictionary(AsyncTrialCriterionDictionaryInDto inDto) { var trialCriterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).FirstNotNullAsync(); if (trialCriterion.ReadingQuestionCriterionSystemId != null) { await _readingCriterionDictionaryRepository.BatchDeleteNoTrackingAsync(x => x.CriterionId == trialCriterion.Id); var criterionDictionaryList = await _readingCriterionDictionaryRepository.Where(x => x.CriterionId == trialCriterion.ReadingQuestionCriterionSystemId.Value) .ToListAsync(); criterionDictionaryList.ForEach(x => { x.Id = NewId.NextGuid(); x.Dictionary = null; x.IsSystemCriterion = false; x.CriterionId = inDto.TrialReadingCriterionId; }); if (trialCriterion.SynchronizeOriginalTime == null ) { // 同步器官 await _iOrganInfoService.SynchronizeSystemOrganToTrial(new SynchronizeSystemOrganToTrialInDto() { TrialReadingCriterionId = inDto.TrialReadingCriterionId, SystemCriterionId = trialCriterion.ReadingQuestionCriterionSystemId }); // 同步问题 await iReadingQuestionService.SynchronizeCriterion(new SynchronizeCriterionInDto() { TrialReadingCriterionId = inDto.TrialReadingCriterionId, }); var systemCriterion = await _readingQuestionCriterionSystemRepository.Where(x => x.Id == trialCriterion.ReadingQuestionCriterionSystemId).FirstNotNullAsync(); await _readingQuestionCriterionTrialRepository.BatchUpdateNoTrackingAsync(x => x.Id == inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial() { IsOncologyReading = systemCriterion.IsOncologyReading, IseCRFShowInDicomReading=systemCriterion.IseCRFShowInDicomReading, }); } await _readingCriterionDictionaryRepository.AddRangeAsync(criterionDictionaryList); await _readingQuestionCriterionTrialRepository.BatchUpdateNoTrackingAsync(x => x.Id == inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial() { SynchronizeOriginalTime = DateTime.Now }); await _readingCriterionDictionaryRepository.SaveChangesAsync(); } return ResponseOutput.Ok(true); } /// /// 修改全局阅片配置信息 /// /// /// [HttpPost] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task SetGlobalReadingInfo(SetGlobalReadingInfoInDto inDto) { //await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial() //{ // IsGlobalReading = inDto.IsGlobalReading //}); await _readingCriterionDictionaryRepository.BatchDeleteNoTrackingAsync(x => x.CriterionId == inDto.TrialReadingCriterionId && x.ParentCode == ReadingCommon.CriterionDictionary.GlobalAssess); await _readingCriterionDictionaryRepository.AddRangeAsync(inDto.GlobalAssessList.Select(x => new ReadingCriterionDictionary { CriterionId = inDto.TrialReadingCriterionId, DictionaryId = x.DictionaryId, IsBaseLineUse=x.IsBaseLineUse, IsFollowVisitUse=x.IsFollowVisitUse, IsSystemCriterion = false, ParentCode = ReadingCommon.CriterionDictionary.GlobalAssess })); var result= await _readingCriterionDictionaryRepository.SaveChangesAsync(); return ResponseOutput.Ok(result); } /// /// 获取全局阅片信息 /// /// /// [HttpPost] public async Task GetGlobalReadingInfo(GetOncologySetInDto inDto) { var trialCriterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).FirstNotNullAsync(); GetGlobalReadingOutDto result = new GetGlobalReadingOutDto() { IsGlobalReading = trialCriterion.IsGlobalReading, IsSystemCriterion= trialCriterion.ReadingQuestionCriterionSystemId!=null, IsSign=trialCriterion.ReadingInfoSignTime!=null, GlobalAssessTypes = await _readingCriterionDictionaryRepository.Where(x => x.CriterionId == inDto.TrialReadingCriterionId && x.ParentCode == ReadingCommon.CriterionDictionary.GlobalAssess ) .Select(x => new CriterionDictionaryInfo() { Id = x.Id, DictionaryId = x.DictionaryId, ChildGroup = x.Dictionary.ChildGroup, IsBaseLineUse = x.IsBaseLineUse, IsFollowVisitUse = x.IsFollowVisitUse, Code = x.Dictionary.Code, Description = x.Dictionary.Description, ShowOrder = x.Dictionary.ShowOrder, ParentCode = x.Dictionary.Parent.Code, Value = x.Dictionary.Value, ValueCN = x.Dictionary.ValueCN }).OrderBy(x => x.ParentCode).ThenBy(x => x.ShowOrder).ToListAsync() }; return result; } /// /// 获取项目肿瘤学配置 /// /// /// [HttpPost] public async Task GetOncologySet(GetOncologySetInDto inDto) { var trialCriterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).FirstNotNullAsync(); return new GetOncologySetOutDto { EvaluationReason = trialCriterion.EvaluationReason.IsNullOrEmpty()? ReadingCommon.EvaluationReason : trialCriterion.EvaluationReason, OncologyAssessIds = await _readingCriterionDictionaryRepository.Where(x => x.CriterionId == inDto.TrialReadingCriterionId && x.ParentCode == ReadingCommon.CriterionDictionary.OncologyAssess).Select(x => x.DictionaryId).ToListAsync(), IsSystemCriterion= trialCriterion.ReadingQuestionCriterionSystemId!=null, IsSign = trialCriterion.ReadingInfoSignTime != null, }; } /// /// 设置项目肿瘤学配置 /// /// /// [HttpPost] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task SetOncologySet(SetOncologySetInDto inDto) { await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial() { EvaluationResult = inDto.EvaluationResult, EvaluationReason = inDto.EvaluationReason, IsShowDetail=inDto.IsShowDetail, }); await _readingCriterionDictionaryRepository.BatchDeleteNoTrackingAsync(x => x.CriterionId == inDto.TrialReadingCriterionId && x.ParentCode == ReadingCommon.CriterionDictionary.OncologyAssess); await _readingCriterionDictionaryRepository.AddRangeAsync(inDto.OncologyAssessIds.Select(x => new ReadingCriterionDictionary { CriterionId = inDto.TrialReadingCriterionId, DictionaryId = x, IsSystemCriterion = false, ParentCode = ReadingCommon.CriterionDictionary.OncologyAssess })); var result = await _readingQuestionCriterionTrialRepository.SaveChangesAsync(); return ResponseOutput.Ok(result); } /// /// 获取项目裁判信息 /// /// /// [HttpPost] public async Task<(List,object)> GetTrialReadingJudgeList(GetTrialReadingInfoInDto inDto) { var trialCriterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).FirstOrDefaultAsync(); var judgeQuestionList= await _readingQuestionTrialRepository .WhereIf(trialCriterion.FormType==FormType.SinglePage,x=>x.ReadingCriterionPageId==null) .WhereIf(trialCriterion.FormType == FormType.MultiplePage, x => x.ReadingCriterionPageId != null) .Where(x => x.ReadingQuestionCriterionTrial.IsConfirm && x.IsJudgeQuestion && x.TrialId == inDto.TrialId&&x.ReadingQuestionCriterionTrialId== trialCriterion.Id) .Select(x => new TrialJudgeQuestion() { AnswerCombination = x.AnswerCombination, AnswerGroup = x.AnswerGroup, JudgeType = x.JudgeType, QuestionId = x.Id, PageName=x.ReadingCriterionPage.PageName, QuestionName = x.QuestionName.LanguageName(x.QuestionEnName, _userInfo.IsEn_Us), ReadingQuestionCriterionTrialId = x.ReadingQuestionCriterionTrialId }).ToListAsync(); return (judgeQuestionList, new { IsSign= trialCriterion.ReadingInfoSignTime!= null, }); } /// /// 获取项目标准分页信息 /// /// /// [HttpPost] public async Task> GetReadingCriterionPageList(GetTrialReadingInfoInDto inDto) { return await _readingCriterionPageRepository.Where(x => x.TrialId == inDto.TrialId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); } /// /// 获取项目阅片标准信息 /// /// /// [HttpPost] public async Task GetTrialReadingCriterionInfo(GetTrialReadingInfoInDto inDto) { GetTrialReadingCriterionInfoOutDto result = new GetTrialReadingCriterionInfoOutDto(); result.ReadingCriterionPageList = await _readingCriterionPageRepository.Where(x => x.TrialId == inDto.TrialId).ProjectTo(_mapper.ConfigurationProvider).OrderBy(x=>x.ShowOrder).ToListAsync(); var trialCriterion = await _readingQuestionCriterionTrialRepository.Where(x => x.Id==inDto.TrialReadingCriterionId).FirstOrDefaultAsync(); result.ReadingInfoSignTime = trialCriterion.ReadingInfoSignTime; result.DigitPlaces = trialCriterion.DigitPlaces; result.TrialCriterionId = trialCriterion.Id; result.FormType = trialCriterion.FormType; result.IsFromSystem = trialCriterion.ReadingQuestionCriterionSystemId != null; result.IsMustGlobalReading = trialCriterion.IsMustGlobalReading; result.IsSystemCriterion = trialCriterion.ReadingQuestionCriterionSystemId != null; result.TrialQuestionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrial.IsConfirm && x.TrialId == inDto.TrialId&&x.ReadingQuestionCriterionTrialId == result.TrialCriterionId &&x.ReadingCriterionPageId==null) .ProjectTo(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder).ToListAsync(); return result; } /// /// 设置项目阅片标准 /// /// [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task SetTrialReadingCriterion(SetTrialReadingCriterionInDto inDto) { if (inDto.IsSignSave) { var criterionFormType = await _readingQuestionCriterionTrialRepository.Where(x => x.Id == inDto.TrialReadingCriterionId).Select(x => x.FormType).FirstOrDefaultAsync(); var count = _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == inDto.TrialReadingCriterionId) .WhereIf(criterionFormType == FormType.SinglePage, x => x.ReadingCriterionPageId == null) .WhereIf(criterionFormType == FormType.MultiplePage, x => x.ReadingCriterionPageId != null).Count(); if (count == 0) { throw new BusinessValidationFailedException("当前标准下未配置问题"); } } await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial() { FormType = inDto.FormType, }); var result = await _trialRepository.SaveChangesAsync(); return ResponseOutput.Ok(result); } /// /// 设置项目阅片信息 /// /// /// [HttpPost] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task SetCriterionReadingInfo(SetCriterionReadingInfoInDto inDto) { ArbitrationRule arbitration = ArbitrationRule.NA; if (inDto.IsArbitrationReading) { arbitration = inDto.IsReadingPeriod ? ArbitrationRule.Reading : ArbitrationRule.Visit; } await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial() { ReadingTool=inDto.ReadingTool, IsReadingPeriod=inDto.IsReadingPeriod, //DigitPlaces=inDto.DigitPlaces, IsReadingTaskViewInOrder =inDto.IsReadingTaskViewInOrder, ReadingTaskViewEnum = inDto.ReadingTaskViewEnum, DigitPlaces= inDto.DigitPlaces, //IsImageIabeled = inDto.IsImageIabeled, IsReadingShowSubjectInfo = inDto.IsReadingShowSubjectInfo, IsReadingShowPreviousResults = inDto.IsReadingShowPreviousResults, GlobalUpdateType=inDto.GlobalUpdateType, ImagePlatform=inDto.ImagePlatform, IseCRFShowInDicomReading=inDto.IseCRFShowInDicomReading, ArbitrationRule= arbitration, ReadingType = inDto.ReadingType, IsGlobalReading = inDto.IsGlobalReading, IsArbitrationReading = inDto.IsArbitrationReading, IsOncologyReading = inDto.IsOncologyReading, }); var result = await _readingQuestionCriterionTrialRepository.SaveChangesAsync(); return ResponseOutput.Ok(result); } /// /// 获取签名文本 /// /// /// [HttpGet("{signCode}")] public async Task GetSignText(string signCode) { var signRawText = await _repository.Where(t => t.Code == signCode).Select(t => new { t.Code, t.Value, t.ValueCN, t.Id, ParentValue = t.Parent.Value, ParentValueCN = t.Parent.ValueCN }).FirstOrDefaultAsync(); if (signRawText == null) { return ResponseOutput.NotOk("该操作需要电子签名确认,但未在系统中找到该场景的签名模板。"); } return ResponseOutput.Ok(new { SignCodeId = signRawText.Id, SignCode = signRawText.Code, SignText = _userInfo.IsEn_Us? signRawText.ParentValue.Replace("xxx", signRawText.Value) : signRawText.ParentValueCN.Replace("xxx", signRawText.ValueCN), //SignTextCN = signRawText.ParentValueCN.Replace("xxx", signRawText.Value) }); } //验证 仅仅在 Initializing/Ongoing 才可以操作 private async Task VerifyOnlyInOngoingOrInitialIzingOptAsync(Guid trialId) { if (!await _trialRepository.AnyAsync(t => t.Id == trialId && (t.TrialStatusStr == StaticData.TrialState.TrialInitializing || t.TrialStatusStr == StaticData.TrialState.TrialOngoing))) { throw new BusinessValidationFailedException("该项目已结束或停止,不允许修改配置。"); } } /// /// 验证签名确认 /// /// /// /// [HttpPost] public async Task VerifyTrialConfigSignatureConfirm(SignConfirmDTO signConfirmDTO) { var trialConfig = (await _trialRepository .Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification }) .FirstOrDefaultAsync(t => t.TrialId == signConfirmDTO.TrialId)) .IfNullThrowException(); var showOrderList = await _repository.Where(t => t.TrialId == signConfirmDTO.TrialId).Select(t => new { t.ShowOrder, ParentShowOrder = (int?)t.ParentQCQuestion.ShowOrder }).ToListAsync(); if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit || trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit) { if (showOrderList.Count == 0) { throw new BusinessValidationFailedException("当前未添加影像质控审核问题。请先添加影像质控审核问题,再进行确认。"); } } if (showOrderList.Count() != showOrderList.Select(t => t.ShowOrder).Distinct().Count()) { throw new BusinessValidationFailedException("影像质控审核问题显示序号不能重复。"); } if (showOrderList.Where(t => t.ParentShowOrder != null).Any(t => t.ParentShowOrder > t.ShowOrder)) { throw new BusinessValidationFailedException("父问题的显示序号要比子问题的显示序号小,请确认。"); } if (await _trialRepository.AnyAsync(t => t.Id == signConfirmDTO.TrialId && t.QCQuestionConfirmedUserId != null && t.QCQuestionConfirmedUserId != _userInfo.Id)) { throw new BusinessValidationFailedException("影像质控审核问题已被其他人员确认,不允许再次确认。"); } return ResponseOutput.Ok(); } /// /// 签名确认 包括项目的三组配置 + QC问题确认 后修改状态 (适用于不会回退的,项目废除、状态修改, 存在回退 不在这里弄,提供单独接口修改状态) /// /// [Authorize(Policy = IRaCISPolicy.PM_APM)] public async Task TrialConfigSignatureConfirm(SignConfirmDTO signConfirmDTO) { await VerifyOnlyInOngoingOrInitialIzingOptAsync(signConfirmDTO.TrialId); if (signConfirmDTO.SignCode == ((int)SignEnum.TrialLogicConfim).ToString()) { await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialBasicLogicConfirmed = true }); } else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialProcessConfim).ToString()) { await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialProcessConfirmed = true }); } else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialUrgentConfim).ToString()) { await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialUrgentConfirmed = true }); } else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialQCQuestionConfirm).ToString()) { var trialConfig = (await _trialRepository .Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification }) .FirstOrDefaultAsync(t => t.TrialId == signConfirmDTO.TrialId)) .IfNullThrowException(); var showOrderList = await _repository.Where(t => t.TrialId == signConfirmDTO.TrialId).Select(t => new { t.ShowOrder, ParentShowOrder = (int?)t.ParentQCQuestion.ShowOrder }).ToListAsync(); if (trialConfig.QCProcessEnum == TrialQCProcess.DoubleAudit || trialConfig.QCProcessEnum == TrialQCProcess.SingleAudit) { if (showOrderList.Count == 0) { throw new BusinessValidationFailedException("当前未添加影像质控审核问题。请先添加影像质控审核问题,再进行确认。"); } } if (showOrderList.Count() != showOrderList.Select(t => t.ShowOrder).Distinct().Count()) { throw new BusinessValidationFailedException("影像质控审核问题显示序号不能重复。"); } if (showOrderList.Where(t => t.ParentShowOrder != null).Any(t => t.ParentShowOrder > t.ShowOrder)) { throw new BusinessValidationFailedException("父问题的显示序号要比子问题的显示序号小,请确认。"); } if (await _trialRepository.AnyAsync(t => t.Id == signConfirmDTO.TrialId && t.QCQuestionConfirmedUserId != null && t.QCQuestionConfirmedUserId != _userInfo.Id)) { throw new BusinessValidationFailedException("影像质控审核问题已被其他人员确认,不允许再次确认。"); } await _trialQCQuestionRepository.UpdatePartialFromQueryAsync(t => t.TrialId == signConfirmDTO.TrialId, x => new TrialQCQuestion { IsConfirm = true }); await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { QCQuestionConfirmedTime = DateTime.Now, QCQuestionConfirmedUserId = _userInfo.Id, IsQCQuestionConfirmed = true }); await _trialRepository.SaveChangesAsync(); } return ResponseOutput.Ok(); } /// /// 配置 基础逻辑信息 /// /// /// [HttpPut] [Authorize(Policy = IRaCISPolicy.PM_APM)] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })] public async Task ConfigTrialBasicInfo(BasicTrialConfig trialConfig) { await VerifyOnlyInOngoingOrInitialIzingOptAsync(trialConfig.TrialId); var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId)).IfNullThrowException(); trialConfig.Modalitys = $"|{String.Join('|', trialConfig.ModalityList)}|"; _mapper.Map(trialConfig, trialInfo); trialInfo.UpdateTime = DateTime.Now; return ResponseOutput.Ok(await _repository.SaveChangesAsync()); } /// /// 配置流程 /// /// /// [HttpPut] [Authorize(Policy = IRaCISPolicy.PM_APM)] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })] public async Task ConfigTrialProcessInfo(TrialProcessConfig trialConfig) { if (!await _trialRepository.Where(t => t.Id == trialConfig.TrialId).IgnoreQueryFilters().AnyAsync(t => t.TrialStatusStr == StaticData.TrialState.TrialInitializing)) { return ResponseOutput.NotOk("该项目当前状态不是初始化,不允许进行该操作。"); } var trialInfo = await _trialRepository.Where(t => t.Id == trialConfig.TrialId, true).Include(t => t.TrialDicList.Where(u => u.KeyName == StaticData.Criterion)).FirstOrDefaultAsync(); if (trialInfo == null) return Null404NotFound(trialInfo); _mapper.Map(trialConfig, trialInfo); //if (trialInfo.IsGlobalReading && (trialInfo.IsArbitrationReading ?? false)) //{ // trialInfo.ArbitrationRule = ArbitrationRule.Reading; //} //if (!trialInfo.IsGlobalReading && (trialInfo.IsArbitrationReading ?? false)) //{ // trialInfo.ArbitrationRule = ArbitrationRule.Visit; //} trialInfo.UpdateTime = DateTime.Now; // 修改临床数据 var noconfirmids = await _clinicalDataTrialSetRepository.Where(x => x.TrialId == trialConfig.TrialId && !trialConfig.ClinicalDataTrialSetIds.Contains(x.Id)).Select(x => x.Id).ToListAsync(); foreach (var item in trialConfig.ClinicalDataTrialSetIds) { await _clinicalDataTrialSetRepository.UpdatePartialFromQueryAsync(item, x => new ClinicalDataTrialSet() { IsConfirm = true }); } foreach (var item in noconfirmids) { await _clinicalDataTrialSetRepository.UpdatePartialFromQueryAsync(item, x => new ClinicalDataTrialSet() { IsConfirm = false }); } // 修改阅片标准 var cancelConfirmCriterionIds = await _readingQuestionCriterionTrialRepository.Where(x => x.TrialId == trialConfig.TrialId && x.IsConfirm && !trialConfig.TrialCriterionIds.Contains(x.Id)).Select(x => x.Id).ToListAsync(); await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(x => cancelConfirmCriterionIds.Contains(x.Id), x => new ReadingQuestionCriterionTrial() { IsConfirm = false }); await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(x => trialConfig.TrialCriterionIds.Contains(x.Id), x => new ReadingQuestionCriterionTrial() { IsConfirm = true }); ; return ResponseOutput.Ok(await _repository.SaveChangesAsync()); } /// /// 配置加急信息 /// /// /// [HttpPut] [Authorize(Policy = IRaCISPolicy.PM_APM)] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })] public async Task ConfigTrialUrgentInfo(TrialUrgentConfig trialConfig) { await VerifyOnlyInOngoingOrInitialIzingOptAsync(trialConfig.TrialId); var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId)).IfNullThrowException(); //项目紧急 当前所有已提交,但未完成的访视,设置为加急。后续提交的访视也设置为加急 (在提交的时候,回去判断 项目加急,Subject加急,是否入组确认,是否Pd,从而设置访视是否加急) if (trialConfig.IsUrgent) { await _repository.BatchUpdateAsync(t => t.TrialId == trialInfo.Id && t.SubmitState == SubmitStateEnum.Submitted && t.ForwardState < ForwardStateEnum.Forwarded, s => new SubjectVisit() { IsUrgent = trialConfig.IsUrgent }); } else //之前设置为加急的访视状态不变。后续提交的访视,为不加急。 { } _mapper.Map(trialConfig, trialInfo); trialInfo.UpdateTime = DateTime.Now; return ResponseOutput.Ok(await _repository.SaveChangesAsync()); } [HttpGet("{trialId:guid}")] public async Task IfTrialCanOngoing(Guid trialId) { var canOPt = await _trialRepository.AnyAsync(trial => trial.Id == trialId && trial.IsTrialBasicLogicConfirmed && trial.IsTrialProcessConfirmed && trial.IsTrialUrgentConfirmed && trial.VisitPlanConfirmed); return ResponseOutput.Ok(canOPt, msg: canOPt ? "" : "该项目的项目配置(基础配置、流程配置、加急配置) 、访视管理,有配置未确认,不能设置项目状态为启动。"); } /// /// 更新项目状态 /// /// /// /// /// [HttpPut("{trialId:guid}/{trialStatusStr}/{reason?}")] [UnitOfWork] [Authorize(Policy = IRaCISPolicy.PM)] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task UpdateTrialState(Guid trialId, string trialStatusStr, string? reason) { var trial = (await _trialRepository.Where(t => t.Id == trialId, true).IgnoreQueryFilters().FirstOrDefaultAsync()).IfNullThrowException(); if (trialStatusStr == StaticData.TrialState.TrialOngoing) { if (trial.IsTrialBasicLogicConfirmed && trial.IsTrialProcessConfirmed && trial.IsTrialUrgentConfirmed && trial.VisitPlanConfirmed) { } else { return ResponseOutput.NotOk("无法变更项目状态。该项目的项目配置、访视管理中,有未确认项"); } } if ((trialStatusStr == StaticData.TrialState.TrialStopped || trialStatusStr == StaticData.TrialState.TrialCompleted) && trial.TrialStatusStr != StaticData.TrialState.TrialOngoing) { return ResponseOutput.NotOk("项目没有进入启动状态,不能设置为停止或完成状态"); } //if (trialStatusStr != StaticData.TrialState.TrialOngoing) //{ // trial.TrialFinishTime = DateTime.Now; //} trial.TrialStateChangeList.Add(new TrialStateChange() { OriginState = trial.TrialStatusStr, NowState = trialStatusStr, Reason = reason ?? String.Empty, TrialId = trialId }); trial.TrialStatusStr = trialStatusStr; //Paused、 添加工总量 算医生读片中 if (trialStatusStr.Contains(StaticData.TrialState.TrialCompleted)) { await _repository.BatchUpdateAsync(u => u.TrialId == trialId, e => new Enroll { EnrollStatus = EnrollStatus.Finished }); await _trialRepository.BatchUpdateNoTrackingAsync(u => u.Id == trialId, s => new Trial { TrialFinishedTime = DateTime.UtcNow.AddHours(8) }); } await _provider.SetAsync(trialId.ToString(), trialStatusStr, TimeSpan.FromDays(7)); await _repository.SaveChangesAsync(); return ResponseOutput.Ok(); } /// /// 项目状态 变更历史 /// /// /// [HttpGet("{trialId:guid}")] public async Task> GetTrialStateChangeList(Guid trialId) { return await _repository.Where(t => t.TrialId == trialId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); } /// /// 废除项目 /// /// /// /// [HttpPut("{trialId:guid}/{isAbandon:bool}")] [Authorize(Policy = IRaCISPolicy.PM)] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })] public async Task AbandonTrial(Guid trialId, /*Guid? signId,*/ bool isAbandon) { await _trialRepository.UpdatePartialFromQueryAsync(trialId, u => new Trial() { IsDeleted = isAbandon, TrialFinishTime = isAbandon ? DateTime.Now : null }, true); return ResponseOutput.Ok(); } /// /// 获取 配置的所有信息 没有分多个接口 /// /// /// [HttpGet("{trialId:guid}")] public async Task GetTrialConfigInfo(Guid trialId) { return await _trialRepository.Where(t => t.Id == trialId).ProjectTo(_mapper.ConfigurationProvider) .FirstOrDefaultAsync().IfNullThrowException(); } /// /// 配置项目任务信息 /// /// /// [HttpPut] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })] //[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task ConfigTrialTaskInfo(TrialTaskConfig trialConfig) { var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId)).IfNullThrowException(); _mapper.Map(trialConfig, trialInfo); return ResponseOutput.Ok(await _trialRepository.SaveChangesAsync()); } /// /// 配置项目读片查看规则 /// /// /// [HttpPut] [TypeFilter(typeof(TrialResourceFilter),Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })] //[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task ConfigTrialReadingTaskViewRule(TrialReadingTaskViewConfig trialConfig) { var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId)).IfNullThrowException(); _mapper.Map(trialConfig, trialInfo); return ResponseOutput.Ok(await _trialRepository.SaveChangesAsync()); } } }