增加打包状态 crc列表增加字段,影像下载打包迁移
continuous-integration/drone/push Build is passing Details

IRC_NewDev
hang 2024-05-17 10:51:30 +08:00
parent 2933d100f7
commit 85439213b2
7 changed files with 299 additions and 13 deletions

View File

@ -96,8 +96,8 @@ namespace IRaCIS.Core.Application.Helper
public interface IOSSService
{
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName);
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath);
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true);
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
@ -124,12 +124,12 @@ namespace IRaCIS.Core.Application.Helper
/// <param name="fileStream"></param>
/// <param name="oosFolderPath"></param>
/// <param name="fileRealName"></param>
/// <param name="isFileNameAddGuid"></param>
/// <returns></returns>
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName)
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
{
var ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}";
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
//var ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}";
//var ossRelativePath = oosFolderPath + "/" + fileRealName;
using (var memoryStream = new MemoryStream())
@ -207,11 +207,12 @@ namespace IRaCIS.Core.Application.Helper
/// <param name="oosFolderPath"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath)
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
{
var localFileName = Path.GetFileName(localFilePath);
var ossRelativePath = $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}";
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
//var ossRelativePath = oosFolderPath + "/" + localFileName;
@ -266,6 +267,7 @@ namespace IRaCIS.Core.Application.Helper
}
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
{

View File

@ -84,16 +84,17 @@
<param name="type"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Helper.OSSService.UploadToOSSAsync(System.IO.Stream,System.String,System.String)">
<member name="M:IRaCIS.Core.Application.Helper.OSSService.UploadToOSSAsync(System.IO.Stream,System.String,System.String,System.Boolean)">
<summary>
oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
</summary>
<param name="fileStream"></param>
<param name="oosFolderPath"></param>
<param name="fileRealName"></param>
<param name="isFileNameAddGuid"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Helper.OSSService.UploadToOSSAsync(System.String,System.String)">
<member name="M:IRaCIS.Core.Application.Helper.OSSService.UploadToOSSAsync(System.String,System.String,System.Boolean)">
<summary>
oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
</summary>
@ -852,6 +853,24 @@
后台托管服务的方式运行
</summary>
</member>
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.RequestPackageAndAnonymizImage(System.Guid,System.Guid,System.Boolean)">
<summary>
打包和匿名化影像 默认是匿名化打包,也可以不匿名化打包
</summary>
<param name="trialId"></param>
<param name="subjectVisitId"></param>
<param name="isAnonymize"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.PackageAndAnonymizImage(System.Guid,System.Guid,System.Boolean)">
<summary>
后台任务调用,前端忽略该接口
</summary>
<param name="trialId"></param>
<param name="subjectVisitId"></param>
<param name="isAnonymize"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.StudyService.AddOrUpdateArchiveStudy(IRaCIS.Core.Application.Contracts.NewArchiveStudyCommand)">
<summary>
上传临床数据

View File

@ -0,0 +1,232 @@
using FellowOakDicom;
using IRaCIS.Core.Application.Helper;
using MassTransit;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Core.Application.Service.ImageAndDoc
{
public interface IDownloadAndUploadService
{
Task PackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isAnonymize = true);
}
[ApiExplorerSettings(GroupName = "Trial")]
public class DownloadAndUploadService : BaseService, IDownloadAndUploadService
{
private readonly IRepository<SystemAnonymization> _systemAnonymizationRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IOSSService _oSSService;
public DownloadAndUploadService(IRepository<SystemAnonymization> systemAnonymizationRepository, IRepository<SubjectVisit> subjectVisitRepository, IOSSService oSSService)
{
_systemAnonymizationRepository = systemAnonymizationRepository;
_subjectVisitRepository = subjectVisitRepository;
_oSSService = oSSService;
}
/// <summary>
/// 打包和匿名化影像 默认是匿名化打包,也可以不匿名化打包
/// </summary>
/// <param name="trialId"></param>
/// <param name="subjectVisitId"></param>
/// <param name="isAnonymize"></param>
/// <returns></returns>
public async Task<IResponseOutput> RequestPackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isAnonymize = true)
{
var subjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
if (subjectVisit.PackState == PackState.WaitPack)
{
HangfireJobHelper.NotImmediatelyOnceOnlyJob<IDownloadAndUploadService>(t => t.PackageAndAnonymizImage(trialId, subjectVisitId, isAnonymize), TimeSpan.FromSeconds(1));
subjectVisit.PackState = PackState.Packing;
await _subjectVisitRepository.SaveChangesAsync();
}
return ResponseOutput.Ok(subjectVisit.VisitImageZipPath);
}
/// <summary>
/// 后台任务调用,前端忽略该接口
/// </summary>
/// <param name="trialId"></param>
/// <param name="subjectVisitId"></param>
/// <param name="isAnonymize"></param>
/// <returns></returns>
public async Task PackageAndAnonymizImage(Guid trialId, Guid subjectVisitId, bool isAnonymize = true)
{
var subjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
try
{
var addOrUpdateFixedFieldList = new List<SystemAnonymization>();
var ircFieldList = new List<SystemAnonymization>();
if (isAnonymize)
{
var systemAnonymizationList = _systemAnonymizationRepository.Where(t => t.IsEnable).ToList();
addOrUpdateFixedFieldList = systemAnonymizationList.Where(t => t.IsFixed).ToList();
ircFieldList = systemAnonymizationList.Where(t => t.IsFixed == false).ToList();
}
var subjectAndVisitInfo = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { SubjectCode = t.Subject.Code, t.Trial.TrialCode, t.VisitNum }).FirstOrDefault();
var query = from sv in _subjectVisitRepository.Where(t => t.Id == subjectVisitId)
select new
{
SubjectCode = sv.Subject.Code,
VisitName = sv.VisitName,
StudyList = sv.StudyList.Select(u => new
{
u.PatientId,
u.StudyTime,
u.StudyCode,
SeriesList = u.SeriesList.Select(z => new
{
z.Modality,
InstancePathList = z.DicomInstanceList.Select(k => new
{
k.Path
})
})
})
};
var info = query.FirstOrDefault();
if (info != null)
{
// 创建一个临时文件夹来存放文件
string tempFolderPath = Path.Combine(Directory.GetCurrentDirectory(), $"DownloadTemp_{NewId.NextGuid()}");
Directory.CreateDirectory(tempFolderPath);
// 遍历查询结果
foreach (var studyInfo in info.StudyList)
{
// 遍历 Series
foreach (var seriesInfo in studyInfo.SeriesList)
{
string studyFolderPath = Path.Combine(tempFolderPath, $"{info.SubjectCode}_{info.VisitName}", $"{studyInfo.StudyCode}_{studyInfo.StudyTime?.ToString("yyyy-MM-dd")}_{seriesInfo.Modality}");
// 创建 影像 文件夹
Directory.CreateDirectory(studyFolderPath);
// 遍历 InstancePathList
foreach (var instanceInfo in seriesInfo.InstancePathList)
{
// 复制文件到相应的文件夹
string destinationPath = Path.Combine(studyFolderPath, Path.GetFileName(instanceInfo.Path));
//下载到当前目录
await _oSSService.DownLoadFromOSSAsync(instanceInfo.Path, destinationPath);
#region 匿名化逻辑
if (isAnonymize)
{
DicomFile dicomFile = await DicomFile.OpenAsync(destinationPath, Encoding.Default);
DicomDataset dataset = dicomFile.Dataset;
foreach (var item in addOrUpdateFixedFieldList)
{
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
dataset.AddOrUpdate(dicomTag, item.ReplaceValue);
}
foreach (var item in ircFieldList)
{
var dicomTag = new DicomTag(Convert.ToUInt16(item.Group, 16), Convert.ToUInt16(item.Element, 16));
if (dicomTag == DicomTag.ClinicalTrialProtocolID)
{
dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.TrialCode);
}
if (dicomTag == DicomTag.ClinicalTrialSiteID)
{
//dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.TrialSiteCode);
}
if (dicomTag == DicomTag.ClinicalTrialSubjectID)
{
dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.SubjectCode);
}
if (dicomTag == DicomTag.ClinicalTrialTimePointID)
{
dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.VisitNum.ToString());
}
if (dicomTag == DicomTag.PatientID)
{
dataset.AddOrUpdate(dicomTag, subjectAndVisitInfo.TrialCode + "_" + subjectAndVisitInfo.SubjectCode);
}
}
}
#endregion
}
}
}
var zipPath = Path.Combine(Directory.GetCurrentDirectory(), $"{info.SubjectCode}_{info.VisitName}_ImageStudy.zip");
ZipFile.CreateFromDirectory(tempFolderPath, zipPath);
//上传到Oss
var relativePath = await _oSSService.UploadToOSSAsync(zipPath, $"download_zip", false);
//subjectVisit.PackState = PackState.Packed;
//subjectVisit.VisitImageZipPath = relativePath;
//await _subjectVisitRepository.SaveChangesAsync();
await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { PackState = PackState.Packed, VisitImageZipPath = relativePath });
//清理文件夹
Directory.Delete(tempFolderPath, true);
File.Delete(zipPath);
}
}
catch (Exception ex)
{
await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { PackState = PackState.WaitPack });
}
}
}
}

