418 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			418 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C#
		
	
	
using IRaCIS.Core.Infrastructure.ExpressionExtend;
 | 
						||
using IRaCIS.Application.Interfaces;
 | 
						||
using IRaCIS.Application.Contracts;
 | 
						||
using IRaCIS.Core.Infra.EFCore;
 | 
						||
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.Application.Service.Inspection.Interface;
 | 
						||
using Newtonsoft.Json;
 | 
						||
using IRaCIS.Core.Infrastructure;
 | 
						||
using MassTransit;
 | 
						||
using IRaCIS.Core.Domain.Common;
 | 
						||
 | 
						||
namespace IRaCIS.Application.Services
 | 
						||
{
 | 
						||
    [ApiExplorerSettings(GroupName = "Trial")]
 | 
						||
    public class VisitPlanService : BaseService, IVisitPlanService
 | 
						||
    {
 | 
						||
        private readonly IRepository<VisitStage> _visitStageRepository;
 | 
						||
        private readonly IRepository<Trial> _trialRepository;
 | 
						||
        private readonly IRepository<SubjectVisit> _subjectVisitRepository;
 | 
						||
        private readonly IRepository<VisitPlanInfluenceStat> _influnceStatRepository;
 | 
						||
        private readonly IRepository<VisitPlanInfluenceStudy> _influnceRepository;
 | 
						||
        private readonly IInspectionService _inspectionService;
 | 
						||
 | 
						||
        public VisitPlanService(IRepository<VisitStage> visitStageRepository, IRepository<Trial> trialRepository, IRepository<SubjectVisit> subjectVisitRepository,
 | 
						||
            IRepository<VisitPlanInfluenceStat> influnceStatRepository,
 | 
						||
            IRepository<VisitPlanInfluenceStudy> visitPlanInfluenceStudy,
 | 
						||
 | 
						||
            IInspectionService inspectionService)
 | 
						||
        {
 | 
						||
            _visitStageRepository = visitStageRepository;
 | 
						||
            _trialRepository = trialRepository;
 | 
						||
            this._subjectVisitRepository = subjectVisitRepository;
 | 
						||
            this._influnceStatRepository = influnceStatRepository;
 | 
						||
            this._influnceRepository = visitPlanInfluenceStudy;
 | 
						||
            this._inspectionService = inspectionService;
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        ///暂时不用
 | 
						||
        /// <summary> 获取项目访视计划</summary>
 | 
						||
        public async Task<PageOutput<VisitStageDTO>> 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<VisitStageDTO>(_mapper.ConfigurationProvider);
 | 
						||
 | 
						||
            return await visitStageQuery.ToPagedListAsync(param.PageIndex, param.PageSize, "CreateTime", param.Asc);
 | 
						||
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary> 根据项目Id,获取项目访视计划(不分页)[New]</summary>
 | 
						||
        [HttpGet("{trialId:guid}")]
 | 
						||
        public async Task<VisitPlanView> GetVisitStageList(Guid trialId)
 | 
						||
        {
 | 
						||
            var query = _visitStageRepository.AsQueryable(true).Where(u => u.TrialId == trialId)
 | 
						||
                .ProjectTo<VisitStageDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum);
 | 
						||
            var list = await query.ToListAsync();
 | 
						||
            var trial = (await _repository.FirstOrDefaultAsync<Trial>(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)
 | 
						||
            };
 | 
						||
        }
 | 
						||
 | 
						||
        /// <summary>
 | 
						||
        /// 获取访视计划下拉框列表
 | 
						||
        /// </summary>
 | 
						||
        /// <param name="trialId"></param>
 | 
						||
        /// <returns></returns>
 | 
						||
        [HttpGet("{trialId:guid}")]
 | 
						||
        public async Task<IEnumerable<VisitStageSelectDTO>> GetTrialVisitStageSelect(Guid trialId)
 | 
						||
        {
 | 
						||
            var query = _visitStageRepository.Where(u => u.TrialId == trialId)
 | 
						||
                .ProjectTo<VisitStageSelectDTO>(_mapper.ConfigurationProvider).OrderBy(t => t.VisitNum);
 | 
						||
            var list = await query.ToListAsync();
 | 
						||
            return list;
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary> 添加或更新访视计划某项[New]</summary>
 | 
						||
        [HttpPost]
 | 
						||
        [UnitOfWork]
 | 
						||
        public async Task<IResponseOutput<VisitStage>> 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(" only in  Initializing  or Ongoing  State  can operate ");
 | 
						||
 | 
						||
            }
 | 
						||
 | 
						||
            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(" For the visit plan, the VisitDay with a larger VisitNum should be larger than the VisitDay with a smaller VisitNum.");
 | 
						||
 | 
						||
                }
 | 
						||
            }
 | 
						||
 | 
						||
            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("For the visit plan, the VisitDay with a larger VisitNum should be larger than the VisitDay with a smaller VisitNum.");
 | 
						||
                }
 | 
						||
            }
 | 
						||
 | 
						||
            if (visitPlan.Id == Guid.Empty || visitPlan.Id == null)//add
 | 
						||
            {
 | 
						||
 | 
						||
                if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && (t.VisitName == visitPlan.VisitName || t.VisitNum == visitPlan.VisitNum), true))
 | 
						||
                {
 | 
						||
                    throw new BusinessValidationFailedException("A visit with the same VisitName/VisitNum already existed in the current visit plan.");
 | 
						||
                }
 | 
						||
 | 
						||
                if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine, true) && visitPlan.IsBaseLine)
 | 
						||
                {
 | 
						||
                    throw new BusinessValidationFailedException("A visit  already is baseline in the current visit plan.");
 | 
						||
                }
 | 
						||
 | 
						||
                //不用前端传递的值
 | 
						||
                visitPlan.BlindName = "B" + ((int)visitPlan.VisitNum * 10).ToString("D3");
 | 
						||
 | 
						||
                var visitPlanItem = await _visitStageRepository.InsertFromDTOAsync(visitPlan,true);
 | 
						||
 | 
						||
                #region 废弃前
 | 
						||
 | 
						||
                // var visitPlanItem = _mapper.Map<VisitStage>(visitPlan);
 | 
						||
 | 
						||
                //visitPlanItem.BlindName = "B" + ((int)visitPlanItem.VisitNum * 10).ToString("D3");
 | 
						||
 | 
						||
                //var result = await _visitStageRepository.AddAsync(visitPlanItem,true);
 | 
						||
                #endregion
 | 
						||
 | 
						||
 | 
						||
                return ResponseOutput.Ok(visitPlanItem);
 | 
						||
            }
 | 
						||
 | 
						||
            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("A visit with the same VisitName/VisitNum already existed in the current visit plan.");
 | 
						||
                }
 | 
						||
 | 
						||
                if (await _visitStageRepository.AnyAsync(t => t.TrialId == visitPlan.TrialId && t.IsBaseLine && t.Id != visitPlan.Id, true) && visitPlan.IsBaseLine)
 | 
						||
                {
 | 
						||
                    throw new BusinessValidationFailedException("A visit  already is baseline in the current visit plan.");
 | 
						||
                }
 | 
						||
 | 
						||
                #region 废弃前  
 | 
						||
 | 
						||
                //var stage = (await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == visitPlan.Id, true)).IfNullThrowException();
 | 
						||
 | 
						||
                ////修改是否是基线
 | 
						||
                //if (stage.IsBaseLine && stage.IsBaseLine != visitPlan.IsBaseLine)
 | 
						||
                //{
 | 
						||
                //    if (await _repository.Where<SubjectVisit>(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<SubjectVisit>(t => t.TrialId == visitPlan.TrialId).AnyAsync(v => v.IsBaseLine && v.SubmitState >= SubmitStateEnum.ToSubmit))
 | 
						||
                    {
 | 
						||
                        throw new BusinessValidationFailedException("有CRC已经为基线上传了影像数据,不允许修改基线");
 | 
						||
                    }
 | 
						||
                }
 | 
						||
 | 
						||
 | 
						||
                return ResponseOutput.Ok(stage);
 | 
						||
            }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        [UnitOfWork]
 | 
						||
        [HttpPost("{trialId:guid}")]
 | 
						||
        [TrialAudit(AuditType.TrialAudit, AuditOptType.ConfirmTrialVisitPlan)]
 | 
						||
 | 
						||
        public async Task<IResponseOutput> 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 });
 | 
						||
 | 
						||
 | 
						||
            //找到访视计划修改的Item
 | 
						||
            var changedList = await _visitStageRepository.Where(t => t.TrialId == trialId && t.IsConfirmed == false)
 | 
						||
                .Select(t => new
 | 
						||
                {
 | 
						||
                    t.Trial.IsHaveFirstGiveMedicineDate,
 | 
						||
                    t.Id,
 | 
						||
                    t.VisitName,
 | 
						||
                    t.TrialId,
 | 
						||
                    t.VisitWindowLeft,
 | 
						||
                    t.VisitWindowRight,
 | 
						||
                    t.VisitDay,
 | 
						||
                    t.VisitNum,
 | 
						||
                    t.IsBaseLine,
 | 
						||
                    t.BlindName,
 | 
						||
                    t.Description,
 | 
						||
                    IsConfirmed = true,
 | 
						||
                }).ToListAsync();
 | 
						||
 | 
						||
 | 
						||
            List<DataInspection> datas = new List<DataInspection>();
 | 
						||
 | 
						||
            var createtime = DateTime.Now.AddSeconds(1);
 | 
						||
 | 
						||
 | 
						||
            changedList.ForEach(x =>
 | 
						||
            {
 | 
						||
 | 
						||
                datas.Add(new DataInspection()
 | 
						||
                {
 | 
						||
                    IsSign = false,
 | 
						||
 | 
						||
                    CreateTime = createtime,
 | 
						||
                    //SubjectVisitName = x.VisitName,
 | 
						||
                    VisitStageId = x.Id,
 | 
						||
                    TrialId = x.TrialId,
 | 
						||
                    JsonDetail = x.ToJcJson(),
 | 
						||
                    Identification = "Confirm|Visit Plan Template|Data|Trial Setting-Visit Plan",
 | 
						||
 | 
						||
                });
 | 
						||
 | 
						||
            });
 | 
						||
 | 
						||
          
 | 
						||
 | 
						||
 | 
						||
            //foreach (var changedItem in changedList)
 | 
						||
            //{
 | 
						||
                
 | 
						||
            //    var list = await _subjectVisitRepository.Where(t => t.TrialId == trialId && t.VisitStageId == changedItem.Id).ToListAsync();
 | 
						||
            //    list.ForEach(x =>
 | 
						||
            //    {
 | 
						||
            //        datas.Add(new DataInspection()
 | 
						||
            //        {
 | 
						||
            //            BlindName = x.BlindName,
 | 
						||
            //            IsSign = false,
 | 
						||
            //            SiteId = x.SiteId,
 | 
						||
            //            SubjectId = x.SubjectId,
 | 
						||
            //            SubjectVisitId = x.Id,
 | 
						||
            //            CreateTime = createtime,
 | 
						||
            //            SubjectVisitName = x.VisitName,
 | 
						||
            //            TrialId = x.TrialId,
 | 
						||
            //            Reason = "确认访视修改状态",
 | 
						||
            //            JsonDetail = JsonConvert.SerializeObject(new
 | 
						||
            //            {
 | 
						||
            //                IsBaseLine = changedItem.IsBaseLine,
 | 
						||
            //                VisitName = changedItem.VisitName,
 | 
						||
            //                VisitNum = changedItem.VisitNum,
 | 
						||
            //                VisitDay = changedItem.VisitDay,
 | 
						||
            //                SubmitState = x.SubmitState,
 | 
						||
            //                VisitWindowLeft = changedItem.VisitWindowLeft,
 | 
						||
            //                VisitWindowRight = changedItem.VisitWindowRight
 | 
						||
            //            }),
 | 
						||
            //            Identification = "Edit|Visit|Info|Visit-Image Upload"
 | 
						||
            //        });
 | 
						||
            //    });
 | 
						||
 | 
						||
            //}
 | 
						||
 | 
						||
            var subjectsids = _repository.GetQueryable<Subject>().Where(x => x.TrialId == trialId).Select(x => new
 | 
						||
            {
 | 
						||
                x.Code,
 | 
						||
                x.SiteId,
 | 
						||
                x.Id,
 | 
						||
                x.IsEnrollment,
 | 
						||
                x.IsUrgent,
 | 
						||
 | 
						||
            });
 | 
						||
 | 
						||
            List<SubjectVisit> subjectVisits = new List<SubjectVisit>();
 | 
						||
 | 
						||
 | 
						||
 | 
						||
            var trial = await _repository.GetQueryable<Trial>().FirstOrDefaultAsync(x => x.Id == trialId);
 | 
						||
 | 
						||
            var addvisitStages = await _visitStageRepository.Where(x => !x.IsHaveFirstConfirmed && x.TrialId == trialId).ToListAsync();
 | 
						||
 | 
						||
 | 
						||
        
 | 
						||
            //await _subjectVisitRepository.AddRangeAsync()
 | 
						||
            await _repository.AddRangeAsync(subjectVisits);
 | 
						||
 | 
						||
            //访视计划 整体状态变更为 确认
 | 
						||
            await _visitStageRepository.BatchUpdateNoTrackingAsync(u => u.TrialId == trialId, t => new VisitStage() { IsConfirmed = true, IsHaveFirstConfirmed = true });
 | 
						||
 | 
						||
            await _repository.SaveChangesAsync();
 | 
						||
            return ResponseOutput.Ok();
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
 | 
						||
 | 
						||
        [HttpGet("{trialId:guid}")]
 | 
						||
        public async Task<List<VisitPlanInfluenceSubjectVisitStatDTO>> GetInfluenceHistoryList(Guid trialId, [FromServices] IRepository<VisitPlanInfluenceStat> _influnceStatRepository)
 | 
						||
        {
 | 
						||
            var list = await _influnceStatRepository.Where(t => t.TrialId == trialId).ProjectTo<VisitPlanInfluenceSubjectVisitStatDTO>(_mapper.ConfigurationProvider).OrderByDescending(t => t.CreateTime).ToListAsync();
 | 
						||
 | 
						||
            return list;
 | 
						||
        }
 | 
						||
 | 
						||
        [HttpGet("{visitPlanInfluenceStatId:guid}")]
 | 
						||
        public async Task<IActionResult> DownloadInflunceStudyList(Guid visitPlanInfluenceStatId)
 | 
						||
        {
 | 
						||
            var list = _influnceRepository.Where(t => t.VisitPlanInfluenceStatId == visitPlanInfluenceStatId)
 | 
						||
                .ProjectTo<VisitPlanInfluenceSubjectVisitDTO>(_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");
 | 
						||
 | 
						||
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
        /// <summary> 删除项目计划某一项 废弃  </summary>
 | 
						||
        [HttpDelete("{id:guid}/{trialId:guid}")]
 | 
						||
        [TrialAudit(AuditType.TrialAudit, AuditOptType.DeleteTrialVisitPlanItem)]
 | 
						||
        [TypeFilter(typeof(TrialResourceFilter))]
 | 
						||
        [Obsolete]
 | 
						||
        public async Task<IResponseOutput> DeleteVisitStage(Guid id)
 | 
						||
        {
 | 
						||
 | 
						||
            var visitPlan = await _visitStageRepository.FirstOrDefaultAsync(t => t.Id == id);
 | 
						||
 | 
						||
            if (visitPlan == null) return Null404NotFound(visitPlan);
 | 
						||
 | 
						||
            if (await _repository.AnyAsync<SubjectVisit>(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<SubjectVisit>(t => t.TrialId == visitPlan.TrialId && t.VisitName == visitPlan.VisitName);
 | 
						||
 | 
						||
            var result = await _visitStageRepository.BatchDeleteNoTrackingAsync(u => u.Id == id);
 | 
						||
 | 
						||
            return ResponseOutput.Result(result);
 | 
						||
        }
 | 
						||
 | 
						||
 | 
						||
    }
 | 
						||
} |