using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Domain.Share; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using IRaCIS.Core.Application.Services; using EasyCaching.Core; using System.Linq.Expressions; using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Infrastructure; namespace IRaCIS.Core.Application.Service.ImageAndDoc { [ApiExplorerSettings(GroupName = "Image")] public class StudyService : BaseService, IStudyService { private readonly IEasyCachingProvider _provider; private readonly IRepository _subjectVisitRepository; private readonly IRepository _dicomInstanceRepository; private readonly IRepository _dicomSeriesRepository; public StudyService( IEasyCachingProvider provider , IRepository subjectVisitRepository, IRepository dicomInstanceRepository, IRepository dicomSeriesRepository) { _provider = provider; _subjectVisitRepository = subjectVisitRepository; _dicomInstanceRepository = dicomInstanceRepository; _dicomSeriesRepository = dicomSeriesRepository; } [HttpPost] public async Task> GetDicomAndNoneDicomStudyList(StudyQuery studyQuery) { var svExpression = QCCommon.GetDicomStudySubjectVisitFilter(studyQuery.VisitPlanArray); var dicomStudyQuery = _repository.Where(t => t.TrialId == studyQuery.TrialId) .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id)) //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo)) .WhereIf(studyQuery.VisitPlanArray != null && studyQuery.VisitPlanArray?.Length > 0, svExpression) .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo)) .Select(t => new UnionStudyViewModel() { TrialId = t.TrialId, SiteId = t.SiteId, SubjectId = t.SubjectId, SubjectVisitId = t.SubjectVisitId, VisitName = t.SubjectVisit.VisitName, VisitNum = t.SubjectVisit.VisitNum, IsDicom = true, SubjectCode = t.Subject.Code, Id = t.Id, Bodypart = t.BodyPartExamined, Modalities = t.Modalities, Count = t.SeriesCount, StudyCode = t.StudyCode, //DicomStudyCode = t.StudyCode, //NoneDicomCode = 0, StudyTime = t.StudyTime, TrialSiteAliasName = t.TrialSite.TrialSiteAliasName, TrialSiteCode = t.TrialSite.TrialSiteCode, Uploader = t.Uploader.UserName, UploadTime = t.CreateTime }); //.ProjectTo(_mapper.ConfigurationProvider); var svExpression2 = QCCommon.GetNoneDicomStudySubjectVisitFilter(studyQuery.VisitPlanArray); var nodeDicomStudyQuery = _repository.Where(t => t.TrialId == studyQuery.TrialId) .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id)) //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo)) .WhereIf(studyQuery.VisitPlanArray != null && studyQuery.VisitPlanArray?.Length > 0, svExpression2) .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo)) .Select(t => new UnionStudyViewModel() { TrialId = t.TrialId, SiteId = t.SiteId, SubjectId = t.SubjectId, SubjectVisitId = t.SubjectVisitId, VisitName = t.SubjectVisit.VisitName, VisitNum = t.SubjectVisit.VisitNum, IsDicom = false, SubjectCode = t.Subject.Code, Id = t.Id, Bodypart = t.BodyPart, Modalities = t.Modality, Count = t.NoneDicomFileList.Count(), StudyCode = t.StudyCode, //NoneDicomCode = t.Code, //DicomStudyCode = string.Empty, StudyTime = t.ImageDate, TrialSiteAliasName = t.TrialSite.TrialSiteAliasName, TrialSiteCode = t.TrialSite.TrialSiteCode, Uploader = t.CreateUser.UserName, UploadTime = t.CreateTime }); //.ProjectTo(_mapper.ConfigurationProvider); var unionQuery = dicomStudyQuery.Union(nodeDicomStudyQuery) .WhereIf(studyQuery.SubjectId != null, t => t.SubjectId == studyQuery.SubjectId) .WhereIf(studyQuery.SubjectVisitId != null, t => t.SubjectId == studyQuery.SubjectVisitId) .WhereIf(studyQuery.SiteId != null, t => t.SiteId == studyQuery.SiteId); return await unionQuery.ToPagedListAsync(studyQuery.PageIndex, studyQuery.PageSize, studyQuery.SortField, studyQuery.Asc); } [HttpPost] public async Task> GetDicomAndNoneDicomStudyMonitorList(StudyQuery studyQuery) { var svExpression = QCCommon.GetStudyMonitorSubjectVisitFilter(studyQuery.VisitPlanArray); var StudyMonitorQuery = _repository.Where(t => t.TrialId == studyQuery.TrialId) .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id)) //.WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo)) .WhereIf(studyQuery.VisitPlanArray != null && studyQuery.VisitPlanArray?.Length > 0, svExpression) .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo)) .WhereIf(studyQuery.SubjectId != null, t => t.SubjectId == studyQuery.SubjectId) .WhereIf(studyQuery.SubjectVisitId != null, t => t.SubjectId == studyQuery.SubjectVisitId) .WhereIf(studyQuery.SiteId != null, t => t.SiteId == studyQuery.SiteId) .Select(t => new UnionStudyMonitorModel() { TrialId = t.TrialId, SiteId = t.SiteId, SubjectId = t.SubjectId, SubjectVisitId = t.SubjectVisitId, VisitName = t.SubjectVisit.VisitName, VisitNum = t.SubjectVisit.VisitNum, SubjectCode = t.Subject.Code, TrialSiteAliasName = t.TrialSite.TrialSiteAliasName, TrialSiteCode = t.TrialSite.TrialSiteCode, Uploader = t.Uploader.UserName, UploadTime = t.CreateTime, IsSuccess=t.IsSuccess, Note=t.Note, IP = t.IP, FileCount = t.FileCount, FileSize = t.FileSize, UploadFinishedTime = t.UploadFinishedTime, UploadStartTime = t.UploadStartTime, TotalMillisecondsInterval = t.TotalMillisecondsInterval, IsDicomReUpload = t.IsDicomReUpload, StudyId = t.Id, IsDicom = t.IsDicom, StudyCode = t.StudyCode }); return await StudyMonitorQuery.ToPagedListAsync(studyQuery.PageIndex, studyQuery.PageSize, string.IsNullOrEmpty(studyQuery.SortField) ? "UploadTime" : studyQuery.SortField, studyQuery.Asc); #region 冗余查询 //var dicomStudyQuery = _repository.Where(t => t.TrialId == studyQuery.TrialId && t.IsDicom) // .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id)) // .WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo)) // .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo)) // .Select(t => new UnionStudyMonitorModel() // { // TrialId = t.TrialId, // SiteId = t.SiteId, // SubjectId = t.SubjectId, // SubjectVisitId = t.SubjectVisitId, // VisitName = t.SubjectVisit.VisitName, // VisitNum = t.SubjectVisit.VisitNum, // SubjectCode = t.Subject.Code, // TrialSiteAliasName = t.TrialSite.TrialSiteAliasName, // TrialSiteCode = t.TrialSite.TrialSiteCode, // Uploader = t.Uploader.FullName, // UploadTime = t.CreateTime, // IP = t.IP, // FileCount = t.FileCount, // FileSize = t.FileSize, // UploadFinishedTime = t.UploadFinishedTime, // UploadStartTime = t.UploadStartTime, // TotalMillisecondsInterval = t.TotalMillisecondsInterval, // IsDicomReUpload = t.IsDicomReUpload, // StudyId = t.Id, // IsDicom = t.IsDicom, // StudyCode = t.DicomStudy.StudyCode // //DicomStudyCode = t.DicomStudy.StudyCode, // //NoneDicomCode = 0, // }); ////.ProjectTo(_mapper.ConfigurationProvider); //var nodeDicomStudyQuery = _repository.Where(t => t.TrialId == studyQuery.TrialId && t.IsDicom == false) // .WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator, t => t.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.Id)) // .WhereIf(!string.IsNullOrEmpty(studyQuery.VisitPlanInfo), studyQuery.VisitPlanInfo.Contains('.') ? t => t.SubjectVisit.VisitNum.ToString().Contains(".") : t => t.SubjectVisit.VisitNum == decimal.Parse(studyQuery.VisitPlanInfo)) // .WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo)) // .Select(t => new UnionStudyMonitorModel() // { // TrialId = t.TrialId, // SiteId = t.SiteId, // SubjectId = t.SubjectId, // SubjectVisitId = t.SubjectVisitId, // VisitName = t.SubjectVisit.VisitName, // VisitNum = t.SubjectVisit.VisitNum, // SubjectCode = t.Subject.Code, // TrialSiteAliasName = t.TrialSite.TrialSiteAliasName, // TrialSiteCode = t.TrialSite.TrialSiteCode, // Uploader = t.Uploader.FullName, // UploadTime = t.CreateTime, // IP = t.IP, // FileCount = t.FileCount, // FileSize = t.FileSize, // UploadFinishedTime = t.UploadFinishedTime, // UploadStartTime = t.UploadStartTime, // TotalMillisecondsInterval = t.TotalMillisecondsInterval, // IsDicomReUpload = t.IsDicomReUpload, // StudyId = t.Id, // IsDicom = t.IsDicom, // StudyCode = t.NoneDicomStudy.StudyCode // //DicomStudyCode = string.Empty, // //NoneDicomCode = t.NoneDicomStudy.Code, // }); ////.ProjectTo(_mapper.ConfigurationProvider); //var unionQuery = dicomStudyQuery.Union(nodeDicomStudyQuery) // .WhereIf(studyQuery.SubjectId != null, t => t.SubjectId == studyQuery.SubjectId) // .WhereIf(studyQuery.SubjectVisitId != null, t => t.SubjectId == studyQuery.SubjectVisitId) // .WhereIf(studyQuery.SiteId != null, t => t.SiteId == studyQuery.SiteId); //return await unionQuery.ToPagedListAsync(studyQuery.PageIndex, studyQuery.PageSize, string.IsNullOrEmpty(studyQuery.SortField) ? "UploadTime" : studyQuery.SortField, studyQuery.Asc); #endregion } /// 指定资源Id,渲染Dicom检查的Jpeg预览图像 /// Dicom检查的Id [HttpGet("{studyId:guid}")] public async Task Preview(Guid studyId) { string path = String.Empty; DicomInstance dicomInstance = await _repository.FirstOrDefaultAsync(s => s.StudyId == studyId); if (dicomInstance != null) { DicomStudy dicomStudy = await _repository.FirstOrDefaultAsync(s => s.Id == dicomInstance.StudyId); if (dicomStudy != null) { path = FileStoreHelper.GetDicomInstanceFilePath(_hostEnvironment, dicomStudy.TrialId, dicomStudy.SiteId, dicomStudy.SubjectId, dicomStudy.SubjectVisitId, dicomStudy.Id, dicomInstance.Id); } } using (var sw = ImageHelper.RenderPreviewJpeg(path)) { var bytes = new byte[sw.Length]; sw.Read(bytes, 0, bytes.Length); sw.Close(); return new FileContentResult(bytes, "image/jpeg"); } } /// /// 获取某个检查的关联检查列表(该受试者在这个想项目下的所有检查) /// 点击检查检查列表中的一个检查获取对应的序列列表(调用之前的接口:/series/list/,根据StudyId,获取访视的序列列表) /// /// [HttpGet("{subjectVisitId:guid}")] [AllowAnonymous] public IResponseOutput> GetAllRelationStudyList(Guid subjectVisitId) { #region 废弃 //var studylist = _studyRepository.Where(u => u.SubjectVisitId == subjectVisitId && u.IsDeleted == false).Select(t => new { StudyId = t.Id, t.SubjectId, t.TrialId }).ToList(); //var subjectId = studylist.FirstOrDefault().SubjectId; //var trialId = studylist.FirstOrDefault().TrialId; //var studyIds = studylist.Select(t => t.StudyId).ToList(); //var query = from studyItem in _studyRepository.Where(u => u.SubjectId == subjectId // && u.TrialId == trialId && u.IsDeleted == false && // !studyIds.Contains(u.Id) // /* && u.Status != (int)StudyStatus.Abandon*/) // join visitItem in _subjectVisitRepository.AsQueryable() // on studyItem.SubjectVisitId equals visitItem.Id // select new RelationStudyDTO // { // StudyId = studyItem.Id, // StudyCode = studyItem.StudyCode, // VisitName = visitItem.VisitName, // Modalities = studyItem.Modalities, // Description = studyItem.Description, // SeriesCount = studyItem.SeriesCount // }; #endregion var studyInfo = _repository.Where(u => u.SubjectVisitId == subjectVisitId).Select(t => new { t.SubjectId, t.TrialId }).FirstOrDefault().IfNullThrowException(); var query = _repository.Where(t => t.SubjectVisitId != subjectVisitId && t.TrialId == studyInfo.TrialId && t.SubjectId == studyInfo.SubjectId) .ProjectTo(_mapper.ConfigurationProvider).ToList(); var list = query.OrderBy(u => u.VisitName).ThenBy(s => s.StudyCode).ToList(); return ResponseOutput.Ok(list); } /// 指定资源Id,获取Dicom检查信息 /// Dicom检查的Id [HttpGet, Route("{studyId:guid}")] [AllowAnonymous] public IResponseOutput Item(Guid studyId) { return ResponseOutput.Ok(_mapper.Map(_repository.Where().FirstOrDefault(s => s.Id == studyId))); } /// /// 批量验证 检查是否可以上传 并告知原因 /// [HttpPost] public IResponseOutput> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo) { var trialInfo = _repository.Where().FirstOrDefault(t => t.Id == verifyInfo.TrialId).IfNullThrowException(); var result = new List(); var visitList = _repository.Where(t => t.SubjectId == verifyInfo.SubjectId).Select(t => new { t.VisitNum, t.EarliestScanDate, t.LatestScanDate, t.Id }).ToList(); verifyInfo.StudyInstanceUidList.ForEach(waitUploadItem => { if (trialInfo.IsVerifyVisitImageDate) { //小于当前访视 最近的最晚拍片 var before = visitList.Where(u => u.VisitNum < verifyInfo.VisitNum).Max(k => k.LatestScanDate); if (before != null && waitUploadItem.StudyDate != null && before > waitUploadItem.StudyDate) { result.Add(new VerifyStudyUploadResult() { ErrorMesseage = $"当前访视检查时间{waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")}不能早于前序访视检查时间{before?.ToString("yyyy-MM-dd")},请核对检查数据是否有误", StudyInstanceUid = waitUploadItem.StudyInstanceUid }); return; } //大于当前访视 最近的最早拍片日期 var after = visitList.Where(u => u.VisitNum > verifyInfo.VisitNum).Min(k => k.EarliestScanDate); if (after != null && waitUploadItem.StudyDate != null && after < waitUploadItem.StudyDate) { result.Add(new VerifyStudyUploadResult() { ErrorMesseage = $"当前访视检查时间{waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")}不能晚于该访视之后的检查时间{after?.ToString("yyyy-MM-dd")},请核对检查数据是否有误", StudyInstanceUid = waitUploadItem.StudyInstanceUid }); return; } } var temp = VerifyStudyUpload(waitUploadItem.StudyInstanceUid, verifyInfo.TrialId, verifyInfo.SubjectVisitId, verifyInfo.SubjectId); result.Add(temp); }); return ResponseOutput.Ok(result); } private VerifyStudyUploadResult VerifyStudyUpload(string studyInstanceUid, Guid trialId, Guid currentSubjectVisitId, Guid SubjectId) { var result = new VerifyStudyUploadResult(); if (_provider.Exists("StudyUid_" + studyInstanceUid)) { result.AllowUpload = false; result.AllowReUpload = false; result.StudyInstanceUid = studyInstanceUid; result.ErrorMesseage = "当前有人正在上传归档该检查!"; return result; } if (_repository.Where(t => t.Id == SubjectId).Select(t => t.Status).FirstOrDefault() == SubjectStatus.EndOfVisit) { result.AllowUpload = false; result.AllowReUpload = false; result.StudyInstanceUid = studyInstanceUid; result.ErrorMesseage = "受试者访视结束,不允许上传!"; return result; } Guid expectStudyId = IdentifierHelper.CreateGuid(studyInstanceUid.Trim(), trialId.ToString()); var verifyStudyInfo = _repository.Where(t => t.TrialId == trialId && t.Id == expectStudyId).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault(); result.StudyInfo = verifyStudyInfo; //数据库不存在该检查 允许上传 if (verifyStudyInfo == null) { result.AllowUpload = true; } //数据库该项目有该检查 看是否支持重传 else { //是同一个受试者 支持重传 if (verifyStudyInfo.SubjectId == SubjectId && verifyStudyInfo.SubjectVisitId == currentSubjectVisitId) { result.AllowReUpload = true; } //不是同一个受试者 else { //有默认值,其实不用写,这里为了好理解 result.AllowUpload = false; result.AllowReUpload = false; result.ErrorMesseage = $"此处不可以上传。当前影像检查已经上传给受试者{verifyStudyInfo.SubjectCode}的{verifyStudyInfo.VisitName}"; } } result.StudyInstanceUid = studyInstanceUid; return result; } /// /// 获取保存到Dicom文件中的信息 /// /// /// public DicomTrialSiteSubjectInfo GetSaveToDicomInfo(Guid subjectVisitId) { //6表连接 subject trial trialSite sponsor subjectVisit site var info = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).ProjectTo(_mapper.ConfigurationProvider).FirstOrDefault().IfNullThrowException(); return info; } public (List SeriesInstanceUid, List SopInstanceUid) GetHasUploadSeriesAndInstance(Guid studyId) { var seriesInstanceUidList = _dicomSeriesRepository.Where(t => t.StudyId == studyId).Select(t => t.SeriesInstanceUid).ToList(); var sopInstanceUidList = _dicomInstanceRepository.Where(t => t.StudyId == studyId).Select(t => t.SopInstanceUid).ToList(); return (seriesInstanceUidList, sopInstanceUidList); } } }