using IRaCIS.Core.Infrastructure.ExpressionExtend; using IRaCIS.Application.Interfaces; using IRaCIS.Application.Contracts; using IRaCIS.Core.Application.Filter; using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Application.MediatR.CommandAndQueries; using Magicodes.ExporterAndImporter.Core; using Magicodes.ExporterAndImporter.Excel; using Magicodes.ExporterAndImporter.Excel.AspNetCore; using IRaCIS.Core.Infrastructure; using Microsoft.AspNetCore.Authorization; using IRaCIS.Core.Application.Auth; namespace IRaCIS.Application.Services { [ApiExplorerSettings(GroupName = "Trial")] public class VisitPlanService : BaseService, IVisitPlanService { private readonly IRepository _visitStageRepository; private readonly IRepository _trialRepository; private readonly IRepository _subjectVisitRepository; private readonly IRepository _influnceRepository; public VisitPlanService(IRepository visitStageRepository, IRepository trialRepository, IRepository subjectVisitRepository, IRepository visitPlanInfluenceStudy) { _visitStageRepository = visitStageRepository; _trialRepository = trialRepository; _subjectVisitRepository = subjectVisitRepository; _influnceRepository = visitPlanInfluenceStudy; } ///暂时不用 /// 获取项目访视计划 [HttpPost] public async Task> GetTrialVisitStageList(VisitPlanQueryDTO param) { var visitStageQuery = _visitStageRepository.AsQueryable(true).Where(u => u.TrialId == param.TrialId) .WhereIf(!string.IsNullOrWhiteSpace(param.Keyword), t => t.VisitName.Contains(param.Keyword)) .ProjectTo(_mapper.ConfigurationProvider); return await visitStageQuery.ToPagedListAsync(param.PageIndex, param.PageSize, "CreateTime", param.Asc); } /// 根据项目Id,获取项目访视计划(不分页)[New] [HttpGet("{trialId:guid}")] public async Task GetVisitStageList(Guid trialId) { var query = _visitStageRepository.AsQueryable(true).Where(u => u.TrialId == trialId) .ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum); var list = await query.ToListAsync(); var trial = (await _repository.FirstOrDefaultAsync(t => t.Id == trialId)).IfNullThrowException(); return new VisitPlanView() { VisitPlanList = list, TimePointsPerPatient = trial.TimePointsPerPatient, VisitPlanConfirmed = trial.VisitPlanConfirmed, IsHaveFirstGiveMedicineDate = trial.IsHaveFirstGiveMedicineDate, //SubjectHasAdded = _subjectVisitRepository.Any(t => t.TrialId == trialId) }; } /// /// 获取访视计划下拉框列表 /// /// /// [HttpGet("{trialId:guid}")] public async Task> GetTrialVisitStageSelect(Guid trialId) { var query = _visitStageRepository.Where(u => u.TrialId == trialId) .ProjectTo(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum); var list = await query.ToListAsync(); return list; } /// 添加或更新访视计划某项 [UnitOfWork] [HttpPost] [Authorize(Policy = IRaCISPolicy.PMAndAPM)] public async Task AddOrUpdateVisitStage(VisitPlanCommand visitPlan) { if (!await _trialRepository.Where(t => t.Id == visitPlan.TrialId).IgnoreQueryFilters().AnyAsync(t => t.TrialStatusStr == StaticData.TrialOngoing || t.TrialStatusStr == StaticData.TrialInitializing)) { throw new BusinessValidationFailedException("只有当项目状态为:初始化或进行中时,可以操作。 "); } var visitPlanList = await _visitStageRepository.Where(t => t.TrialId == visitPlan.TrialId, ignoreQueryFilters: true) .Select(t => new { t.Id, t.VisitNum, t.VisitDay }).OrderBy(t => t.VisitNum).ToListAsync(); //更新的时候,需要排除自己 if (visitPlan.Id != null) { visitPlanList = visitPlanList.Where(t => t.Id != visitPlan.Id).ToList(); } if (visitPlanList.Any(t => t.VisitNum < visitPlan.VisitNum)) { //比当前 visitNum小的 visitDay的最大值 还小 不允许添加 if (visitPlan.VisitDay <= visitPlanList.Where(t => t.VisitNum < visitPlan.VisitNum).Select(t => t.VisitDay).Max()) { throw new BusinessValidationFailedException("访视计划中,访视号大的访视,其访视间隔也应该比访视号小的访视大。"); } } if (visitPlanList.Any(t => t.VisitNum > visitPlan.VisitNum)) { if (visitPlan.VisitDay >= visitPlanList.Where(t => t.VisitNum > visitPlan.VisitNum).Select(t => t.VisitDay).Min()) { throw new BusinessValidationFailedException("访视计划中,访视号大的计划访视,其访视间隔也应该比访视号小的计划访视大。"); } } if (visitPlan.Id == Guid.Empty || visitPlan.Id == null)//add { var trial = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == visitPlan.TrialId)).IfNullThrowException(); trial.VisitPlanConfirmed = false; if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum), true)) { throw new BusinessValidationFailedException("访视计划中已经存在具有项目访视名称或者访视号的计划访视模板。"); } if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine, true) && visitPlan.IsBaseLine) { throw new BusinessValidationFailedException("访视计划中已经存在基线。"); } //不用前端传递的值 visitPlan.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3"); var visitPlanItem = await _visitStageRepository.InsertFromDTOAsync(visitPlan, true); #region 废弃前 // var visitPlanItem = _mapper.Map(visitPlan); //visitPlanItem.BlindName = "B" + ((int)visitPlanItem.VisitNum * 10).ToString("D3"); //var result = await _visitStageRepository.AddAsync(visitPlanItem,true); #endregion return ResponseOutput.Ok(visitPlanItem.Id); } else//update { if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum) && t.Id != visitPlan.Id, true)) { throw new BusinessValidationFailedException("访视计划中已经存在具有项目访视名称或者访视号的计划访视模板。"); } if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine && t.Id != visitPlan.Id, true) && visitPlan.IsBaseLine) { throw new BusinessValidationFailedException("访视计划中已经存在基线。"); } #region 废弃前 //var stage = (await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == visitPlan.Id, true)).IfNullThrowException(); ////修改是否是基线 //if (stage.IsBaseLine && stage.IsBaseLine != visitPlan.IsBaseLine) //{ // if (await _repository.Where(t => t.TrialId == visitPlan.TrialId).AnyAsync(v => v.IsBaseLine && v.SubmitState >= SubmitStateEnum.ToSubmit)) // { // throw new BusinessValidationFailedException("有CRC已经为基线上传了影像数据,不允许修改基线"); // } //} //_mapper.Map(visitPlan, stage); //stage.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3"); //await _visitStageRepository.SaveChangesAsync(); #endregion //不用前端传递的值 visitPlan.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3"); //返回的是数据库查询的数据 var stage = await _visitStageRepository.UpdateFromDTOAsync(visitPlan, true); if (stage.IsBaseLine && stage.IsBaseLine != visitPlan.IsBaseLine) { if (await _repository.Where(t => t.TrialId == visitPlan.TrialId).AnyAsync(v => v.IsBaseLine && v.SubmitState >= SubmitStateEnum.ToSubmit)) { throw new BusinessValidationFailedException("有受试者的基线已经上传了影像数据,不允许修改基线访视。"); } } return ResponseOutput.Ok(); } } [UnitOfWork] [HttpPost("{trialId:guid}")] [Authorize(Policy = IRaCISPolicy.PMAndAPM)] public async Task ConfirmTrialVisitPlan(Guid trialId) { if (!await _trialRepository.AnyAsync(t => t.Id == trialId && (t.TrialStatusStr == StaticData.TrialInitializing || t.TrialStatusStr == StaticData.TrialOngoing))) { return ResponseOutput.NotOk("仅仅在项目初始化或者进行中时,才允许修改确认"); } if (!await _visitStageRepository.AnyAsync(t => t.TrialId == trialId && t.IsBaseLine)) { return ResponseOutput.NotOk("没有基线,不允许确认"); } if (!await _trialRepository.AnyAsync(t => t.Id == trialId && t.IsTrialBasicLogicConfirmed && t.IsTrialProcessConfirmed && t.IsTrialUrgentConfirmed)) { return ResponseOutput.NotOk("项目配置未确认,不允许确认访视计划"); } var svList = await _visitStageRepository.Where(t => t.TrialId == trialId).Select(u => new { u.VisitDay, u.IsBaseLine }).ToListAsync(); if (svList.Min(t => t.VisitDay) != svList.Where(t => t.IsBaseLine).FirstOrDefault()?.VisitDay) { return ResponseOutput.NotOk("基线VisitDay 不是最小的, 不允许确认"); } //更新项目访视计划状态为已确认 必定生成更新的sql 通过状态改变 触发操作 //await _trialRepository.UpdatePartialNowNoQueryAsync(trialId, t => new Trial() { VisitPlanConfirmed = true }); var trial = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId)).IfNullThrowException(); trial.VisitPlanConfirmed = true; var subjects = _repository.GetQueryable().Where(x => x.TrialId == trialId).Select(x => new { x.Code, x.SiteId, x.Id, x.IsEnrollment, x.IsUrgent, x.TrialId }); List subjectVisits = new List(); var addvisitStages = await _visitStageRepository.Where(x => !x.IsHaveFirstConfirmed && x.TrialId == trialId).ToListAsync(); addvisitStages.ForEach(visitPlan => { subjects.ForEach(subject => { var addSv = _mapper.Map(visitPlan); addSv.SubjectId = subject.Id; addSv.TrialId = subject.TrialId; addSv.SiteId = subject.SiteId; subjectVisits.Add(addSv); }); }); await _subjectVisitRepository.AddRangeAsync(subjectVisits); //访视计划 整体状态变更为 确认 await _visitStageRepository.UpdatePartialFromQueryAsync(u => u.TrialId == trialId && u.IsConfirmed == false, t => new VisitStage() { IsConfirmed = true, IsHaveFirstConfirmed = true }); await _visitStageRepository.SaveChangesAsync(); return ResponseOutput.Ok(); } [HttpGet("{trialId:guid}")] public async Task> GetInfluenceHistoryList(Guid trialId, [FromServices] IRepository _influnceStatRepository) { var list = await _influnceStatRepository.Where(t => t.TrialId == trialId).ProjectTo(_mapper.ConfigurationProvider).OrderByDescending(t => t.CreateTime).ToListAsync(); return list; } [HttpGet("{visitPlanInfluenceStatId:guid}")] public async Task DownloadInflunceStudyList(Guid visitPlanInfluenceStatId) { var list = _influnceRepository.Where(t => t.VisitPlanInfluenceStatId == visitPlanInfluenceStatId) .ProjectTo(_mapper.ConfigurationProvider).ToList(); IExporter exporter = new ExcelExporter(); var result = await exporter.ExportAsByteArray(list); return new XlsxFileResult(bytes: result, fileDownloadName: $"检查导出_{DateTime.Now.ToString("yyyy-MM-dd:hh:mm:ss")}.xlsx"); } /// 删除项目计划某一项 废弃 [HttpDelete("{id:guid}/{trialId:guid}")] [TrialAudit(AuditType.TrialAudit, AuditOptType.DeleteTrialVisitPlanItem)] [TypeFilter(typeof(TrialResourceFilter))] [Obsolete] public async Task DeleteVisitStage(Guid id) { var visitPlan = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == id); if (visitPlan == null) return Null404NotFound(visitPlan); if (await _repository.AnyAsync(t => t.VisitName == visitPlan.VisitName && t.TrialId == visitPlan.TrialId && t.VisitExecuted == VisitExecutedEnum.Executed)) { return ResponseOutput.NotOk("The visit plan has been assigned to the subjects and executed."); } await _repository.BatchDeleteAsync(t => t.TrialId == visitPlan.TrialId && t.VisitName == visitPlan.VisitName); var result = await _visitStageRepository.BatchDeleteNoTrackingAsync(u => u.Id == id); return ResponseOutput.Result(result); } } }