整理检查服务

Uat_Study
hang 2022-05-29 19:12:59 +08:00
parent 5d96df5d00
commit d8098a948a
12 changed files with 1715 additions and 1989 deletions

View File

@ -136,9 +136,9 @@ namespace IRaCIS.Core.API.Controllers
/// <summary> 流式上传 Dicom上传 需要返回文件数量 </summary> /// <summary> 流式上传 Dicom上传 </summary>
[Route("base")] [Route("base")]
public virtual async Task<int> DicomFileUploadAsync(Func<string ,Stream, Task> filePathFunc) public virtual async Task<int> DicomFileUploadAsync(Func<string, Stream, Task> filePathFunc)
{ {
var fileCount = 0; var fileCount = 0;
@ -155,7 +155,7 @@ namespace IRaCIS.Core.API.Controllers
if (hasContentDispositionHeader) if (hasContentDispositionHeader)
{ {
var fileName = contentDisposition.FileName.Value??String.Empty; var fileName = contentDisposition.FileName.Value ?? String.Empty;
string mediaType = section.ContentType ?? String.Empty; string mediaType = section.ContentType ?? String.Empty;
@ -172,8 +172,6 @@ namespace IRaCIS.Core.API.Controllers
++fileCount; ++fileCount;
await filePathFunc(entry.Key, entry.OpenEntryStream()); await filePathFunc(entry.Key, entry.OpenEntryStream());
} }
} }
} }
@ -186,11 +184,8 @@ namespace IRaCIS.Core.API.Controllers
await filePathFunc(fileName, section.Body); await filePathFunc(fileName, section.Body);
} }
} }
} }
section = await reader.ReadNextSectionAsync(); section = await reader.ReadNextSectionAsync();
} }
@ -223,186 +218,6 @@ namespace IRaCIS.Core.API.Controllers
_userInfo = userInfo; _userInfo = userInfo;
} }
/// <summary>Dicom 归档</summary>
[HttpPost, Route("Study/ArchiveStudy1/{trialId:guid}")]
[DisableFormValueModelBinding]
[DisableRequestSizeLimit]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> ArchiveStudy([FromForm] ArchiveStudyCommand archiveStudyCommand,
[FromServices] ILogger<UploadDownLoadController> _logger,
[FromServices] IEasyCachingProvider _provider,
[FromServices] IStudyService _studyService,
[FromServices] IDicomArchiveService _dicomArchiveService
)
{
string studycode = string.Empty;
var startTime = DateTime.Now;
if (_provider.Exists("StudyUid_" + archiveStudyCommand.StudyInstanceUid))
{
return ResponseOutput.NotOk("当前已有人正在上传和归档该检查!");
}
else
{
_provider.Set("StudyUid_" + archiveStudyCommand.StudyInstanceUid, _userInfo.Id, TimeSpan.FromMinutes(30));
}
var archiveResult = new DicomArchiveResult();
var archivedStudyIds = new List<Guid>();
var (seriesInstanceUidList, sopInstanceUidList) = (new List<string>(), new List<string>());
//重传的时候找出当前检查已经上传的series instance
if (archiveStudyCommand.AbandonStudyId != null)
{
(seriesInstanceUidList, sopInstanceUidList) = _studyService.GetHasUploadSeriesAndInstance(archiveStudyCommand.AbandonStudyId.Value);
}
var savedInfo = _studyService.GetSaveToDicomInfo(archiveStudyCommand.SubjectVisitId);
var boundary = HeaderUtilities.RemoveQuotes(MediaTypeHeaderValue.Parse(Request.ContentType).Boundary).Value;
var reader = new MultipartReader(boundary, HttpContext.Request.Body);
var section = await reader.ReadNextSectionAsync();
while (section != null)
{
//采用post方式 这里多加一个判断 过滤其他参数
if (string.IsNullOrEmpty(section.ContentType))
{
section = await reader.ReadNextSectionAsync();
continue;
}
var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out var contentDisposition);
if (hasContentDispositionHeader)
{
string fileName = contentDisposition.FileName.Value;
try
{
string mediaType = section.ContentType;
if (mediaType.Contains("zip"))
{
var partStream = section.Body;
using (var zipArchive = new ZipArchive(partStream, ZipArchiveMode.Read))
{
foreach (var entry in zipArchive.Entries)
{
if (entry.FullName.EndsWith("/")) continue;
try
{
++archiveResult.ReceivedFileCount;
using (var memoryStream = new MemoryStream())
{
await section.Body.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
var archiveStudyId = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, sopInstanceUidList);
studycode = archiveStudyId.Item2;
if (!archivedStudyIds.Contains(archiveStudyId.Item1))
archivedStudyIds.Add(archiveStudyId.Item1);
}
}
catch
{
archiveResult.ErrorFiles.Add($"{fileName}/{entry.FullName}");
}
}
}
}
++archiveResult.ReceivedFileCount;
if (mediaType.Contains("octet-stream"))
{
using (var memoryStream = new MemoryStream())
{
await section.Body.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin);
var archiveStudyId = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, sopInstanceUidList);
studycode = archiveStudyId.Item2;
if (!archivedStudyIds.Contains(archiveStudyId.Item1))
archivedStudyIds.Add(archiveStudyId.Item1);
}
}
}
catch (Exception e)
{
_logger.LogError(e.Message + e.StackTrace);
archiveResult.ErrorFiles.Add(fileName);
_provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);
}
}
section = await reader.ReadNextSectionAsync();
}
try
{
if (archivedStudyIds.Count > 0) // 上传成功,处理逻辑
{
// 同一个访视 多个线程上传处理 批量保存 可能造成死锁 https://www.cnblogs.com/johnblogs/p/9945767.html
await _dicomArchiveService.DicomDBDataSaveChange();
//sw.Stop();
_studyService.UploadOrReUploadNeedTodo(archiveStudyCommand, archivedStudyIds, ref archiveResult, new StudyMonitor()
{
TrialId = savedInfo.TrialId,
SiteId = savedInfo.SiteId,
SubjectId = savedInfo.SubjectId,
SubjectVisitId = savedInfo.SubjectVisitId,
StudyId = archivedStudyIds[0],
StudyCode = studycode,
UploadStartTime = startTime,
UploadFinishedTime = DateTime.Now,
//TotalMillisecondsInterval = (DateTime.Now- startTime).TotalMilliseconds,
FileSize = (decimal)HttpContext.Request.ContentLength,
FileCount = archiveResult.ReceivedFileCount,
IsDicom = true,
IsDicomReUpload = archiveStudyCommand.AbandonStudyId != null,
IP = _userInfo.IP
});
_provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);
}
else
{
return ResponseOutput.NotOk("未完成该检查的归档");
}
}
catch (Exception e)
{
_logger.LogError(e.Message + e.StackTrace);
_provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);
return ResponseOutput.NotOk(e.Message, ApiResponseCodeEnum.ProgramException);
}
return ResponseOutput.Ok(archiveResult);
}
/// <summary>Dicom 归档</summary> /// <summary>Dicom 归档</summary>
[HttpPost, Route("Study/ArchiveStudy/{trialId:guid}")] [HttpPost, Route("Study/ArchiveStudy/{trialId:guid}")]
@ -413,7 +228,8 @@ namespace IRaCIS.Core.API.Controllers
[FromServices] ILogger<UploadDownLoadController> _logger, [FromServices] ILogger<UploadDownLoadController> _logger,
[FromServices] IEasyCachingProvider _provider, [FromServices] IEasyCachingProvider _provider,
[FromServices] IStudyService _studyService, [FromServices] IStudyService _studyService,
[FromServices] IDicomArchiveService _dicomArchiveService [FromServices] IDicomArchiveService _dicomArchiveService,
[FromServices] IRepository _repository
) )
{ {
@ -438,42 +254,48 @@ namespace IRaCIS.Core.API.Controllers
//重传的时候找出当前检查已经上传的series instance //重传的时候找出当前检查已经上传的series instance
if (archiveStudyCommand.AbandonStudyId != null) if (archiveStudyCommand.AbandonStudyId != null)
{ {
(seriesInstanceUidList, sopInstanceUidList) =_studyService.GetHasUploadSeriesAndInstance(archiveStudyCommand.AbandonStudyId.Value); (seriesInstanceUidList, sopInstanceUidList) = _studyService.GetHasUploadSeriesAndInstance(archiveStudyCommand.AbandonStudyId.Value);
} }
var savedInfo = _studyService.GetSaveToDicomInfo(archiveStudyCommand.SubjectVisitId); var savedInfo = _studyService.GetSaveToDicomInfo(archiveStudyCommand.SubjectVisitId);
archiveResult.ReceivedFileCount= await DicomFileUploadAsync(async (fileName, fileStream) => archiveResult.ReceivedFileCount = await DicomFileUploadAsync(async (fileName, fileStream) =>
{ {
try try
{ {
using (var memoryStream = new MemoryStream()) using (var memoryStream = new MemoryStream())
{ {
await fileStream.CopyToAsync(memoryStream); await fileStream.CopyToAsync(memoryStream);
memoryStream.Seek(0, SeekOrigin.Begin); memoryStream.Seek(0, SeekOrigin.Begin);
var archiveStudyId = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, sopInstanceUidList); var (studyId, studyCode) = await _dicomArchiveService.ArchiveDicomStreamAsync(memoryStream, savedInfo, seriesInstanceUidList, sopInstanceUidList);
studycode = archiveStudyId.Item2;
if (!archivedStudyIds.Contains(archiveStudyId.Item1)) if (!archivedStudyIds.Contains(studyId))
archivedStudyIds.Add(archiveStudyId.Item1); {
} archivedStudyIds.Add(studyId);
} archiveResult.ArchivedDicomStudies.Add(new DicomStudyBasicDTO() { StudyCode = studyCode, Id = studyId });
catch (Exception e) }
{
_logger.LogError(e.Message + e.StackTrace);
archiveResult.ErrorFiles.Add(fileName);
_provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);
}
}); }
}
catch (Exception e)
{
_logger.LogError(e.Message + e.StackTrace);
archiveResult.ErrorFiles.Add(fileName);
_provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);
}
});
try try
@ -485,7 +307,9 @@ namespace IRaCIS.Core.API.Controllers
await _dicomArchiveService.DicomDBDataSaveChange(); await _dicomArchiveService.DicomDBDataSaveChange();
_studyService.UploadOrReUploadNeedTodo(archiveStudyCommand, archivedStudyIds, ref archiveResult, new StudyMonitor() archiveResult.ReuploadNewStudyId = archivedStudyIds[0] == archiveStudyCommand.AbandonStudyId ? archivedStudyIds[0] : Guid.Empty;
await _repository.AddAsync(new StudyMonitor()
{ {
TrialId = savedInfo.TrialId, TrialId = savedInfo.TrialId,
SiteId = savedInfo.SiteId, SiteId = savedInfo.SiteId,
@ -496,20 +320,22 @@ namespace IRaCIS.Core.API.Controllers
StudyCode = studycode, StudyCode = studycode,
UploadStartTime = startTime, UploadStartTime = startTime,
UploadFinishedTime = DateTime.Now, UploadFinishedTime = DateTime.Now,
//TotalMillisecondsInterval = (DateTime.Now- startTime).TotalMilliseconds,
FileSize = (decimal)HttpContext.Request.ContentLength, FileSize = (decimal)HttpContext.Request.ContentLength,
FileCount = archiveResult.ReceivedFileCount, FileCount = archiveResult.ReceivedFileCount,
IsDicom = true, IsDicom = true,
IsDicomReUpload = archiveStudyCommand.AbandonStudyId != null, IsDicomReUpload = archiveStudyCommand.AbandonStudyId != null,
IP = _userInfo.IP IP = _userInfo.IP
}); }, true);
//_studyService.UploadOrReUploadNeedTodo(archiveStudyCommand, archivedStudyIds, ref archiveResult, );
_provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid); _provider.Remove("StudyUid_" + archiveStudyCommand.StudyInstanceUid);
} }
else else
{ {
return ResponseOutput.NotOk("未完成该检查的归档"); return ResponseOutput.NotOk(archiveResult);
} }
@ -543,7 +369,7 @@ namespace IRaCIS.Core.API.Controllers
[HttpPost("ClinicalData/UploadVisitClinicalData/{trialId:guid}/{subjectVisitId:guid}")] [HttpPost("ClinicalData/UploadVisitClinicalData/{trialId:guid}/{subjectVisitId:guid}")]
[DisableRequestSizeLimit] [DisableRequestSizeLimit]
[Authorize(Policy = IRaCISPolicy.CRC)] [Authorize(Policy = IRaCISPolicy.CRC)]
public async Task<IResponseOutput> UploadVisitClinicalData( Guid subjectVisitId, [FromServices] IRepository _repository) public async Task<IResponseOutput> UploadVisitClinicalData(Guid subjectVisitId, [FromServices] IRepository _repository)
{ {
await QCCommonVerify.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId); await QCCommonVerify.VerifyIsCRCSubmmitAsync(_repository, _userInfo, subjectVisitId);

View File

@ -159,12 +159,9 @@
<summary> 流式上传 通用封装 不返回任何数据,后续还有事情处理 </summary> <summary> 流式上传 通用封装 不返回任何数据,后续还有事情处理 </summary>
</member> </member>
<member name="M:IRaCIS.Core.API.Controllers.UploadBaseController.DicomFileUploadAsync(System.Func{System.String,System.IO.Stream,System.Threading.Tasks.Task})"> <member name="M:IRaCIS.Core.API.Controllers.UploadBaseController.DicomFileUploadAsync(System.Func{System.String,System.IO.Stream,System.Threading.Tasks.Task})">
<summary> 流式上传 Dicom上传 需要返回文件数量 </summary> <summary> 流式上传 Dicom上传 </summary>
</member> </member>
<member name="M:IRaCIS.Core.API.Controllers.StudyController.ArchiveStudy(IRaCIS.Core.Application.Contracts.ArchiveStudyCommand,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.API.Controllers.UploadDownLoadController},EasyCaching.Core.IEasyCachingProvider,IRaCIS.Application.Interfaces.IStudyService,IRaCIS.Core.Application.Contracts.Dicom.IDicomArchiveService)"> <member name="M:IRaCIS.Core.API.Controllers.StudyController.ArchiveStudyNew(IRaCIS.Core.Application.Contracts.ArchiveStudyCommand,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.API.Controllers.UploadDownLoadController},EasyCaching.Core.IEasyCachingProvider,IRaCIS.Core.Application.Contracts.IStudyService,IRaCIS.Core.Application.Contracts.Dicom.IDicomArchiveService,IRaCIS.Core.Infra.EFCore.IRepository)">
<summary>Dicom 归档</summary>
</member>
<member name="M:IRaCIS.Core.API.Controllers.StudyController.ArchiveStudyNew(IRaCIS.Core.Application.Contracts.ArchiveStudyCommand,Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.API.Controllers.UploadDownLoadController},EasyCaching.Core.IEasyCachingProvider,IRaCIS.Application.Interfaces.IStudyService,IRaCIS.Core.Application.Contracts.Dicom.IDicomArchiveService)">
<summary>Dicom 归档</summary> <summary>Dicom 归档</summary>
</member> </member>
<member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitClinicalData(System.Guid,IRaCIS.Core.Infra.EFCore.IRepository)"> <member name="M:IRaCIS.Core.API.Controllers.StudyController.UploadVisitClinicalData(System.Guid,IRaCIS.Core.Infra.EFCore.IRepository)">

View File

@ -160,6 +160,13 @@
批量验证 检查是否可以上传 并告知原因 批量验证 检查是否可以上传 并告知原因
</summary> </summary>
</member> </member>
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.StudyService.GetSaveToDicomInfo(System.Guid)">
<summary>
获取保存到Dicom文件中的信息
</summary>
<param name="subjectVisitId"></param>
<returns></returns>
</member>
<member name="T:IRaCIS.Core.Application.Service.SystemAnonymizationService"> <member name="T:IRaCIS.Core.Application.Service.SystemAnonymizationService">
<summary> <summary>
SystemAnonymizationService SystemAnonymizationService
@ -2223,13 +2230,6 @@
分页获取奖励单价列表 分页获取奖励单价列表
</summary> </summary>
</member> </member>
<member name="M:IRaCIS.Application.Services.StudyService.GetSaveToDicomInfo(System.Guid)">
<summary>
获取保存到Dicom文件中的信息
</summary>
<param name="subjectVisitId"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Application.Services.CroService.GetCroList(IRaCIS.Application.Contracts.CROCompanyQueryDTO)"> <member name="M:IRaCIS.Application.Services.CroService.GetCroList(IRaCIS.Application.Contracts.CROCompanyQueryDTO)">
<summary> 分页获取CRO列表 </summary> <summary> 分页获取CRO列表 </summary>
</member> </member>

View File

@ -7,6 +7,7 @@ namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
{ {
public int ReceivedFileCount { get; set; } public int ReceivedFileCount { get; set; }
public ICollection<string> ErrorFiles { get; set; } public ICollection<string> ErrorFiles { get; set; }
public ICollection<DicomStudyBasicDTO> ArchivedDicomStudies { get; set; } public ICollection<DicomStudyBasicDTO> ArchivedDicomStudies { get; set; }
public Guid ReuploadNewStudyId { get; set; } = Guid.Empty; public Guid ReuploadNewStudyId { get; set; } = Guid.Empty;
@ -15,6 +16,7 @@ namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
{ {
ReceivedFileCount = 0; ReceivedFileCount = 0;
ErrorFiles = new List<string>(); ErrorFiles = new List<string>();
ArchivedDicomStudies = new List<DicomStudyBasicDTO>(); ArchivedDicomStudies = new List<DicomStudyBasicDTO>();
} }
} }

View File

@ -48,7 +48,7 @@ namespace IRaCIS.Core.Application.Services
return success; return success;
} }
public async Task<Tuple<Guid, string>> ArchiveDicomStreamAsync(Stream dicomStream, public async Task<(Guid StudyId, string StudyCode)> ArchiveDicomStreamAsync(Stream dicomStream,
DicomTrialSiteSubjectInfo addtionalInfo, List<string> seriesInstanceUidList, List<string> instanceUidList) DicomTrialSiteSubjectInfo addtionalInfo, List<string> seriesInstanceUidList, List<string> instanceUidList)
{ {
@ -63,7 +63,7 @@ namespace IRaCIS.Core.Application.Services
if (instanceUidList.Any(t => t == sopInstanceUid)) if (instanceUidList.Any(t => t == sopInstanceUid))
{ {
return new Tuple<Guid, string>(IdentifierHelper.CreateGuid(studyInstanceUid, addtionalInfo.TrialId.ToString()), string.Empty) ; return (IdentifierHelper.CreateGuid(studyInstanceUid, addtionalInfo.TrialId.ToString()), string.Empty) ;
} }
@ -116,52 +116,6 @@ namespace IRaCIS.Core.Application.Services
} }
#region 调整废弃
////按照配置文件 匿名化
//foreach (var anonymizeItem in SystemConfig.AnonymizeTagList)
//{
// if (anonymizeItem.Enable)
// {
// ushort group = Convert.ToUInt16(anonymizeItem.Group, 16);
// ushort element = Convert.ToUInt16(anonymizeItem.Element, 16);
// dataset.AddOrUpdate(new DicomTag(group, element), anonymizeItem.ReplaceValue);
// }
//}
//if (AppSettings.AddClinicalInfo) //是否需要写入临床信息
//{
// //Dicom 文件中写入临床信息
// dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolID, addtionalInfo.TrialCode); //Trial
// dataset.AddOrUpdate(DicomTag.ClinicalTrialProtocolName, addtionalInfo.TrialIndication); //indication
// dataset.AddOrUpdate(DicomTag.ClinicalTrialSponsorName, addtionalInfo.Sponsor);//sponsor
// dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteID, addtionalInfo.SiteCode); //SiteId
// dataset.AddOrUpdate(DicomTag.ClinicalTrialSiteName, addtionalInfo.SiteName);//SiteName
// dataset.AddOrUpdate(DicomTag.ClinicalTrialSubjectID, addtionalInfo.SubjectCode + " " + addtionalInfo.SubjectSex);//SubjectId
// dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointID, addtionalInfo.VisitNum.ToString()); // TimePoint
// dataset.AddOrUpdate(DicomTag.ClinicalTrialTimePointDescription, addtionalInfo.VisitName + " " + addtionalInfo.SVUPDES);
//}
//DicomStudy dicomStudy = null;
//DicomSeries dicomSeries = null;
//DicomInstance dicomInstance = null;
//lock (lockTest)
//{
// dicomStudy = CreateDicomStudy(dataset, addtionalInfo, out bool isStudyNeedAdd);
// dicomSeries = CreateDicomSeries(dataset, dicomStudy, out bool isSeriesNeedAdd);
// dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries);
// if (isStudyNeedAdd) _studyRepository.Add(dicomStudy);
// if (isSeriesNeedAdd) _seriesRepository.Add(dicomSeries);
// _instanceRepository.Add(dicomInstance);
//}
#endregion
DicomStudy dicomStudy = CreateDicomStudy(dataset, addtionalInfo, out bool isStudyNeedAdd); DicomStudy dicomStudy = CreateDicomStudy(dataset, addtionalInfo, out bool isStudyNeedAdd);
DicomSeries dicomSeries = CreateDicomSeries(dataset, dicomStudy, out bool isSeriesNeedAdd); DicomSeries dicomSeries = CreateDicomSeries(dataset, dicomStudy, out bool isSeriesNeedAdd);
DicomInstance dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries); DicomInstance dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries);
@ -210,7 +164,7 @@ namespace IRaCIS.Core.Application.Services
if (dataset.InternalTransferSyntax.IsEncapsulated) await dicomFile.SaveAsync(filePath); if (dataset.InternalTransferSyntax.IsEncapsulated) await dicomFile.SaveAsync(filePath);
else await dicomFile.Clone(DicomTransferSyntax.RLELossless).SaveAsync(filePath); //RLELossless else await dicomFile.Clone(DicomTransferSyntax.RLELossless).SaveAsync(filePath); //RLELossless
} }
return new Tuple<Guid, string>(dicomInstance.StudyId, dicomStudy.StudyCode); return (dicomInstance.StudyId, dicomStudy.StudyCode);
} }

