using IRaCIS.Application.Interfaces; using IRaCIS.Application.Contracts; using IRaCIS.Core.Application.Filter; using IRaCIS.Core.Domain.Share; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using IRaCIS.Core.Application.Auth; using MassTransit; using Panda.DynamicWebApi.Attributes; using DocumentFormat.OpenXml.Spreadsheet; using AutoMapper.EntityFrameworkCore; using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Application.Service.Reading.Dto; using Microsoft.Extensions.Options; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration.Json; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using SharpCompress.Common; using System.Reactive.Subjects; using Subject = IRaCIS.Core.Domain.Models.Subject; using IRaCIS.Core.Application.ViewModel; using Medallion.Threading; using IRaCIS.Core.Infrastructure; using EasyCaching.Core; using Pipelines.Sockets.Unofficial.Arenas; using IRaCIS.Core.Application.Contracts; using MailKit.Search; using DocumentFormat.OpenXml.Office2010.Excel; using IRaCIS.Core.Application.Contracts.Dicom.DTO; using IRaCIS.Core.Application.Helper; using NPOI.SS.Formula.Functions; using System.Linq; using System.Linq.Dynamic.Core; using System.Text; using DocumentFormat.OpenXml.EMMA; using Azure; using System.IO.Compression; using static IRaCIS.Core.Domain.Share.StaticData; using FellowOakDicom; using DocumentFormat.OpenXml.Office2010.Drawing; using EasyCaching.Core.DistributedLock; using IDistributedLockProvider = Medallion.Threading.IDistributedLockProvider; using DocumentFormat.OpenXml.InkML; namespace IRaCIS.Application.Services { [ApiExplorerSettings(GroupName = "Trial")] public class PatientService : BaseService { private readonly IRepository _trialRepository; private readonly IRepository _patientRepository; private readonly IRepository _scpStudyRepository; private readonly IRepository _subjectRepository; private readonly IRepository _subjectVisitRepository; private readonly IDistributedLockProvider _distributedLockProvider; public PatientService(IRepository studyRepository, IRepository trialRepository, IRepository patientRepository, IRepository subjectRepository, IRepository subjectVisitRepository, IDistributedLockProvider distributedLockProvider) { _scpStudyRepository = studyRepository; _trialRepository = trialRepository; _patientRepository = patientRepository; _subjectRepository = subjectRepository; _subjectVisitRepository = subjectVisitRepository; _distributedLockProvider = distributedLockProvider; } /// /// scp 影像推送记录表 /// /// /// [HttpPost] public async Task>> GetSCPImageUploadList(SCPImageUploadQuery inQuery) { var query = _repository.Where() .WhereIf(!string.IsNullOrWhiteSpace(inQuery.CalledAE), t => t.CalledAE.Contains(inQuery.CalledAE)) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAEIP), t => t.CallingAEIP.Contains(inQuery.CallingAEIP)) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.CallingAE.Contains(inQuery.CallingAE)) .WhereIf(inQuery.StartTime != null, t => t.StartTime >= inQuery.StartTime) .WhereIf(inQuery.EndTime != null, t => t.EndTime <= inQuery.EndTime) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.TrialSiteKeyInfo), t => t.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteKeyInfo) || t.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteKeyInfo) || t.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteKeyInfo)) .ProjectTo(_mapper.ConfigurationProvider); var pageList = await query.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, inQuery.SortField == string.Empty ? nameof(SCPImageUploadView.CallingAE) : inQuery.SortField, inQuery.Asc); return ResponseOutput.Ok(pageList); } #region 患者检查管理 /// ///影像检查列表-患者为维度组织 /// /// /// [HttpPost] public async Task>> GetPatientList(PatientTrialQuery inQuery) { #region new ok var query = _patientRepository.Where(t => t.TrialId == inQuery.TrialId) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.PatientIdStr.Contains(inQuery.PatientIdStr)) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.PatientName.Contains(inQuery.PatientName)) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubejctCode), t => t.Subject.Code.Contains(inQuery.SubejctCode)) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.TrialSiteKeyInfo), t => t.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteKeyInfo) || t.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteKeyInfo) || t.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteKeyInfo)) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.SCPStudyList.Any(t => t.CallingAE == inQuery.CallingAE)) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.CalledAE), t => t.SCPStudyList.Any(t => t.CalledAE == inQuery.CalledAE)) .WhereIf(inQuery.BeginPushTime != null, t => t.LatestPushTime >= inQuery.BeginPushTime) .WhereIf(inQuery.EndPushTime != null, t => t.LatestPushTime <= inQuery.EndPushTime); //foreach (var calledAE in inQuery.CalledAEList) //{ // query = query.Where(t => t.SCPStudyList.Select(c => c.CalledAE).Contains(calledAE)); //} var resultQuery = from patient in query select new PatientSubjectView() { PatientId = patient.Id, PatientBirthDate = patient.PatientBirthDate, CreateTime = patient.CreateTime, CalledAEList = patient.SCPStudyList.Select(t => t.CalledAE).Distinct().ToList(), CallingAEList = patient.SCPStudyList.Select(t => t.CallingAE).Distinct().ToList(), CreateUserId = patient.CreateUserId, UpdateTime = patient.UpdateTime, UpdateUserId = patient.UpdateUserId, EarliestStudyTime = patient.EarliestStudyTime, LatestStudyTime = patient.LatestStudyTime, LatestPushTime = patient.LatestPushTime, PatientAge = patient.PatientAge, PatientName = patient.PatientName, PatientIdStr = patient.PatientIdStr, PatientSex = patient.PatientSex, StudyCount = patient.SCPStudyList.Count(), TrialId = patient.TrialId, SubejctId = patient.SubjectId, SubjectCode = patient.Subject.Code, TrialSiteAliasName = patient.TrialSite.TrialSiteAliasName, TrialSiteCode = patient.TrialSite.TrialSiteCode, TrialSiteName = patient.TrialSite.TrialSiteName }; var pageList = await resultQuery.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, inQuery.SortField == string.Empty ? nameof(PatientQueryView.PatientIdStr) : inQuery.SortField, inQuery.Asc); #endregion return ResponseOutput.Ok(pageList); } /// /// 影像检查列表-> 获取患者的检查列表 /// /// /// [HttpPost] public async Task> GetPatientStudyList(PatientStudyInfoQuery inQuery) { var query = from scpStudy in _scpStudyRepository.Where(t => t.PatientId == inQuery.PatientId) .WhereIf(inQuery.EarliestStudyTime != null, t => t.StudyTime >= inQuery.EarliestStudyTime) .WhereIf(inQuery.LatestStudyTime != null, t => t.StudyTime <= inQuery.LatestStudyTime) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.Modalities), t => t.Modalities.Contains(inQuery.Modalities)) select new PatientStudySimpleView() { Description = scpStudy.Description, CalledAE = scpStudy.CalledAE, CallingAE = scpStudy.CallingAE, InstanceCount = scpStudy.InstanceCount, Modalities = scpStudy.Modalities, PatientId = scpStudy.PatientId, SCPStudyId = scpStudy.Id, SeriesCount = scpStudy.SeriesCount, StudyTime = scpStudy.StudyTime, SubjectVisitId = scpStudy.SubjectVisitId, VisitName = scpStudy.SubjectVisit.VisitName, BlindName = scpStudy.SubjectVisit.BlindName }; //var sortField = string.IsNullOrWhiteSpace(inQuery.SortField) ? nameof(PatientStudySimpleView.StudyTime) : inQuery.SortField; //var orderQuery = inQuery.Asc ? query.OrderBy(sortField) : query.OrderBy(sortField + " desc"); //var list = await orderQuery.ToListAsync(); var pageList = await query.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, inQuery.SortField == string.Empty ? nameof(PatientStudySimpleView.StudyTime) : inQuery.SortField, inQuery.Asc); return pageList; } public async Task> GetDicomCalledAEList(Guid trialId) { var list = await _scpStudyRepository.Where(t => t.TrialId == trialId).Select(t => t.CalledAE).Distinct().ToListAsync(); return list; } public async Task> GetDicomCallingAEList(Guid trialId) { var list = await _scpStudyRepository.Where(t => t.TrialId == trialId).Select(t => t.CallingAE).Distinct().ToListAsync(); return list; } public async Task> GetDicomModalityList(Guid trialId) { var list = await _scpStudyRepository.Where(t => t.TrialId == trialId).SelectMany(t => t.SeriesList).Select(t=>t.Modality).Distinct().ToListAsync(); return list; } /// /// 影像访视上传 检查列表 /// /// /// [HttpPost] public async Task> GetVisitPatientStudyFilterList(VisitPatientStudyFilterQuery inQuery) { var trialSiteId = _subjectRepository.Where(t => t.Id == inQuery.SubjectId).Select(t => t.TrialSiteId).FirstOrDefault(); var query = from scpStudy in _scpStudyRepository //未绑定的患者,或者自己已绑定但是未绑定访视的 .Where(t => t.Patient.SubjectId == null || (t.Patient.SubjectId == inQuery.SubjectId && t.SubjectVisitId == null)) //中心 .Where(t => t.TrialSiteId == trialSiteId) .WhereIf(inQuery.EarliestStudyTime != null, t => t.StudyTime >= inQuery.EarliestStudyTime) .WhereIf(inQuery.LatestStudyTime != null, t => t.StudyTime <= inQuery.LatestStudyTime) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.Modalities), t => t.Modalities.Contains(inQuery.Modalities)) .WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientInfo), t => t.PatientIdStr.Contains(inQuery.PatientInfo) || t.PatientName.Contains(inQuery.PatientInfo) || t.PatientSex.Contains(inQuery.PatientInfo)) select new VisitPatientStudyFilterView() { Description = scpStudy.Description, CalledAE = scpStudy.CalledAE, CallingAE = scpStudy.CallingAE, InstanceCount = scpStudy.InstanceCount, Modalities = scpStudy.Modalities, PatientId = scpStudy.PatientId, SCPStudyId = scpStudy.Id, SeriesCount = scpStudy.SeriesCount, StudyTime = scpStudy.StudyTime, BodyPartExamined=scpStudy.BodyPartExamined, AccessionNumber=scpStudy.AccessionNumber, PatientBirthDate=scpStudy.PatientBirthDate, PatientAge = scpStudy.PatientAge, PatientIdStr = scpStudy.PatientIdStr, PatientName = scpStudy.PatientName, PatientSex = scpStudy.PatientSex, }; var pageList = await query.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, inQuery.SortField == string.Empty ? nameof(PatientStudySimpleView.StudyTime) : inQuery.SortField, inQuery.Asc); return pageList; } /// /// 提交 患者检查和访视的绑定 /// /// /// [HttpPost] [UnitOfWork] [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task SubmitVisitStudyBinding(SubmitVisitStudyBindingCommand inCommand) { var subjectId = inCommand.SubjectId; var subjectVisitId = inCommand.SubjectVisitId; var trialId = inCommand.TrialId; var @lock = _distributedLockProvider.CreateLock($"StudyCode"); using (await @lock.AcquireAsync()) { var dbStudyCodeIntMax = _repository.Where(s => s.TrialId == inCommand.TrialId).Select(t => t.Code).DefaultIfEmpty().Max(); int currentNextCodeInt = dbStudyCodeIntMax + 1; foreach (var scpStudyId in inCommand.SCPStudyIdList) { var find = _scpStudyRepository.Where(t => t.Id == scpStudyId).Include(t => t.SeriesList).Include(t => t.InstanceList).FirstOrDefault(); if (find != null) { var newStuty = _mapper.Map(find); await _repository.AddAsync(newStuty); newStuty.SeqId = Guid.Empty; newStuty.Code = currentNextCodeInt; newStuty.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(DicomStudy)); newStuty.IsFromPACS = true; newStuty.TrialId = trialId; newStuty.SubjectId = subjectId; newStuty.SubjectVisitId = subjectVisitId; var newSeriesList = _mapper.Map>(find.SeriesList); foreach (var series in newSeriesList) { series.SeqId = Guid.Empty; series.TrialId = trialId; series.SubjectId = subjectId; series.SubjectVisitId = subjectVisitId; } await _repository.AddRangeAsync(newSeriesList); var newInstanceList = _mapper.Map>(find.InstanceList); foreach (var instance in newInstanceList) { instance.SeqId = Guid.Empty; instance.TrialId = trialId; instance.SubjectId = subjectId; instance.SubjectVisitId = subjectVisitId; } await _repository.AddRangeAsync(newInstanceList); } currentNextCodeInt++; } } await _repository.SaveChangesAsync(); return ResponseOutput.Ok(); } #endregion } }