View File

@ -1470,6 +1470,10 @@ namespace IRaCIS.Core.Application.Contracts
public bool IsLostVisit { get; set; }
public string VisitImageZipPath { get; set; }
public PackState PackState { get; set; }
//public Guid? ClinicalDataSignUserId { get; set; }
}

View File

@ -57,7 +57,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <param name="visitSearchDTO"></param>
/// <returns></returns>
[HttpPost]
public async Task<(PageOutput<QCCRCVisitViewModel>, TrialSubjectAndSVConfig)> GetCRCVisitList(CRCVisitSearchDTO visitSearchDTO)
public async Task<IResponseOutput< PageOutput<QCCRCVisitViewModel>>> GetCRCVisitList(CRCVisitSearchDTO visitSearchDTO)
{
var svExpression = QCCommon.GetSubjectVisitFilter(visitSearchDTO.VisitPlanArray);
@ -83,7 +83,7 @@ namespace IRaCIS.Core.Application.Image.QA
var config = await _repository.Where<Trial>(t => t.Id == visitSearchDTO.TrialId).ProjectTo<TrialSubjectAndSVConfig>(_mapper.ConfigurationProvider).FirstOrDefaultAsync().IfNullThrowException();
config.IsHaveSubjectClinicalData = await _clinicalDataTrialSet.AnyAsync(x => x.TrialId == visitSearchDTO.TrialId && x.IsConfirm && (x.ClinicalDataLevel == ClinicalLevel.Subject ) && x.UploadRole == UploadRole.CRC);
config.IsHaveVisitClinicalData = await _clinicalDataTrialSet.AnyAsync(x => x.TrialId == visitSearchDTO.TrialId && x.IsConfirm && (x.ClinicalDataLevel == ClinicalLevel.SubjectVisit) && x.UploadRole == UploadRole.CRC);
return (pageList, config);
return ResponseOutput.Ok (pageList, config);
}