View File

@ -2,7 +2,7 @@
{ {
public interface IDicomArchiveService public interface IDicomArchiveService
{ {
Task<Tuple<Guid,string>> ArchiveDicomStreamAsync(Stream dicomStream, DicomTrialSiteSubjectInfo addtionalInfo, List<string> seriesInstanceUidList, List<string> instanceUidList); Task<(Guid StudyId, string StudyCode)> ArchiveDicomStreamAsync(Stream dicomStream, DicomTrialSiteSubjectInfo addtionalInfo, List<string> seriesInstanceUidList, List<string> instanceUidList);
//ICollection<DicomStudyDTO> GetArchivedStudyList(List<Guid> archivedStudyIds); //ICollection<DicomStudyDTO> GetArchivedStudyList(List<Guid> archivedStudyIds);
Task<bool> DicomDBDataSaveChange(); Task<bool> DicomDBDataSaveChange();

View File

@ -1,97 +1,17 @@
using System; using IRaCIS.Core.Application.Contracts;
using System.Collections.Generic; using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using System.Threading.Tasks;
using IRaCIS.Core.Infrastructure.Extention;
using IRaCIS.Core.Application.Contracts;
namespace IRaCIS.Application.Interfaces namespace IRaCIS.Core.Application.Contracts
{ {
public interface IStudyService public interface IStudyService
{ {
IResponseOutput<List<RelationStudyDTO>> GetAllRelationStudyList(Guid subjectVisitId);
Task<PageOutput<UnionStudyViewModel>> GetDicomAndNoneDicomStudyList(StudyQuery studyQuery);
Task<PageOutput<UnionStudyMonitorModel>> GetDicomAndNoneDicomStudyMonitorList(StudyQuery studyQuery);
(List<string> SeriesInstanceUid, List<string> SopInstanceUid) GetHasUploadSeriesAndInstance(Guid studyId);
//IResponseOutput ForwardStudy(Guid studyId); DicomTrialSiteSubjectInfo GetSaveToDicomInfo(Guid subjectVisitId);
IResponseOutput<DicomStudyDTO> Item(Guid studyId);
DicomTrialSiteSubjectInfo GetSaveToDicomInfo(Guid subjctVisitId); Task<FileContentResult> Preview(Guid studyId);
IResponseOutput<List<VerifyStudyUploadResult>> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo);
(List<string> SeriesInstanceUid, List<string> SopInstanceUid) GetHasUploadSeriesAndInstance(Guid studyId);
void UploadOrReUploadNeedTodo(ArchiveStudyCommand archiveStudyCommand, List<Guid> archiveStudyIds, ref DicomArchiveResult reusult, StudyMonitor monitor);
//PageOutput<StudyDTO> GetStudyList(StudyQueryDTO queryDto);
//Task<IResponseOutput> DicomAnonymize(Guid studyId, string optuserName);
//List<StudyStatusDetailDTO> GetStudyStatusDetailList(Guid studyId);
//IEnumerable<RelationVisitDTO> GetRelationVisitList(decimal visitNum, string tpCode);
//List<SubjectVisitStudyDTO> GetSubjectVisitStudyList(Guid trialId, Guid siteId, Guid subjectId, Guid subjectVisitId);
//PageOutput<DistributeReviewerStudyStatusDTO> GetDistributeStudyList(StudyStatusQueryDTO studyStatusQueryDto);
//IEnumerable<RelationStudyDTO> GetAllRelationStudyList(Guid studyId);
//IEnumerable<StudyStatDTO> GetStudyStatList(Guid trialId, Guid subjectId, Guid siteId);
//bool UpdateReUploadNewStudyCode(Guid studyId, Guid newStudyId);
//void ReUploadSameStudy(Guid subjectVisitId, Guid studyId);
//VerifyStudyUploadResult VerifyStudyAllowUpload(string studyInstanceUid, Guid trialId, Guid? studyId);
//List< VerifyStudyUploadResult> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyList);
//void ClearStudyInstanceAndSeriseData(Guid studyId);
//IResponseOutput DeleteStudy(Guid id);
//Guid AddSubjectVisit(Guid subjectId, Guid siteId, Guid visitStageId, DateTime? SVSTDTC, DateTime? SVENDTC);
//void UpdateSubjectLatestInfo(Guid subjectVisitId);
//void UpdateSubjectVisit(Guid subjectVisitId, Guid studyId);
//bool DistributeStudy(StudyReviewerCommand studyReviewer);
//IResponseOutput EditStudyReviewer(StudyReviewerEditCommand studyReviewerEditCommand);
//void UploadStudyDeal(Guid studyId);
//List<ReviewerDistributionDTO> GetReviewerListByTrialId(Guid trialId);
//IResponseOutput UpdateStudyStatus(StudyStatusDetailCommand studyStatusDetailDTO);
//string GetStudyPreview(Guid studyId);
//DicomStudyDTO GetStudyItem(Guid studyId);
////bool SaveImageLabel(ImageLabelDTO label);
//bool SaveImageLabelList(ImageLabelCommand imageLabelCommand);
//IEnumerable<ImageLabelDTO> GetImageLabel(string tpCode);
//IResponseOutput DealNonDicomFile(Dictionary<string,string> filePathDic, ArchiveStudyCommand archiveStudyCommand);
//bool ReUploadDifferentStudy(Guid subjectVisitId, Guid abandonStudyId, Guid newStudyId);
//List<QANoticeDTO> GetQANoticeList(Guid studyId);
} }
} }

View File

@ -1,586 +0,0 @@
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Dicom;
using Microsoft.AspNetCore.Authorization;
using IRaCIS.Core.Application.Services;
using EasyCaching.Core;
using System.Linq.Expressions;
namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
[ApiExplorerSettings(GroupName = "Image")]
public class StudyService : BaseService
{
private readonly DicomFileStoreHelper _dicomFileStoreHelper;
private readonly IEasyCachingProvider _provider;
public StudyService(DicomFileStoreHelper dicomFileStoreHelper, IEasyCachingProvider provider)
{
_dicomFileStoreHelper = dicomFileStoreHelper;
_provider = provider;
}
private Expression<Func<DicomStudy, bool>> GetDicomStudySubjectVisitFilter(string[]? VisitPlanArray)
{
Expression<Func<DicomStudy, bool>> svExpression = x => true;
bool isNeedVisitSearch = VisitPlanArray != null && VisitPlanArray?.Length > 0;
if (isNeedVisitSearch)
{
var inPlanArray = VisitPlanArray!.Where(t => !t.Contains('.')).Select(t => decimal.Parse(t)).ToArray();
var isSelectOutPlan = VisitPlanArray!.Any(t => t.Contains('.'));
if (inPlanArray.Length > 0)
{
svExpression = svExpression.And(t => inPlanArray.Contains(t.SubjectVisit.VisitNum));
}
if (isSelectOutPlan)
{
svExpression = svExpression.Or(t => t.SubjectVisit.InPlan == false);
}
}
return svExpression;
}
private Expression<Func<NoneDicomStudy, bool>> GetNoneDicomStudySubjectVisitFilter(string[]? VisitPlanArray)
{
Expression<Func<NoneDicomStudy, bool>> svExpression = x => true;
bool isNeedVisitSearch = VisitPlanArray != null && VisitPlanArray?.Length > 0;
if (isNeedVisitSearch)
{
var inPlanArray = VisitPlanArray!.Where(t => !t.Contains('.')).Select(t => decimal.Parse(t)).ToArray();
var isSelectOutPlan = VisitPlanArray!.Any(t => t.Contains('.'));
if (inPlanArray.Length > 0)
{
svExpression = svExpression.And(t => inPlanArray.Contains(t.SubjectVisit.VisitNum));
}
if (isSelectOutPlan)
{
svExpression = svExpression.Or(t => t.SubjectVisit.InPlan == false);
}
}
return svExpression;
}
private Expression<Func<StudyMonitor, bool>> GetStudyMonitorSubjectVisitFilter(string[]? VisitPlanArray)
{
Expression<Func<StudyMonitor, bool>> svExpression = x => true;
bool isNeedVisitSearch = VisitPlanArray != null && VisitPlanArray?.Length > 0;
if (isNeedVisitSearch)
{
var inPlanArray = VisitPlanArray!.Where(t => !t.Contains('.')).Select(t => decimal.Parse(t)).ToArray();
var isSelectOutPlan = VisitPlanArray!.Any(t => t.Contains('.'));
if (inPlanArray.Length > 0)
{
svExpression = svExpression.And(t => inPlanArray.Contains(t.SubjectVisit.VisitNum));
}
if (isSelectOutPlan)
{
svExpression = svExpression.Or(t => t.SubjectVisit.InPlan == false);
}
}
return svExpression;
}
[HttpPost]
public async Task<PageOutput<UnionStudyViewModel>> GetDicomAndNoneDicomStudyList(StudyQuery studyQuery)
{
var svExpression = 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 = 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 = 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,
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 = _dicomFileStoreHelper.GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id.ToString());
}
}
using (var sw = DicomRenderingHelper.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;
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -719,7 +719,7 @@ namespace IRaCIS.Core.Application.Image.QA
[HttpPost, Route("{trialId:guid}/{subjectVisitId:guid}")] [HttpPost, Route("{trialId:guid}/{subjectVisitId:guid}")]
[TypeFilter(typeof(TrialResourceFilter))] [TypeFilter(typeof(TrialResourceFilter))]
[UnitOfWork] [UnitOfWork]
[Authorize(Policy = IRaCISPolicy.IQC)] [Authorize(Policy = IRaCISPolicy.CRC_IQC)]
public async Task<IResponseOutput> DeleteStudyList(Guid[] ids, Guid subjectVisitId, Guid trialId) public async Task<IResponseOutput> DeleteStudyList(Guid[] ids, Guid subjectVisitId, Guid trialId)
{ {

View File

@ -9,10 +9,13 @@ namespace IRaCIS.Core.Application.Triggers
public class SubjectVisitTrigger : IAfterSaveTrigger<NoneDicomStudy>, IAfterSaveTrigger<DicomStudy>, IAfterSaveTrigger<NoneDicomStudyFile> public class SubjectVisitTrigger : IAfterSaveTrigger<NoneDicomStudy>, IAfterSaveTrigger<DicomStudy>, IAfterSaveTrigger<NoneDicomStudyFile>
{ {
private readonly IRepository<SubjectVisit> _subjectVisitRepository; private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IRepository _repository;
public SubjectVisitTrigger(IRepository<SubjectVisit> subjectVisitRepository) public SubjectVisitTrigger(IRepository<SubjectVisit> subjectVisitRepository,IRepository repository)
{ {
_subjectVisitRepository = subjectVisitRepository; _subjectVisitRepository = subjectVisitRepository;
_repository = repository;
} }
//注意删除不能用扩展方法必须用EF跟踪的实体 否则不能取到 SubjectVisitId //注意删除不能用扩展方法必须用EF跟踪的实体 否则不能取到 SubjectVisitId
@ -45,6 +48,15 @@ namespace IRaCIS.Core.Application.Triggers
if (context.ChangeType == ChangeType.Added ) if (context.ChangeType == ChangeType.Added )
{ {
await UpdateSubjectVisitImageDateAsync(subjectVisitId); await UpdateSubjectVisitImageDateAsync(subjectVisitId);
var studyId = context.Entity.Id;
//处理Modality
var seriesModalityList = _repository.Where<DicomSeries>(t => t.StudyId == studyId).Select(u => u.Modality).Distinct();
string ModaliyStr = string.Join('、', seriesModalityList.ToList());
context.Entity.Modalities = ModaliyStr;
await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit()
{ {
VisitExecuted = VisitExecutedEnum.Executed VisitExecuted = VisitExecutedEnum.Executed