.net10 -合并编译错误

This commit is contained in:
2026-06-04 13:19:17 +08:00
136 changed files with 251650 additions and 1484 deletions
@@ -3,6 +3,7 @@ using FellowOakDicom;
using FellowOakDicom.Media;
using IRaCIS.Core.Application.ViewModel;
using IRaCIS.Core.Domain.Models;
using NPOI.Util;
using System;
using System.Collections.Generic;
using System.Data;
@@ -160,6 +161,91 @@ namespace IRaCIS.Core.Application.Helper
}
public static async Task GenerateStudyDIR(List<StudyDIRInfo> list, Dictionary<string, string> dic, string? dirSavePath = null, Stream? outputStream = null)
{
var mappings = new List<string>();
int index = 1;
var trialId = Guid.Empty;
var studyUid = list.FirstOrDefault()?.StudyInstanceUid;
var dicomDir = new DicomDirectory();
foreach (var item in list.OrderBy(t => t.SeriesNumber).ThenBy(t => t.InstanceNumber))
{
var dicomUid = DicomUID.Enumerate().FirstOrDefault(uid => uid.UID == item.TransferSytaxUID);
if (dicomUid != null)
{
var ts = DicomTransferSyntax.Query(dicomUid);
var dataset = new DicomDataset(ts)
{
{ DicomTag.PatientID, item.PatientId ?? string.Empty },
{ DicomTag.PatientName, item.PatientName ?? string.Empty },
{ DicomTag.PatientBirthDate, item.PatientBirthDate ?? string.Empty },
{ DicomTag.PatientSex, item.PatientSex ?? string.Empty },
{ DicomTag.StudyInstanceUID, item.StudyInstanceUid ?? string.Empty },
{ DicomTag.StudyID, item.StudyId ?? string.Empty },
{ DicomTag.StudyDate, item.DicomStudyDate ?? string.Empty },
{ DicomTag.StudyTime, item.DicomStudyTime ?? string.Empty },
{ DicomTag.AccessionNumber, item.AccessionNumber ?? string.Empty },
{ DicomTag.StudyDescription, item.StudyDescription ?? string.Empty },
{ DicomTag.SeriesInstanceUID, item.SeriesInstanceUid ?? string.Empty },
{ DicomTag.Modality, item.Modality ?? string.Empty },
{ DicomTag.SeriesDate, item.DicomSeriesDate ?? string.Empty },
{ DicomTag.SeriesTime, item.DicomSeriesTime ?? string.Empty },
{ DicomTag.SeriesNumber, item.SeriesNumber.ToString() ?? string.Empty },
{ DicomTag.SeriesDescription, item.SeriesDescription ?? string.Empty },
{ DicomTag.SOPInstanceUID, item.SopInstanceUid ?? string.Empty },
{ DicomTag.SOPClassUID, item.SOPClassUID ?? string.Empty },
{ DicomTag.InstanceNumber, item.InstanceNumber.ToString() ?? string.Empty },
{ DicomTag.MediaStorageSOPClassUID, item.MediaStorageSOPClassUID ?? string.Empty },
{ DicomTag.MediaStorageSOPInstanceUID, item.MediaStorageSOPInstanceUID ?? string.Empty },
{ DicomTag.TransferSyntaxUID, item.TransferSytaxUID ?? string.Empty },
};
var dicomFile = new DicomFile(dataset);
// 文件名递增格式:IM_00001, IM_00002, ...
string filename = $@"IMAGE\IM_{index:D5}"; // :D5 表示补足5位
mappings.Add($"{filename} => {item.InstanceId}");
dic.Add(item.InstanceId.ToString(), filename.TrimEnd('/', '\\').Split('/', '\\').Last());
dicomDir.AddFile(dicomFile, filename);
index++;
}
}
//有实际的文件
if (mappings.Count > 0)
{
// 保存 DICOMDIR 到临时文件 不能直接写入到流种
if (dirSavePath.IsNotNullOrEmpty())
{
await dicomDir.SaveAsync(dirSavePath);
}
else
{
await dicomDir.SaveAsync(outputStream);
}
}
}
public static StudyDIRInfo ReadDicomDIRInfo(DicomFile dicomFile)
{
@@ -17,7 +17,7 @@ public static class SendEmailHelper
//没有收件人 那么不发送
if (messageToSend.To.Count == 0)
{
{
return string.Empty;
}
@@ -62,8 +62,15 @@ public static class SendEmailHelper
}
public static async Task<string> SendEmailAsync(MimeMessage messageToSend, Trial trial, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
/// <summary>
/// 发送项目邮件
/// </summary>
/// <param name="messageToSend"></param>
/// <param name="trial"></param>
/// <param name="messageSentSuccess"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static async Task<string> SendTrialEmailAsync(MimeMessage messageToSend, Trial trial, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
{
// 项目的需要重设 发件地址与邮件地址
@@ -78,12 +85,39 @@ public static class SendEmailHelper
string result = string.Empty;
result = messageToSend.MessageId;
//没有收件人 那么不发送
if (messageToSend.To.Count == 0)
{
return string.Empty;
}
// 替换邮件标题
if (!string.IsNullOrEmpty(messageToSend.Subject))
{
foreach (var item in trial.TrialObjectNameList)
{
// 把标题里的占位符替换成真实名称
messageToSend.Subject = messageToSend.Subject.Replace(item.Name, item.TrialName);
}
}
// 构建替换字典
var replacements = new Dictionary<string, string>();
foreach (var item in trial.TrialObjectNameList)
{
replacements[item.Name] = item.TrialName;
}
// 安全替换 HTML
ReplaceHtmlContent(messageToSend.Body, replacements);
try
{
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
@@ -128,6 +162,27 @@ public static class SendEmailHelper
return result;
}
// 遍历邮件体,找到 HTML 部分并替换
public static void ReplaceHtmlContent(MimeEntity entity, Dictionary<string, string> replacements)
{
if (entity is Multipart multipart)
{
foreach (var part in multipart)
{
ReplaceHtmlContent(part, replacements);
}
}
else if (entity is TextPart textPart && textPart.IsHtml)
{
// 只有这里才是真正的 HTML
foreach (var kv in replacements)
{
textPart.Text = textPart.Text.Replace(kv.Key, kv.Value);
}
}
}
public static async Task<bool> TestEmailConfigAsync(SystemEmailSendConfig _systemEmailConfig)
{
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
@@ -147,7 +202,7 @@ public static class SendEmailHelper
return true;
}
public static async Task SendEmailAsync(SMTPEmailConfig sMTPEmailConfig,Trial? trial, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
public static async Task SendEmailAsync(SMTPEmailConfig sMTPEmailConfig, Trial? trial, EventHandler<MessageSentEventArgs>? messageSentSuccess = null)
{
var messageToSend = new MimeMessage();
@@ -161,8 +216,9 @@ public static class SendEmailHelper
if (sMTPEmailConfig.ToMailAddressList.Count == 0)
{
return;
//---没有收件人
throw new ArgumentException(I18n.T("SendEmail_NoRecipient"));
//throw new ArgumentException(I18n.T("SendEmail_NoRecipient"));
}
else
{
+42 -15
View File
@@ -220,7 +220,7 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
public object result { get; private set; }
private static readonly object _tokenLock = new();
/// <summary>
/// 将指定前缀下的所有现有文件立即转为目标存储类型
@@ -918,7 +918,7 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
uploadInfo.FileSize = fileStream.CanSeek ? fileStream.Length : 0;
uploadInfo.Path = returnPath;
uploadInfo.FileName = fileRealName;
uploadInfo.FileType = Path.GetExtension(returnPath);
uploadInfo.FileType = Path.GetExtension(returnPath).TrimStart('.');
await _fileUploadRecordService.AddOrUpdateFileUploadRecord(uploadInfo);
@@ -934,32 +934,52 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
//后端批量上传 或者下载,不每个文件获取临时token
private void BackBatchGetToken()
{
// 过期时间 ≤ 当前时间 + 15分钟 时需要续期
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
{
if (AliyunOSSTempToken == null)
if (AliyunOSSTempToken != null && AliyunOSSTempToken.Expiration > DateTime.Now.AddMinutes(15))
{
GetObjectStoreTempToken();
}
//token 过期了
if (AliyunOSSTempToken?.Expiration.AddSeconds(10) <= DateTime.Now)
{
GetObjectStoreTempToken();
return; // 还有15分钟以上,不需要续期
}
lock (_tokenLock)
{
if (AliyunOSSTempToken == null ||
AliyunOSSTempToken.Expiration <= DateTime.Now.AddMinutes(15))
{
GetObjectStoreTempToken();
Log.Logger.Warning("后端获取阿里云临时 Token");
}
}
}
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
{
if (AWSTempToken == null)
if (AWSTempToken != null && AWSTempToken.Expiration > DateTime.Now.AddMinutes(15))
{
GetObjectStoreTempToken();
return;
}
//token 过期了
if (AWSTempToken.Expiration?.AddSeconds(10) <= DateTime.Now)
lock (_tokenLock)
{
GetObjectStoreTempToken();
if (AWSTempToken == null ||
AWSTempToken.Expiration <= DateTime.Now.AddMinutes(15))
{
GetObjectStoreTempToken();
Log.Logger.Warning("后端获取s3 临时 Token");
}
}
}
}
@@ -1057,7 +1077,7 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
uploadInfo.FileSize = fileSize;
uploadInfo.Path = returnPath;
uploadInfo.FileName = Path.GetFileName(localFilePath);
uploadInfo.FileType = Path.GetExtension(returnPath);
uploadInfo.FileType = Path.GetExtension(returnPath).TrimStart(".");
await _fileUploadRecordService.AddOrUpdateFileUploadRecord(uploadInfo);
@@ -1073,6 +1093,13 @@ public class OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options,
{
BackBatchGetToken();
// 确保目标目录存在
string directory = Path.GetDirectoryName(localFilePath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
ossRelativePath = ossRelativePath.TrimStart('/');
try
{
@@ -237,6 +237,20 @@ public static class DicomPixelMasker
{
workingDataset.AddOrUpdate(DicomTag.BurnedInAnnotation, "NO");
}
//// 转 JPEG Baseline(最稳定)
//var transcoder = new DicomTranscoder(
// DicomTransferSyntax.ExplicitVRLittleEndian,
// DicomTransferSyntax.JPEGProcess1);
//var finalFile = await Task.Run(
// () => transcoder.Transcode(workingFile),
// cancellationToken).ConfigureAwait(false);
//if (output.CanSeek)
// output.SetLength(0);
//await finalFile.SaveAsync(output).ConfigureAwait(false);
// 不要把 original photometric 强行写回
var finalFile = await ReEncodeToOriginalTransferSyntaxAsync(
workingFile,
@@ -422,17 +436,26 @@ public static class DicomPixelMasker
DicomPixelData sourcePixelData,
IReadOnlyList<IByteBuffer> frames)
{
//dataset.Remove(DicomTag.PixelData);
//var newPixelData = DicomPixelData.Create(dataset, true);
////newPixelData.BitsAllocated = sourcePixelData.BitsAllocated;
//newPixelData.BitsStored = sourcePixelData.BitsStored;
//newPixelData.HighBit = sourcePixelData.HighBit;
//newPixelData.SamplesPerPixel = sourcePixelData.SamplesPerPixel;
//newPixelData.PixelRepresentation = sourcePixelData.PixelRepresentation;
//newPixelData.PlanarConfiguration = sourcePixelData.PlanarConfiguration;
//newPixelData.Height = sourcePixelData.Height;
//newPixelData.Width = sourcePixelData.Width;
//newPixelData.PhotometricInterpretation = sourcePixelData.PhotometricInterpretation;
//foreach (var frame in frames)
//{
// newPixelData.AddFrame(frame);
//}
dataset.Remove(DicomTag.PixelData);
var newPixelData = DicomPixelData.Create(dataset, true);
//newPixelData.BitsAllocated = sourcePixelData.BitsAllocated;
newPixelData.BitsStored = sourcePixelData.BitsStored;
newPixelData.HighBit = sourcePixelData.HighBit;
newPixelData.SamplesPerPixel = sourcePixelData.SamplesPerPixel;
newPixelData.PixelRepresentation = sourcePixelData.PixelRepresentation;
newPixelData.PlanarConfiguration = sourcePixelData.PlanarConfiguration;
newPixelData.Height = sourcePixelData.Height;
newPixelData.Width = sourcePixelData.Width;
newPixelData.PhotometricInterpretation = sourcePixelData.PhotometricInterpretation;
foreach (var frame in frames)
{
newPixelData.AddFrame(frame);