Merge branch 'Test_HIR_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_HIR_Net8
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
commit
5f7c4dda97
|
|
@ -0,0 +1,42 @@
|
||||||
|
using Serilog;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Helper
|
||||||
|
{
|
||||||
|
public static class SafeBussinessHelper
|
||||||
|
{
|
||||||
|
public static async Task<bool> RunAsync(Func<Task> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await func();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<(bool Success, T? Result)> RunAsync<T>(Func<Task<T>> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await func();
|
||||||
|
return (true, result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
|
||||||
|
return (false, default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -227,7 +227,11 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
foreach (var item in findCmoveInfo.HopitalGroupIdList)
|
foreach (var item in findCmoveInfo.HopitalGroupIdList)
|
||||||
{
|
{
|
||||||
await _studyGroupRepository.AddAsync(new SCPStudyHospitalGroup() { SCPStudyId = g.Key.SCPStudyId, HospitalGroupId = item });
|
if (!_studyGroupRepository.Any(t => t.SCPStudyId == g.Key.SCPStudyId && t.HospitalGroupId == item))
|
||||||
|
{
|
||||||
|
await _studyGroupRepository.AddAsync(new SCPStudyHospitalGroup() { SCPStudyId = g.Key.SCPStudyId, HospitalGroupId = item });
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ using IRaCIS.Core.SCP.Service;
|
||||||
using IRaCIS.Core.Infra.EFCore;
|
using IRaCIS.Core.Infra.EFCore;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using Serilog.Sinks.File;
|
using Serilog.Sinks.File;
|
||||||
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP.Service
|
namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
|
|
@ -149,6 +150,10 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
Id = studyId,
|
Id = studyId,
|
||||||
StudyInstanceUid = studyInstanceUid,
|
StudyInstanceUid = studyInstanceUid,
|
||||||
StudyTime = studyTime,
|
StudyTime = studyTime,
|
||||||
|
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
|
||||||
|
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
|
||||||
|
|
||||||
|
|
||||||
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||||
//ModalityForEdit = modalityForEdit,
|
//ModalityForEdit = modalityForEdit,
|
||||||
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||||
|
|
@ -183,6 +188,11 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
|
findStudy.PatientBirthDate = $"{findStudy.PatientBirthDate[0]}{findStudy.PatientBirthDate[1]}{findStudy.PatientBirthDate[2]}{findStudy.PatientBirthDate[3]}-{findStudy.PatientBirthDate[4]}{findStudy.PatientBirthDate[5]}-{findStudy.PatientBirthDate[6]}{findStudy.PatientBirthDate[7]}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findStudy.DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty);
|
||||||
|
findStudy.DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (findSerice == null)
|
if (findSerice == null)
|
||||||
|
|
@ -200,6 +210,9 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
|
//SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, DateTime.Now).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, DateTime.Now).TimeOfDay),
|
||||||
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
|
//SeriesTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.SeriesDate) + dataset.GetSingleValue<string>(DicomTag.SeriesTime), out DateTime dt) ? dt : null,
|
||||||
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
|
SeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.SeriesDate).Add(dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.SeriesTime).TimeOfDay),
|
||||||
|
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
|
||||||
|
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
|
||||||
|
|
||||||
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||||
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||||
|
|
@ -221,7 +234,19 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
|
|
||||||
++findStudy.SeriesCount;
|
++findStudy.SeriesCount;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findSerice.DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty);
|
||||||
|
findSerice.DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
var transferSyntaxUID = dataset.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty);
|
||||||
|
|
||||||
|
var isEncapsulated = false;
|
||||||
|
if (transferSyntaxUID.IsNotNullOrEmpty())
|
||||||
|
{
|
||||||
|
isEncapsulated = DicomTransferSyntax.Lookup(DicomUID.Parse(transferSyntaxUID)).IsEncapsulated;
|
||||||
|
}
|
||||||
|
|
||||||
if (findInstance == null)
|
if (findInstance == null)
|
||||||
{
|
{
|
||||||
|
|
@ -235,6 +260,12 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
SeriesInstanceUid = findSerice.SeriesInstanceUid,
|
SeriesInstanceUid = findSerice.SeriesInstanceUid,
|
||||||
|
|
||||||
SopInstanceUid = sopInstanceUid,
|
SopInstanceUid = sopInstanceUid,
|
||||||
|
SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty),
|
||||||
|
MediaStorageSOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty),
|
||||||
|
TransferSyntaxUID = transferSyntaxUID,
|
||||||
|
MediaStorageSOPInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty),
|
||||||
|
IsEncapsulated = isEncapsulated,
|
||||||
|
|
||||||
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
|
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
|
||||||
InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.ContentTime).TimeOfDay),
|
InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.ContentDate).Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.ContentTime).TimeOfDay),
|
||||||
//InstanceTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,
|
//InstanceTime = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,
|
||||||
|
|
@ -261,6 +292,14 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
++findStudy.InstanceCount;
|
++findStudy.InstanceCount;
|
||||||
++findSerice.InstanceCount;
|
++findSerice.InstanceCount;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
findInstance.SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty);
|
||||||
|
findInstance.MediaStorageSOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty);
|
||||||
|
findInstance.TransferSyntaxUID = transferSyntaxUID;
|
||||||
|
findInstance.MediaStorageSOPInstanceUID = dataset.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty);
|
||||||
|
findInstance.IsEncapsulated = isEncapsulated;
|
||||||
|
}
|
||||||
|
|
||||||
if (isPatientNeedAdd)
|
if (isPatientNeedAdd)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,6 @@
|
||||||
<PackageReference Include="Hangfire.InMemory" Version="1.0.0" />
|
<PackageReference Include="Hangfire.InMemory" Version="1.0.0" />
|
||||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.20" />
|
<PackageReference Include="Hangfire.SqlServer" Version="1.8.20" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.3" />
|
|
||||||
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
|
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.Email" Version="4.0.0" />
|
<PackageReference Include="Serilog.Sinks.Email" Version="4.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||||
|
|
@ -155,6 +154,12 @@
|
||||||
</Content>
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Resources\GeoLite2-City.mmdb">
|
||||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ProjectExtensions>
|
<ProjectExtensions>
|
||||||
<VisualStudio>
|
<VisualStudio>
|
||||||
<UserProperties properties_4launchsettings_1json__JsonSchema="" />
|
<UserProperties properties_4launchsettings_1json__JsonSchema="" />
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 73 MiB |
|
|
@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.Filters;
|
using Microsoft.AspNetCore.Mvc.Filters;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Service.BusinessFilter;
|
namespace IRaCIS.Core.Application.Service.BusinessFilter;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,5 +10,6 @@ global using Microsoft.Extensions.Localization;
|
||||||
global using AutoMapper;
|
global using AutoMapper;
|
||||||
global using IRaCIS.Core.Domain.Share;
|
global using IRaCIS.Core.Domain.Share;
|
||||||
global using IRaCIS.Core.Application.BusinessFilter;
|
global using IRaCIS.Core.Application.BusinessFilter;
|
||||||
|
global using Serilog;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,190 @@
|
||||||
|
using FellowOakDicom;
|
||||||
|
using FellowOakDicom.Media;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Helper
|
||||||
|
{
|
||||||
|
|
||||||
|
public class StudyDIRInfo
|
||||||
|
{
|
||||||
|
public Guid SubjectVisitId { get; set; }
|
||||||
|
// Study
|
||||||
|
public Guid DicomStudyId { get; set; }
|
||||||
|
|
||||||
|
public string PatientId { get; set; }
|
||||||
|
public string PatientName { get; set; }
|
||||||
|
public string PatientBirthDate { get; set; }
|
||||||
|
public string PatientSex { get; set; }
|
||||||
|
|
||||||
|
public string StudyInstanceUid { get; set; }
|
||||||
|
public string StudyId { get; set; }
|
||||||
|
public string DicomStudyDate { get; set; }
|
||||||
|
public string DicomStudyTime { get; set; }
|
||||||
|
public string AccessionNumber { get; set; }
|
||||||
|
public string StudyDescription { get; set; }
|
||||||
|
|
||||||
|
// Series
|
||||||
|
public string SeriesInstanceUid { get; set; }
|
||||||
|
public string Modality { get; set; }
|
||||||
|
public string DicomSeriesDate { get; set; }
|
||||||
|
public string DicomSeriesTime { get; set; }
|
||||||
|
public int SeriesNumber { get; set; }
|
||||||
|
public string SeriesDescription { get; set; }
|
||||||
|
|
||||||
|
// Instance
|
||||||
|
public Guid InstanceId { get; set; }
|
||||||
|
public string SopInstanceUid { get; set; }
|
||||||
|
public string SOPClassUID { get; set; }
|
||||||
|
public int InstanceNumber { get; set; }
|
||||||
|
public string MediaStorageSOPClassUID { get; set; }
|
||||||
|
public string MediaStorageSOPInstanceUID { get; set; }
|
||||||
|
public string TransferSyntaxUID { get; set; }
|
||||||
|
}
|
||||||
|
public static class DicomDIRHelper
|
||||||
|
{
|
||||||
|
|
||||||
|
public static async Task GenerateStudyDIRAndUploadAsync(List<StudyDIRInfo> list, Dictionary<string, string> dic, string ossFolder, IOSSService _oSSService)
|
||||||
|
{
|
||||||
|
var mappings = new List<string>();
|
||||||
|
int index = 1;
|
||||||
|
|
||||||
|
|
||||||
|
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.TransferSyntaxUID);
|
||||||
|
|
||||||
|
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.TransferSyntaxUID ?? 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(), Path.GetFileName(filename));
|
||||||
|
|
||||||
|
dicomDir.AddFile(dicomFile, filename);
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//有实际的文件
|
||||||
|
if (mappings.Count > 0)
|
||||||
|
{
|
||||||
|
#region 写入临时路径
|
||||||
|
var tempFilePath = Path.GetTempFileName();
|
||||||
|
|
||||||
|
// 保存 DICOMDIR 到临时文件 不能直接写入到流种
|
||||||
|
await dicomDir.SaveAsync(tempFilePath);
|
||||||
|
|
||||||
|
using (var memoryStream = new MemoryStream(File.ReadAllBytes(tempFilePath)))
|
||||||
|
{
|
||||||
|
// 重置流位置
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
|
||||||
|
await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//清理临时文件
|
||||||
|
File.Delete(tempFilePath);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 映射上传
|
||||||
|
|
||||||
|
// 将映射写入内存流
|
||||||
|
var mappingText = string.Join(Environment.NewLine, mappings);
|
||||||
|
await using var mappingStream = new MemoryStream(Encoding.UTF8.GetBytes(mappingText));
|
||||||
|
|
||||||
|
await _oSSService.UploadToOSSAsync(mappingStream, ossFolder, $"Download_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", false);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static StudyDIRInfo ReadDicomDIRInfo(DicomFile dicomFile)
|
||||||
|
{
|
||||||
|
var dataset = dicomFile.Dataset;
|
||||||
|
|
||||||
|
|
||||||
|
var info = new StudyDIRInfo
|
||||||
|
{
|
||||||
|
PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||||||
|
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||||||
|
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
|
||||||
|
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
|
||||||
|
|
||||||
|
StudyInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty),
|
||||||
|
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
|
||||||
|
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
|
||||||
|
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
|
||||||
|
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
|
||||||
|
StudyDescription = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||||
|
|
||||||
|
SeriesInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty),
|
||||||
|
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||||
|
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
|
||||||
|
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
|
||||||
|
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
|
||||||
|
SeriesDescription = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||||
|
|
||||||
|
SopInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty),
|
||||||
|
SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty),
|
||||||
|
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
|
||||||
|
|
||||||
|
MediaStorageSOPClassUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty),
|
||||||
|
MediaStorageSOPInstanceUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty),
|
||||||
|
|
||||||
|
TransferSyntaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty)
|
||||||
|
};
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using AlibabaCloud.SDK.Sts20150401;
|
using AlibabaCloud.SDK.Sts20150401;
|
||||||
using Aliyun.OSS;
|
using Aliyun.OSS;
|
||||||
|
using Aliyun.OSS.Common;
|
||||||
using Amazon;
|
using Amazon;
|
||||||
using Amazon.Runtime;
|
using Amazon.Runtime;
|
||||||
using Amazon.S3;
|
using Amazon.S3;
|
||||||
|
|
@ -9,32 +10,24 @@ using Amazon.SecurityToken.Model;
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
|
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
|
using MassTransit.Caching.Internals;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Minio;
|
using Minio;
|
||||||
|
using Minio.DataModel;
|
||||||
using Minio.DataModel.Args;
|
using Minio.DataModel.Args;
|
||||||
using Newtonsoft.Json;
|
using Minio.Exceptions;
|
||||||
using System.Net;
|
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Web;
|
||||||
|
|
||||||
namespace IRaCIS.Core.Application.Helper;
|
namespace IRaCIS.Core.Application.Helper;
|
||||||
|
|
||||||
#region 绑定和返回模型
|
#region 绑定和返回模型
|
||||||
|
|
||||||
[LowerCamelCaseJson]
|
[LowerCamelCaseJson]
|
||||||
public class MinIOOptions
|
public class MinIOOptions : AWSOptions
|
||||||
{
|
{
|
||||||
public int Port { get; set; }
|
public int Port { get; set; }
|
||||||
public string EndPoint { get; set; }
|
|
||||||
public bool UseSSL { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("accessKey")]
|
|
||||||
public string AccessKeyId { get; set; }
|
|
||||||
|
|
||||||
[JsonProperty("secretKey")]
|
|
||||||
public string SecretAccessKey { get; set; }
|
|
||||||
public string BucketName { get; set; }
|
|
||||||
public string ViewEndpoint { get; set; }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -43,19 +36,13 @@ public class AWSOptions
|
||||||
{
|
{
|
||||||
public string EndPoint { get; set; }
|
public string EndPoint { get; set; }
|
||||||
public bool UseSSL { get; set; }
|
public bool UseSSL { get; set; }
|
||||||
|
|
||||||
[JsonProperty("AccessKey")]
|
|
||||||
public string AccessKeyId { get; set; }
|
public string AccessKeyId { get; set; }
|
||||||
public string RoleArn { get; set; }
|
public string RoleArn { get; set; }
|
||||||
|
|
||||||
[JsonProperty("SecretKey")]
|
|
||||||
public string SecretAccessKey { get; set; }
|
public string SecretAccessKey { get; set; }
|
||||||
public string BucketName { get; set; }
|
public string BucketName { get; set; }
|
||||||
public string ViewEndpoint { get; set; }
|
public string ViewEndpoint { get; set; }
|
||||||
public int DurationSeconds { get; set; }
|
public int DurationSeconds { get; set; }
|
||||||
public string Region { get; set; }
|
public string Region { get; set; }
|
||||||
|
|
||||||
public string viewEndpoint { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AliyunOSSOptions
|
public class AliyunOSSOptions
|
||||||
|
|
@ -77,7 +64,7 @@ public class AliyunOSSOptions
|
||||||
|
|
||||||
public int DurationSeconds { get; set; }
|
public int DurationSeconds { get; set; }
|
||||||
|
|
||||||
|
public string PreviewEndpoint { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,6 +110,9 @@ public class AliyunOSSTempToken
|
||||||
public string SecurityToken { get; set; }
|
public string SecurityToken { get; set; }
|
||||||
public DateTime Expiration { get; set; }
|
public DateTime Expiration { get; set; }
|
||||||
|
|
||||||
|
public string PreviewEndpoint { get; set; }
|
||||||
|
|
||||||
|
public string DownloadEndPoint => EndPoint.Insert(EndPoint.IndexOf("//") + 2, BucketName + ".");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,7 +126,7 @@ public class AWSTempToken
|
||||||
public string SecretAccessKey { get; set; }
|
public string SecretAccessKey { get; set; }
|
||||||
public string BucketName { get; set; }
|
public string BucketName { get; set; }
|
||||||
public string ViewEndpoint { get; set; }
|
public string ViewEndpoint { get; set; }
|
||||||
public DateTime Expiration { get; set; }
|
public DateTime? Expiration { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ObjectStoreUse
|
public enum ObjectStoreUse
|
||||||
|
|
@ -157,13 +147,23 @@ public interface IOSSService
|
||||||
|
|
||||||
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
|
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
|
||||||
|
|
||||||
|
public Task<Stream> GetStreamFromOSSAsync(string ossRelativePath);
|
||||||
|
|
||||||
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
||||||
|
|
||||||
public Task<string> GetSignedUrl(string ossRelativePath);
|
public Task<string> GetSignedUrl(string ossRelativePath);
|
||||||
|
|
||||||
public Task DeleteFromPrefix(string prefix);
|
public Task DeleteFromPrefix(string prefix, bool isCache = false);
|
||||||
|
|
||||||
|
public Task DeleteObjects(List<string> objectKeys);
|
||||||
|
|
||||||
|
List<string> GetRootFolderNames();
|
||||||
|
|
||||||
public ObjectStoreDTO GetObjectStoreTempToken();
|
public ObjectStoreDTO GetObjectStoreTempToken();
|
||||||
|
|
||||||
|
public Task MoveObject(string sourcePath, string destPath, bool overwrite = true);
|
||||||
|
|
||||||
|
public Task<long> GetObjectSizeAsync(string sourcePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -194,7 +194,7 @@ public class OSSService : IOSSService
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
BackBatchGetToken();
|
||||||
|
|
||||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
|
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
|
||||||
|
|
||||||
|
|
@ -223,17 +223,11 @@ public class OSSService : IOSSService
|
||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
{
|
{
|
||||||
var httpClientHandler = new HttpClientHandler
|
|
||||||
{
|
|
||||||
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
|
||||||
};
|
|
||||||
|
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
.WithHttpClient(new HttpClient(httpClientHandler))
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var putObjectArgs = new PutObjectArgs()
|
var putObjectArgs = new PutObjectArgs()
|
||||||
|
|
@ -290,6 +284,37 @@ public class OSSService : IOSSService
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//后端批量上传 或者下载,不每个文件获取临时token
|
||||||
|
private void BackBatchGetToken()
|
||||||
|
{
|
||||||
|
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||||
|
{
|
||||||
|
if (AliyunOSSTempToken == null)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
}
|
||||||
|
//token 过期了
|
||||||
|
else if (AliyunOSSTempToken.Expiration.AddSeconds(10) <= DateTime.Now)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
|
{
|
||||||
|
if (AWSTempToken == null)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
}
|
||||||
|
//token 过期了
|
||||||
|
else if (AWSTempToken.Expiration?.AddSeconds(10) <= DateTime.Now)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||||
|
|
@ -301,7 +326,7 @@ public class OSSService : IOSSService
|
||||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||||
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
BackBatchGetToken();
|
||||||
|
|
||||||
var localFileName = Path.GetFileName(localFilePath);
|
var localFileName = Path.GetFileName(localFilePath);
|
||||||
|
|
||||||
|
|
@ -320,18 +345,11 @@ public class OSSService : IOSSService
|
||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
{
|
{
|
||||||
|
|
||||||
var httpClientHandler = new HttpClientHandler
|
|
||||||
{
|
|
||||||
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
|
||||||
};
|
|
||||||
|
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
.WithHttpClient(new HttpClient(httpClientHandler))
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
var putObjectArgs = new PutObjectArgs()
|
var putObjectArgs = new PutObjectArgs()
|
||||||
|
|
@ -378,7 +396,7 @@ public class OSSService : IOSSService
|
||||||
|
|
||||||
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
BackBatchGetToken();
|
||||||
|
|
||||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||||
try
|
try
|
||||||
|
|
@ -391,33 +409,23 @@ public class OSSService : IOSSService
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||||
|
|
||||||
// 上传文件
|
|
||||||
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
||||||
|
|
||||||
// 将下载的文件流保存到本地文件
|
// 将下载的文件流保存到本地文件
|
||||||
using (var fs = File.OpenWrite(localFilePath))
|
using (var fs = File.OpenWrite(localFilePath))
|
||||||
{
|
{
|
||||||
result.Content.CopyTo(fs);
|
await result.Content.CopyToAsync(fs);
|
||||||
fs.Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
{
|
{
|
||||||
|
|
||||||
var httpClientHandler = new HttpClientHandler
|
|
||||||
{
|
|
||||||
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
|
|
||||||
};
|
|
||||||
|
|
||||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
.WithHttpClient(new HttpClient(httpClientHandler))
|
|
||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
var getObjectArgs = new GetObjectArgs()
|
var getObjectArgs = new GetObjectArgs()
|
||||||
.WithBucket(minIOConfig.BucketName)
|
.WithBucket(minIOConfig.BucketName)
|
||||||
.WithObject(ossRelativePath)
|
.WithObject(ossRelativePath)
|
||||||
|
|
@ -470,6 +478,96 @@ public class OSSService : IOSSService
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<Stream> GetStreamFromOSSAsync(string ossRelativePath)
|
||||||
|
{
|
||||||
|
BackBatchGetToken();
|
||||||
|
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||||
|
{
|
||||||
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
|
var _ossClient = new OssClient(
|
||||||
|
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
|
||||||
|
AliyunOSSTempToken.AccessKeyId,
|
||||||
|
AliyunOSSTempToken.AccessKeySecret,
|
||||||
|
AliyunOSSTempToken.SecurityToken
|
||||||
|
);
|
||||||
|
|
||||||
|
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
||||||
|
|
||||||
|
// 将OSS返回的流复制到内存流中并返回
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
await result.Content.CopyToAsync(memoryStream);
|
||||||
|
memoryStream.Position = 0; // 重置位置以便读取
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
|
{
|
||||||
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
var minioClient = new MinioClient()
|
||||||
|
.WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey)
|
||||||
|
.WithSSL(minIOConfig.UseSSL)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
|
||||||
|
var getObjectArgs = new GetObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.BucketName)
|
||||||
|
.WithObject(ossRelativePath)
|
||||||
|
.WithCallbackStream(stream => stream.CopyToAsync(memoryStream));
|
||||||
|
|
||||||
|
await minioClient.GetObjectAsync(getObjectArgs);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
|
{
|
||||||
|
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
|
var credentials = new SessionAWSCredentials(
|
||||||
|
AWSTempToken.AccessKeyId,
|
||||||
|
AWSTempToken.SecretAccessKey,
|
||||||
|
AWSTempToken.SessionToken
|
||||||
|
);
|
||||||
|
|
||||||
|
var clientConfig = new AmazonS3Config
|
||||||
|
{
|
||||||
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
|
UseHttp = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
|
|
||||||
|
var getObjectRequest = new Amazon.S3.Model.GetObjectRequest
|
||||||
|
{
|
||||||
|
BucketName = awsConfig.BucketName,
|
||||||
|
Key = ossRelativePath
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await amazonS3Client.GetObjectAsync(getObjectRequest);
|
||||||
|
|
||||||
|
var memoryStream = new MemoryStream();
|
||||||
|
await response.ResponseStream.CopyToAsync(memoryStream);
|
||||||
|
memoryStream.Position = 0;
|
||||||
|
return memoryStream;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new BusinessValidationFailedException("oss流获取失败! " + ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<string> GetSignedUrl(string ossRelativePath)
|
public async Task<string> GetSignedUrl(string ossRelativePath)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
GetObjectStoreTempToken();
|
||||||
|
|
@ -565,12 +663,240 @@ public class OSSService : IOSSService
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移动OSS文件到新路径
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourcePath">原文件路径(格式:bucket/key)</param>
|
||||||
|
/// <param name="destPath">新文件路径(格式:bucket/key)</param>
|
||||||
|
/// <param name="overwrite">是否覆盖已存在的目标文件(默认true)</param>
|
||||||
|
public async Task MoveObject(string sourcePath, string destPath, bool overwrite = true)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
|
||||||
|
switch (ObjectStoreServiceOptions.ObjectStoreUse)
|
||||||
|
{
|
||||||
|
case "AliyunOSS":
|
||||||
|
#region 阿里云
|
||||||
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
var client = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||||
|
if (sourcePath.StartsWith("/"))
|
||||||
|
{
|
||||||
|
sourcePath = sourcePath.Substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (destPath.StartsWith("/"))
|
||||||
|
{
|
||||||
|
destPath = destPath.Substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
var sourceBucket = aliConfig.BucketName;
|
||||||
|
var sourceKey = sourcePath;
|
||||||
|
|
||||||
|
var destBucket = aliConfig.BucketName;
|
||||||
|
|
||||||
|
var destKey = destPath;
|
||||||
|
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 检查目标是否存在(当不允许覆盖时)
|
||||||
|
if (!overwrite && client.DoesObjectExist(destBucket, destKey))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("File Exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//var copyRequest = new Aliyun.OSS.CopyObjectRequest(sourceBucket, sourceKey, sourceBucket, destKey);
|
||||||
|
//var result = client.CopyObject(copyRequest);
|
||||||
|
|
||||||
|
//// 2. 删除原文件(可选,根据是否需要保留原文件)
|
||||||
|
//client.DeleteObject(sourceBucket, sourceKey);
|
||||||
|
|
||||||
|
// 执行复制
|
||||||
|
var copyRequestAli = new Aliyun.OSS.CopyObjectRequest(
|
||||||
|
sourceBucket, sourceKey,
|
||||||
|
destBucket, destKey);
|
||||||
|
|
||||||
|
// 保持原文件元数据
|
||||||
|
copyRequestAli.NewObjectMetadata = new ObjectMetadata
|
||||||
|
{
|
||||||
|
ContentType = client.GetObjectMetadata(sourceBucket, sourceKey).ContentType
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = client.CopyObject(copyRequestAli);
|
||||||
|
|
||||||
|
// 删除原文件(仅在复制成功后)
|
||||||
|
client.DeleteObject(sourceBucket, sourceKey);
|
||||||
|
}
|
||||||
|
catch (OssException ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"[{ex.ErrorCode}] {ex.Message}", ex);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "MinIO":
|
||||||
|
#region MinIO
|
||||||
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
var minioClient = new MinioClient()
|
||||||
|
.WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey)
|
||||||
|
.WithSSL(minIOConfig.UseSSL)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// 定义源路径和目标路径
|
||||||
|
string destinationKey = "b路径/文件名";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 1. 复制文件到新路径[2,5](@ref)
|
||||||
|
using (var memoryStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
// 下载源文件流
|
||||||
|
await minioClient.GetObjectAsync(new GetObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.BucketName)
|
||||||
|
.WithObject(sourcePath)
|
||||||
|
.WithCallbackStream(stream => stream.CopyTo(memoryStream)));
|
||||||
|
|
||||||
|
memoryStream.Position = 0; // 重置流位置
|
||||||
|
|
||||||
|
// 上传到新路径
|
||||||
|
await minioClient.PutObjectAsync(new PutObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.BucketName)
|
||||||
|
.WithObject(destinationKey)
|
||||||
|
.WithStreamData(memoryStream)
|
||||||
|
.WithObjectSize(memoryStream.Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 删除原文件[1,6](@ref)
|
||||||
|
await minioClient.RemoveObjectAsync(new RemoveObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.BucketName)
|
||||||
|
.WithObject(sourcePath));
|
||||||
|
}
|
||||||
|
catch (MinioException ex)
|
||||||
|
{
|
||||||
|
// 处理异常(例如:记录日志或抛出)
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "AWS":
|
||||||
|
#region AWS
|
||||||
|
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
|
var credentials = new SessionAWSCredentials(
|
||||||
|
AWSTempToken.AccessKeyId,
|
||||||
|
AWSTempToken.SecretAccessKey,
|
||||||
|
AWSTempToken.SessionToken
|
||||||
|
);
|
||||||
|
|
||||||
|
var clientConfig = new AmazonS3Config
|
||||||
|
{
|
||||||
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
|
UseHttp = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
|
|
||||||
|
// 定义原路径和目标路径
|
||||||
|
|
||||||
|
|
||||||
|
// 1. 复制对象到新路径
|
||||||
|
var copyRequest = new Amazon.S3.Model.CopyObjectRequest
|
||||||
|
{
|
||||||
|
SourceBucket = awsConfig.BucketName,
|
||||||
|
SourceKey = sourcePath,
|
||||||
|
DestinationBucket = awsConfig.BucketName,
|
||||||
|
DestinationKey = destPath
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 执行复制操作
|
||||||
|
await amazonS3Client.CopyObjectAsync(copyRequest);
|
||||||
|
|
||||||
|
// 2. 删除原对象
|
||||||
|
var deleteRequest = new Amazon.S3.Model.DeleteObjectRequest
|
||||||
|
{
|
||||||
|
BucketName = awsConfig.BucketName,
|
||||||
|
Key = sourcePath
|
||||||
|
};
|
||||||
|
await amazonS3Client.DeleteObjectAsync(deleteRequest);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (AmazonS3Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"ERROR: {ex.Message}");
|
||||||
|
// 可根据异常类型细化处理(如文件不存在、权限问题等)
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new BusinessValidationFailedException("ERROR");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有根目录名称
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<string> GetRootFolderNames()
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
|
||||||
|
AliyunOSSTempToken.AccessKeyId,
|
||||||
|
AliyunOSSTempToken.AccessKeySecret,
|
||||||
|
AliyunOSSTempToken.SecurityToken);
|
||||||
|
|
||||||
|
List<string> rootFolders = new List<string>();
|
||||||
|
string nextMarker = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ObjectListing objectListing = null;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
// 列出根目录下的对象和文件夹
|
||||||
|
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
|
||||||
|
{
|
||||||
|
|
||||||
|
MaxKeys = 1000,
|
||||||
|
Marker = nextMarker,
|
||||||
|
Delimiter = "/" // 使用分隔符来模拟文件夹
|
||||||
|
});
|
||||||
|
|
||||||
|
// 遍历 CommonPrefixes 获取根文件夹名称
|
||||||
|
foreach (var prefix in objectListing.CommonPrefixes)
|
||||||
|
{
|
||||||
|
rootFolders.Add(prefix.TrimEnd('/')); // 去掉末尾的斜杠
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置 NextMarker 以获取下一页的数据
|
||||||
|
nextMarker = objectListing.NextMarker;
|
||||||
|
|
||||||
|
} while (objectListing.IsTruncated);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rootFolders;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 删除某个目录的文件
|
/// 删除某个目录的文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="prefix"></param>
|
/// <param name="prefix"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task DeleteFromPrefix(string prefix)
|
public async Task DeleteFromPrefix(string prefix, bool isCache = false)
|
||||||
{
|
{
|
||||||
GetObjectStoreTempToken();
|
GetObjectStoreTempToken();
|
||||||
|
|
||||||
|
|
@ -580,6 +906,21 @@ public class OSSService : IOSSService
|
||||||
|
|
||||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||||
|
|
||||||
|
var bucketName = string.Empty;
|
||||||
|
|
||||||
|
if (isCache)
|
||||||
|
{
|
||||||
|
Uri uri = new Uri(aliConfig.ViewEndpoint);
|
||||||
|
string host = uri.Host; // 获取 "zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com"
|
||||||
|
string[] parts = host.Split('.');
|
||||||
|
bucketName = parts[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bucketName = aliConfig.BucketName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -588,7 +929,7 @@ public class OSSService : IOSSService
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
// 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker
|
// 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker
|
||||||
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
|
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(bucketName)
|
||||||
{
|
{
|
||||||
Prefix = prefix,
|
Prefix = prefix,
|
||||||
MaxKeys = 1000,
|
MaxKeys = 1000,
|
||||||
|
|
@ -600,7 +941,7 @@ public class OSSService : IOSSService
|
||||||
// 删除获取到的文件
|
// 删除获取到的文件
|
||||||
if (keys.Count > 0)
|
if (keys.Count > 0)
|
||||||
{
|
{
|
||||||
_ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, keys, false));
|
_ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(bucketName, keys, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置 NextMarker 以获取下一页的数据
|
// 设置 NextMarker 以获取下一页的数据
|
||||||
|
|
@ -657,7 +998,6 @@ public class OSSService : IOSSService
|
||||||
|
|
||||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
|
|
||||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
||||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||||
|
|
||||||
|
|
@ -709,6 +1049,155 @@ public class OSSService : IOSSService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task DeleteObjects(List<string> objectKeys)
|
||||||
|
{
|
||||||
|
GetObjectStoreTempToken();
|
||||||
|
|
||||||
|
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||||
|
{
|
||||||
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||||
|
|
||||||
|
if (objectKeys.Count > 0)
|
||||||
|
{
|
||||||
|
var result = _ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, objectKeys, false));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
|
{
|
||||||
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
|
if (objectKeys.Count > 0)
|
||||||
|
{
|
||||||
|
var objArgs = new RemoveObjectsArgs()
|
||||||
|
.WithBucket(minIOConfig.BucketName)
|
||||||
|
.WithObjects(objectKeys);
|
||||||
|
|
||||||
|
// 删除对象
|
||||||
|
await minioClient.RemoveObjectsAsync(objArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
|
{
|
||||||
|
|
||||||
|
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
|
|
||||||
|
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
||||||
|
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||||
|
|
||||||
|
//提供awsEndPoint(域名)进行访问配置
|
||||||
|
var clientConfig = new AmazonS3Config
|
||||||
|
{
|
||||||
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
|
UseHttp = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
|
|
||||||
|
if (objectKeys.Count > 0)
|
||||||
|
{
|
||||||
|
// 准备删除请求
|
||||||
|
var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
|
||||||
|
{
|
||||||
|
BucketName = awsConfig.BucketName,
|
||||||
|
Objects = objectKeys.Select(t => new KeyVersion() { Key = t }).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 批量删除对象
|
||||||
|
var deleteObjectsResponse = await amazonS3Client.DeleteObjectsAsync(deleteObjectsRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<long> GetObjectSizeAsync(string sourcePath)
|
||||||
|
{
|
||||||
|
BackBatchGetToken();
|
||||||
|
|
||||||
|
|
||||||
|
var objectkey = sourcePath.Trim('/');
|
||||||
|
|
||||||
|
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||||
|
{
|
||||||
|
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||||
|
|
||||||
|
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||||
|
|
||||||
|
var key = HttpUtility.UrlDecode(objectkey);
|
||||||
|
var metadata = _ossClient.GetObjectMetadata(aliConfig.BucketName, key);
|
||||||
|
|
||||||
|
long fileSize = metadata?.ContentLength ?? 0; // 文件大小(字节)
|
||||||
|
|
||||||
|
return fileSize;
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||||
|
{
|
||||||
|
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||||
|
|
||||||
|
|
||||||
|
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||||
|
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
|
||||||
|
var stat = await minioClient.StatObjectAsync(new Minio.DataModel.Args.StatObjectArgs()
|
||||||
|
.WithBucket(minIOConfig.BucketName)
|
||||||
|
.WithObject(objectkey));
|
||||||
|
|
||||||
|
return stat.Size; // 文件大小(字节)
|
||||||
|
}
|
||||||
|
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||||
|
{
|
||||||
|
|
||||||
|
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||||
|
|
||||||
|
|
||||||
|
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
||||||
|
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||||
|
|
||||||
|
//提供awsEndPoint(域名)进行访问配置
|
||||||
|
var clientConfig = new AmazonS3Config
|
||||||
|
{
|
||||||
|
RegionEndpoint = RegionEndpoint.USEast1,
|
||||||
|
UseHttp = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
var request = new Amazon.S3.Model.GetObjectMetadataRequest
|
||||||
|
{
|
||||||
|
BucketName = awsConfig.BucketName,
|
||||||
|
Key = objectkey
|
||||||
|
};
|
||||||
|
|
||||||
|
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||||
|
|
||||||
|
var response = await amazonS3Client.GetObjectMetadataAsync(request);
|
||||||
|
|
||||||
|
long fileSize = response.ContentLength; // 文件大小(字节)
|
||||||
|
|
||||||
|
return fileSize;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ObjectStoreDTO GetObjectStoreTempToken()
|
public ObjectStoreDTO GetObjectStoreTempToken()
|
||||||
{
|
{
|
||||||
|
|
@ -752,6 +1241,7 @@ public class OSSService : IOSSService
|
||||||
BucketName = ossOptions.BucketName,
|
BucketName = ossOptions.BucketName,
|
||||||
EndPoint = ossOptions.EndPoint,
|
EndPoint = ossOptions.EndPoint,
|
||||||
ViewEndpoint = ossOptions.ViewEndpoint,
|
ViewEndpoint = ossOptions.ViewEndpoint,
|
||||||
|
PreviewEndpoint = ossOptions.PreviewEndpoint
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Application.Helper
|
||||||
|
{
|
||||||
|
public static class SafeBussinessHelper
|
||||||
|
{
|
||||||
|
public static async Task<bool> RunAsync(Func<Task> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await func();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<(bool Success, T? Result)> RunAsync<T>(Func<Task<T>> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await func();
|
||||||
|
return (true, result);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
|
||||||
|
return (false, default);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -34,36 +34,37 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" />
|
<PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" />
|
||||||
<PackageReference Include="IdentityModel.OidcClient" Version="6.0.0" />
|
<PackageReference Include="IdentityModel.OidcClient" Version="6.0.0" />
|
||||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.4" />
|
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.6" />
|
||||||
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.400.36" />
|
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.2" />
|
||||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
||||||
<PackageReference Include="AWSSDK.S3" Version="3.7.405" />
|
<PackageReference Include="AWSSDK.S3" Version="4.0.6.8" />
|
||||||
<PackageReference Include="DocX" Version="3.0.1" />
|
<PackageReference Include="DocX" Version="4.0.25105.5786" />
|
||||||
<PackageReference Include="FreeSpire.Doc" Version="12.2.0" />
|
<PackageReference Include="FreeSpire.Doc" Version="12.2.0" />
|
||||||
<PackageReference Include="ExcelDataReader" Version="3.7.0" />
|
<PackageReference Include="ExcelDataReader" Version="3.7.0" />
|
||||||
<PackageReference Include="ExcelDataReader.DataSet" Version="3.7.0" />
|
<PackageReference Include="ExcelDataReader.DataSet" Version="3.7.0" />
|
||||||
<PackageReference Include="DistributedLock.Redis" Version="1.0.3" />
|
<PackageReference Include="DistributedLock.Redis" Version="1.1.0" />
|
||||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.5" />
|
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||||
<PackageReference Include="fo-dicom" Version="5.1.3" />
|
<PackageReference Include="fo-dicom" Version="5.2.2" />
|
||||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.3" />
|
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.2" />
|
||||||
<PackageReference Include="fo-dicom.Codecs" Version="5.15.1" />
|
<PackageReference Include="fo-dicom.Codecs" Version="5.16.4" />
|
||||||
<PackageReference Include="IP2Region.Net" Version="2.0.2" />
|
<PackageReference Include="IP2Region.Net" Version="2.0.2" />
|
||||||
<PackageReference Include="MailKit" Version="4.7.1.1" />
|
<PackageReference Include="MailKit" Version="4.13.0" />
|
||||||
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0" />
|
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
|
||||||
<PackageReference Include="MimeKit" Version="4.7.1" />
|
<PackageReference Include="MimeKit" Version="4.13.0" />
|
||||||
<PackageReference Include="MiniExcel" Version="1.34.2" />
|
<PackageReference Include="MiniExcel" Version="1.41.3" />
|
||||||
<PackageReference Include="Minio" Version="6.0.3" />
|
<PackageReference Include="Minio" Version="6.0.5" />
|
||||||
<PackageReference Include="MiniWord" Version="0.9.2" />
|
<PackageReference Include="MiniWord" Version="0.9.2" />
|
||||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||||
<TreatAsUsed>true</TreatAsUsed>
|
<TreatAsUsed>true</TreatAsUsed>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="NPOI" Version="2.7.1" />
|
<PackageReference Include="NPOI" Version="2.7.4" />
|
||||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.5" />
|
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||||
|
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="9.0.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="9.0.0" />
|
||||||
<PackageReference Include="ZiggyCreatures.FusionCache" Version="1.4.0" />
|
<PackageReference Include="ZiggyCreatures.FusionCache" Version="2.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -1510,6 +1510,20 @@
|
||||||
<param name="modality"></param>
|
<param name="modality"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.GetTrialVisitImageStatInfo(System.Guid)">
|
||||||
|
<summary>
|
||||||
|
获取项目影像统计,有影像的subject 数量 访视数量
|
||||||
|
</summary>
|
||||||
|
<param name="trialId"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.GetExportSubjectVisitImageList(IRaCIS.Core.Application.Contracts.TrialExportImageCommand)">
|
||||||
|
<summary>
|
||||||
|
批量勾选访视 进行下载
|
||||||
|
</summary>
|
||||||
|
<param name="inCommand"></param>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.GetSubejectOrVisitZipInfo(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Application.Contracts.SubejctZipInfoQuery)">
|
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.GetSubejectOrVisitZipInfo(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Application.Contracts.SubejctZipInfoQuery)">
|
||||||
<summary>
|
<summary>
|
||||||
受试者级别所有的影像
|
受试者级别所有的影像
|
||||||
|
|
@ -13870,7 +13884,21 @@
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
<exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception>
|
<exception cref="T:IRaCIS.Core.Infrastructure.BusinessValidationFailedException"></exception>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Core.Application.Helper.OSSService.DeleteFromPrefix(System.String)">
|
<member name="M:IRaCIS.Core.Application.Helper.OSSService.MoveObject(System.String,System.String,System.Boolean)">
|
||||||
|
<summary>
|
||||||
|
移动OSS文件到新路径
|
||||||
|
</summary>
|
||||||
|
<param name="sourcePath">原文件路径(格式:bucket/key)</param>
|
||||||
|
<param name="destPath">新文件路径(格式:bucket/key)</param>
|
||||||
|
<param name="overwrite">是否覆盖已存在的目标文件(默认true)</param>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.Application.Helper.OSSService.GetRootFolderNames">
|
||||||
|
<summary>
|
||||||
|
获取所有根目录名称
|
||||||
|
</summary>
|
||||||
|
<returns></returns>
|
||||||
|
</member>
|
||||||
|
<member name="M:IRaCIS.Core.Application.Helper.OSSService.DeleteFromPrefix(System.String,System.Boolean)">
|
||||||
<summary>
|
<summary>
|
||||||
删除某个目录的文件
|
删除某个目录的文件
|
||||||
</summary>
|
</summary>
|
||||||
|
|
@ -18239,7 +18267,7 @@
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Application.Services.PatientService.ModifySCPStudyHospitalGroup(IRaCIS.Application.Contracts.SCPStudyHospitalGroupCommand)">
|
<member name="M:IRaCIS.Application.Services.PatientService.ModifySCPStudyHospitalGroup(IRaCIS.Application.Contracts.SCPStudyHospitalGroupCommand)">
|
||||||
<summary>
|
<summary>
|
||||||
修改检查课题组 1是添加 2是删除
|
修改检查课题组 1是添加 2是删除,3是更新
|
||||||
</summary>
|
</summary>
|
||||||
<param name="incommand"></param>
|
<param name="incommand"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
|
|
@ -18408,7 +18436,7 @@
|
||||||
<param name="inQuery"></param>
|
<param name="inQuery"></param>
|
||||||
<returns></returns>
|
<returns></returns>
|
||||||
</member>
|
</member>
|
||||||
<member name="M:IRaCIS.Application.Services.PatientService.GetDownloadSubjectVisitStudyInfo(System.Guid,System.Guid)">
|
<member name="M:IRaCIS.Application.Services.PatientService.GetDownloadSubjectVisitStudyInfo(System.Guid,System.Guid,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomStudy},IRaCIS.Core.Application.Helper.IOSSService)">
|
||||||
<summary>
|
<summary>
|
||||||
获取下载的访视检查信息
|
获取下载的访视检查信息
|
||||||
</summary>
|
</summary>
|
||||||
|
|
|
||||||
|
|
@ -620,4 +620,178 @@ namespace IRaCIS.Core.Application.Contracts
|
||||||
|
|
||||||
public Guid TaskId { get; set; }
|
public Guid TaskId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TrialVisitImageQuery : PageInput
|
||||||
|
{
|
||||||
|
[NotDefault]
|
||||||
|
public Guid TrialId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public Guid? TrialSiteId { get; set; }
|
||||||
|
|
||||||
|
public string? SubjectCode { get; set; }
|
||||||
|
|
||||||
|
public DateTime? BeginScanDate { get; set; }
|
||||||
|
public DateTime? EndScanDate { get; set; }
|
||||||
|
}
|
||||||
|
public class TrialVisitImageStatView
|
||||||
|
{
|
||||||
|
public Guid TrialId { get; set; }
|
||||||
|
|
||||||
|
public Guid SubjectVisitId { get; set; }
|
||||||
|
|
||||||
|
public Guid TrialSiteId { get; set; }
|
||||||
|
|
||||||
|
public string TrialSiteCode { get; set; }
|
||||||
|
|
||||||
|
public string SubjectCode { get; set; }
|
||||||
|
|
||||||
|
public string VisitName { get; set; }
|
||||||
|
|
||||||
|
public decimal VisitNum { get; set; }
|
||||||
|
|
||||||
|
public DateTime? EarliestScanDate { get; set; }
|
||||||
|
public DateTime? LatestScanDate { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public int TotalStudyCount { get; set; }
|
||||||
|
|
||||||
|
public int TotalImageCount { get; set; }
|
||||||
|
|
||||||
|
public long? TotalImageSize { get; set; }
|
||||||
|
|
||||||
|
public long? TotalReadingImageSize { get; set; }
|
||||||
|
|
||||||
|
public string TotalImageSizeStr => TotalImageSize.HasValue
|
||||||
|
? $"{TotalImageSize.Value / 1024d / 1024d:F3} MB"
|
||||||
|
: "0.000 MB";
|
||||||
|
|
||||||
|
public string TotalReadingImageSizeStr => TotalReadingImageSize.HasValue
|
||||||
|
? $"{TotalReadingImageSize.Value / 1024d / 1024d:F3} MB"
|
||||||
|
: "0.000 MB";
|
||||||
|
|
||||||
|
public string ImageTypeStr => $"{(IsHaveDicom ? "DICOM" : "")}{(IsHaveNoneDicom && IsHaveDicom ? " , " : "")}{(IsHaveNoneDicom ? "Non-DICOM" : "")}";
|
||||||
|
|
||||||
|
public bool IsHaveDicom { get; set; }
|
||||||
|
|
||||||
|
public bool IsHaveNoneDicom { get; set; }
|
||||||
|
|
||||||
|
#region 废弃,为了字段排序
|
||||||
|
//public int TotalStudyCount => DicomStudyCount + NoneDicomStudyCount;
|
||||||
|
|
||||||
|
//public int TotalImageCount => DicomImageCount + NoneDicomImageCount;
|
||||||
|
|
||||||
|
//public long? TotalImageSize => DicomImageSize + NoneDicomImageSize;
|
||||||
|
|
||||||
|
//public int DicomStudyCount { get; set; }
|
||||||
|
//public int DicomImageCount { get; set; }
|
||||||
|
//public long? DicomImageSize { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
//public int NoneDicomStudyCount { get; set; }
|
||||||
|
//public int NoneDicomImageCount { get; set; }
|
||||||
|
//public long? NoneDicomImageSize { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TrialExportImageCommand
|
||||||
|
{
|
||||||
|
[NotDefault]
|
||||||
|
public Guid TrialId { get; set; }
|
||||||
|
|
||||||
|
public List<Guid> SubjectVisitIdList { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public bool IsKeyImage { get; set; }
|
||||||
|
|
||||||
|
// true 导出阅片,null 就是所有影像
|
||||||
|
public bool? IsExportReading { get; set; }
|
||||||
|
}
|
||||||
|
public class TrialKeyImageExportDTO
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public string ResearchProgramNo { get; set; }
|
||||||
|
public string CriterionName { get; set; }
|
||||||
|
public ArbitrationRule ArbitrationRule { get; set; }
|
||||||
|
|
||||||
|
public bool IsGlobalReading { get; set; }
|
||||||
|
|
||||||
|
public List<decimal> SubjectCriterionReadingPeriodVisitNumList { get; set; }
|
||||||
|
|
||||||
|
public string TrialSiteCode { get; set; }
|
||||||
|
|
||||||
|
public string VisitName { get; set; }
|
||||||
|
|
||||||
|
public Decimal VisitTaskNum { get; set; }
|
||||||
|
|
||||||
|
public string SubjectCode { get; set; }
|
||||||
|
|
||||||
|
public Arm ArmEnum { get; set; }
|
||||||
|
|
||||||
|
public Guid? JudgeResultTaskId { get; set; }
|
||||||
|
|
||||||
|
public bool? IsTrigerJudge { get; set; }
|
||||||
|
public bool? IsJudgeSelect { get; set; }
|
||||||
|
|
||||||
|
public ReadingCategory ReadingCategory { get; set; }
|
||||||
|
|
||||||
|
public List<TrialKeyPicturePath> ReadingNoneDicomMarkPathList { get; set; }
|
||||||
|
public List<TrialKeyPicturePath> QuestionMarkPictureList { get; set; }
|
||||||
|
|
||||||
|
public List<TrialKeyPicturePath> TableQuestionRowPictureList { get; set; }
|
||||||
|
}
|
||||||
|
public class TrialKeyPicturePath
|
||||||
|
{
|
||||||
|
public string PicturePath { get; set; }
|
||||||
|
|
||||||
|
public string OtherPicturePath { get; set; }
|
||||||
|
}
|
||||||
|
public class TrialImageStatInfo
|
||||||
|
{
|
||||||
|
public int SubjectCount { get; set; }
|
||||||
|
|
||||||
|
public int SubjectVisitCount { get; set; }
|
||||||
|
|
||||||
|
public long? TotalImageSize { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public string TotalImageSizeStr => TotalImageSize.HasValue
|
||||||
|
? $"{TotalImageSize.Value / 1024d / 1024d:F3} MB"
|
||||||
|
: "0.000 MB";
|
||||||
|
|
||||||
|
|
||||||
|
public string SubjectImageAVGSizeStr => TotalImageSize.HasValue
|
||||||
|
? $"{TotalImageSize.Value / SubjectCount / 1024d / 1024d:F3} MB"
|
||||||
|
: "0.000 MB";
|
||||||
|
|
||||||
|
|
||||||
|
public string SubjectVisitImageAVGSizeStr => TotalImageSize.HasValue
|
||||||
|
? $"{TotalImageSize.Value / SubjectVisitCount / 1024d / 1024d:F3} MB"
|
||||||
|
: "0.000 MB";
|
||||||
|
|
||||||
|
public long? TotalReadingImageSize { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public string TotalReadingImageSizeStr => TotalReadingImageSize.HasValue
|
||||||
|
? $"{TotalReadingImageSize.Value / 1024d / 1024d:F3} MB"
|
||||||
|
: "0.000 MB";
|
||||||
|
|
||||||
|
|
||||||
|
public string SubjectReadingImageAVGSizeStr => TotalReadingImageSize.HasValue
|
||||||
|
? $"{TotalReadingImageSize.Value / SubjectCount / 1024d / 1024d:F3} MB"
|
||||||
|
: "0.000 MB";
|
||||||
|
|
||||||
|
|
||||||
|
public string SubjectVisitReadingImageAVGSizeStr => TotalReadingImageSize.HasValue
|
||||||
|
? $"{TotalReadingImageSize.Value / SubjectVisitCount / 1024d / 1024d:F3} MB"
|
||||||
|
: "0.000 MB";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using IRaCIS.Core.Application.Helper;
|
||||||
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
|
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
|
||||||
using IRaCIS.Core.Domain.Models;
|
using IRaCIS.Core.Domain.Models;
|
||||||
using IRaCIS.Core.Domain.Share;
|
using IRaCIS.Core.Domain.Share;
|
||||||
|
using IRaCIS.Core.Infra.EFCore.Common;
|
||||||
using IRaCIS.Core.Infrastructure;
|
using IRaCIS.Core.Infrastructure;
|
||||||
using MassTransit;
|
using MassTransit;
|
||||||
using MassTransit.Initializers;
|
using MassTransit.Initializers;
|
||||||
|
|
@ -1154,6 +1155,407 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
||||||
return ResponseOutput.Ok();
|
return ResponseOutput.Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region 影像汇总页面
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IResponseOutput<PageOutput<TrialVisitImageStatView>>> GetTrialVisitImageStatList(TrialVisitImageQuery inQuery)
|
||||||
|
{
|
||||||
|
var query = _subjectVisitRepository.Where(t => t.TrialId == inQuery.TrialId)
|
||||||
|
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
|
||||||
|
.WhereIf(inQuery.SubjectCode.IsNotNullOrEmpty(), t => t.Subject.Code.Contains(inQuery.SubjectCode))
|
||||||
|
.WhereIf(inQuery.BeginScanDate != null, t => t.LatestScanDate >= inQuery.BeginScanDate)
|
||||||
|
.WhereIf(inQuery.EndScanDate != null, t => t.LatestScanDate == inQuery.EndScanDate)
|
||||||
|
.Select(t => new TrialVisitImageStatView()
|
||||||
|
{
|
||||||
|
TrialId = t.TrialId,
|
||||||
|
SubjectVisitId = t.Id,
|
||||||
|
SubjectCode = t.Subject.Code,
|
||||||
|
TrialSiteCode = t.TrialSite.TrialSiteCode,
|
||||||
|
TrialSiteId = t.TrialSiteId,
|
||||||
|
VisitName = t.VisitName,
|
||||||
|
VisitNum = t.VisitNum,
|
||||||
|
EarliestScanDate = t.EarliestScanDate,
|
||||||
|
LatestScanDate = t.LatestScanDate,
|
||||||
|
|
||||||
|
IsHaveDicom = t.StudyList.Any(),
|
||||||
|
|
||||||
|
IsHaveNoneDicom = t.NoneDicomStudyList.Any(),
|
||||||
|
|
||||||
|
|
||||||
|
TotalStudyCount = t.StudyList.Count() + t.NoneDicomStudyList.Count(),
|
||||||
|
|
||||||
|
TotalImageCount = t.StudyList.Sum(t => t.InstanceCount) + t.NoneDicomStudyList.Sum(t => t.FileCount),
|
||||||
|
|
||||||
|
TotalImageSize = t.StudyList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize) + t.NoneDicomStudyList.SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize),
|
||||||
|
|
||||||
|
TotalReadingImageSize = t.StudyList.SelectMany(t => t.InstanceList/*.Where(t => t.IsReading && t.DicomSerie.IsReading)*/).Sum(t => t.FileSize)
|
||||||
|
+ t.NoneDicomStudyList/*.Where(t => t.IsReading)*/.SelectMany(t => t.NoneDicomFileList/*.Where(t => t.IsReading)*/).Sum(t => t.FileSize),
|
||||||
|
|
||||||
|
|
||||||
|
//DicomStudyCount = t.StudyList.Count(),
|
||||||
|
//NoneDicomStudyCount = t.NoneDicomStudyList.Count(),
|
||||||
|
|
||||||
|
//DicomImageCount = t.StudyList.Sum(t => t.InstanceCount),
|
||||||
|
//NoneDicomImageCount = t.NoneDicomStudyList.Sum(t => t.FileCount),
|
||||||
|
|
||||||
|
//DicomImageSize = t.StudyList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize),
|
||||||
|
//NoneDicomImageSize = t.NoneDicomStudyList.SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize)
|
||||||
|
});
|
||||||
|
var defalutSortArray = new string[] { nameof(TrialVisitImageStatView.TrialSiteCode), nameof(QCCRCVisitViewModel.SubjectCode), nameof(QCCRCVisitViewModel.VisitNum) };
|
||||||
|
|
||||||
|
var pagelist = await query.Where(t => t.TotalImageCount > 0).ToPagedListAsync(inQuery, defalutSortArray);
|
||||||
|
|
||||||
|
return ResponseOutput.Ok(pagelist);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取项目影像统计,有影像的subject 数量 访视数量
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="trialId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async Task<IResponseOutput<TrialImageStatInfo>> GetTrialVisitImageStatInfo(Guid trialId)
|
||||||
|
{
|
||||||
|
var subjectImageList = _subjectVisitRepository.Where(t => t.TrialId == trialId)
|
||||||
|
.Where(t => t.StudyList.Sum(t => t.InstanceCount) > 0 || t.NoneDicomStudyList.Sum(t => t.FileCount) > 0)
|
||||||
|
.GroupBy(t => t.SubjectId)
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
SubjectId = g.Key,
|
||||||
|
VisitCount = g.Count(),
|
||||||
|
ReadingImageSize = g.SelectMany(t => t.NoneDicomStudyList/*.Where(t => t.IsReading)*/).SelectMany(t => t.NoneDicomFileList/*.Where(t => t.IsReading)*/).Sum(t => t.FileSize)
|
||||||
|
|
||||||
|
+ g.SelectMany(t => t.StudyList).SelectMany(t => t.InstanceList.Where(t => /*t.IsReading &&*/ t.DicomSerie.IsReading)).Sum(t => t.FileSize),
|
||||||
|
|
||||||
|
ImageSize = g.SelectMany(t => t.NoneDicomStudyList).SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize)
|
||||||
|
|
||||||
|
+ g.SelectMany(t => t.StudyList).SelectMany(t => t.InstanceList).Sum(t => t.FileSize)
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var subjectCount = subjectImageList.Count;
|
||||||
|
|
||||||
|
var subjectVisitCount = subjectImageList.Sum(t => t.VisitCount);
|
||||||
|
|
||||||
|
var totalImageSize = subjectImageList.Sum(t => t.ImageSize);
|
||||||
|
|
||||||
|
var totalReadingImageSize = subjectImageList.Sum(t => t.ReadingImageSize);
|
||||||
|
|
||||||
|
return ResponseOutput.Ok(new TrialImageStatInfo { SubjectCount = subjectCount, SubjectVisitCount = subjectVisitCount, TotalImageSize = totalImageSize, TotalReadingImageSize = totalReadingImageSize });
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 批量勾选访视 进行下载
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="inCommand"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
[HttpPost]
|
||||||
|
public async Task<IResponseOutput> GetExportSubjectVisitImageList(TrialExportImageCommand inCommand)
|
||||||
|
{
|
||||||
|
|
||||||
|
var isExportReading = inCommand.IsExportReading == true;
|
||||||
|
|
||||||
|
if (inCommand.IsKeyImage)
|
||||||
|
{
|
||||||
|
var downloadInfoList = _visitTaskRepository.Where(t => t.TrialId == inCommand.TrialId && (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global)
|
||||||
|
&& t.ReadingTaskState == ReadingTaskState.HaveSigned && t.IsAnalysisCreate == false && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze))
|
||||||
|
.Where(t => inCommand.SubjectVisitIdList.Contains((Guid)t.SourceSubjectVisitId))
|
||||||
|
.Select(t => new TrialKeyImageExportDTO()
|
||||||
|
{
|
||||||
|
ResearchProgramNo = t.Trial.ResearchProgramNo,
|
||||||
|
CriterionName = t.TrialReadingCriterion.CriterionName,
|
||||||
|
ArbitrationRule = t.TrialReadingCriterion.ArbitrationRule,
|
||||||
|
IsGlobalReading = t.TrialReadingCriterion.IsGlobalReading,
|
||||||
|
SubjectCriterionReadingPeriodVisitNumList = t.Subject.ReadModuleList
|
||||||
|
.Where(u => u.TrialReadingCriterionId == t.TrialReadingCriterionId && u.ReadingSetType == ReadingSetType.ImageReading).Select(c => c.SubjectVisit.VisitNum).ToList(),
|
||||||
|
|
||||||
|
TrialSiteCode = t.Subject.TrialSite.TrialSiteCode,
|
||||||
|
SubjectCode = t.Subject.Code,
|
||||||
|
|
||||||
|
ReadingCategory = t.ReadingCategory,
|
||||||
|
|
||||||
|
VisitName = t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.VisitName : "",
|
||||||
|
|
||||||
|
VisitTaskNum = t.VisitTaskNum,
|
||||||
|
|
||||||
|
ArmEnum = t.ArmEnum,
|
||||||
|
|
||||||
|
//ReadingNoneDicomMarkPathList = t.ReadingNoneDicomMarkList.Select(c => new TrialKeyPicturePath { PicturePath = c.Path, OtherPicturePath = string.Empty }).ToList(),
|
||||||
|
|
||||||
|
QuestionMarkPictureList = t.ReadingTaskQuestionMarkList.Select(c => new TrialKeyPicturePath { PicturePath = c.PicturePath, OtherPicturePath = c.OtherPicturePath }).ToList(),
|
||||||
|
|
||||||
|
TableQuestionRowPictureList = t.LesionList.Select(c => new TrialKeyPicturePath { PicturePath = c.PicturePath, OtherPicturePath = c.OtherPicturePath }).ToList(),
|
||||||
|
|
||||||
|
Id = t.Id,
|
||||||
|
//裁判选择结果
|
||||||
|
JudgeResultTaskId = t.JudgeVisitTask.JudgeResultTaskId,
|
||||||
|
|
||||||
|
//是否触发裁判
|
||||||
|
IsTrigerJudge = t.JudgeVisitTaskId != null,
|
||||||
|
|
||||||
|
IsJudgeSelect = null
|
||||||
|
|
||||||
|
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
foreach (var subjectCriterionGroup in downloadInfoList.GroupBy(t => new { t.SubjectCode, t.CriterionName, t.ArbitrationRule, t.IsGlobalReading }))
|
||||||
|
{
|
||||||
|
var arbitrationRule = subjectCriterionGroup.Key.ArbitrationRule;
|
||||||
|
var isGlobalReading = subjectCriterionGroup.Key.IsGlobalReading;
|
||||||
|
|
||||||
|
foreach (var item in subjectCriterionGroup)
|
||||||
|
{
|
||||||
|
if (arbitrationRule == ArbitrationRule.Visit)
|
||||||
|
{
|
||||||
|
//是否产生裁判
|
||||||
|
|
||||||
|
if (item.IsTrigerJudge == true)
|
||||||
|
{
|
||||||
|
//裁判做完了
|
||||||
|
if (item.JudgeResultTaskId != null)
|
||||||
|
{
|
||||||
|
//裁判选择了自己,那么设置
|
||||||
|
if (item.JudgeResultTaskId == item.Id)
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//没产生 且两个人做完了 默认R1
|
||||||
|
|
||||||
|
if (subjectCriterionGroup.Where(t => t.VisitTaskNum == item.VisitTaskNum && t.SubjectCode == item.SubjectCode).Select(t => t.ArmEnum).Distinct().Count() == 2)
|
||||||
|
{
|
||||||
|
if (item.ArmEnum == Arm.DoubleReadingArm1)
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (arbitrationRule == ArbitrationRule.Reading)
|
||||||
|
{
|
||||||
|
|
||||||
|
//阅片期访视号
|
||||||
|
var subjectReadingPeriondVisitNumList = subjectCriterionGroup.FirstOrDefault()?.SubjectCriterionReadingPeriodVisitNumList;
|
||||||
|
|
||||||
|
//两个人完成最大得任务号(访视+全局)
|
||||||
|
var subjectMaxFinishedTaskNum = subjectCriterionGroup.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).DefaultIfEmpty().Max();
|
||||||
|
|
||||||
|
var addReadingPeriodNum = isGlobalReading ? ReadingCommon.TaskNumDic[ReadingCategory.Global] : 0;
|
||||||
|
|
||||||
|
//可能没有配置阅片期 ,或者配置了 没有完成
|
||||||
|
var finishedGlobalCount = 0;
|
||||||
|
|
||||||
|
var globalFinishedVisitTaskNumList = new List<decimal>();
|
||||||
|
|
||||||
|
//没有配置阅片期
|
||||||
|
if (subjectReadingPeriondVisitNumList == null)
|
||||||
|
{
|
||||||
|
finishedGlobalCount = 0;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
globalFinishedVisitTaskNumList = subjectCriterionGroup.Where(t => subjectReadingPeriondVisitNumList.Any(c => (c + addReadingPeriodNum) == t.VisitTaskNum))
|
||||||
|
.Select(t => new { t.VisitTaskNum, t.ArmEnum }).Distinct()
|
||||||
|
.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).ToList();
|
||||||
|
|
||||||
|
finishedGlobalCount = globalFinishedVisitTaskNumList.Count();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finishedGlobalCount != 0)
|
||||||
|
{
|
||||||
|
//最大的完成的全局是否产生裁判
|
||||||
|
|
||||||
|
var maxFinishedGlobalNum = globalFinishedVisitTaskNumList.Max();
|
||||||
|
|
||||||
|
var globalMaxTask = subjectCriterionGroup.FirstOrDefault(t => t.VisitTaskNum == maxFinishedGlobalNum);
|
||||||
|
|
||||||
|
// 触发了裁判
|
||||||
|
if (globalMaxTask.IsTrigerJudge == true)
|
||||||
|
{
|
||||||
|
//最大裁判完成了
|
||||||
|
|
||||||
|
var maxJudgeVisitTaskNum = maxFinishedGlobalNum + ReadingCommon.TaskNumDic[ReadingCategory.Judge];
|
||||||
|
|
||||||
|
if (globalMaxTask.JudgeResultTaskId != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
var maxJudgeArmEnum = subjectCriterionGroup.Where(t => t.Id == globalMaxTask.JudgeResultTaskId).FirstOrDefault().ArmEnum;
|
||||||
|
|
||||||
|
if (item.VisitTaskNum < maxJudgeVisitTaskNum)
|
||||||
|
{
|
||||||
|
//触发裁判
|
||||||
|
item.IsTrigerJudge = true;
|
||||||
|
|
||||||
|
if (item.ArmEnum == maxJudgeArmEnum)
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = true;
|
||||||
|
}
|
||||||
|
//裁判没选择的人设置为false
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//最大的裁判未完成
|
||||||
|
|
||||||
|
//找到当前未阅最大裁判之前的已完成的最大裁判任务
|
||||||
|
|
||||||
|
var finishedGlobalFinishedMaxJudge = subjectCriterionGroup.Where(t => globalFinishedVisitTaskNumList.Contains(t.VisitTaskNum) && t.IsTrigerJudge == true && t.JudgeResultTaskId != null).OrderByDescending(t => t.VisitTaskNum).FirstOrDefault();
|
||||||
|
|
||||||
|
|
||||||
|
//未完成裁判之前 没有已完成的全局裁判
|
||||||
|
if (finishedGlobalFinishedMaxJudge == null)
|
||||||
|
{
|
||||||
|
if (item.VisitTaskNum < maxJudgeVisitTaskNum)
|
||||||
|
{
|
||||||
|
item.IsTrigerJudge = true;
|
||||||
|
//item.IsJudgeSelect = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
var maxFinishedJudgeVisitTaskNum = finishedGlobalFinishedMaxJudge.VisitTaskNum + +ReadingCommon.TaskNumDic[ReadingCategory.Judge];
|
||||||
|
|
||||||
|
var maxFinishedJudgeArmEnum = subjectCriterionGroup.Where(t => t.Id == finishedGlobalFinishedMaxJudge.JudgeResultTaskId).FirstOrDefault().ArmEnum;
|
||||||
|
|
||||||
|
if (item.VisitTaskNum < maxFinishedJudgeVisitTaskNum)
|
||||||
|
{
|
||||||
|
item.IsTrigerJudge = true;
|
||||||
|
|
||||||
|
if (item.ArmEnum == maxFinishedJudgeArmEnum)
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = true;
|
||||||
|
}
|
||||||
|
//裁判没选择的人设置为false
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (item.VisitTaskNum > maxFinishedJudgeVisitTaskNum && item.VisitTaskNum < maxJudgeVisitTaskNum)
|
||||||
|
{
|
||||||
|
//完成裁判 和未完成裁判之间的 裁判选择标记默认是null
|
||||||
|
|
||||||
|
item.IsTrigerJudge = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//在未完成全局裁判之后的访视 未知 都是null
|
||||||
|
|
||||||
|
item.IsTrigerJudge = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//最大的全局未产生裁判
|
||||||
|
|
||||||
|
if (item.VisitTaskNum <= maxFinishedGlobalNum)
|
||||||
|
{
|
||||||
|
item.IsTrigerJudge = false;
|
||||||
|
|
||||||
|
if (item.ArmEnum == Arm.DoubleReadingArm1)
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item.IsJudgeSelect = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadInfoList = downloadInfoList.Where(t => t.ReadingCategory == ReadingCategory.Visit).ToList();
|
||||||
|
return ResponseOutput.Ok(downloadInfoList);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
var downloadInfo = _trialRepository.Where(t => t.Id == inCommand.TrialId).Select(t => new
|
||||||
|
{
|
||||||
|
t.ResearchProgramNo,
|
||||||
|
|
||||||
|
VisitList = t.SubjectVisitList.Where(t => inCommand.SubjectVisitIdList.Contains(t.Id)).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/*.Where(t => isExportReading ? t.IsReading : true)*/.Select(z => new
|
||||||
|
{
|
||||||
|
z.Modality,
|
||||||
|
|
||||||
|
InstancePathList = z.DicomInstanceList/*.Where(t => isExportReading ? t.IsReading : true)*/.Select(k => new
|
||||||
|
{
|
||||||
|
k.Path
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
}),
|
||||||
|
|
||||||
|
NoneDicomStudyList = sv.NoneDicomStudyList/*.Where(t => isExportReading ? t.IsReading : true)*/.Select(nd => new
|
||||||
|
{
|
||||||
|
nd.Modality,
|
||||||
|
nd.StudyCode,
|
||||||
|
nd.ImageDate,
|
||||||
|
|
||||||
|
FileList = nd.NoneDicomFileList/*.Where(t => isExportReading ? t.IsReading : true)*/.Select(file => new
|
||||||
|
{
|
||||||
|
file.FileName,
|
||||||
|
file.Path,
|
||||||
|
file.FileType
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}).ToList()
|
||||||
|
|
||||||
|
}).FirstOrDefault();
|
||||||
|
|
||||||
|
|
||||||
|
return ResponseOutput.Ok(downloadInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region 之前后端下载废弃
|
#region 之前后端下载废弃
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,7 @@ namespace IRaCIS.Application.Contracts
|
||||||
|
|
||||||
public List<UserAddUserType> UserRoleList { get; set; }
|
public List<UserAddUserType> UserRoleList { get; set; }
|
||||||
|
|
||||||
public List<Guid> HospitalGroupIdList { get; set; }
|
public List<Guid> HospitalGroupIdList { get; set; } = new List<Guid>();
|
||||||
|
|
||||||
public string BaseUrl { get; set; } = string.Empty;
|
public string BaseUrl { get; set; } = string.Empty;
|
||||||
public string RouteUrl { get; set; } = string.Empty;
|
public string RouteUrl { get; set; } = string.Empty;
|
||||||
|
|
|
||||||
|
|
@ -668,7 +668,7 @@ namespace IRaCIS.Core.Application.Service
|
||||||
user.IdentityUserHospitalGroupList.AddRange(addIdList.Select(t => new HospitalGroupIdentityUser() { HospitalGroupId = t, IsManager = false, IdentityUserId = user.Id }));
|
user.IdentityUserHospitalGroupList.AddRange(addIdList.Select(t => new HospitalGroupIdentityUser() { HospitalGroupId = t, IsManager = false, IdentityUserId = user.Id }));
|
||||||
|
|
||||||
|
|
||||||
var success = await _userRoleRepository.SaveChangesAsync();
|
var success = await _identityUserRepository.SaveChangesAsync();
|
||||||
|
|
||||||
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = _userInfo.IdentityUserId, ActionUserName = _userInfo.UserName, TargetIdentityUserId = model.Id, OptType = UserOptType.UpdateUser }, true);
|
await _userLogRepository.AddAsync(new UserLog() { IP = _userInfo.IP, ActionIdentityUserId = _userInfo.IdentityUserId, ActionUserName = _userInfo.UserName, TargetIdentityUserId = model.Id, OptType = UserOptType.UpdateUser }, true);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,8 @@ namespace IRaCIS.Core.Application.Service
|
||||||
|
|
||||||
CreateMap<IdentityUser, UserRole>();
|
CreateMap<IdentityUser, UserRole>();
|
||||||
|
|
||||||
CreateMap<UserCommand, IdentityUser>();
|
CreateMap<UserCommand, IdentityUser>()
|
||||||
|
.ForMember(d => d.UserRoleList, c => c.Ignore());
|
||||||
|
|
||||||
CreateMap<IdentityUser, UserBasicInfo>()
|
CreateMap<IdentityUser, UserBasicInfo>()
|
||||||
.ForMember(d => d.IdentityUserId, c => c.MapFrom(t => t.Id))
|
.ForMember(d => d.IdentityUserId, c => c.MapFrom(t => t.Id))
|
||||||
|
|
|
||||||
|
|
@ -1148,4 +1148,31 @@ namespace IRaCIS.Application.Contracts
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public class DownloadDicomStudyDto
|
||||||
|
{
|
||||||
|
public string PatientId { get; set; }
|
||||||
|
public DateTime? StudyTime { get; set; }
|
||||||
|
public string StudyCode { get; set; }
|
||||||
|
public string StudyInstanceUid { get; set; }
|
||||||
|
public string StudyDIRPath { get; set; }
|
||||||
|
|
||||||
|
public List<DownloadDicomSeriesDto> SeriesList { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DownloadDicomSeriesDto
|
||||||
|
{
|
||||||
|
public string Modality { get; set; }
|
||||||
|
|
||||||
|
public List<DownloadDicomInstanceDto> InstanceList { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DownloadDicomInstanceDto
|
||||||
|
{
|
||||||
|
public bool IsEncapsulated { get; set; }
|
||||||
|
public Guid InstanceId { get; set; }
|
||||||
|
public string FileName { get; set; }
|
||||||
|
public string Path { get; set; }
|
||||||
|
public long? FileSize { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,9 @@ namespace IRaCIS.Application.Contracts
|
||||||
|
|
||||||
public string? ModalitiesInStudy { get; set; }
|
public string? ModalitiesInStudy { get; set; }
|
||||||
|
|
||||||
public List<HospitalGroupInfo> HospitalGroupList { get; set; }
|
public Guid? SCPStudyId { get; set; }
|
||||||
|
|
||||||
|
public List<HospitalGroupInfo> HospitalGroupList { get; set; } = new List<HospitalGroupInfo>();
|
||||||
|
|
||||||
public List<HospitalGroupInfo> CurrentUserHospitalGroupList { get; set; } = new List<HospitalGroupInfo>();
|
public List<HospitalGroupInfo> CurrentUserHospitalGroupList { get; set; } = new List<HospitalGroupInfo>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ using MailKit.Search;
|
||||||
using DocumentFormat.OpenXml.Office2010.Excel;
|
using DocumentFormat.OpenXml.Office2010.Excel;
|
||||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||||
using IRaCIS.Core.Application.Helper;
|
using IRaCIS.Core.Application.Helper;
|
||||||
using NPOI.SS.Formula.Functions;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Dynamic.Core;
|
using System.Linq.Dynamic.Core;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
@ -36,7 +35,6 @@ using Azure;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using static IRaCIS.Core.Domain.Share.StaticData;
|
using static IRaCIS.Core.Domain.Share.StaticData;
|
||||||
using FellowOakDicom;
|
using FellowOakDicom;
|
||||||
using DocumentFormat.OpenXml.Office2010.Drawing;
|
|
||||||
using IDistributedLockProvider = Medallion.Threading.IDistributedLockProvider;
|
using IDistributedLockProvider = Medallion.Threading.IDistributedLockProvider;
|
||||||
using DocumentFormat.OpenXml.InkML;
|
using DocumentFormat.OpenXml.InkML;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
@ -46,16 +44,11 @@ using FellowOakDicom.Network;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using DocumentFormat.OpenXml.Wordprocessing;
|
using DocumentFormat.OpenXml.Wordprocessing;
|
||||||
using System;
|
using System;
|
||||||
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
|
|
||||||
using DocumentFormat.OpenXml.Vml.Office;
|
|
||||||
using IRaCIS.Core.Infra.EFCore.Migrations;
|
using IRaCIS.Core.Infra.EFCore.Migrations;
|
||||||
using System.Dynamic;
|
using System.Dynamic;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using NPOI.HSSF.Record.Chart;
|
|
||||||
using IRaCIS.Core.Application.Helper.OtherTool;
|
using IRaCIS.Core.Application.Helper.OtherTool;
|
||||||
using IRaCIS.Core.Infrastructure.Extention;
|
using IRaCIS.Core.Infrastructure.Extention;
|
||||||
using DocumentFormat.OpenXml.Drawing.Charts;
|
|
||||||
using DocumentFormat.OpenXml.Drawing.Diagrams;
|
|
||||||
|
|
||||||
|
|
||||||
namespace IRaCIS.Application.Services
|
namespace IRaCIS.Application.Services
|
||||||
|
|
@ -918,9 +911,25 @@ namespace IRaCIS.Application.Services
|
||||||
[HttpDelete]
|
[HttpDelete]
|
||||||
public async Task<IResponseOutput> DeletePatientStudy(Guid patiendId, Guid scpStudyId,
|
public async Task<IResponseOutput> DeletePatientStudy(Guid patiendId, Guid scpStudyId,
|
||||||
[FromServices] IRepository<SCPSeries> _SeriesRepository,
|
[FromServices] IRepository<SCPSeries> _SeriesRepository,
|
||||||
[FromServices] IRepository<SCPInstance> _instanceRepository)
|
[FromServices] IRepository<SCPInstance> _instanceRepository,
|
||||||
|
[FromServices] IRepository<SCPStudyHospitalGroup> _scpStudyHospitalGroupRepository)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
var existList = _scpStudyHospitalGroupRepository.Where(t => t.SCPStudyId == scpStudyId).Select(t => t.HospitalGroupId).ToList();
|
||||||
|
|
||||||
|
var isAdminOrOAOrGA = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.Admin || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.OA
|
||||||
|
|| _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SuperAdmin || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.GA;
|
||||||
|
|
||||||
|
// abc 课题组,人属于AB 课题组,删除仅仅删除这个标签 直接返回
|
||||||
|
if (!isAdminOrOAOrGA && existList.Count > _userInfo.HospitalGroupList.Count)
|
||||||
|
{
|
||||||
|
|
||||||
|
await _scpStudyHospitalGroupRepository.BatchDeleteNoTrackingAsync(t => t.SCPStudyId == scpStudyId && _userInfo.HospitalGroupIdList.Contains(t.HospitalGroupId));
|
||||||
|
|
||||||
|
return ResponseOutput.Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (_studySubjectVisitRepository.Any(t => t.SCPStudyId == scpStudyId && t.StudyId != null))
|
if (_studySubjectVisitRepository.Any(t => t.SCPStudyId == scpStudyId && t.StudyId != null))
|
||||||
{
|
{
|
||||||
|
|
@ -928,11 +937,15 @@ namespace IRaCIS.Application.Services
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
await _subjectPatientRepository.DeleteFromQueryAsync(t => t.PatientId == patiendId);
|
await _subjectPatientRepository.DeleteFromQueryAsync(t => t.PatientId == patiendId);
|
||||||
await _studySubjectVisitRepository.DeleteFromQueryAsync(t => t.SCPStudyId == scpStudyId);
|
await _studySubjectVisitRepository.DeleteFromQueryAsync(t => t.SCPStudyId == scpStudyId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
await _scpStudyHospitalGroupRepository.BatchDeleteNoTrackingAsync(t => t.SCPStudyId == scpStudyId);
|
||||||
|
|
||||||
await _studyRepository.BatchDeleteNoTrackingAsync(t => t.Id == scpStudyId);
|
await _studyRepository.BatchDeleteNoTrackingAsync(t => t.Id == scpStudyId);
|
||||||
await _SeriesRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == scpStudyId);
|
await _SeriesRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == scpStudyId);
|
||||||
await _instanceRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == scpStudyId);
|
await _instanceRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == scpStudyId);
|
||||||
|
|
@ -2911,8 +2924,73 @@ namespace IRaCIS.Application.Services
|
||||||
/// <param name="trialId"></param>
|
/// <param name="trialId"></param>
|
||||||
/// <param name="subjectVisitId"></param>
|
/// <param name="subjectVisitId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task<IResponseOutput> GetDownloadSubjectVisitStudyInfo(Guid trialId, Guid subjectVisitId)
|
public async Task<IResponseOutput> GetDownloadSubjectVisitStudyInfo(Guid trialId, Guid subjectVisitId,
|
||||||
|
[FromServices] IRepository<DicomStudy> _dicomStudyRepository, [FromServices] IOSSService _oSSService)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
var dirDic = new Dictionary<string, string>();
|
||||||
|
#region DIR处理导出文件名,并将对应关系上传到OSS里面存储
|
||||||
|
|
||||||
|
//有传输语法值的导出 才生成DIR
|
||||||
|
if (_subjectVisitRepository.Where(t => t.Id == subjectVisitId).SelectMany(t => t.StudyList.SelectMany(t => t.InstanceList)).All(c => c.TransferSyntaxUID != string.Empty))
|
||||||
|
{
|
||||||
|
var list = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).SelectMany(t => t.StudyList)
|
||||||
|
.SelectMany(t => t.InstanceList)
|
||||||
|
.Select(t => new StudyDIRInfo()
|
||||||
|
{
|
||||||
|
|
||||||
|
DicomStudyId = t.DicomStudy.Id,
|
||||||
|
|
||||||
|
PatientId = t.DicomStudy.PatientId,
|
||||||
|
PatientName = t.DicomStudy.PatientName,
|
||||||
|
PatientBirthDate = t.DicomStudy.PatientBirthDate,
|
||||||
|
PatientSex = t.DicomStudy.PatientSex,
|
||||||
|
|
||||||
|
StudyInstanceUid = t.StudyInstanceUid,
|
||||||
|
StudyId = t.DicomStudy.StudyId,
|
||||||
|
DicomStudyDate = t.DicomStudy.DicomStudyDate,
|
||||||
|
DicomStudyTime = t.DicomStudy.DicomStudyTime,
|
||||||
|
AccessionNumber = t.DicomStudy.AccessionNumber,
|
||||||
|
|
||||||
|
StudyDescription = t.DicomStudy.Description,
|
||||||
|
|
||||||
|
SeriesInstanceUid = t.DicomSerie.SeriesInstanceUid,
|
||||||
|
Modality = t.DicomSerie.Modality,
|
||||||
|
DicomSeriesDate = t.DicomSerie.DicomSeriesDate,
|
||||||
|
DicomSeriesTime = t.DicomSerie.DicomSeriesTime,
|
||||||
|
SeriesNumber = t.DicomSerie.SeriesNumber,
|
||||||
|
SeriesDescription = t.DicomSerie.Description,
|
||||||
|
|
||||||
|
InstanceId = t.Id,
|
||||||
|
SopInstanceUid = t.SopInstanceUid,
|
||||||
|
SOPClassUID = t.SOPClassUID,
|
||||||
|
InstanceNumber = t.InstanceNumber,
|
||||||
|
MediaStorageSOPClassUID = t.MediaStorageSOPClassUID,
|
||||||
|
MediaStorageSOPInstanceUID = t.MediaStorageSOPInstanceUID,
|
||||||
|
TransferSyntaxUID = t.TransferSyntaxUID,
|
||||||
|
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
var pathInfo = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { t.TrialId, t.SubjectId, VisitId = t.Id }).FirstNotNullAsync();
|
||||||
|
|
||||||
|
foreach (var item in list.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId }))
|
||||||
|
{
|
||||||
|
var ossFolder = $"{pathInfo.TrialId}/Image/{pathInfo.SubjectId}/{pathInfo.VisitId}/{item.Key.StudyInstanceUid}";
|
||||||
|
|
||||||
|
var isSucess = await SafeBussinessHelper.RunAsync(async () => await DicomDIRHelper.GenerateStudyDIRAndUploadAsync(item.ToList(), dirDic, ossFolder, _oSSService));
|
||||||
|
|
||||||
|
|
||||||
|
if (isSucess)
|
||||||
|
{
|
||||||
|
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/DICOMDIR" });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
var query = from sv in _subjectVisitRepository.Where(t => t.Id == subjectVisitId)
|
var query = from sv in _subjectVisitRepository.Where(t => t.Id == subjectVisitId)
|
||||||
|
|
||||||
select new
|
select new
|
||||||
|
|
@ -2923,23 +3001,27 @@ namespace IRaCIS.Application.Services
|
||||||
VisitName = sv.VisitName,
|
VisitName = sv.VisitName,
|
||||||
|
|
||||||
StudyList = sv.StudyList
|
StudyList = sv.StudyList
|
||||||
|
.Select(u => new DownloadDicomStudyDto()
|
||||||
.Select(u => new
|
|
||||||
{
|
{
|
||||||
u.PatientIdStr,
|
PatientId = u.PatientIdStr,
|
||||||
u.StudyTime,
|
StudyTime = u.StudyTime,
|
||||||
u.StudyCode,
|
StudyCode = u.StudyCode,
|
||||||
|
StudyInstanceUid = u.StudyInstanceUid,
|
||||||
|
StudyDIRPath = u.StudyDIRPath,
|
||||||
|
|
||||||
SeriesList = u.SeriesList.Select(z => new
|
SeriesList = u.SeriesList.Select(z => new DownloadDicomSeriesDto()
|
||||||
{
|
{
|
||||||
z.Modality,
|
Modality = z.Modality,
|
||||||
|
|
||||||
InstanceList = z.DicomInstanceList.Select(k => new
|
InstanceList = z.DicomInstanceList.Select(k => new DownloadDicomInstanceDto()
|
||||||
{
|
{
|
||||||
k.Path,
|
IsEncapsulated = k.IsEncapsulated,
|
||||||
k.FileSize
|
InstanceId = k.Id,
|
||||||
})
|
FileName = string.Empty,
|
||||||
})
|
Path = k.Path,
|
||||||
|
FileSize = k.FileSize
|
||||||
|
}).ToList()
|
||||||
|
}).ToList()
|
||||||
|
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
|
|
||||||
|
|
@ -2948,6 +3030,15 @@ namespace IRaCIS.Application.Services
|
||||||
|
|
||||||
var result = query.FirstOrDefault();
|
var result = query.FirstOrDefault();
|
||||||
|
|
||||||
|
foreach (var item in result.StudyList.SelectMany(t => t.SeriesList).SelectMany(t => t.InstanceList))
|
||||||
|
{
|
||||||
|
var key = item.InstanceId.ToString();
|
||||||
|
if (dirDic.ContainsKey(key))
|
||||||
|
{
|
||||||
|
item.FileName = dirDic[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var preDownloadInfo = new SubejctVisitDownload()
|
var preDownloadInfo = new SubejctVisitDownload()
|
||||||
{
|
{
|
||||||
Id = NewId.NextSequentialGuid(),
|
Id = NewId.NextSequentialGuid(),
|
||||||
|
|
@ -3099,13 +3190,12 @@ namespace IRaCIS.Application.Services
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DebugStudyResponse(DicomCFindResponse response, ILogger _logger)
|
public static void DebugStudyResponse(DicomCFindResponse response)
|
||||||
{
|
{
|
||||||
if (response.Status == DicomStatus.Pending)
|
if (response.Status == DicomStatus.Pending)
|
||||||
{
|
{
|
||||||
|
|
||||||
// print the results
|
// print the results
|
||||||
_logger.LogDebug($"Patient {response.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty)}, {(response.Dataset.TryGetString(DicomTag.ModalitiesInStudy, out var dummy) ? dummy : string.Empty)}-Study from {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyDate, new DateTime())} with UID {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty)} ");
|
Log.Logger.Debug($"Patient {response.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty)}, {(response.Dataset.TryGetString(DicomTag.ModalitiesInStudy, out var dummy) ? dummy : string.Empty)}-Study from {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyDate, new DateTime())} with UID {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty)} ");
|
||||||
}
|
}
|
||||||
if (response.Status == DicomStatus.Success)
|
if (response.Status == DicomStatus.Success)
|
||||||
{
|
{
|
||||||
|
|
@ -3381,7 +3471,7 @@ namespace IRaCIS.Application.Services
|
||||||
var resultInstanceUidList = result.Select(t => t.StudyInstanceUID).ToList();
|
var resultInstanceUidList = result.Select(t => t.StudyInstanceUID).ToList();
|
||||||
|
|
||||||
var existStudyIdList = _studyRepository.Where(t => resultInstanceUidList.Contains(t.StudyInstanceUid))
|
var existStudyIdList = _studyRepository.Where(t => resultInstanceUidList.Contains(t.StudyInstanceUid))
|
||||||
.Select(t => new { t.StudyInstanceUid, HospitalGroupList = t.HospitalGroupList.Select(t => new HospitalGroupInfo { Id = t.HospitalGroupId, Name = t.HospitalGroup.Name, Code = t.HospitalGroup.Code }).ToList() }).ToList();
|
.Select(t => new { SCPStudyId = t.Id, t.StudyInstanceUid, HospitalGroupList = t.HospitalGroupList.Select(t => new HospitalGroupInfo { Id = t.HospitalGroupId, Name = t.HospitalGroup.Name, Code = t.HospitalGroup.Code }).ToList() }).ToList();
|
||||||
|
|
||||||
var allHospitalGroupList = _hospitalGroupRepository.Where(t => t.IsEnable).Select(t => new HospitalGroupInfo() { Name = t.Name, Id = t.Id, Code = t.Code }).ToList();
|
var allHospitalGroupList = _hospitalGroupRepository.Where(t => t.IsEnable).Select(t => new HospitalGroupInfo() { Name = t.Name, Id = t.Id, Code = t.Code }).ToList();
|
||||||
|
|
||||||
|
|
@ -3390,8 +3480,9 @@ namespace IRaCIS.Application.Services
|
||||||
|
|
||||||
foreach (var item in result)
|
foreach (var item in result)
|
||||||
{
|
{
|
||||||
|
item.SCPStudyId = existStudyIdList.FirstOrDefault(t => t.StudyInstanceUid == item.StudyInstanceUID)?.SCPStudyId;
|
||||||
item.IsStudyExist = existStudyIdList.Any(t => t.StudyInstanceUid == item.StudyInstanceUID);
|
item.IsStudyExist = existStudyIdList.Any(t => t.StudyInstanceUid == item.StudyInstanceUID);
|
||||||
item.HospitalGroupList = existStudyIdList.FirstOrDefault(t => t.StudyInstanceUid == item.StudyInstanceUID)?.HospitalGroupList;
|
item.HospitalGroupList = existStudyIdList.FirstOrDefault(t => t.StudyInstanceUid == item.StudyInstanceUID)?.HospitalGroupList ?? new List<HospitalGroupInfo>();
|
||||||
|
|
||||||
if (isAdminOrOA)
|
if (isAdminOrOA)
|
||||||
{
|
{
|
||||||
|
|
@ -3532,6 +3623,9 @@ namespace IRaCIS.Application.Services
|
||||||
var latestInstanceList = await _scpInstanceRepository.Where(t => inCommand.StudyInstanceUIDList.Contains(t.StudyInstanceUid))
|
var latestInstanceList = await _scpInstanceRepository.Where(t => inCommand.StudyInstanceUIDList.Contains(t.StudyInstanceUid))
|
||||||
.GroupBy(t => t.StudyInstanceUid).Select(g => g.OrderByDescending(t => t.CreateTime).FirstOrDefault()).ToListAsync();
|
.GroupBy(t => t.StudyInstanceUid).Select(g => g.OrderByDescending(t => t.CreateTime).FirstOrDefault()).ToListAsync();
|
||||||
|
|
||||||
|
await _cmoveStudyRepository.AddAsync(new CmoveStudy() { CallingAE = hirClient.CalledAE, CalledAE = find.CalledAE, StudyInstanceUIDList = inCommand.StudyInstanceUIDList, HopitalGroupIdList = inCommand.HospitalGroupIdList }, true);
|
||||||
|
|
||||||
|
|
||||||
var task = Task.Run(async () =>
|
var task = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var client = DicomClientFactory.Create(find.IP, find.Port, false, hirClient.CalledAE, find.CalledAE);
|
var client = DicomClientFactory.Create(find.IP, find.Port, false, hirClient.CalledAE, find.CalledAE);
|
||||||
|
|
@ -3575,8 +3669,6 @@ namespace IRaCIS.Application.Services
|
||||||
|
|
||||||
if (cmoveRequestList.Count > 0)
|
if (cmoveRequestList.Count > 0)
|
||||||
{
|
{
|
||||||
await _cmoveStudyRepository.AddAsync(new CmoveStudy() { CallingAE = hirClient.CalledAE, CalledAE = find.CalledAE, StudyInstanceUIDList = cmoveStudyUIdList, HopitalGroupIdList = inCommand.HospitalGroupIdList }, true);
|
|
||||||
|
|
||||||
await client.AddRequestsAsync(cmoveRequestList);
|
await client.AddRequestsAsync(cmoveRequestList);
|
||||||
await client.SendAsync();
|
await client.SendAsync();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,14 @@ namespace IRaCIS.Core.Domain.Models;
|
||||||
public class VisitTask : BaseFullAuditEntity
|
public class VisitTask : BaseFullAuditEntity
|
||||||
{
|
{
|
||||||
#region 导航属性
|
#region 导航属性
|
||||||
|
|
||||||
|
//[JsonIgnore]
|
||||||
|
//public List<ReadingNoneDicomMark> ReadingNoneDicomMarkList { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
|
||||||
|
public List<ReadingTaskQuestionMark> ReadingTaskQuestionMarkList { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public List<TaskStudy> TaskStudyList { get; set; }
|
public List<TaskStudy> TaskStudyList { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,4 +75,20 @@ public class DicomInstance : BaseFullAuditEntity, IEntitySeqId
|
||||||
|
|
||||||
|
|
||||||
public string WindowWidth { get; set; } = null!;
|
public string WindowWidth { get; set; } = null!;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region DIR 增加
|
||||||
|
|
||||||
|
public string SOPClassUID { get; set; }
|
||||||
|
|
||||||
|
public string MediaStorageSOPClassUID { get; set; }
|
||||||
|
|
||||||
|
public string TransferSyntaxUID { get; set; }
|
||||||
|
|
||||||
|
public string MediaStorageSOPInstanceUID { get; set; }
|
||||||
|
|
||||||
|
public bool IsEncapsulated { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -68,5 +68,13 @@ public class DicomSeries : BaseFullDeleteAuditEntity, IEntitySeqId
|
||||||
public string TriggerTime { get; set; } = null!;
|
public string TriggerTime { get; set; } = null!;
|
||||||
|
|
||||||
public Guid? VisitTaskId { get; set; }
|
public Guid? VisitTaskId { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
#region DIR 增加
|
||||||
|
|
||||||
|
public string DicomSeriesDate { get; set; }
|
||||||
|
|
||||||
|
public string DicomSeriesTime { get; set; }
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@ public class DicomStudy : BaseFullDeleteAuditEntity, IEntitySeqId
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public List<DicomSeries> SeriesList { get; set; }
|
public List<DicomSeries> SeriesList { get; set; }
|
||||||
|
|
||||||
|
[JsonIgnore]
|
||||||
|
public List<DicomInstance> InstanceList { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
[ForeignKey("SubjectId")]
|
[ForeignKey("SubjectId")]
|
||||||
public Subject Subject { get; set; }
|
public Subject Subject { get; set; }
|
||||||
|
|
@ -95,4 +98,15 @@ public class DicomStudy : BaseFullDeleteAuditEntity, IEntitySeqId
|
||||||
|
|
||||||
|
|
||||||
public string PatientIdStr { get; set; } = string.Empty;
|
public string PatientIdStr { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
#region DIR 增加字段
|
||||||
|
|
||||||
|
public string DicomStudyDate { get; set; }
|
||||||
|
|
||||||
|
public string DicomStudyTime { get; set; }
|
||||||
|
|
||||||
|
public string StudyDIRPath { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,19 @@ public class SCPInstance : BaseFullAuditEntity, IEntitySeqId
|
||||||
public string Path { get; set; } = string.Empty;
|
public string Path { get; set; } = string.Empty;
|
||||||
|
|
||||||
public long? FileSize { get; set; }
|
public long? FileSize { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
#region DIR 增加
|
||||||
|
|
||||||
|
public string SOPClassUID { get; set; }
|
||||||
|
|
||||||
|
public string MediaStorageSOPClassUID { get; set; }
|
||||||
|
|
||||||
|
public string TransferSyntaxUID { get; set; }
|
||||||
|
|
||||||
|
public string MediaStorageSOPInstanceUID { get; set; }
|
||||||
|
|
||||||
|
public bool IsEncapsulated { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,4 +39,12 @@ public class SCPSeries : BaseFullDeleteAuditEntity, IEntitySeqId
|
||||||
[StringLength(1000)]
|
[StringLength(1000)]
|
||||||
public string ImageResizePath { get; set; } = string.Empty;
|
public string ImageResizePath { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
|
||||||
|
#region DIR 增加
|
||||||
|
|
||||||
|
public string DicomSeriesDate { get; set; }
|
||||||
|
|
||||||
|
public string DicomSeriesTime { get; set; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,16 @@ public class SCPStudy : BaseFullDeleteAuditEntity, IEntitySeqId
|
||||||
//public Guid? SubjectVisitId { get; set; }
|
//public Guid? SubjectVisitId { get; set; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region DIR 增加字段
|
||||||
|
|
||||||
|
public string DicomStudyDate { get; set; }
|
||||||
|
|
||||||
|
public string DicomStudyTime { get; set; }
|
||||||
|
|
||||||
|
public string StudyDIRPath { get; set; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SCPStudyHospitalGroup : BaseFullAuditEntity
|
public class SCPStudyHospitalGroup : BaseFullAuditEntity
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ namespace IRaCIS.Core.Domain.Models
|
||||||
|
|
||||||
[Comment("后台 - 系统真实账户表")]
|
[Comment("后台 - 系统真实账户表")]
|
||||||
[Table("IdentityUser")]
|
[Table("IdentityUser")]
|
||||||
public class IdentityUser : BaseFullAuditEntityNoNavigat
|
public class IdentityUser : BaseFullAuditEntity
|
||||||
{
|
{
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ namespace IRaCIS.Core.Domain.Models;
|
||||||
|
|
||||||
[Comment("后台 - 系统账户")]
|
[Comment("后台 - 系统账户")]
|
||||||
[Table("User")]
|
[Table("User")]
|
||||||
public class UserRole : BaseFullAuditEntityNoNavigat
|
public class UserRole : BaseFullAuditEntity
|
||||||
{
|
{
|
||||||
#region 导航属性
|
#region 导航属性
|
||||||
|
|
||||||
//[ForeignKey("IdentityUserId")]
|
[ForeignKey("IdentityUserId")]
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public IdentityUser IdentityUser { get; set; }
|
public IdentityUser IdentityUser { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ public class DicomStudyConfigration : IEntityTypeConfiguration<DicomStudy>
|
||||||
{
|
{
|
||||||
builder.HasKey(e => e.SeqId);
|
builder.HasKey(e => e.SeqId);
|
||||||
|
|
||||||
|
builder.HasMany(s => s.InstanceList).WithOne(se => se.DicomStudy).HasForeignKey(se => se.StudyId).HasPrincipalKey(st => st.Id);
|
||||||
|
|
||||||
builder.HasMany(s => s.SeriesList).WithOne(se => se.DicomStudy).HasForeignKey(se => se.StudyId).HasPrincipalKey(st => st.Id);
|
builder.HasMany(s => s.SeriesList).WithOne(se => se.DicomStudy).HasForeignKey(se => se.StudyId).HasPrincipalKey(st => st.Id);
|
||||||
|
|
||||||
builder.HasMany(s => s.DicomStudyMonitorList).WithOne(sm => sm.DicomStudy).HasForeignKey(sm => sm.StudyId).HasPrincipalKey(se => se.Id);
|
builder.HasMany(s => s.DicomStudyMonitorList).WithOne(sm => sm.DicomStudy).HasForeignKey(sm => sm.StudyId).HasPrincipalKey(se => se.Id);
|
||||||
|
|
@ -40,7 +42,7 @@ public class DicomInstanceConfigration : IEntityTypeConfiguration<DicomInstance>
|
||||||
{
|
{
|
||||||
builder.HasKey(e => e.SeqId);
|
builder.HasKey(e => e.SeqId);
|
||||||
|
|
||||||
builder.HasOne(e => e.DicomStudy).WithMany().HasForeignKey(t => t.StudyId).HasPrincipalKey(st => st.Id);
|
builder.HasOne(e => e.DicomStudy).WithMany(c => c.InstanceList).HasForeignKey(t => t.StudyId).HasPrincipalKey(st => st.Id);
|
||||||
|
|
||||||
builder.HasMany(s => s.ReadingTableAnswerRowInfoList).WithOne(di => di.Instance).HasForeignKey(t => t.InstanceId).HasPrincipalKey(se => se.Id);
|
builder.HasMany(s => s.ReadingTableAnswerRowInfoList).WithOne(di => di.Instance).HasForeignKey(t => t.InstanceId).HasPrincipalKey(se => se.Id);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -72,18 +72,17 @@ namespace IRaCIS.Core.Infra.EFCore.EntityConfigration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//public class IdentityUserConfigration : IEntityTypeConfiguration<IdentityUser>
|
public class IdentityUserConfigration : IEntityTypeConfiguration<IdentityUser>
|
||||||
//{
|
{
|
||||||
// //当一个实体,针对同一个类,有两个一对一导航属性,但是是不同的外键,一个外键是一对一,一个是一对多,那么需要显示配置一对多的关系
|
//当一个实体,针对同一个类,有两个一对一导航属性,但是是不同的外键,一个外键是一对一,一个是一对多,那么需要显示配置一对多的关系
|
||||||
// public void Configure(EntityTypeBuilder<IdentityUser> builder)
|
public void Configure(EntityTypeBuilder<IdentityUser> builder)
|
||||||
// {
|
{
|
||||||
// builder.HasMany(s => s.UserRoleList)
|
builder.HasMany(s => s.UserRoleList)
|
||||||
// .WithOne(t=>t.IdentityUser)
|
.WithOne(t => t.IdentityUser)
|
||||||
// .HasForeignKey(s => s.IdentityUserId);
|
.HasForeignKey(s => s.IdentityUserId);
|
||||||
|
|
||||||
|
}
|
||||||
// }
|
}
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
public class TrialIdentityUserConfigration : IEntityTypeConfiguration<TrialIdentityUser>
|
public class TrialIdentityUserConfigration : IEntityTypeConfiguration<TrialIdentityUser>
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,12 @@
|
||||||
<PackageReference Include="Hangfire.Core" Version="1.8.18" />
|
<PackageReference Include="Hangfire.Core" Version="1.8.18" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="8.0.10" />
|
<PackageReference Include="Microsoft.Extensions.Localization.Abstractions" Version="8.0.10" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.19" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.15" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.19">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.15">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.19">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.10">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,256 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class dicomDir : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DicomStudyDate",
|
||||||
|
table: "SCPStudy",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DicomStudyTime",
|
||||||
|
table: "SCPStudy",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "StudyDIRPath",
|
||||||
|
table: "SCPStudy",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DicomSeriesDate",
|
||||||
|
table: "SCPSeries",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DicomSeriesTime",
|
||||||
|
table: "SCPSeries",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsEncapsulated",
|
||||||
|
table: "SCPInstance",
|
||||||
|
type: "bit",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "MediaStorageSOPClassUID",
|
||||||
|
table: "SCPInstance",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "MediaStorageSOPInstanceUID",
|
||||||
|
table: "SCPInstance",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "SOPClassUID",
|
||||||
|
table: "SCPInstance",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "TransferSyntaxUID",
|
||||||
|
table: "SCPInstance",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DicomStudyDate",
|
||||||
|
table: "DicomStudy",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DicomStudyTime",
|
||||||
|
table: "DicomStudy",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "StudyDIRPath",
|
||||||
|
table: "DicomStudy",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DicomSeriesDate",
|
||||||
|
table: "DicomSeries",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "DicomSeriesTime",
|
||||||
|
table: "DicomSeries",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "IsEncapsulated",
|
||||||
|
table: "DicomInstance",
|
||||||
|
type: "bit",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "MediaStorageSOPClassUID",
|
||||||
|
table: "DicomInstance",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "MediaStorageSOPInstanceUID",
|
||||||
|
table: "DicomInstance",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "SOPClassUID",
|
||||||
|
table: "DicomInstance",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "TransferSyntaxUID",
|
||||||
|
table: "DicomInstance",
|
||||||
|
type: "nvarchar(400)",
|
||||||
|
maxLength: 400,
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DicomStudyDate",
|
||||||
|
table: "SCPStudy");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DicomStudyTime",
|
||||||
|
table: "SCPStudy");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "StudyDIRPath",
|
||||||
|
table: "SCPStudy");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DicomSeriesDate",
|
||||||
|
table: "SCPSeries");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DicomSeriesTime",
|
||||||
|
table: "SCPSeries");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsEncapsulated",
|
||||||
|
table: "SCPInstance");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MediaStorageSOPClassUID",
|
||||||
|
table: "SCPInstance");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MediaStorageSOPInstanceUID",
|
||||||
|
table: "SCPInstance");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SOPClassUID",
|
||||||
|
table: "SCPInstance");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "TransferSyntaxUID",
|
||||||
|
table: "SCPInstance");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DicomStudyDate",
|
||||||
|
table: "DicomStudy");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DicomStudyTime",
|
||||||
|
table: "DicomStudy");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "StudyDIRPath",
|
||||||
|
table: "DicomStudy");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DicomSeriesDate",
|
||||||
|
table: "DicomSeries");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DicomSeriesTime",
|
||||||
|
table: "DicomSeries");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "IsEncapsulated",
|
||||||
|
table: "DicomInstance");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MediaStorageSOPClassUID",
|
||||||
|
table: "DicomInstance");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "MediaStorageSOPInstanceUID",
|
||||||
|
table: "DicomInstance");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "SOPClassUID",
|
||||||
|
table: "DicomInstance");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "TransferSyntaxUID",
|
||||||
|
table: "DicomInstance");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -936,6 +936,19 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
b.Property<DateTime?>("InstanceTime")
|
b.Property<DateTime?>("InstanceTime")
|
||||||
.HasColumnType("datetime2");
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEncapsulated")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<string>("MediaStorageSOPClassUID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("MediaStorageSOPInstanceUID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<int>("NumberOfFrames")
|
b.Property<int>("NumberOfFrames")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
|
@ -949,6 +962,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
.HasColumnType("nvarchar(400)");
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("SOPClassUID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<Guid>("SeriesId")
|
b.Property<Guid>("SeriesId")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
|
@ -984,6 +1002,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
b.Property<Guid>("SubjectVisitId")
|
b.Property<Guid>("SubjectVisitId")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
b.Property<string>("TransferSyntaxUID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<Guid>("TrialId")
|
b.Property<Guid>("TrialId")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
|
@ -1060,6 +1083,16 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
.HasColumnType("nvarchar(400)");
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("DicomSeriesDate")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("DicomSeriesTime")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
|
@ -1218,6 +1251,16 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
.HasColumnType("nvarchar(400)");
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("DicomStudyDate")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("DicomStudyTime")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
|
@ -1287,6 +1330,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
.HasColumnType("nvarchar(400)");
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("StudyDIRPath")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<string>("StudyId")
|
b.Property<string>("StudyId")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
|
|
@ -7675,6 +7723,19 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
b.Property<DateTime?>("InstanceTime")
|
b.Property<DateTime?>("InstanceTime")
|
||||||
.HasColumnType("datetime2");
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<bool>("IsEncapsulated")
|
||||||
|
.HasColumnType("bit");
|
||||||
|
|
||||||
|
b.Property<string>("MediaStorageSOPClassUID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("MediaStorageSOPInstanceUID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<int>("NumberOfFrames")
|
b.Property<int>("NumberOfFrames")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
|
@ -7688,6 +7749,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
.HasColumnType("nvarchar(400)");
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("SOPClassUID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<Guid>("SeriesId")
|
b.Property<Guid>("SeriesId")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
|
@ -7717,6 +7783,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
.HasColumnType("nvarchar(400)");
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("TransferSyntaxUID")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<DateTime>("UpdateTime")
|
b.Property<DateTime>("UpdateTime")
|
||||||
.HasColumnType("datetime2");
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
|
@ -7851,6 +7922,16 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
.HasColumnType("nvarchar(400)");
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("DicomSeriesDate")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("DicomSeriesTime")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
|
@ -8000,6 +8081,16 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
.HasColumnType("nvarchar(400)");
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("DicomStudyDate")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
|
b.Property<string>("DicomStudyTime")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<Guid>("Id")
|
b.Property<Guid>("Id")
|
||||||
.HasColumnType("uniqueidentifier");
|
.HasColumnType("uniqueidentifier");
|
||||||
|
|
||||||
|
|
@ -8058,6 +8149,11 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
b.Property<int>("SeriesCount")
|
b.Property<int>("SeriesCount")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("StudyDIRPath")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(400)
|
||||||
|
.HasColumnType("nvarchar(400)");
|
||||||
|
|
||||||
b.Property<string>("StudyId")
|
b.Property<string>("StudyId")
|
||||||
.IsRequired()
|
.IsRequired()
|
||||||
.HasMaxLength(400)
|
.HasMaxLength(400)
|
||||||
|
|
@ -14699,7 +14795,7 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
b.HasOne("IRaCIS.Core.Domain.Models.DicomStudy", "DicomStudy")
|
b.HasOne("IRaCIS.Core.Domain.Models.DicomStudy", "DicomStudy")
|
||||||
.WithMany()
|
.WithMany("InstanceList")
|
||||||
.HasForeignKey("StudyId")
|
.HasForeignKey("StudyId")
|
||||||
.HasPrincipalKey("Id")
|
.HasPrincipalKey("Id")
|
||||||
.OnDelete(DeleteBehavior.Cascade)
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
|
@ -18493,6 +18589,8 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
|
||||||
{
|
{
|
||||||
b.Navigation("DicomStudyMonitorList");
|
b.Navigation("DicomStudyMonitorList");
|
||||||
|
|
||||||
|
b.Navigation("InstanceList");
|
||||||
|
|
||||||
b.Navigation("ReadingClinicalDataList");
|
b.Navigation("ReadingClinicalDataList");
|
||||||
|
|
||||||
b.Navigation("ReadingConsistentClinicalDataList");
|
b.Navigation("ReadingConsistentClinicalDataList");
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
<PackageReference Include="SharpCompress" Version="0.38.0" />
|
<PackageReference Include="SharpCompress" Version="0.38.0" />
|
||||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
||||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.4.6" />
|
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.7" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue