添加项目文件。
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
||||
{
|
||||
public sealed class DicomArchiveResult
|
||||
{
|
||||
public int ReceivedFileCount { get; set; }
|
||||
public ICollection<string> ErrorFiles { get; set; }
|
||||
public ICollection<DicomStudyBasicDTO> ArchivedDicomStudies { get; set; }
|
||||
|
||||
public Guid ReuploadNewStudyId { get; set; } = Guid.Empty;
|
||||
|
||||
public DicomArchiveResult()
|
||||
{
|
||||
ReceivedFileCount = 0;
|
||||
ErrorFiles = new List<string>();
|
||||
ArchivedDicomStudies = new List<DicomStudyBasicDTO>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
namespace IRaCIS.Core.Application.Contracts
|
||||
{
|
||||
public class DicomInstanceDTO
|
||||
{
|
||||
public Guid Id { get; set;}
|
||||
public Guid StudyId { get; set; }
|
||||
public Guid SeriesId { get; set; }
|
||||
public string StudyInstanceUid { get; set; } = string.Empty;
|
||||
public string SeriesInstanceUid { get; set; } = string.Empty;
|
||||
public string SopInstanceUid { get; set; } = string.Empty;
|
||||
public int InstanceNumber { get; set; }
|
||||
public DateTime InstanceTime { get; set; }
|
||||
public bool CPIStatus { get; set; }
|
||||
public int ImageRows { get; set; }
|
||||
public int ImageColumns { get; set; }
|
||||
public int SliceLocation { get; set; }
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
//public Guid CreateUserId { get; set; }
|
||||
//public DateTime CreateTime { get; set; }
|
||||
//public Guid UpdateUserId { get; set; }
|
||||
//public DateTime UpdateTime { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class DicomTrialSiteSubjectInfo
|
||||
{
|
||||
public string TrialSiteCode { get; set; } = string.Empty;
|
||||
public string SiteCode { get; set; } = string.Empty;
|
||||
public string SiteName { get; set; } = string.Empty;
|
||||
public string SubjectCode { get; set; } = string.Empty;
|
||||
public int? SubjectAge { get; set; }
|
||||
public string SubjectSex { get; set; } = string.Empty;
|
||||
public string TrialCode { get; set; } = string.Empty;
|
||||
public string ResearchProgramNo { get; set; } = string.Empty;
|
||||
public string TrialIndication { get; set; } = string.Empty;
|
||||
|
||||
|
||||
|
||||
public decimal VisitNum { get; set; }
|
||||
public string SVUPDES { get; set; } = string.Empty;
|
||||
public string VisitName { get; set; } = string.Empty;
|
||||
public string Sponsor { get; set; } = string.Empty;
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
//public string SubjectName => LastName + " / " + FirstName;
|
||||
//public string FirstName { get; set; } = string.Empty;
|
||||
//public string LastName { get; set; } = string.Empty;
|
||||
//public bool IsDoubleReview { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
||||
{
|
||||
public class DicomSeriesDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid StudyId { get; set; }
|
||||
public string StudyInstanceUid { get; set; } = String.Empty;
|
||||
public string SeriesInstanceUid { get; set; } = String.Empty;
|
||||
public int SeriesNumber { get; set; }
|
||||
public DateTime SeriesTime { get; set; }
|
||||
public string Modality { get; set; } = String.Empty;
|
||||
public string Description { get; set; }=String.Empty;
|
||||
public int InstanceCount { get; set; }
|
||||
public string SliceThickness { get; set; } = String.Empty;
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public Guid CreateUserId { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
public List<Guid> InstanceList { get; set; } = new List<Guid>();
|
||||
}
|
||||
|
||||
public class DicomSeriesWithLabelDTO : DicomSeriesDTO
|
||||
{
|
||||
public bool HasLabel { get; set; } = false;
|
||||
public bool KeySeries { get; set; } = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
namespace IRaCIS.Core.Application.Contracts
|
||||
{
|
||||
public class DicomStudyBasicDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public string StudyCode { get; set; } = string.Empty;
|
||||
|
||||
public DateTime StudyTime { get; set; }
|
||||
}
|
||||
|
||||
public class DicomStudyDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public string StudyCode { get; set; } = string.Empty;
|
||||
|
||||
public int Status { get; set; } = 1;
|
||||
|
||||
public string StudyInstanceUid { get; set; } = string.Empty;
|
||||
public DateTime StudyTime { get; set; }
|
||||
public string Modalities { get; set; } = string.Empty;
|
||||
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public int SeriesCount { get; set; } = 0;
|
||||
public int InstanceCount { get; set; } = 0;
|
||||
|
||||
public bool SoftDelete { get; set; } = false;
|
||||
|
||||
public string InstitutionName { get; set; } = string.Empty;
|
||||
public string PatientId { get; set; } = string.Empty;
|
||||
public string PatientName { get; set; } = string.Empty;
|
||||
public string PatientAge { get; set; } = string.Empty;
|
||||
public string PatientSex { get; set; } = string.Empty;
|
||||
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; }
|
||||
public Guid CreateUserId { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
|
||||
public class RelationVisitDTO
|
||||
{
|
||||
public string VisitName { get; set; } = string.Empty;
|
||||
public string TpCode { get; set; } = string.Empty;
|
||||
public Guid StudyId { get; set; }
|
||||
}
|
||||
|
||||
public class RelationStudyDTO
|
||||
{
|
||||
public string VisitName { get; set; } = string.Empty;
|
||||
public string StudyCode { get; set; } = string.Empty;
|
||||
public Guid StudyId { get; set; }
|
||||
public int SeriesCount { get; set; }
|
||||
public string Modalities { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
public class UploadViewInitDto
|
||||
{
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public Guid SubjectId { get; set; }
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
//public string SubjectName { get; set; }
|
||||
|
||||
public string SubjectCode { get; set; } = string.Empty;
|
||||
|
||||
public string TrialSiteCode { get; set; } = string.Empty;
|
||||
|
||||
public decimal VisitNum { get; set; }
|
||||
|
||||
public string VisitName { get; set; } = string.Empty;
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
||||
{
|
||||
public class ImageLabelDTO
|
||||
{
|
||||
public Guid Id { get; set; } = Guid.Empty;
|
||||
public string TpCode { get; set; } = string.Empty;
|
||||
public Guid StudyId { get; set; } = Guid.Empty;
|
||||
public Guid SeriesId { get; set; } = Guid.Empty;
|
||||
public Guid InstanceId { get; set; } = Guid.Empty;
|
||||
public string LabelValue { get; set; } = string.Empty;
|
||||
}
|
||||
public class ImageLabelInfo
|
||||
{
|
||||
public Guid StudyId { get; set; } = Guid.Empty;
|
||||
public Guid SeriesId { get; set; } = Guid.Empty;
|
||||
public Guid InstanceId { get; set; } = Guid.Empty;
|
||||
public string LabelValue { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class ImageLabelCommand
|
||||
{
|
||||
public string TpCode { get; set; } = string.Empty;
|
||||
public List<ImageLabelInfo> ImageLabelList { get; set; } = new List<ImageLabelInfo>();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
||||
{
|
||||
public class ImageShareCommand
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SiteId { get; set; }
|
||||
public Guid SubjectId { get; set; }
|
||||
public Guid? StudyId { get; set; }
|
||||
|
||||
public DateTime? ExpireTime { get; set; }
|
||||
|
||||
public string Password { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class ResourceInfo
|
||||
{
|
||||
public Guid StudyId { get; set; }
|
||||
|
||||
public string Token { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
||||
{
|
||||
public class StudyDTFDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid StudyId { get; set; }
|
||||
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
public string Path { get; set; } = string.Empty;
|
||||
public Guid CreateUserId { get; set; }
|
||||
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
public DateTime CreateTime { get; set; }
|
||||
}
|
||||
|
||||
public class StudyDTFAddOrUpdateCommand
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid StudyId { get; set; }
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
public string Path { get; set; } = string.Empty;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
||||
{
|
||||
public class StudyReviewerDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid StudyId { get; set; }
|
||||
public Guid ReviewerId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class StudyDistributeInfo
|
||||
{
|
||||
public Guid StudyId { get; set; }
|
||||
public int Status { get; set; }
|
||||
//public int ReviewerCount { get; set; }
|
||||
}
|
||||
|
||||
public class StudyReviewerCommand
|
||||
{
|
||||
public List<StudyDistributeInfo> StudyList { get; set; } = new List<StudyDistributeInfo>();
|
||||
//public List<Guid> StudyIdList { get; set; }
|
||||
public Guid ReviewerId { get; set; }
|
||||
//public int WorkloadType { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
//public bool IsDoubleReview { get; set; }
|
||||
}
|
||||
|
||||
public class StudyReviewerEditCommand
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid StudyId { get; set; }
|
||||
public bool IsDoubleReview { get; set; }
|
||||
|
||||
public Guid? ReviewerId1 { get; set; }
|
||||
public Guid? ReviewerId2 { get; set; }
|
||||
public Guid? ReviewerIdForAD { get; set; }
|
||||
}
|
||||
|
||||
public class ReviewerDistributionDTO
|
||||
{
|
||||
public Guid ReviewerId { get; set; }
|
||||
public string FirstName { get; set; } = string.Empty;
|
||||
public string LastName { get; set; } = string.Empty;
|
||||
public string ReviewerCode { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
||||
{
|
||||
public class StudyStatusDetailDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid StudyId { get; set; }
|
||||
public int Status { get; set; }
|
||||
public string OptUserName { get; set; }=string.Empty;
|
||||
public DateTime OptTime { get; set; }
|
||||
public string Note { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class StudyStatusDetailCommand
|
||||
{
|
||||
public Guid StudyId { get; set; }
|
||||
|
||||
public int Status { get; set; }
|
||||
|
||||
public DateTime? DeadlineTime { get; set; }
|
||||
public string Note { get; set; } = string.Empty;
|
||||
|
||||
//QA不通过的时候传递参数
|
||||
public string QAComment { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2022-03-03 15:28:20
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
namespace IRaCIS.Core.Application.ViewModel
|
||||
{
|
||||
/// <summary> SystemAnonymizationView 列表视图模型 </summary>
|
||||
public class SystemAnonymizationView: SystemAnonymizationAddOrEdit
|
||||
{
|
||||
|
||||
public Guid CreateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; }
|
||||
public Guid UpdateUserId { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
///<summary>SystemAnonymizationQuery 列表查询参数模型</summary>
|
||||
public class SystemAnonymizationQuery:PageInput
|
||||
{
|
||||
public string Group { get; set; } = string.Empty;
|
||||
|
||||
public bool? IsAdd { get; set; }
|
||||
|
||||
public string Element { get; set; } = string.Empty;
|
||||
|
||||
public string TagDescription { get; set; } = string.Empty;
|
||||
|
||||
public string ValueRepresentation { get; set; } = string.Empty;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
///<summary> SystemAnonymizationAddOrEdit 列表查询参数模型</summary>
|
||||
public class SystemAnonymizationAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public string Group { get; set; } = String.Empty;
|
||||
public string Element { get; set; } = String.Empty;
|
||||
public string TagDescription { get; set; } = String.Empty;
|
||||
public string TagDescriptionCN { get; set; } = String.Empty;
|
||||
public string ReplaceValue { get; set; } = String.Empty;
|
||||
|
||||
public string ValueRepresentation { get; set; } = String.Empty;
|
||||
|
||||
public bool IsAdd { get; set; }
|
||||
|
||||
public bool IsEnable { get; set; }
|
||||
|
||||
public bool IsFixed { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IRaCIS.Core.Application.Contracts
|
||||
{
|
||||
|
||||
public class UnionStudyBaseModel
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public Guid SiteId { get; set; }
|
||||
|
||||
public Guid SubjectId { get; set; }
|
||||
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
|
||||
public string VisitName { get; set; } = string.Empty;
|
||||
|
||||
public decimal VisitNum { get; set; }
|
||||
|
||||
public string TrialSiteCode { get; set; } = string.Empty;
|
||||
|
||||
public string TrialSiteAliasName { get; set; } = string.Empty;
|
||||
|
||||
public string Uploader { get; set; } = string.Empty;
|
||||
|
||||
public DateTime UploadTime { get; set; }
|
||||
|
||||
public string StudyCode => IsDicom ? DicomStudyCode : "NST" + NoneDicomCode.ToString("D5");
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public string DicomStudyCode { get; set; } = string.Empty;
|
||||
[JsonIgnore]
|
||||
public int NoneDicomCode { get; set; }
|
||||
|
||||
public bool IsDicom { get; set; }
|
||||
}
|
||||
|
||||
public class UnionStudyMonitorModel : UnionStudyBaseModel
|
||||
{
|
||||
public Guid StudyId { get; set; }
|
||||
|
||||
|
||||
public DateTime UploadStartTime { get; set; }
|
||||
|
||||
|
||||
public DateTime UploadFinishedTime { get; set; }
|
||||
|
||||
|
||||
public decimal FileSize { get; set; }
|
||||
|
||||
public string IP { get; set; }
|
||||
|
||||
|
||||
public bool IsDicomReUpload { get; set; }
|
||||
|
||||
public bool IsDicom { get; set; }
|
||||
|
||||
public int FileCount { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class UnionStudyViewModel:UnionStudyBaseModel
|
||||
{
|
||||
|
||||
public Guid Id { get; set; }
|
||||
|
||||
|
||||
|
||||
public int? Count { get; set; }
|
||||
|
||||
|
||||
public string Modalities { get; set; } = string.Empty;
|
||||
|
||||
public string Bodypart { get; set; } = string.Empty;
|
||||
|
||||
public DateTime? StudyTime { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class StudyQuery:PageInput
|
||||
{
|
||||
[NotDefault]
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public Guid? SubjectId { get; set; }
|
||||
|
||||
public Guid? SiteId { get; set; }
|
||||
public Guid? SubjectVisitId { get; set; }
|
||||
|
||||
public string SubjectInfo { get; set; } = String.Empty;
|
||||
|
||||
public string VisitPlanInfo { get; set; } = String.Empty;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
using Dicom;
|
||||
using Dicom.Imaging.Codec;
|
||||
using EasyCaching.Core;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System.Text;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
|
||||
namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
public class DicomArchiveService : IDicomArchiveService
|
||||
{
|
||||
private readonly IRepository<DicomStudy> _studyRepository;
|
||||
private readonly IRepository<DicomSeries> _seriesRepository;
|
||||
private readonly IRepository<DicomInstance> _instanceRepository;
|
||||
|
||||
private readonly IEasyCachingProvider _provider;
|
||||
private readonly DicomFileStoreHelper _dicomFileStoreHelper;
|
||||
|
||||
|
||||
private static object lockCodeGenerate = new object();
|
||||
|
||||
public DicomArchiveService(IRepository<DicomStudy> studyRepository,
|
||||
IRepository<DicomSeries> seriesRepository,
|
||||
IRepository<DicomInstance> instanceRepository,
|
||||
IHostEnvironment hostEnvironment,
|
||||
DicomFileStoreHelper dicomFileStoreHelper,
|
||||
IEasyCachingProvider provider)
|
||||
{
|
||||
_dicomFileStoreHelper = dicomFileStoreHelper;
|
||||
|
||||
_studyRepository = studyRepository;
|
||||
|
||||
_seriesRepository = seriesRepository;
|
||||
|
||||
_instanceRepository = instanceRepository;
|
||||
|
||||
_provider = provider;
|
||||
|
||||
}
|
||||
|
||||
public async Task<bool> DicomDBDataSaveChange()
|
||||
{
|
||||
var success = await _studyRepository.SaveChangesAsync();
|
||||
return success;
|
||||
}
|
||||
|
||||
public async Task<Guid> ArchiveDicomStreamAsync(Stream dicomStream,
|
||||
DicomTrialSiteSubjectInfo addtionalInfo, List<string> seriesInstanceUidList, List<string> instanceUidList)
|
||||
{
|
||||
|
||||
|
||||
DicomFile dicomFile = await DicomFile.OpenAsync(dicomStream, Encoding.Default);
|
||||
|
||||
DicomDataset dataset = dicomFile.Dataset;
|
||||
|
||||
//如果数据库存在该instance 记录 那么就不处理
|
||||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||
|
||||
if (instanceUidList.Any(t => t == sopInstanceUid))
|
||||
{
|
||||
return IdentifierHelper.CreateGuid(studyInstanceUid, addtionalInfo.TrialId.ToString());
|
||||
}
|
||||
|
||||
|
||||
var anonymize_AddFixedFiledList = _provider.Get<List<SystemAnonymization>>(StaticData.Anonymize_AddFixedFiled).Value;
|
||||
var anonymize_AddIRCInfoFiled = _provider.Get<List<SystemAnonymization>>(StaticData.Anonymize_AddIRCInfoFiled).Value;
|
||||
var anonymize_FixedField = _provider.Get<List<SystemAnonymization>>(StaticData.Anonymize_FixedField).Value;
|
||||
var anonymize_IRCInfoField = _provider.Get<List<SystemAnonymization>>(StaticData.Anonymize_IRCInfoField).Value;
|
||||
|
||||
|
||||
|
||||
foreach (var item in anonymize_AddFixedFiledList.Union(anonymize_FixedField))
|
||||
{
|
||||
|
||||
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
|
||||
|
||||
dataset.AddOrUpdate(dicomTag, item.ReplaceValue);
|
||||
}
|
||||
|
||||
foreach (var item in anonymize_AddIRCInfoFiled.Union(anonymize_IRCInfoField))
|
||||
{
|
||||
|
||||
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
|
||||
|
||||
if (dicomTag == DicomTag.ClinicalTrialProtocolID)
|
||||
{
|
||||
dataset.AddOrUpdate(dicomTag, addtionalInfo.TrialCode);
|
||||
|
||||
}
|
||||
if (dicomTag == DicomTag.ClinicalTrialSiteID)
|
||||
{
|
||||
dataset.AddOrUpdate(dicomTag, addtionalInfo.TrialSiteCode);
|
||||
|
||||
}
|
||||
if (dicomTag == DicomTag.ClinicalTrialSubjectID)
|
||||
{
|
||||
dataset.AddOrUpdate(dicomTag, addtionalInfo.SubjectCode);
|
||||
|
||||
}
|
||||
if (dicomTag == DicomTag.ClinicalTrialTimePointID)
|
||||
{
|
||||
dataset.AddOrUpdate(dicomTag, addtionalInfo.VisitNum.ToString());
|
||||
|
||||
}
|
||||
if (dicomTag == DicomTag.PatientID)
|
||||
{
|
||||
dataset.AddOrUpdate(dicomTag, addtionalInfo.TrialCode+"_"+ addtionalInfo.SubjectCode);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#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);
|
||||
DicomSeries dicomSeries = CreateDicomSeries(dataset, dicomStudy, out bool isSeriesNeedAdd);
|
||||
DicomInstance dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries);
|
||||
|
||||
if (isStudyNeedAdd) await _studyRepository.AddAsync(dicomStudy);
|
||||
if (isSeriesNeedAdd) await _seriesRepository.AddAsync(dicomSeries);
|
||||
await _instanceRepository.AddAsync(dicomInstance);
|
||||
|
||||
|
||||
|
||||
string filePath = _dicomFileStoreHelper.CreateInstanceFilePath(dicomStudy, dicomSeries.Id, dicomInstance.Id);
|
||||
|
||||
var samplesPerPixel = dataset.GetSingleValueOrDefault(DicomTag.SamplesPerPixel, string.Empty);
|
||||
var photometricInterpretation = dataset.GetSingleValueOrDefault(DicomTag.PhotometricInterpretation, string.Empty);
|
||||
if (samplesPerPixel == "1" && (photometricInterpretation.ToUpper() == "MONOCHROME2" || photometricInterpretation.ToUpper() == "MONOCHROME1"))//MONOCHROME2
|
||||
{
|
||||
if (dataset.InternalTransferSyntax.IsEncapsulated)
|
||||
{
|
||||
await dicomFile.SaveAsync(filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
await dicomFile.Clone(DicomTransferSyntax.JPEGLSLossless).SaveAsync(filePath);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dataset.InternalTransferSyntax.IsEncapsulated) await dicomFile.SaveAsync(filePath);
|
||||
else await dicomFile.Clone(DicomTransferSyntax.RLELossless).SaveAsync(filePath); //RLELossless
|
||||
}
|
||||
return dicomInstance.StudyId;
|
||||
}
|
||||
|
||||
|
||||
private DicomStudy CreateDicomStudy(DicomDataset dataset, DicomTrialSiteSubjectInfo addtionalInfo, out bool isStudyNeedAdd)
|
||||
{
|
||||
|
||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, addtionalInfo.TrialId.ToString());
|
||||
|
||||
|
||||
|
||||
// 每个线程都查询数据库最大的,和缓存中最大的,取最大值为基数生成Code
|
||||
//var id = Thread.CurrentThread.ManagedThreadId.ToString("00");
|
||||
|
||||
//虽然每个文件都会进来,但是只要查询过,就会跟踪,不会再次查询数据库 这里线程并发会有问题,得加锁,不然生成Code 出错
|
||||
DicomStudy dicomStudy = _studyRepository.ImageFind(studyId, typeof(DicomStudy));
|
||||
|
||||
if (dicomStudy != null)
|
||||
{
|
||||
isStudyNeedAdd = false;
|
||||
return dicomStudy;
|
||||
}
|
||||
|
||||
//_logger.LogWarning($"Thread {id} ,studyUid{studyInstanceUid}, 生成StudyId:{studyId}");
|
||||
|
||||
isStudyNeedAdd = true;
|
||||
|
||||
dicomStudy = new DicomStudy
|
||||
{
|
||||
Id = studyId,
|
||||
StudyInstanceUid = studyInstanceUid,
|
||||
StudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, DateTime.Now).TimeOfDay),//dataset.GetDateTime(DicomTag.StudyDate, DicomTag.StudyTime),
|
||||
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||
InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty),
|
||||
PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||||
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||||
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
||||
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
|
||||
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
|
||||
|
||||
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
|
||||
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
|
||||
|
||||
//需要特殊处理
|
||||
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
|
||||
|
||||
|
||||
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
|
||||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
||||
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
|
||||
|
||||
|
||||
SiteId = addtionalInfo.SiteId,
|
||||
TrialId = addtionalInfo.TrialId,
|
||||
SubjectId = addtionalInfo.SubjectId,
|
||||
SubjectVisitId = addtionalInfo.SubjectVisitId,
|
||||
//IsDoubleReview = addtionalInfo.IsDoubleReview,
|
||||
SeriesCount = 0,
|
||||
InstanceCount = 0
|
||||
};
|
||||
|
||||
if (dicomStudy.PatientBirthDate.Length == 8)
|
||||
{
|
||||
dicomStudy.PatientBirthDate = $"{dicomStudy.PatientBirthDate[0]}{dicomStudy.PatientBirthDate[1]}{dicomStudy.PatientBirthDate[2]}{dicomStudy.PatientBirthDate[3]}-{dicomStudy.PatientBirthDate[4]}{dicomStudy.PatientBirthDate[5]}-{dicomStudy.PatientBirthDate[6]}{dicomStudy.PatientBirthDate[7]}";
|
||||
}
|
||||
|
||||
lock (lockCodeGenerate)
|
||||
{
|
||||
|
||||
//查询数据库获取最大的Code 没有记录则为0
|
||||
var dbStudyCodeIntMax = _studyRepository.Where(s => s.TrialId == addtionalInfo.TrialId).Select(t => t.Code).DefaultIfEmpty().Max();
|
||||
|
||||
//获取缓存中的值 并发的时候,需要记录,已被占用的值 这样其他线程在此占用的最大的值上递增
|
||||
var cacheMaxCodeInt = _provider.Get<int>($"{addtionalInfo.TrialId }_{ StaticData.StudyMaxCode}").Value;
|
||||
|
||||
int currentNextCodeInt = cacheMaxCodeInt > dbStudyCodeIntMax ? cacheMaxCodeInt + 1 : dbStudyCodeIntMax + 1;
|
||||
|
||||
dicomStudy.Code = currentNextCodeInt;
|
||||
|
||||
dicomStudy.StudyCode = "ST" + currentNextCodeInt.ToString("D5");
|
||||
|
||||
_provider.Set<int>($"{addtionalInfo.TrialId }_{ StaticData.StudyMaxCode}", dicomStudy.Code, TimeSpan.FromMinutes(30));
|
||||
|
||||
}
|
||||
|
||||
#region Setting Code old
|
||||
|
||||
//var studyCode = _studyRepository.Where(s => s.TrialId == addtionalInfo.TrialId).Select(t => t.StudyCode).OrderByDescending(c => c).FirstOrDefault();
|
||||
|
||||
//var cacheMaxCode = _provider.Get<string>($"{addtionalInfo.TrialId }_{ StaticData.StudyMaxCode}").Value;
|
||||
|
||||
//if (studyCode == null && string.IsNullOrEmpty(cacheMaxCode))
|
||||
//{
|
||||
// dicomStudy.StudyCode = "ST" + 1.ToString().PadLeft(5, '0');
|
||||
|
||||
// _logger.LogWarning($"Thread {id} DB:{studyCode} 生成{ dicomStudy.StudyCode}");
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// int dbNum = 0;
|
||||
|
||||
// int cacheNum = 0;
|
||||
|
||||
// if (studyCode != null)
|
||||
// {
|
||||
// int.TryParse(studyCode.Substring(studyCode.Length - 5, 5), out dbNum);
|
||||
// }
|
||||
|
||||
// if (!string.IsNullOrEmpty(cacheMaxCode))
|
||||
// {
|
||||
// int.TryParse(cacheMaxCode.Substring(cacheMaxCode.Length - 5, 5), out cacheNum);
|
||||
// }
|
||||
|
||||
// dbNum = cacheNum > dbNum ? cacheNum : dbNum;
|
||||
|
||||
|
||||
// dicomStudy.StudyCode = "ST" + (++dbNum).ToString().PadLeft(5, '0');
|
||||
|
||||
// _logger.LogWarning($" Thread {id} DB:{studyCode} cache:{cacheNum} 生成{ dicomStudy.StudyCode}");
|
||||
//}
|
||||
|
||||
//_provider.Set<string>($"{addtionalInfo.TrialId }_{ StaticData.StudyMaxCode}", dicomStudy.StudyCode, TimeSpan.FromMinutes(30));
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
return dicomStudy;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
private DicomSeries CreateDicomSeries(DicomDataset dataset, DicomStudy dicomStudy, out bool isSeriesNeedAdd)
|
||||
{
|
||||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||
Guid seriesId = IdentifierHelper.CreateGuid(dicomStudy.StudyInstanceUid, seriesInstanceUid, dicomStudy.TrialId.ToString());
|
||||
|
||||
//有几个序列会查询几次
|
||||
|
||||
DicomSeries dicomSeries = _seriesRepository.ImageFind(seriesId, typeof(DicomSeries));
|
||||
|
||||
if (dicomSeries != null)
|
||||
{
|
||||
isSeriesNeedAdd = false;
|
||||
return dicomSeries;
|
||||
}
|
||||
else
|
||||
{
|
||||
//var id = Thread.CurrentThread.ManagedThreadId.ToString("00");
|
||||
|
||||
isSeriesNeedAdd = true;
|
||||
dicomSeries = new DicomSeries
|
||||
{
|
||||
Id = seriesId,
|
||||
StudyId = dicomStudy.Id,
|
||||
|
||||
StudyInstanceUid = dicomStudy.StudyInstanceUid,
|
||||
SeriesInstanceUid = seriesInstanceUid,
|
||||
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
|
||||
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay), // dataset.GetDateTime(DicomTag.SeriesDate, DicomTag.SeriesTime),
|
||||
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||
|
||||
ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
|
||||
ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
|
||||
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
|
||||
SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty),
|
||||
ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty),
|
||||
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||
|
||||
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||
|
||||
SiteId = dicomStudy.SiteId,
|
||||
TrialId = dicomStudy.TrialId,
|
||||
SubjectId = dicomStudy.SubjectId,
|
||||
SubjectVisitId = dicomStudy.SubjectVisitId,
|
||||
|
||||
InstanceCount = 0
|
||||
};
|
||||
|
||||
++dicomStudy.SeriesCount;
|
||||
|
||||
|
||||
//_logger.LogWarning($"线程:{id},sericeId:{seriesId},count:{SeriesDic.Keys.Count}");
|
||||
|
||||
return dicomSeries;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private DicomInstance CreateDicomInstance(DicomDataset dataset, DicomStudy dicomStudy, DicomSeries dicomSeries)
|
||||
{
|
||||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||||
Guid instanceId = IdentifierHelper.CreateGuid(dicomStudy.StudyInstanceUid, dicomSeries.SeriesInstanceUid, sopInstanceUid, dicomStudy.TrialId.ToString());
|
||||
|
||||
DicomInstance dicomInstance = new DicomInstance
|
||||
{
|
||||
Id = instanceId,
|
||||
StudyId = dicomStudy.Id,
|
||||
SeriesId = dicomSeries.Id,
|
||||
|
||||
SiteId = dicomStudy.SiteId,
|
||||
TrialId = dicomStudy.TrialId,
|
||||
SubjectId = dicomStudy.SubjectId,
|
||||
SubjectVisitId = dicomStudy.SubjectVisitId,
|
||||
|
||||
StudyInstanceUid = dicomStudy.StudyInstanceUid,
|
||||
SeriesInstanceUid = dicomSeries.SeriesInstanceUid,
|
||||
SopInstanceUid = sopInstanceUid,
|
||||
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
|
||||
InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, DateTime.Now).TimeOfDay),
|
||||
//dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime)
|
||||
CPIStatus = false,
|
||||
ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0),
|
||||
ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0),
|
||||
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
|
||||
|
||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
|
||||
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
|
||||
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
|
||||
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
|
||||
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
|
||||
};
|
||||
|
||||
++dicomStudy.InstanceCount;
|
||||
++dicomSeries.InstanceCount;
|
||||
|
||||
return dicomInstance;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using System;
|
||||
using System.IO;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
||||
namespace IRaCIS.Core.Application
|
||||
{
|
||||
public class DicomFileStoreHelper
|
||||
{
|
||||
private readonly IWebHostEnvironment _hostEnvironment;
|
||||
private static string _fileStorePath = string.Empty;
|
||||
|
||||
private readonly ILogger<DicomFileStoreHelper> _logger;
|
||||
|
||||
public DicomFileStoreHelper(IWebHostEnvironment hostEnvironment, ILogger<DicomFileStoreHelper> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_hostEnvironment = hostEnvironment;
|
||||
var rootPath = Directory.GetParent(_hostEnvironment.ContentRootPath.TrimEnd('\\')).IfNullThrowException().FullName;
|
||||
|
||||
//上传根路径
|
||||
_fileStorePath = Path.Combine(rootPath, StaticData.TrialDataFolder);
|
||||
|
||||
}
|
||||
|
||||
public string GetInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, string instanceId)
|
||||
{
|
||||
return Path.Combine(_fileStorePath, dicomStudy.TrialId.ToString(),
|
||||
dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.SubjectVisitId.ToString(), StaticData.DicomFolder, dicomStudy.Id.ToString(), instanceId.ToString() + ".dcm");
|
||||
}
|
||||
|
||||
|
||||
public string CreateInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId)
|
||||
{
|
||||
|
||||
//加入访视层级 和Data
|
||||
var path = Path.Combine(_fileStorePath, dicomStudy.TrialId.ToString(),
|
||||
dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.SubjectVisitId.ToString(), StaticData.DicomFolder, dicomStudy.Id.ToString());
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
{
|
||||
Directory.CreateDirectory(path);
|
||||
}
|
||||
return Path.Combine(path, instanceId.ToString() + ".dcm");
|
||||
}
|
||||
|
||||
|
||||
public string GetSubjectVisitPath(Guid trialId,Guid siteId,Guid subjectId, Guid subjectVisitId)
|
||||
{
|
||||
return Path.Combine(_fileStorePath, trialId.ToString(),
|
||||
siteId.ToString(), subjectId.ToString(), subjectVisitId.ToString(), StaticData.DicomFolder);
|
||||
}
|
||||
|
||||
//public static string CreateInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId)
|
||||
//{
|
||||
// string path = Path.Combine(_fileStorePath, "Dicom", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(),
|
||||
// dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString());
|
||||
// if (!Directory.Exists(path)) Directory.CreateDirectory(path);
|
||||
|
||||
// return Path.Combine(path, instanceId.ToString() + ".dcm");
|
||||
//}
|
||||
|
||||
//public static string GetInstanceFilePath(DicomStudy dicomStudy, Guid seriesId, Guid instanceId)
|
||||
//{
|
||||
// return Path.Combine(_fileStorePath, "Dicom", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(),
|
||||
// dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString(), instanceId.ToString() + ".dcm");
|
||||
//}
|
||||
|
||||
|
||||
//public static void RemoveStudyDirectory(DicomStudy dicomStudy)
|
||||
//{
|
||||
// string path = Path.Combine(_fileStorePath, "Dicom", dicomStudy.CreateTime.Year.ToString(), dicomStudy.TrialId.ToString(),
|
||||
// dicomStudy.SiteId.ToString(), dicomStudy.SubjectId.ToString(), dicomStudy.Id.ToString());
|
||||
// if (Directory.Exists(path)) Directory.Delete(path, true);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using FellowOakDicom.Imaging;
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
|
||||
namespace IRaCIS.Core.Application.Dicom
|
||||
{
|
||||
public static class DicomRenderingHelper
|
||||
{
|
||||
public static Stream RenderPreviewJpeg(string filePath)
|
||||
{
|
||||
string jpegPath = filePath + ".preview.jpg";
|
||||
|
||||
if (!File.Exists(jpegPath))
|
||||
{
|
||||
using (Stream stream = new FileStream(jpegPath, FileMode.Create))
|
||||
{
|
||||
DicomImage image = new DicomImage(filePath);
|
||||
//image.ShowOverlays = false;
|
||||
//image.Scale = Math.Min(Math.Min(128.0 / image.Width, 128.0 / image.Height), 1.0);
|
||||
//image.RenderImage().AsClonedBitmap().Save(stream, ImageFormat.Jpeg);
|
||||
|
||||
var sharpimage = image.RenderImage().AsSharpImage();
|
||||
|
||||
sharpimage.Save(stream, new JpegEncoder());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return new FileStream(jpegPath, FileMode.Open);
|
||||
}
|
||||
|
||||
public static void RemovePreviewJpeg(string filePath)
|
||||
{
|
||||
string jpegPath = filePath + ".preview.jpg";
|
||||
if (File.Exists(jpegPath)) File.Delete(jpegPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
static class IdentifierHelper
|
||||
{
|
||||
//private static MD5 md5 = new MD5CryptoServiceProvider
|
||||
//
|
||||
private static MD5 md5 = MD5.Create();
|
||||
|
||||
private static object lockObj =new object();
|
||||
|
||||
public static Guid CreateGuid(params string[] parts)
|
||||
{
|
||||
lock (lockObj)
|
||||
{
|
||||
return new Guid(md5.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(parts))));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using IRaCIS.Core.Application.Contracts.Dicom;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using IRaCIS.Core.Application.Auth;
|
||||
|
||||
namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
[AllowAnonymous, ApiExplorerSettings(GroupName = "Image")]
|
||||
public class ImageShareService : BaseService, IImageShareService
|
||||
{
|
||||
|
||||
private readonly IRepository<ImageShare> _imageShareRepository;
|
||||
private readonly IRepository<DicomStudy> _studyRepository;
|
||||
private readonly IConfiguration _configuration;
|
||||
private readonly ITokenService _tokenService;
|
||||
|
||||
public ImageShareService(IRepository<ImageShare> imageShareRepository, IRepository<DicomStudy> studyRepository, IConfiguration configuration, ITokenService tokenService)
|
||||
{
|
||||
|
||||
_imageShareRepository = imageShareRepository;
|
||||
_studyRepository = studyRepository;
|
||||
_configuration = configuration;
|
||||
_tokenService = tokenService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> CreateImageShare(ImageShareCommand imageShareCommand)
|
||||
{
|
||||
if (imageShareCommand.StudyId == null)
|
||||
{
|
||||
|
||||
#region 上传不按照访视上传,基线没传,数据可能出错
|
||||
|
||||
//var subjectVisit1 = _subjectVisitRepository.FirstOrDefault(t =>
|
||||
// t.TrialId == imageShareCommand.TrialId && t.SubjectId == imageShareCommand.SubjectId &&
|
||||
// t.VisitNum == 1);
|
||||
|
||||
//if (subjectVisit1 == null)
|
||||
//{
|
||||
// return ResponseOutput.NotOk("当前无影像数据,无法分享!");
|
||||
//}
|
||||
|
||||
//imageShareCommand.StudyId =
|
||||
// _studyRepository.GetAll().First(t => t.SubjectVisitId == subjectVisit1.Id&&t.Status != (int)StudyStatus.Abandon).Id;
|
||||
|
||||
#endregion
|
||||
|
||||
var studyIds = await _studyRepository.AsQueryable()
|
||||
.Where(t => t.TrialId == imageShareCommand.TrialId && t.SubjectId == imageShareCommand.SubjectId &&
|
||||
t.SiteId == imageShareCommand.SiteId)
|
||||
.Select(u => u.Id).ToListAsync();
|
||||
|
||||
if (!studyIds.Any())
|
||||
{
|
||||
return ResponseOutput.NotOk("There is no image in the current study and cannot be shared! ");
|
||||
}
|
||||
|
||||
imageShareCommand.StudyId = studyIds.First();
|
||||
|
||||
}
|
||||
|
||||
//验证码 4位
|
||||
int verificationPassWord = new Random().Next(1000, 10000);
|
||||
|
||||
imageShareCommand.Password = verificationPassWord.ToString();
|
||||
|
||||
//配置文件读取过期时间
|
||||
var days = int.Parse(_configuration.GetSection("imageShare:ExpireDays").Value);
|
||||
|
||||
imageShareCommand.ExpireTime = DateTime.Now.AddDays(days);
|
||||
|
||||
var imageShare = _mapper.Map<ImageShare>(imageShareCommand);
|
||||
|
||||
await _imageShareRepository.AddAsync(imageShare);
|
||||
|
||||
var success = await _imageShareRepository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Result(success, new { ResourceId = imageShare.Id, Password = verificationPassWord.ToString() });
|
||||
|
||||
|
||||
}
|
||||
|
||||
[HttpGet, Route("{resourceId:guid}/{password}")]
|
||||
public async Task<IResponseOutput> VerifyShareImage(Guid resourceId, string password)
|
||||
{
|
||||
var pWord = password.Trim();
|
||||
var imageShare = await _imageShareRepository.FirstOrDefaultAsync(t => t.Id == resourceId);
|
||||
|
||||
if (imageShare == null)
|
||||
{
|
||||
return ResponseOutput.NotOk("The resource does not exist! ");
|
||||
}
|
||||
|
||||
if (pWord != imageShare.Password.Trim())
|
||||
{
|
||||
return ResponseOutput.NotOk("Shared password error!");
|
||||
}
|
||||
|
||||
if (DateTime.Now > imageShare.ExpireTime)
|
||||
{
|
||||
return ResponseOutput.NotOk("Resource sharing has expired!");
|
||||
}
|
||||
|
||||
var resource = new ResourceInfo()
|
||||
{
|
||||
StudyId = imageShare.StudyId,
|
||||
Token = _tokenService.GetToken(IRaCISClaims.Create(new UserBasicInfo()
|
||||
{
|
||||
Id = Guid.Empty,
|
||||
IsReviewer = false,
|
||||
IsAdmin = false,
|
||||
RealName = "Share001",
|
||||
UserName = "Share001",
|
||||
Sex = 0,
|
||||
//UserType = "ShareType",
|
||||
UserTypeEnum = UserTypeEnum.ShareImage,
|
||||
Code = "ShareCode001",
|
||||
}))
|
||||
};
|
||||
|
||||
|
||||
return ResponseOutput.Ok(resource);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
using IRaCIS.Core.Application.Contracts.Dicom;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Application.Dicom;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
||||
namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
[ApiExplorerSettings(GroupName = "Image")]
|
||||
[AllowAnonymous]
|
||||
public class InstanceService : BaseService, IInstanceService
|
||||
{
|
||||
private readonly IRepository<DicomInstance> _instanceRepository;
|
||||
private readonly IRepository<DicomStudy> _studyRepository;
|
||||
private readonly IRepository<KeyInstance> _keyInstanceRepository;
|
||||
private readonly DicomFileStoreHelper _dicomFileStoreHelper;
|
||||
public InstanceService(IRepository<DicomInstance> instanceRepository, IRepository<DicomStudy> studyRepository,
|
||||
IRepository<KeyInstance> keyInstanceRepository, DicomFileStoreHelper dicomFileStoreHelper)
|
||||
{
|
||||
_dicomFileStoreHelper = dicomFileStoreHelper;
|
||||
_instanceRepository = instanceRepository;
|
||||
_studyRepository = studyRepository;
|
||||
_keyInstanceRepository = keyInstanceRepository;
|
||||
}
|
||||
|
||||
/// <summary> 指定资源Id,获取Dicom序列所属的实例信息列表 </summary>
|
||||
/// <param name="seriesId"> Dicom序列的Id </param>
|
||||
[HttpGet("{seriesId:guid}")]
|
||||
public async Task<IEnumerable<DicomInstanceDTO>> List(Guid seriesId)
|
||||
{
|
||||
return await _instanceRepository.Where(s => s.SeriesId == seriesId).OrderBy(s => s.InstanceNumber).
|
||||
ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
|
||||
.ProjectTo<DicomInstanceDTO>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
/// <summary> 指定资源Id,获取Dicom序列所属的实例Id列表 </summary>
|
||||
/// <param name="seriesId"> Dicom序列的Id </param>
|
||||
/// <param name="tpCode"></param>
|
||||
/// <param name="key"></param>
|
||||
[HttpGet, Route("{seriesId:guid}/{tpCode?}/{key?}")]
|
||||
public IEnumerable<Guid> List(Guid seriesId, string tpCode, bool? key)
|
||||
{
|
||||
if (key != null && key.HasValue && key.Value)
|
||||
{
|
||||
return _keyInstanceRepository.Where(s => s.TpCode == tpCode).Select(t => t.InstanceId).Distinct();
|
||||
}
|
||||
else
|
||||
return _instanceRepository.Where(s => s.SeriesId == seriesId).OrderBy(s => s.InstanceNumber).Select(t => t.Id);
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet, Route("{instanceId:guid}")]
|
||||
public async Task<FileContentResult> Preview(Guid instanceId)
|
||||
{
|
||||
var path = string.Empty;
|
||||
|
||||
DicomInstance dicomInstance = await _instanceRepository.FirstOrDefaultAsync(s => s.Id == instanceId).IfNullThrowException();
|
||||
|
||||
DicomStudy dicomStudy = await _studyRepository.FirstOrDefaultAsync(s => s.Id == dicomInstance.StudyId).IfNullThrowException();
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet, Route("{instanceId:guid}")]
|
||||
public async Task<FileContentResult> Content(Guid instanceId)
|
||||
{
|
||||
var filePath = string.Empty;
|
||||
DicomInstance dicomInstance = await _instanceRepository.FirstOrDefaultAsync(s => s.Id == instanceId).IfNullThrowException();
|
||||
|
||||
DicomStudy dicomStudy = await _studyRepository.FirstOrDefaultAsync(s => s.Id == dicomInstance.StudyId).IfNullThrowException();
|
||||
|
||||
|
||||
if (dicomInstance.Anonymize) //被匿名化
|
||||
{
|
||||
filePath = _dicomFileStoreHelper.GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id + ".Anonymize");
|
||||
}
|
||||
|
||||
else filePath = _dicomFileStoreHelper.GetInstanceFilePath(dicomStudy, dicomInstance.SeriesId, dicomInstance.Id.ToString());
|
||||
|
||||
|
||||
|
||||
using (var sw = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
var bytes = new byte[sw.Length];
|
||||
sw.Read(bytes, 0, bytes.Length);
|
||||
sw.Close();
|
||||
return new FileContentResult(bytes, "application/octet-stream");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace IRaCIS.Core.Application.Contracts.Dicom
|
||||
{
|
||||
public interface IDicomArchiveService
|
||||
{
|
||||
Task<Guid> ArchiveDicomStreamAsync(Stream dicomStream, DicomTrialSiteSubjectInfo addtionalInfo, List<string> seriesInstanceUidList, List<string> instanceUidList);
|
||||
//ICollection<DicomStudyDTO> GetArchivedStudyList(List<Guid> archivedStudyIds);
|
||||
|
||||
Task<bool> DicomDBDataSaveChange();
|
||||
|
||||
|
||||
//[EasyCachingAble(Expiration = 6000)]
|
||||
|
||||
|
||||
|
||||
//IEnumerable<DicomSeriesDTO> GetSeriesList(Guid studyId);
|
||||
//IEnumerable<DicomSeriesWithLabelDTO> GetSeriesWithLabelList(Guid studyId,string tpCode);
|
||||
|
||||
////[EasyCachingAble(Expiration = 6000)]
|
||||
//string GetSeriesPreview(Guid seriesId);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
|
||||
namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
public interface IImageShareService
|
||||
{
|
||||
Task<IResponseOutput> CreateImageShare(ImageShareCommand imageShareCommand);
|
||||
Task<IResponseOutput> VerifyShareImage(Guid resourceId, string password);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
public interface IInstanceService
|
||||
{
|
||||
Task<FileContentResult> Content(Guid instanceId);
|
||||
Task<IEnumerable<DicomInstanceDTO>> List(Guid seriesId);
|
||||
IEnumerable<Guid> List(Guid seriesId, string tpCode, bool? key);
|
||||
Task<FileContentResult> Preview(Guid instanceId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
||||
namespace IRaCIS.Core.Application.Contracts.Image
|
||||
{
|
||||
public interface IStudyDTFService
|
||||
{
|
||||
IResponseOutput AddStudyDTF(StudyDTFAddOrUpdateCommand studyDtfAddOrUpdate);
|
||||
IResponseOutput DeleteStudyDTF(Guid studyDTFId );
|
||||
|
||||
List<StudyDTFDTO> GetStudyDtfdtos(Guid triaId, string studyInstanceUid);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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
|
||||
{
|
||||
public interface IStudyService
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
//IResponseOutput ForwardStudy(Guid studyId);
|
||||
|
||||
DicomTrialSiteSubjectInfo GetSaveToDicomInfo(Guid subjctVisitId);
|
||||
|
||||
void GetHasUploadSeriesAndInstance(Guid studyId, ref List<string> seriesInstanceUidList, ref List<string> instanceUidList);
|
||||
|
||||
|
||||
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);
|
||||
|
||||
/// <summary> 根据项目Id,医生Id,获取受试者访视点(不分页)</summary>
|
||||
//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);
|
||||
/// <summary>
|
||||
/// 更新Study 表中的Status,并且往 StudyStatusDetail详情表中插入一条状态变化记录
|
||||
/// </summary>
|
||||
/// <param name="studyStatusDetailDTO"></param>
|
||||
|
||||
//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);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2022-03-03 15:28:27
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
namespace IRaCIS.Core.Application.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// ISystemAnonymizationService
|
||||
/// </summary>
|
||||
public interface ISystemAnonymizationService
|
||||
{
|
||||
|
||||
|
||||
Task<PageOutput<SystemAnonymizationView>> GetSystemAnonymizationList(SystemAnonymizationQuery querySystemAnonymization);
|
||||
|
||||
Task<IResponseOutput> AddOrUpdateSystemAnonymization(SystemAnonymizationAddOrEdit addOrEditSystemAnonymization);
|
||||
|
||||
Task<IResponseOutput> DeleteSystemAnonymization(Guid systemAnonymizationId);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
using IRaCIS.Core.Application.Contracts.Dicom;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Application.Dicom;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace IRaCIS.Core.Application.Services
|
||||
{
|
||||
[ApiExplorerSettings(GroupName = "Image")]
|
||||
[AllowAnonymous]
|
||||
public class SeriesService : BaseService
|
||||
{
|
||||
private readonly IRepository<ImageLabel> _imageLabelRepository;
|
||||
private readonly IRepository<DicomSeries> _seriesRepository;
|
||||
private readonly IRepository<DicomInstance> _instanceRepository;
|
||||
private readonly IRepository<DicomStudy> _studyRepository;
|
||||
private readonly IRepository<KeyInstance> _keyInstanceRepository;
|
||||
private readonly DicomFileStoreHelper _dicomFileStoreHelper;
|
||||
public SeriesService(IRepository<DicomInstance> instanceRepository, IRepository<DicomStudy> studyRepository,
|
||||
IRepository<KeyInstance> keyInstanceRepository, DicomFileStoreHelper dicomFileStoreHelper, IRepository<DicomSeries> seriesRepository, IRepository<ImageLabel> imageLabelRepository)
|
||||
{
|
||||
_seriesRepository = seriesRepository;
|
||||
_dicomFileStoreHelper = dicomFileStoreHelper;
|
||||
_instanceRepository = instanceRepository;
|
||||
_studyRepository = studyRepository;
|
||||
_keyInstanceRepository = keyInstanceRepository;
|
||||
_imageLabelRepository = imageLabelRepository;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//医生读片那一块有耦合,关键序列 这里暂时留存
|
||||
/// <summary> 指定资源Id,获取Dicom检查所属序列信息列表 </summary>
|
||||
/// <param name="studyId"> Dicom检查的Id </param>
|
||||
/// <param name="tpCode"></param>
|
||||
[HttpGet, Route("{studyId:guid}/{tpCode?}")]
|
||||
public async Task<IResponseOutput<List<DicomSeriesWithLabelDTO>>> List(Guid studyId, string? tpCode)
|
||||
{
|
||||
|
||||
var seriesList = await _seriesRepository.Where(s => s.StudyId == studyId).OrderBy(s => s.SeriesNumber).
|
||||
ThenBy(s => s.SeriesTime).ThenBy(s => s.CreateTime)
|
||||
.ProjectTo<DicomSeriesWithLabelDTO>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
|
||||
bool hasKeyInstance = false;
|
||||
var SeriesIdList = _imageLabelRepository.Where(u => u.TpCode == tpCode).Select(s => s.SeriesId).Distinct().ToList();
|
||||
var instanceIdList = _imageLabelRepository.Where(u => u.TpCode == tpCode).Select(s => s.InstanceId).Distinct().ToList();
|
||||
foreach (var item in seriesList)
|
||||
{
|
||||
if (SeriesIdList.Contains(item.Id))
|
||||
{
|
||||
item.HasLabel = true;
|
||||
hasKeyInstance = true;
|
||||
}
|
||||
else item.HasLabel = false;
|
||||
}
|
||||
if (hasKeyInstance)
|
||||
{
|
||||
seriesList.Add(new DicomSeriesWithLabelDTO
|
||||
{
|
||||
KeySeries = true,
|
||||
Id = SeriesIdList[0],
|
||||
InstanceCount = instanceIdList.Count,
|
||||
HasLabel = true,
|
||||
Modality = seriesList[0].Modality,
|
||||
Description = "Key Series"
|
||||
});
|
||||
}
|
||||
|
||||
var idList = await _instanceRepository.Where(s => s.StudyId == studyId).ToListAsync();//.GroupBy(u => u.SeriesId);
|
||||
|
||||
foreach (var item in seriesList)
|
||||
{
|
||||
if (item.KeySeries)
|
||||
{
|
||||
item.InstanceList = instanceIdList;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.InstanceList = idList.Where(s => s.SeriesId == item.Id).OrderBy(t => t.InstanceNumber)
|
||||
.ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime).Select(u => u.Id).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseOutput.Ok(seriesList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary> 指定资源Id,渲染Dicom序列的Jpeg预览图像 </summary>
|
||||
/// <param name="seriesId"> Dicom序列的Id </param>
|
||||
[HttpGet, Route("{seriesId:guid}")]
|
||||
[AllowAnonymous]
|
||||
public async Task<FileContentResult> Preview(Guid seriesId)
|
||||
{
|
||||
string path = string.Empty;
|
||||
DicomInstance dicomInstance = await _instanceRepository.FirstOrDefaultAsync(s => s.SeriesId == seriesId).IfNullThrowException();
|
||||
|
||||
DicomStudy dicomStudy = await _studyRepository.FirstOrDefaultAsync(s => s.Id == dicomInstance.StudyId).IfNullThrowException();
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
//using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
//using IRaCIS.Core.Application.Contracts.Image;
|
||||
//using IRaCIS.Core.Infrastructure.Extention;
|
||||
//using IRaCIS.Core.Infra.EFCore;
|
||||
//using IRaCIS.Core.Domain.Models;
|
||||
//using Microsoft.AspNetCore.Authorization;
|
||||
//using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
//namespace IRaCIS.Core.Application.Services
|
||||
//{
|
||||
// [ ApiExplorerSettings(GroupName = "Image")]
|
||||
// public class StudyDTFService : BaseService, IStudyDTFService
|
||||
// {
|
||||
// private readonly IRepository<StudyDTF> _studyDtfRepository;
|
||||
|
||||
// private readonly IRepository<User> _userRepository;
|
||||
|
||||
|
||||
// public StudyDTFService(IRepository<StudyDTF> studyDtfRepository, IRepository<User> userRepository)
|
||||
// {
|
||||
// _studyDtfRepository = studyDtfRepository;
|
||||
|
||||
// _userRepository = userRepository;
|
||||
// }
|
||||
|
||||
// public IResponseOutput AddStudyDTF(StudyDTFAddOrUpdateCommand studyDtfAddOrUpdate)
|
||||
// {
|
||||
// var studyDtf = _mapper.Map<StudyDTF>(studyDtfAddOrUpdate);
|
||||
|
||||
// _studyDtfRepository.Add(studyDtf);
|
||||
|
||||
// var success = _studyDtfRepository.SaveChanges();
|
||||
|
||||
// return ResponseOutput.Result(success);
|
||||
// }
|
||||
|
||||
// //[NonDynamicMethod]
|
||||
// //[AllowAnonymous]
|
||||
// //public async Task<IResponseOutput> UpdateStudyDTF(StudyDTFAddOrUpdateCommand studyDtfAddOrUpdate)
|
||||
// //{
|
||||
// // studyDtfAddOrUpdate.Id.IfNullThrowException();
|
||||
// // var studyDTF = await _studyDtfRepository.FindAsync( studyDtfAddOrUpdate.Id.Value );
|
||||
|
||||
// // studyDTF.Path = "9999";
|
||||
|
||||
// // //var success= await _efStudyDtfRepository.UpdateAsync(studyDTF,true);
|
||||
|
||||
// // var success = await _studyDtfRepository.SaveChangesAsync();
|
||||
|
||||
// // //_efStudyDtfRepository.UpdateAsync();
|
||||
|
||||
|
||||
// // return ResponseOutput.Ok(success);
|
||||
// //}
|
||||
|
||||
// [HttpDelete("{trialId:guid}/{studyDTFId:guid}")]
|
||||
// public IResponseOutput DeleteStudyDTF(Guid studyDTFId)
|
||||
// {
|
||||
// return ResponseOutput.Result(_studyDtfRepository.Delete(t => t.Id == studyDTFId));
|
||||
// }
|
||||
|
||||
// [HttpGet("{trialId:guid}/{studyInstanceUid}")]
|
||||
// public List<StudyDTFDTO> GetStudyDtfdtos(Guid trialId, string studyInstanceUid)
|
||||
// {
|
||||
// var studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
|
||||
|
||||
// var query = from studyDtf in _studyDtfRepository.Where(t => t.StudyId == studyId)
|
||||
// join user in _userRepository.AsQueryable() on studyDtf.CreateUserId equals user.Id
|
||||
// select new StudyDTFDTO()
|
||||
// {
|
||||
// CreateTime = studyDtf.CreateTime,
|
||||
// CreateUserId = studyDtf.CreateUserId,
|
||||
// FileName = studyDtf.FileName,
|
||||
// Id = studyDtf.Id,
|
||||
// FirstName = user.FirstName,
|
||||
// LastName = user.LastName,
|
||||
// UserName = user.UserName,
|
||||
// Path = studyDtf.Path
|
||||
// };
|
||||
|
||||
// return query.ToList();
|
||||
// }
|
||||
|
||||
|
||||
// [HttpGet("{trialId:guid}/{studyId:guid}")]
|
||||
// public List<StudyDTFDTO> GetStudyDtfList(Guid trialId, Guid studyId)
|
||||
// {
|
||||
// //var studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
|
||||
|
||||
// var query = from studyDtf in _studyDtfRepository.Where(t => t.StudyId == studyId)
|
||||
// join user in _userRepository.AsQueryable() on studyDtf.CreateUserId equals user.Id
|
||||
// select new StudyDTFDTO()
|
||||
// {
|
||||
// CreateTime = studyDtf.CreateTime,
|
||||
// CreateUserId = studyDtf.CreateUserId,
|
||||
// FileName = studyDtf.FileName,
|
||||
// Id = studyDtf.Id,
|
||||
// FirstName = user.FirstName,
|
||||
// LastName = user.LastName,
|
||||
// UserName = user.UserName,
|
||||
// Path = studyDtf.Path
|
||||
// };
|
||||
|
||||
// return query.ToList();
|
||||
// }
|
||||
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,417 @@
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<UnionStudyViewModel>> GetDicomAndNoneDicomStudyList(StudyQuery studyQuery)
|
||||
{
|
||||
|
||||
var dicomStudyQuery = _repository.Where<DicomStudy>(t => t.TrialId == studyQuery.TrialId)
|
||||
.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 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,
|
||||
|
||||
DicomStudyCode = t.StudyCode,
|
||||
NoneDicomCode = 0,
|
||||
|
||||
StudyTime = t.StudyTime,
|
||||
|
||||
TrialSiteAliasName = t.TrialSite.TrialSiteAliasName,
|
||||
|
||||
TrialSiteCode = t.TrialSite.TrialSiteCode,
|
||||
|
||||
Uploader = t.Uploader.LastName + " / " + t.Uploader.LastName,
|
||||
|
||||
UploadTime = t.CreateTime
|
||||
|
||||
});
|
||||
|
||||
|
||||
//.ProjectTo<UnionStudyViewDodel>(_mapper.ConfigurationProvider);
|
||||
|
||||
|
||||
|
||||
var nodeDicomStudyQuery = _repository.Where<NoneDicomStudy>(t => t.TrialId == studyQuery.TrialId)
|
||||
.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 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(),
|
||||
|
||||
NoneDicomCode = t.Code,
|
||||
DicomStudyCode = string.Empty,
|
||||
|
||||
StudyTime = t.ImageDate,
|
||||
|
||||
TrialSiteAliasName = t.TrialSite.TrialSiteAliasName,
|
||||
|
||||
TrialSiteCode = t.TrialSite.TrialSiteCode,
|
||||
|
||||
Uploader = t.CreateUser.LastName + " / " + t.CreateUser.LastName,
|
||||
|
||||
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 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.LastName + " / " + t.Uploader.LastName,
|
||||
|
||||
UploadTime = t.CreateTime,
|
||||
|
||||
|
||||
IP = t.IP,
|
||||
FileCount = t.FileCount,
|
||||
FileSize = t.FileSize,
|
||||
UploadFinishedTime = t.UploadFinishedTime,
|
||||
UploadStartTime = t.UploadStartTime,
|
||||
IsDicomReUpload = t.IsDicomReUpload,
|
||||
StudyId = t.Id,
|
||||
IsDicom = t.IsDicom,
|
||||
|
||||
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.LastName + " / " + t.Uploader.LastName,
|
||||
UploadTime = t.CreateTime,
|
||||
|
||||
IP = t.IP,
|
||||
FileCount = t.FileCount,
|
||||
FileSize = t.FileSize,
|
||||
UploadFinishedTime = t.UploadFinishedTime,
|
||||
UploadStartTime = t.UploadStartTime,
|
||||
IsDicomReUpload = t.IsDicomReUpload,
|
||||
StudyId = t.Id,
|
||||
IsDicom = t.IsDicom,
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/// <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}")]
|
||||
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.EarliestScanDate);
|
||||
|
||||
if (before != null && before > waitUploadItem.StudyDate)
|
||||
{
|
||||
result.Add(new VerifyStudyUploadResult() { ErrorMesseage = "当前访视检查时间不能小于该访视之前检查的时间,请核对检查数据是否有误", StudyInstanceUid = waitUploadItem.StudyInstanceUid });
|
||||
return;
|
||||
}
|
||||
|
||||
//大于当前访视 最近的最晚拍片日期
|
||||
var after = visitList.Where(u => u.VisitNum > verifyInfo.VisitNum).Min(k => k.LatestScanDate);
|
||||
|
||||
if (after != null && after < waitUploadItem.StudyDate)
|
||||
{
|
||||
result.Add(new VerifyStudyUploadResult() { ErrorMesseage = "当前访视检查时间不能大于该访视之后的检查时间,请核对检查数据是否有误", 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.StudyTime }: This DICOM images have been uploaded and allocate to the {verifyStudyInfo.VisitName} of the subject {verifyStudyInfo.SubjectCode} (Study ID: {verifyStudyInfo.StudyCode}), which cannot continue to upload and assign it to others.";
|
||||
}
|
||||
}
|
||||
result.StudyInstanceUid = studyInstanceUid;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,67 @@
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2022-03-03 15:28:32
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.MediatR.Handlers;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using MediatR;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// SystemAnonymizationService
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(GroupName = "Image")]
|
||||
public class SystemAnonymizationService : BaseService, ISystemAnonymizationService
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
private readonly IRepository<SystemAnonymization> systemAnonymizationRepository;
|
||||
|
||||
public SystemAnonymizationService(IMediator mediator, IRepository<SystemAnonymization> systemAnonymizationRepository)
|
||||
{
|
||||
_mediator = mediator;
|
||||
this.systemAnonymizationRepository = systemAnonymizationRepository;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<SystemAnonymizationView>> GetSystemAnonymizationList(SystemAnonymizationQuery querySystemAnonymization)
|
||||
{
|
||||
|
||||
var systemAnonymizationQueryable = systemAnonymizationRepository
|
||||
.WhereIf(!string.IsNullOrEmpty(querySystemAnonymization.Group), t => t.Group.Contains(querySystemAnonymization.Group))
|
||||
.WhereIf(!string.IsNullOrEmpty(querySystemAnonymization.Element), t => t.Element.Contains(querySystemAnonymization.Element))
|
||||
.WhereIf(querySystemAnonymization.IsAdd != null, t => t.IsAdd == querySystemAnonymization.IsAdd)
|
||||
.WhereIf(!string.IsNullOrEmpty(querySystemAnonymization.ValueRepresentation), t => t.ValueRepresentation.Contains(querySystemAnonymization.ValueRepresentation))
|
||||
.ProjectTo<SystemAnonymizationView>(_mapper.ConfigurationProvider);
|
||||
|
||||
return await systemAnonymizationQueryable.ToPagedListAsync(querySystemAnonymization.PageIndex, querySystemAnonymization.PageSize, querySystemAnonymization.SortField, querySystemAnonymization.Asc);
|
||||
}
|
||||
|
||||
|
||||
public async Task<IResponseOutput> AddOrUpdateSystemAnonymization(SystemAnonymizationAddOrEdit addOrEditSystemAnonymization)
|
||||
{
|
||||
|
||||
var entity = await _repository.InsertOrUpdateAsync<SystemAnonymization, SystemAnonymizationAddOrEdit>(addOrEditSystemAnonymization, true);
|
||||
|
||||
await _mediator.Send(new AnonymizeCacheRequest());
|
||||
|
||||
return ResponseOutput.Ok(entity.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpDelete("{systemAnonymizationId:guid}")]
|
||||
public async Task<IResponseOutput> DeleteSystemAnonymization(Guid systemAnonymizationId)
|
||||
{
|
||||
var success = await systemAnonymizationRepository.DeleteFromQueryAsync(t => t.Id == systemAnonymizationId);
|
||||
|
||||
return ResponseOutput.Result(success);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using AutoMapper;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using IRaCIS.Core.Application.Contracts.DTO;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
public class ImageAndDocConfig : Profile
|
||||
{
|
||||
public ImageAndDocConfig()
|
||||
{
|
||||
CreateMap<Report, ReportDTO>();
|
||||
CreateMap<ImageLabel, ImageLabelDTO>();
|
||||
CreateMap<DicomSeries, DicomSeriesWithLabelDTO>();
|
||||
|
||||
//影像上传 检查
|
||||
CreateMap<DicomStudy, VerifyStudyDto>()
|
||||
.ForMember(d => d.SubjectId, u => u.MapFrom(s => s.Subject.Id))
|
||||
.ForMember(d => d.VisitName, u => u.MapFrom(s => s.SubjectVisit.VisitName))
|
||||
.ForMember(d => d.SubjectCode, u => u.MapFrom(s => s.Subject.Code))
|
||||
.ForMember(d => d.FirstName, u => u.MapFrom(s => s.Subject.FirstName))
|
||||
.ForMember(d => d.LastName, u => u.MapFrom(s => s.Subject.LastName));
|
||||
|
||||
|
||||
|
||||
CreateMap<DicomStudy, StudyDTO>().IncludeMembers(t => t.Subject, u => u.SubjectVisit)
|
||||
.ForMember(d => d.UploaderFirstName, u => u.MapFrom(s => s.Site.SiteName))
|
||||
.ForMember(d => d.SiteName, u => u.MapFrom(s => s.Site.SiteName))
|
||||
.ForMember(d => d.UploaderFirstName, u => u.MapFrom(s => s.Uploader.FirstName))
|
||||
.ForMember(d => d.UploaderLastName, u => u.MapFrom(s => s.Uploader.LastName))
|
||||
.ForMember(d => d.StudyStatus, u => u.MapFrom(s => s.Status))
|
||||
.ForMember(d => d.UploadedTime, u => u.MapFrom(s => s.CreateTime))
|
||||
|
||||
.ForMember(d => d.DTFCount, u => u.MapFrom(s => s.StudyDTFList.Count()));
|
||||
|
||||
CreateMap<Subject, StudyDTO>();
|
||||
|
||||
CreateMap<SubjectVisit, StudyDTO>();
|
||||
|
||||
CreateMap<DicomStudy, RelationStudyDTO>()
|
||||
.ForMember(d => d.StudyId, u => u.MapFrom(s => s.Id))
|
||||
.ForMember(d => d.VisitName, u => u.MapFrom(s => s.SubjectVisit.VisitName));
|
||||
|
||||
CreateMap<DicomStudy, DicomStudyBasicDTO>();
|
||||
|
||||
|
||||
CreateMap<DicomSeries, QASeriesInfoDto>()
|
||||
.ForMember(o => o.StudyCode, t => t.MapFrom(u => u.DicomStudy.StudyCode))
|
||||
.ForMember(o => o.InstanceList, t => t.MapFrom(u => u.DicomInstanceList.Select(t=>t.Id).ToArray()))
|
||||
;
|
||||
|
||||
CreateMap<DicomStudy, QAStudyInfoDTO>()
|
||||
.ForMember(o => o.UploadedTime, t => t.MapFrom(u => u.CreateTime))
|
||||
.ForMember(o => o.Uploader, t => t.MapFrom(u => u.Uploader.LastName + " / " + u.Uploader.FirstName))
|
||||
.ForMember(o => o.StudyId, t => t.MapFrom(u => u.Id));
|
||||
|
||||
|
||||
|
||||
CreateMap<StudyCommand, DicomStudy>();
|
||||
|
||||
//CreateMap<ImageQACommand, ImageQA>();
|
||||
|
||||
CreateMap<ImageShareCommand, ImageShare>();
|
||||
|
||||
CreateMap<StudyDTFAddOrUpdateCommand, StudyDTF>();
|
||||
|
||||
|
||||
|
||||
CreateMap<StudyStatusDetail, StudyStatusDetailDTO>();
|
||||
|
||||
CreateMap<DicomInstance, DicomInstanceDTO>();
|
||||
CreateMap<DicomStudy, DicomStudyDTO>();
|
||||
CreateMap<DicomSeries, DicomSeriesDTO>();
|
||||
|
||||
|
||||
|
||||
CreateMap<SystemAnonymization, SystemAnonymizationAddOrEdit>().ReverseMap();
|
||||
|
||||
CreateMap<SystemAnonymization, SystemAnonymizationView>();
|
||||
|
||||
|
||||
|
||||
CreateMap<DicomStudy, UnionStudyViewModel>()
|
||||
.ForMember(d => d.DicomStudyCode, u => u.MapFrom(s => s.StudyCode))
|
||||
//.ForMember(d => d.Modality, u => u.MapFrom(s => s.Modalities))
|
||||
.ForMember(d => d.Bodypart, u => u.MapFrom(s => s.BodyPartExamined))
|
||||
.ForMember(d => d.StudyTime, u => u.MapFrom(s => s.StudyTime))
|
||||
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.TrialSite.TrialSiteCode))
|
||||
.ForMember(d => d.TrialSiteAliasName, u => u.MapFrom(s => s.TrialSite.TrialSiteAliasName))
|
||||
.ForMember(d => d.IsDicom, u => u.MapFrom(s => true))
|
||||
.ForMember(d => d.Count, u => u.MapFrom(s => s.SeriesCount))
|
||||
.ForMember(d => d.VisitNum, u => u.MapFrom(s => s.SubjectVisit.VisitNum))
|
||||
.ForMember(d => d.VisitName, u => u.MapFrom(s => s.SubjectVisit.VisitName));
|
||||
|
||||
CreateMap<NoneDicomStudy, UnionStudyViewModel>()
|
||||
.ForMember(d => d.NoneDicomCode, u => u.MapFrom(s => s.Code))
|
||||
//.ForMember(d => d.Modality, u => u.MapFrom(s => s.Modalities))
|
||||
.ForMember(d => d.Bodypart, u => u.MapFrom(s => s.BodyPart))
|
||||
.ForMember(d => d.StudyTime, u => u.MapFrom(s => s.ImageDate))
|
||||
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.TrialSite.TrialSiteCode))
|
||||
.ForMember(d => d.TrialSiteAliasName, u => u.MapFrom(s => s.TrialSite.TrialSiteAliasName))
|
||||
.ForMember(d => d.IsDicom, u => u.MapFrom(s => false))
|
||||
.ForMember(d => d.Count, u => u.MapFrom(s => s.NoneDicomFileList.Count()))
|
||||
.ForMember(d => d.VisitNum, u => u.MapFrom(s => s.SubjectVisit.VisitNum))
|
||||
.ForMember(d => d.VisitName, u => u.MapFrom(s => s.SubjectVisit.VisitName));
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user