@ -1,22 +1,30 @@
using DocumentFormat.OpenXml.EMMA ;
using DocumentFormat.OpenXml.Office2010.Excel ;
using DocumentFormat.OpenXml.Office2013.Drawing.ChartStyle ;
using FellowOakDicom ;
using FellowOakDicom.Imaging ;
using FellowOakDicom.Imaging.Render ;
using FellowOakDicom.IO.Buffer ;
using IRaCIS.Core.Application.Helper ;
using IRaCIS.Core.Application.ViewModel ;
using IRaCIS.Core.Domain.Models ;
using MassTransit ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Hosting ;
using Microsoft.AspNetCore.Mvc ;
using MiniExcelLibs ;
using SharpCompress.Common ;
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Diagnostics ;
using System.Linq ;
using System.Text ;
using System.Text.RegularExpressions ;
using System.Threading.Tasks ;
using System.Web ;
using static IRaCIS . Core . Domain . Share . StaticData ;
using static Microsoft . EntityFrameworkCore . DbLoggerCategory ;
namespace IRaCIS.Core.Application.Service
{
@ -243,11 +251,12 @@ namespace IRaCIS.Core.Application.Service
/// <returns></returns>
[HttpGet]
[AllowAnonymous]
public async Task < IResponseOutput > DownloadAndUploadTrialData ( Guid trialId , [ FromServices ] IRepository < DicomInstance > _instanceRepository ,
public async Task < IResponseOutput > DownloadAndUploadTrialData ( Guid trialId ,
[FromServices] IRepository < DicomInstance > _instanceRepository ,
[FromServices] IRepository < DicomStudy > _studyRepository ,
[FromServices] IRepository < DicomSeries > _seriesRepository )
{
var list = await _instanceRepository . Where ( t = > t . TrialId = = trialId & & t . SubjectVisitId = = Guid . Parse ( "01000000-0a00-0242-bd20-08dcce543ded" ) & & t . DicomStudy . ModalityForEdit = = "IVUS" )
var list = await _instanceRepository . Where ( t = > t . TrialId = = trialId & & t . SubjectVisitId = = Guid . Parse ( "01000000-0a00-0242-bd20-08dcce543ded" ) & & t . DicomStudy . ModalityForEdit = = "IVUS" )
. Select ( t = > new { t . SeriesId , t . StudyId , t . Id , t . Path } ) . ToListAsync ( ) ;
int totalCount = list . Count ;
@ -288,7 +297,7 @@ namespace IRaCIS.Core.Application.Service
await _instanceRepository . BatchUpdateNoTrackingAsync ( t = > t . Id = = item . Id ,
u = > new DicomInstance ( )
{
IsEncapsulated = syntax . IsEncapsulated ,
IsEncapsulated = syntax . IsEncapsulated ,
TransferSytaxUID = dirInfo . TransferSytaxUID ,
SOPClassUID = dirInfo . SOPClassUID ,
MediaStorageSOPClassUID = dirInfo . MediaStorageSOPClassUID ,
@ -334,6 +343,609 @@ namespace IRaCIS.Core.Application.Service
return ResponseOutput . Ok ( ) ;
}
/// <summary>
/// 维护dir 需求新增的字段
/// </summary>
/// <param name="trialId"></param>
/// <param name="_instanceRepository"></param>
/// <param name="_studyRepository"></param>
/// <param name="_seriesRepository"></param>
/// <returns></returns>
public async Task < IResponseOutput > TrialImageAddExtralField ( Guid trialId ,
[FromServices] IRepository < DicomInstance > _instanceRepository ,
[FromServices] IRepository < DicomStudy > _studyRepository ,
[FromServices] IRepository < DicomSeries > _seriesRepository )
{
// UPDATE DicomStudy
//SET DicomStudyDate = CONVERT(char(8), StudyTime, 112), --yyyyMMdd
// DicomStudyTime = REPLACE(CONVERT(char(8), StudyTime, 108), ':', ''); --HHmmss
// where DicomStudyDate = ''
//instance 找到传输语法为空的,然后分组
var seriesList = _instanceRepository . Where ( t = > t . TrialId = = trialId & & t . TransferSytaxUID = = "" )
//按照序列 和 NumberOfFrames 分组
. GroupBy ( t = > new { t . NumberOfFrames , t . SeriesId } )
// 每个分组 取数据最小的一条
. Select ( g = > new { g . Key . SeriesId , g . Key . NumberOfFrames , g . OrderBy ( t = > t . FileSize ) . First ( ) . Path } ) . ToList ( ) ;
foreach ( var item in seriesList )
{
var stream = await _oSSService . GetStreamFromOSSAsync ( item . Path ) ;
var dicomFile = DicomFile . Open ( stream ) ;
var pixelData = DicomPixelData . Create ( dicomFile . Dataset ) ;
//获取像素是否为封装形式
var syntax = dicomFile . Dataset . InternalTransferSyntax ;
//读取需要维护的值
var transferSyntaxUID = dicomFile . FileMetaInfo . GetSingleValueOrDefault ( DicomTag . TransferSyntaxUID , string . Empty ) ;
var mediaStorageSOPClassUID = dicomFile . FileMetaInfo . GetSingleValueOrDefault ( DicomTag . MediaStorageSOPClassUID , string . Empty ) ;
var mediaStorageSOPInstanceUID = dicomFile . FileMetaInfo . GetSingleValueOrDefault ( DicomTag . MediaStorageSOPInstanceUID , string . Empty ) ;
var sOPClassUID = dicomFile . Dataset . GetSingleValueOrDefault ( DicomTag . SOPClassUID , string . Empty ) ;
//维护序列层级四个字段 后再用sql 维护study series 时间拆分 和 MediaStorageSOPInstanceUID
await _instanceRepository . BatchUpdateNoTrackingAsync ( t = > t . SeriesId = = item . SeriesId , t = > new DicomInstance ( )
{
IsEncapsulated = syntax . IsEncapsulated ,
TransferSytaxUID = transferSyntaxUID ,
MediaStorageSOPClassUID = mediaStorageSOPClassUID ,
SOPClassUID = sOPClassUID ,
} ) ;
}
return ResponseOutput . Ok ( ) ;
}
/// <summary>
/// 下载已经删除的影像
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public async Task < IResponseOutput > DownloadDeleteTrialImage ( Guid trialId )
{
trialId = Guid . Parse ( "01000000-ac13-0242-6397-08dcd2d2a091" ) ;
var downloadInfo = _trialRepository . Where ( t = > t . Id = = trialId , ignoreQueryFilters : true ) . Select ( t = > new
{
t . ResearchProgramNo ,
VisitList = t . SubjectVisitList
. Select ( sv = > new
{
TrialSiteCode = sv . TrialSite . TrialSiteCode ,
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 ,
z . SeriesNumber ,
InstancePathList = z . DicomInstanceList . Where ( t = > t . IsDeleted = = true | | t . DicomSerie . IsDeleted = = true | | t . IsReading = = false | | t . DicomSerie . IsReading = = false ) . Select ( k = > new
{
k . Path ,
k . FileSize
} ) . ToList ( )
} )
} ) . ToList ( )
} ) . ToList ( )
} ) . FirstOrDefault ( ) ;
var filesizes = downloadInfo . VisitList . SelectMany ( t = > t . StudyList ) . SelectMany ( t = > t . SeriesList ) . SelectMany ( t = > t . InstancePathList ) . Sum ( t = > t . FileSize ) ;
var count2 = downloadInfo . VisitList . SelectMany ( t = > t . StudyList ) . SelectMany ( t = > t . SeriesList ) . SelectMany ( t = > t . InstancePathList ) . Count ( ) ;
Console . WriteLine ( $"下载总数量:{count2},总大小{filesizes}" ) ;
if ( downloadInfo ! = null )
{
var downloadJobs = new List < ( string Path , Func < Task > Job ) > ( ) ;
var rootFolder = @"E:\DownloadImage" ;
//var rootFolder = FileStoreHelper.GetDonwnloadImageFolder(_hostEnvironment);
// 获取无效字符(系统定义的)
string invalidChars = new string ( Path . GetInvalidFileNameChars ( ) ) + new string ( Path . GetInvalidPathChars ( ) ) ;
// 用正则表达式替换所有非法字符为下划线或空字符
string pattern = $"[{Regex.Escape(invalidChars)}]" ;
var regexNo = Regex . Replace ( downloadInfo . ResearchProgramNo , pattern , "_" ) ;
// 创建一个临时文件夹来存放文件
string trialFolderPath = Path . Combine ( rootFolder , $"{regexNo}_{NewId.NextGuid()}" ) ;
Directory . CreateDirectory ( trialFolderPath ) ;
foreach ( var visitItem in downloadInfo . VisitList )
{
if ( visitItem . StudyList . Count ( ) = = 0 )
{
continue ;
}
#region 处理 中心, 受试者dicom non-dicom 文件夹层级
//var siteFolderPath = Path.Combine(trialFolderPath, visitItem.TrialSiteCode);
//if (!Directory.Exists(siteFolderPath))
//{
// Directory.CreateDirectory(siteFolderPath);
//}
# endregion
foreach ( var studyInfo in visitItem . StudyList )
{
// 遍历 Series
foreach ( var seriesInfo in studyInfo . SeriesList )
{
string studyDicomFolderPath = Path . Combine ( trialFolderPath , $"{visitItem.SubjectCode}_{visitItem.VisitName}" , $"{studyInfo.StudyCode}_{studyInfo.StudyTime?.ToString(" yyyy - MM - dd ")}" , $"{seriesInfo.SeriesNumber}" ) ;
// 创建 影像 文件夹
Directory . CreateDirectory ( studyDicomFolderPath ) ;
// 遍历 InstancePathList
foreach ( var instanceInfo in seriesInfo . InstancePathList )
{
// 复制文件到相应的文件夹
string destinationPath = Path . Combine ( studyDicomFolderPath , Path . GetFileName ( instanceInfo . Path ) ) ;
//加入到下载任务里
downloadJobs . Add ( ( instanceInfo . Path , ( ) = > _oSSService . DownLoadFromOSSAsync ( instanceInfo . Path , destinationPath ) ) ) ;
//下载到当前目录
//await _oSSService.DownLoadFromOSSAsync(instanceInfo.Path, destinationPath);
}
}
}
}
#region 异步方式处理
int totalCount = downloadJobs . Count ;
int downloadedCount = 0 ;
// 在 trialFolderPath 下面放一个失败记录文件
string failedLogPath = Path . Combine ( trialFolderPath , "failed_downloads.txt" ) ;
// 确保文件存在(如果之前有就清空)
File . WriteAllText ( failedLogPath , "" ) ;
foreach ( var job in downloadJobs )
{
try
{
await job . Job ( ) ;
}
catch ( Exception ex )
{
string errorMessage = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] 下载失败: {job.Path}, 错误: {ex.Message}\r\n" ;
Console . WriteLine ( errorMessage ) ;
await File . AppendAllTextAsync ( failedLogPath , errorMessage ) ;
}
downloadedCount + + ;
// 每处理50个, 输出一次进度( 或最后一个时也输出)
if ( downloadedCount % 50 = = 0 | | downloadedCount = = totalCount )
{
Console . WriteLine ( $"已下载 {downloadedCount} / {totalCount} 个文件,完成 {(downloadedCount * 100.0 / totalCount):F2}%" ) ;
}
}
# endregion
#region 多线程测试
//const int batchSize = 15;
//int totalCount = downloadJobs.Count;
//int downloadedCount = 0;
//for (int i = 0; i < downloadJobs.Count; i += batchSize)
//{
// var batch = downloadJobs.Skip(i).Take(batchSize).Select(job => job());
// await Task.WhenAll(batch);
// downloadedCount += batch.Count();
// Console.WriteLine($"已下载 {downloadedCount} / {totalCount} 个文件,完成 {(downloadedCount * 100.0 / totalCount):F2}%");
//}
# endregion
}
return ResponseOutput . Ok ( ) ;
}
[AllowAnonymous]
public async Task < IResponseOutput > ReadDicomDataWriteDB ( [ FromServices ] IRepository < DicomInstance > _instanceRepository )
{
var testPath = @"E:\WXT001" ;
var path = @"E:\WXT001" ;
var files = Directory . GetFiles ( testPath , "*" , SearchOption . AllDirectories )
// 只要没有后缀( Windows 显示类型是 .file)
. Where ( f = > string . IsNullOrEmpty ( Path . GetExtension ( f ) ) )
. Where ( f = > Guid . TryParse ( Path . GetFileNameWithoutExtension ( f ) , out _ ) )
. ToList ( ) ;
Console . WriteLine ( $"找到 {files.Count} 个 DICOM 文件" ) ;
int total = files . Count ;
int processed = 0 ;
double lastPercent = 0 ;
var options = new ParallelOptions { MaxDegreeOfParallelism = 12 } ;
// 输出文件路径
var outputFile = Path . Combine ( @"D:\dicomWrite" , $"{Guid.NewGuid()}_dicom_info.txt" ) ;
var outputErrorFile = Path . Combine ( @"D:\dicomWrite" , $"{Guid.NewGuid()}_dicom_info_error.txt" ) ;
// 用并发安全的写法(锁保护)
var fileLock = new object ( ) ;
foreach ( var file in files )
{
try
{
var id = Guid . Parse ( Path . GetFileNameWithoutExtension ( file ) ) ;
var dicomFile = DicomFile . Open ( file ) ;
var dataset = dicomFile . Dataset ;
var fileMeta = dicomFile . FileMetaInfo ;
var syntax = dataset . InternalTransferSyntax ;
//单位 设备 PatientId Visit 检查UId 帧数
var stationName = dataset . GetSingleValueOrDefault ( DicomTag . StationName , string . Empty ) ;
var institutionName = dataset . GetSingleValueOrDefault ( DicomTag . InstitutionName , string . Empty ) ;
var manufacturer = dataset . GetSingleValueOrDefault ( DicomTag . Manufacturer , string . Empty ) ;
//PatientID TrialCode_SubjectCode
//var patientID = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
//SubjectCode
var clinicalTrialSubjectID = dataset . GetSingleValueOrDefault ( DicomTag . ClinicalTrialSubjectID , string . Empty ) ;
//访视visitNum
var clinicalTrialTimePointID = dataset . GetSingleValueOrDefault ( DicomTag . ClinicalTrialTimePointID , string . Empty ) ;
var studyInstanceUID = dataset . GetSingleValueOrDefault ( DicomTag . StudyInstanceUID , string . Empty ) ;
var seriesInstanceUID = dataset . GetSingleValueOrDefault ( DicomTag . SeriesInstanceUID , string . Empty ) ;
var sOPInstanceUID = dataset . GetSingleValueOrDefault ( DicomTag . SOPInstanceUID , string . Empty ) ;
var numberOfFrames = dataset . GetSingleValueOrDefault ( DicomTag . NumberOfFrames , 1 ) ;
// 传输语法
var transferSyntaxUID = fileMeta . GetSingleValueOrDefault ( DicomTag . TransferSyntaxUID , string . Empty ) ;
var sOPClassUID = dataset . GetSingleValueOrDefault ( DicomTag . SOPClassUID , string . Empty ) ;
var mediaStorageSOPClassUID = fileMeta . GetSingleValueOrDefault ( DicomTag . MediaStorageSOPClassUID , string . Empty ) ;
var mediaStorageSOPInstanceUID = fileMeta . GetSingleValueOrDefault ( DicomTag . MediaStorageSOPInstanceUID , string . Empty ) ;
// 拼接一行 CSV 格式
var line = string . Join ( "," ,
id ,
stationName ,
institutionName ,
manufacturer ,
clinicalTrialSubjectID ,
clinicalTrialTimePointID ,
studyInstanceUID ,
seriesInstanceUID ,
sOPInstanceUID ,
numberOfFrames ,
transferSyntaxUID ,
sOPClassUID ,
mediaStorageSOPClassUID ,
mediaStorageSOPInstanceUID
) ;
await File . AppendAllTextAsync ( outputFile , line + Environment . NewLine ) ;
await _instanceRepository . BatchUpdateNoTrackingAsync (
t = > t . Id = = id ,
t = > new DicomInstance
{
IsEncapsulated = syntax . IsEncapsulated ,
TransferSytaxUID = transferSyntaxUID ,
MediaStorageSOPClassUID = mediaStorageSOPClassUID ,
SOPClassUID = sOPClassUID ,
MediaStorageSOPInstanceUID = mediaStorageSOPInstanceUID
} , false ) ;
}
catch ( Exception ex )
{
var errorMsg = $"{DateTime.Now}❌ {file} 解析失败: {ex.Message}" ;
Console . WriteLine ( errorMsg ) ;
await File . AppendAllTextAsync ( outputErrorFile , errorMsg + Environment . NewLine ) ;
}
finally
{
var done = Interlocked . Increment ( ref processed ) ;
double percent = done * 100.0 / total ;
// 只在进度提升 >= 1% 时打印
if ( percent - lastPercent > = 5.0 | | done = = total )
{
lastPercent = percent ;
Console . WriteLine ( $"{DateTime.Now} 进度: {done}/{total} ({percent:F2}%)" ) ;
}
}
}
return ResponseOutput . Ok ( ) ;
}
#region 维护已经下载本地的数据
[AllowAnonymous]
public async Task < IResponseOutput > ReadExcelData ( [ FromServices ] IRepository < DicomInstance > _instanceRepository )
{
var rows = await MiniExcel . QueryAsync < DicomSOPInfo > ( @"C:\Users\hang\Desktop\维护数据读取.xlsx" ) ;
rows = rows . Where ( t = > ! string . IsNullOrEmpty ( t . InstanceId . ToString ( ) ) ) . ToList ( ) ;
var outputErrorFile = Path . Combine ( @"D:\dicomWrite" , $"{Guid.NewGuid()}_dicom_info_error.txt" ) ;
foreach ( var item in rows )
{
try
{
await _instanceRepository . BatchUpdateNoTrackingAsync (
t = > t . Id = = item . InstanceId ,
t = > new DicomInstance
{
IsEncapsulated = item . IsEncapsulated ,
TransferSytaxUID = item . TransferSyntaxUID ,
MediaStorageSOPClassUID = item . MediaStorageSOPClassUID ,
SOPClassUID = item . SOPClassUID ,
MediaStorageSOPInstanceUID = item . MediaStorageSOPInstanceUID
} , false ) ;
}
catch ( Exception ex )
{
var errorMsg = $"{item.InstanceId} {DateTime.Now} 更新失败: {ex.Message}" ;
Console . WriteLine ( errorMsg ) ;
await File . AppendAllTextAsync ( outputErrorFile , errorMsg + Environment . NewLine ) ;
}
}
return ResponseOutput . Ok ( ) ;
}
public class DicomSOPInfo
{
public Guid InstanceId { get ; set ; }
public string TransferSyntaxUID { get ; set ; }
public string SOPClassUID { get ; set ; }
public string MediaStorageSOPClassUID { get ; set ; }
public string MediaStorageSOPInstanceUID { get ; set ; }
public bool IsEncapsulated = > DicomTransferSyntax . Lookup ( DicomUID . Parse ( TransferSyntaxUID ) ) . IsEncapsulated ;
}
# endregion
#region 通过Excel 读取未下载的,边下载边维护数据
[AllowAnonymous]
public async Task < IResponseOutput > WriteNeedDealData ( [ FromServices ] IRepository < DicomInstance > _instanceRepository )
{
#region 获取差集数据
//var rows = await MiniExcel.QueryAsync<DicomSOPInfo>(@"C:\Users\hang\Desktop\维护数据读取.xlsx");
//rows = rows.Where(t => !string.IsNullOrEmpty(t.InstanceId.ToString())).ToList();
//var allRows = await MiniExcel.QueryAsync<NeedDealInstanceInfo>(@"C:\Users\hang\Desktop\AllData.xlsx");
//allRows = allRows.Where(t => !string.IsNullOrEmpty(t.InstanceId.ToString())).ToList();
//var needDealRows = allRows.Where(t => !rows.Select(c => c.InstanceId).Contains(t.InstanceId)).ToList();
//var outputFile = Path.Combine(@"D:\dicomWrite", $"{Guid.NewGuid()}_dicom_info.txt");
//foreach (var item in needDealRows)
//{
// var line = string.Join(",", item.InstanceId, item.Path);
// await File.AppendAllTextAsync(outputFile, line + Environment.NewLine);
//}
# endregion
var folder = FileStoreHelper . GetIRaCISRootDataFolder ( _hostEnvironment ) ;
var needDealRows = await MiniExcel . QueryAsync < NeedDealInstanceInfo > ( Path . Combine ( folder , "needDownload.xlsx" ) ) ;
needDealRows = needDealRows . Where ( t = > ! string . IsNullOrEmpty ( t . InstanceId . ToString ( ) ) ) . ToList ( ) ;
var outputFile = Path . Combine ( folder , $"{Guid.NewGuid()}_dicom_info.txt" ) ;
var outputErrorFile = Path . Combine ( folder , $"{Guid.NewGuid()}_dicom_info_error.txt" ) ;
int total = needDealRows . Count ( ) ;
Console . WriteLine ( $"需要处理数量{total}" ) ;
int processed = 0 ;
double lastPercent = 0 ;
foreach ( var item in needDealRows )
{
try
{
await using var stream = await _oSSService . GetStreamFromOSSAsync ( item . Path ) ;
var dicomFile = DicomFile . Open ( stream ) ;
var dataset = dicomFile . Dataset ;
var fileMeta = dicomFile . FileMetaInfo ;
var pixelData = DicomPixelData . Create ( dicomFile . Dataset ) ;
//获取像素是否为封装形式
var syntax = dicomFile . Dataset . InternalTransferSyntax ;
var stationName = dataset . GetSingleValueOrDefault ( DicomTag . StationName , string . Empty ) ;
var institutionName = dataset . GetSingleValueOrDefault ( DicomTag . InstitutionName , string . Empty ) ;
var manufacturer = dataset . GetSingleValueOrDefault ( DicomTag . Manufacturer , string . Empty ) ;
//PatientID TrialCode_SubjectCode
//var patientID = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty);
//SubjectCode
var clinicalTrialSubjectID = dataset . GetSingleValueOrDefault ( DicomTag . ClinicalTrialSubjectID , string . Empty ) ;
//访视visitNum
var clinicalTrialTimePointID = dataset . GetSingleValueOrDefault ( DicomTag . ClinicalTrialTimePointID , string . Empty ) ;
var studyInstanceUID = dataset . GetSingleValueOrDefault ( DicomTag . StudyInstanceUID , string . Empty ) ;
var seriesInstanceUID = dataset . GetSingleValueOrDefault ( DicomTag . SeriesInstanceUID , string . Empty ) ;
var sOPInstanceUID = dataset . GetSingleValueOrDefault ( DicomTag . SOPInstanceUID , string . Empty ) ;
var numberOfFrames = dataset . GetSingleValueOrDefault ( DicomTag . NumberOfFrames , 1 ) ;
// 传输语法
var transferSyntaxUID = fileMeta . GetSingleValueOrDefault ( DicomTag . TransferSyntaxUID , string . Empty ) ;
var sOPClassUID = dataset . GetSingleValueOrDefault ( DicomTag . SOPClassUID , string . Empty ) ;
var mediaStorageSOPClassUID = fileMeta . GetSingleValueOrDefault ( DicomTag . MediaStorageSOPClassUID , string . Empty ) ;
var mediaStorageSOPInstanceUID = fileMeta . GetSingleValueOrDefault ( DicomTag . MediaStorageSOPInstanceUID , string . Empty ) ;
var line = string . Join ( "," ,
item . InstanceId ,
stationName ,
institutionName ,
manufacturer ,
clinicalTrialSubjectID ,
clinicalTrialTimePointID ,
studyInstanceUID ,
seriesInstanceUID ,
sOPInstanceUID ,
numberOfFrames ,
transferSyntaxUID ,
sOPClassUID ,
mediaStorageSOPClassUID ,
mediaStorageSOPInstanceUID
) ;
await File . AppendAllTextAsync ( outputFile , line + Environment . NewLine ) ;
//维护序列层级四个字段 后再用sql 维护study series 时间拆分 和 MediaStorageSOPInstanceUID
await _instanceRepository . BatchUpdateNoTrackingAsync (
t = > t . Id = = item . InstanceId ,
t = > new DicomInstance
{
IsEncapsulated = syntax . IsEncapsulated ,
TransferSytaxUID = transferSyntaxUID ,
MediaStorageSOPClassUID = mediaStorageSOPClassUID ,
SOPClassUID = sOPClassUID ,
MediaStorageSOPInstanceUID = mediaStorageSOPInstanceUID
} , false ) ;
}
catch ( Exception ex )
{
var errorMsg = $"{DateTime.Now}❌ 失败: {ex.Message}" ;
Console . WriteLine ( errorMsg ) ;
await File . AppendAllTextAsync ( outputErrorFile , errorMsg + Environment . NewLine ) ;
}
finally
{
processed + + ;
double percent = processed * 100.0 / total ;
// 每提升 5% 或完成时输出
if ( percent - lastPercent > = 5.0 | | processed = = total )
{
lastPercent = percent ;
Console . WriteLine ( $"{DateTime.Now} 进度: {processed}/{total} ({percent:F2}%)" ) ;
}
}
}
return ResponseOutput . Ok ( ) ;
}
public class NeedDealInstanceInfo
{
public Guid InstanceId { get ; set ; }
public string Path { get ; set ; }
}
# endregion
}
}