irc-netcore-api/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs

533 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<SubjectVisit> _subjectVisitRepository;
private readonly IRepository<DicomInstance> _dicomInstanceRepository;
private readonly IRepository<DicomSeries> _dicomSeriesRepository;
public StudyService( IEasyCachingProvider provider
, IRepository<SubjectVisit> subjectVisitRepository,
IRepository<DicomInstance> dicomInstanceRepository,
IRepository<DicomSeries> dicomSeriesRepository)
{
_provider = provider;
_subjectVisitRepository = subjectVisitRepository;
_dicomInstanceRepository = dicomInstanceRepository;
_dicomSeriesRepository = dicomSeriesRepository;
}
[HttpPost]
public async Task<PageOutput<UnionStudyViewModel>> GetDicomAndNoneDicomStudyList(StudyQuery studyQuery)
{
var svExpression = QCCommon.GetDicomStudySubjectVisitFilter(studyQuery.VisitPlanArray);
var dicomStudyQuery = _repository.Where<DicomStudy>(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<UnionStudyViewDodel>(_mapper.ConfigurationProvider);
var svExpression2 = QCCommon.GetNoneDicomStudySubjectVisitFilter(studyQuery.VisitPlanArray);
var nodeDicomStudyQuery = _repository.Where<NoneDicomStudy>(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<UnionStudyViewDodel>(_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<PageOutput<UnionStudyMonitorModel>> GetDicomAndNoneDicomStudyMonitorList(StudyQuery studyQuery)
{
var svExpression = QCCommon.GetStudyMonitorSubjectVisitFilter(studyQuery.VisitPlanArray);
var StudyMonitorQuery = _repository.Where<StudyMonitor>(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<StudyMonitor>(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<UnionStudyViewDodel>(_mapper.ConfigurationProvider);
//var nodeDicomStudyQuery = _repository.Where<StudyMonitor>(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<UnionStudyViewDodel>(_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
}
/// <summary> 指定资源Id渲染Dicom检查的Jpeg预览图像 </summary>
/// <param name="studyId"> Dicom检查的Id </param>
[HttpGet("{studyId:guid}")]
public async Task<FileContentResult> Preview(Guid studyId)
{
string path = String.Empty;
DicomInstance dicomInstance = await _repository.FirstOrDefaultAsync<DicomInstance>(s => s.StudyId == studyId);
if (dicomInstance != null)
{
DicomStudy dicomStudy = await _repository.FirstOrDefaultAsync<DicomStudy>(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");
}
}
/// <summary>
/// 获取某个检查的关联检查列表(该受试者在这个想项目下的所有检查)
/// 点击检查检查列表中的一个检查获取对应的序列列表(调用之前的接口:/series/list/根据StudyId获取访视的序列列表
/// </summary>
/// <returns></returns>
[HttpGet("{subjectVisitId:guid}")]
[AllowAnonymous]
public IResponseOutput<List<RelationStudyDTO>> 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<DicomStudy>(u => u.SubjectVisitId == subjectVisitId).Select(t => new { t.SubjectId, t.TrialId }).FirstOrDefault().IfNullThrowException();
var query = _repository.Where<DicomStudy>(t => t.SubjectVisitId != subjectVisitId && t.TrialId == studyInfo.TrialId && t.SubjectId == studyInfo.SubjectId)
.ProjectTo<RelationStudyDTO>(_mapper.ConfigurationProvider).ToList();
var list = query.OrderBy(u => u.VisitName).ThenBy(s => s.StudyCode).ToList();
return ResponseOutput.Ok(list);
}
/// <summary> 指定资源Id获取Dicom检查信息 </summary>
/// <param name="studyId"> Dicom检查的Id </param>
[HttpGet, Route("{studyId:guid}")]
[AllowAnonymous]
public IResponseOutput<DicomStudyDTO> Item(Guid studyId)
{
return ResponseOutput.Ok(_mapper.Map<DicomStudyDTO>(_repository.Where<DicomStudy>().FirstOrDefault(s => s.Id == studyId)));
}
/// <summary>
/// 批量验证 检查是否可以上传 并告知原因
/// </summary>
[HttpPost]
public IResponseOutput<List<VerifyStudyUploadResult>> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo)
{
var trialInfo = _repository.Where<Trial>().FirstOrDefault(t => t.Id == verifyInfo.TrialId).IfNullThrowException();
var result = new List<VerifyStudyUploadResult>();
var visitList = _repository.Where<SubjectVisit>(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<Subject>(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<DicomStudy>(t => t.TrialId == trialId && t.Id == expectStudyId).ProjectTo<VerifyStudyDto>(_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;
}
/// <summary>
/// 获取保存到Dicom文件中的信息
/// </summary>
/// <param name="subjectVisitId"></param>
/// <returns></returns>
public DicomTrialSiteSubjectInfo GetSaveToDicomInfo(Guid subjectVisitId)
{
//6表连接 subject trial trialSite sponsor subjectVisit site
var info = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).ProjectTo<DicomTrialSiteSubjectInfo>(_mapper.ConfigurationProvider).FirstOrDefault().IfNullThrowException();
return info;
}
public (List<string> SeriesInstanceUid, List<string> 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);
}
}
}