irc-netcore-api/IRaCIS.Core.Application/Service/Visit/PatientService.cs

394 lines
17 KiB
C#

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<Trial> _trialRepository;
private readonly IRepository<SCPPatient> _patientRepository;
private readonly IRepository<SCPStudy> _scpStudyRepository;
private readonly IRepository<Subject> _subjectRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
public PatientService(IRepository<SCPStudy> studyRepository, IRepository<Trial> trialRepository, IRepository<SCPPatient> patientRepository, IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository, IDistributedLockProvider distributedLockProvider)
{
_scpStudyRepository = studyRepository;
_trialRepository = trialRepository;
_patientRepository = patientRepository;
_subjectRepository = subjectRepository;
_subjectVisitRepository = subjectVisitRepository;
_distributedLockProvider = distributedLockProvider;
}
/// <summary>
/// scp 影像推送记录表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<SCPImageUploadView>>> GetSCPImageUploadList(SCPImageUploadQuery inQuery)
{
var query = _repository.Where<SCPImageUpload>()
.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<SCPImageUploadView>(_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 患者检查管理
/// <summary>
///影像检查列表-患者为维度组织
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatientSubjectView>>> 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);
}
/// <summary>
/// 影像检查列表-> 获取患者的检查列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<PatientStudySimpleView>> 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<List<string>> GetDicomCalledAEList(Guid trialId)
{
var list = await _scpStudyRepository.Where(t => t.TrialId == trialId).Select(t => t.CalledAE).Distinct().ToListAsync();
return list;
}
public async Task<List<string>> GetDicomCallingAEList(Guid trialId)
{
var list = await _scpStudyRepository.Where(t => t.TrialId == trialId).Select(t => t.CallingAE).Distinct().ToListAsync();
return list;
}
public async Task<List<string>> GetDicomModalityList(Guid trialId)
{
var list = await _scpStudyRepository.Where(t => t.TrialId == trialId).SelectMany(t => t.SeriesList).Select(t=>t.Modality).Distinct().ToListAsync();
return list;
}
/// <summary>
/// 影像访视上传 检查列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<VisitPatientStudyFilterView>> 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;
}
/// <summary>
/// 提交 患者检查和访视的绑定
/// </summary>
/// <param name="inCommand"></param>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task<IResponseOutput> 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<DicomStudy>(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<DicomStudy>(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<List<DicomSeries>>(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<List<DicomInstance>>(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
}
}