View File

@ -342,7 +342,8 @@ namespace IRaCIS.Core.Application.Contracts
public class GetTrialReadingInfoOutDto
{
public string TrialModalitys { get; set;}
public string TrialModalitys { get; set;}
/// <summary>
/// 项目ID
@ -501,6 +502,11 @@ namespace IRaCIS.Core.Application.Contracts
public string CriterionModalitys { get; set; }
public ReadingImageDownload? ImageDownloadEnum { get; set; }
public ReadingImageUpload? ImageUploadEnum { get; set; }
}
public class ReadingCriterionPageDto

View File

@ -240,6 +240,29 @@ namespace IRaCIS.Core.Domain.Models
public List<SubjectCriteriaEvaluationVisitFilter> SubjectCriteriaEvaluationVisitFilterList { get; set; }
public ReadingStatusEnum ReadingStatus { get; set; }
public string VisitImageZipPath { get; set; } = string.Empty;
public PackState PackState { get; set; }
}
/// <summary>
/// 影像下载打包状态
/// </summary>
public enum PackState
{
/// <summary>
/// 待打包
/// </summary>
WaitPack = 0,
/// <summary>
/// 打包中
/// </summary>
Packing = 1,
/// <summary>
/// 打包完成
/// </summary>
Packed = 2
}
}