using IRaCIS.Core.Infrastructure.ExpressionExtend; using IRaCIS.Core.Application.Filter; using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Application.Contracts.Dicom.DTO; using Microsoft.AspNetCore.Authorization; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Interfaces; using IRaCIS.Core.Application.Service.Inspection.Interface; using Newtonsoft.Json; namespace IRaCIS.Core.Application.Services { [ApiExplorerSettings(GroupName = "Trial")] public class SubjectVisitService : BaseService, ISubjectVisitService { private readonly IRepository _subjectVisitRepository; private readonly IInspectionService _inspectionService; private readonly IRepository _subjectRepository; public SubjectVisitService(IRepository subjectVisitRepository, IInspectionService inspectionService,IRepository subjectRepository) { _subjectVisitRepository = subjectVisitRepository; this._inspectionService = inspectionService; _subjectRepository = subjectRepository; } [HttpPost] [TypeFilter(typeof(TrialResourceFilter))] [UnitOfWork] public async Task> AddOrUpdateSV(SubjectVisitCommand svCommand) { bool isadd=false; if (svCommand.Id == null) { isadd=true; } var verifyExp1 = new EntityVerifyExp() { VerifyExp = t => t.VisitNum == svCommand.VisitNum && t.SubjectId == svCommand.SubjectId, VerifyMsg = "This subject's visit plan already contains a visit with the same visitnum." }; var verifyExp2 = new EntityVerifyExp() { VerifyExp = t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit, VerifyMsg = "该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视", IsVerify=svCommand.IsFinalVisit }; svCommand.BlindName = "B" + ((int)(svCommand.VisitNum * 10)).ToString("D3"); var subject = (await _subjectRepository.FirstOrDefaultAsync(t => t.Id == svCommand.SubjectId)).IfNullThrowException(); svCommand.VisitExecuted = svCommand.IsLostVisit ? VisitExecutedEnum.Executed : svCommand.VisitExecuted; //设置末次评估后,不允许添加计划外访视 if (svCommand.InPlan == false && svCommand.Id == null) { if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit)) { return ResponseOutput.NotOk("设置末次评估后,不允许添加计划外访视"); } } //更新的时候,返回的是数据库此时的实体数据 var needDealEntity = await _subjectVisitRepository.InsertOrUpdateAsync(svCommand, false, verifyExp1, verifyExp2); if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.SubmitState == SubmitStateEnum.Submitted) { return ResponseOutput.NotOk("CRC提交后,不允许修改PD确认状态"); } if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.RequestBackState == RequestBackStateEnum.PM_AgressBack) { return ResponseOutput.NotOk("回退的访视,不允许修改PD确认状态"); } if (svCommand.IsFinalVisit) { if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitNum > svCommand.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit)) { return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视"); } subject.Status = SubjectStatus.OutOfVisit; //末次访视后的 访视设置为不可用 await _subjectVisitRepository.BatchUpdateAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitNum > svCommand.VisitNum, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable }); } else { //回退 subject.Status = SubjectStatus.OnVisit; await _subjectVisitRepository.BatchUpdateAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitExecuted == VisitExecutedEnum.Unavailable, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.UnExecuted }); } if (svCommand.IsLostVisit && svCommand.Id == null) { if (await _subjectVisitRepository.AnyAsync(t => t.Id==svCommand.Id && t.SubmitState == SubmitStateEnum.ToSubmit)) { return ResponseOutput.NotOk("该受试者此访视有影像上传,不允许设置为失访"); } } //更新受试者 首次给药日期 是否入组确认 if (svCommand.SubjectFirstGiveMedicineTime != null) { if (svCommand.IsBaseLine) { List datas = new List(); // 更新受试者 subject.FirstGiveMedicineTime = svCommand.SubjectFirstGiveMedicineTime; datas.Add(new DataInspection() { SubjectId = subject.Id, SiteId = subject.SiteId, TrialId = subject.TrialId, IsSign = false, Identification = "Edit|Subject|Info|Subject", CreateTime = DateTime.Now.AddSeconds(1), JsonDetail = JsonConvert.SerializeObject(new { FirstGiveMedicineTime = subject.FirstGiveMedicineTime.Value.ToString("yyyy-MM-dd") }) }); await _inspectionService.AddListInspectionRecordAsync(datas); } } if (svCommand.IsEnrollmentConfirm != null) { await _subjectVisitRepository.BatchUpdateAsync(t => t.SubjectId == svCommand.SubjectId && t.IsBaseLine , u => new SubjectVisit() { IsEnrollmentConfirm = svCommand.IsEnrollmentConfirm.Value }); //needDealEntity.IsUrgent = true; } await _repository.SaveChangesAsync(); if (isadd) { List dataInspection=new List(); dataInspection.Add(new DataInspection() { TrialId = svCommand.TrialId, SiteId = svCommand.SiteId, SubjectId = svCommand.SubjectId, SubjectVisitId = svCommand.Id, SubjectVisitName = svCommand.VisitName, IsSign = false, CreateTime = DateTime.Now.AddSeconds(1), Identification = "Init|Visit|Status|Visit-Image Upload", JsonDetail = JsonConvert.SerializeObject(new { VisitName = svCommand.VisitName, SubmitState = "", AuditState = "", }) }); await _inspectionService.AddListInspectionRecordAsync(dataInspection); } // 保存数据后,重新算下是否缺失影像 应对状态撤回 //if (svCommand.IsLostVisit == false) //{ // var currentSubmittedVisitNum = await _repository.Where(t => t.SubmitState == SubmitStateEnum.Submitted).MaxAsync(t => t.VisitNum); // var isMissing = await _repository.AnyAsync(t => (t.VisitNum < currentSubmittedVisitNum && t.SubmitState != SubmitStateEnum.Submitted) || t.IsLostVisit); // await _repository.UpdateFromQueryAsync(t => t.Id == svCommand.SubjectId, u => new Subject() // { // IsMissingImages = isMissing // }); //} return ResponseOutput.Ok(needDealEntity.Id.ToString()); } [HttpPut("{trialId:guid}/{subjectVisitId:guid}/{isUrgent:bool}")] public async Task SetSubjectVisitUrgent(Guid subjectVisitId, bool isUrgent) { await _subjectVisitRepository.BatchUpdateAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { IsUrgent = isUrgent }); return ResponseOutput.Ok(); } [HttpDelete, Route("{id:guid}/{trialId:guid}")] [TrialAudit(AuditType.SubjectAudit, AuditOptType.DeleteSubjectOutPlanVisit)] [TypeFilter(typeof(TrialResourceFilter))] public async Task DeleteSV(Guid id) { if (await _repository.AnyAsync(t => t.SubjectVisitId == id)) { return ResponseOutput.NotOk("This visit is associated with the uploaded study images and couldn't be deleted."); } if (await _subjectVisitRepository.AnyAsync(t => t.Id == id && t.InPlan)) { return ResponseOutput.NotOk("This visit is InPlan and couldn't be deleted."); } if (await _subjectVisitRepository.AnyAsync(t => t.OutPlanPreviousVisitId == id )) { return ResponseOutput.NotOk("This visit is OutPlanPreviousVisitId and couldn't be deleted."); } return ResponseOutput.Result(await _repository.BatchDeleteAsync(s => s.Id == id)); } /// /// 设置受试者访视已执行 也就是将studyUploaded状态置为true 为了那些没有影像 人工设置准备 /// /// /// [HttpPost("{subjectVisitId:guid}/{trialId:guid}")] [TrialAudit(AuditType.SubjectAudit, AuditOptType.SetSVExecuted)] [TypeFilter(typeof(TrialResourceFilter))] public async Task SetSVExecuted(Guid subjectVisitId) { return ResponseOutput.Result(await _subjectVisitRepository.BatchUpdateAsync(s => s.Id == subjectVisitId, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Executed })); } /// /// 获取访视下的Dicom 检查信息 分所有的, 阅片的 不阅片 isReading : 0 查询所有 1 查询仅仅阅片的 /// /// /// /// /// [HttpGet, Route("{trialId:guid}/{sujectVisitId:guid}/{isReading}")] [AllowAnonymous] public async Task> GetVisitStudyList(Guid trialId, Guid sujectVisitId, int isReading) { var studyList = await _repository.Where(t => t.TrialId == trialId && t.SubjectVisitId == sujectVisitId).Select(k => new VisitStudyDTO() { InstanceCount = k.InstanceCount, Modalities = k.Modalities, SeriesCount = k.SeriesCount, StudyCode = k.StudyCode, StudyId = k.Id }).ToListAsync(); var studyIds = studyList.Select(t => t.StudyId).ToList(); var instanceList = await _repository.Where(t => studyIds.Contains(t.StudyId)) .Select(t => new { t.SeriesId, t.Id, t.InstanceNumber }).ToListAsync(); foreach (var t in studyList) { t.SeriesList = await _repository.Where(s => s.StudyId == t.StudyId) .WhereIf(isReading == 1, s => s.IsReading).OrderBy(s => s.SeriesNumber). ThenBy(s => s.SeriesTime) .ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); t.SeriesList.ForEach(series => series.InstanceList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k => k.Id).ToList()); //设置为阅片与否 不更改数据库检查 的instance数量 和 SeriesCount 所以这里要实时统计 t.SeriesCount = t.SeriesList.Count(); t.InstanceCount = t.SeriesList.SelectMany(t => t.InstanceList).Count(); } return studyList; //return ResponseOutput.Ok(studyList.Where(t => t.SeriesList.Count > 0).ToList()); } } }