拉取影像
continuous-integration/drone/push Build is passing Details

Test_HIR_Net8
hang 2024-12-12 16:28:43 +08:00
parent 959fa1c40c
commit 39e7218b52
8 changed files with 18949 additions and 1 deletions

View File

@ -18251,5 +18251,22 @@
<param name="inQuery"></param> <param name="inQuery"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:IRaCIS.Application.Services.PatientService.GetCFindStudyList(IRaCIS.Application.Contracts.SCUQuery,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomAE},Microsoft.Extensions.Logging.ILogger{IRaCIS.Application.Services.PatientService})">
<summary>
获取 检查列表
</summary>
<param name="inQuery"></param>
<param name="_dicomAEReposiotry"></param>
<param name="_logger"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Application.Services.PatientService.CmoveStudyList(IRaCIS.Application.Contracts.SCUCmoveCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomAE})">
<summary>
拉取影像
</summary>
<param name="inCommand"></param>
<param name="_dicomAEReposiotry"></param>
<returns></returns>
</member>
</members> </members>
</doc> </doc>

View File

@ -48,6 +48,8 @@ namespace IRaCIS.Core.Application.ViewModel
public int Port { get; set; } public int Port { get; set; }
public string Modality { get; set; } = string.Empty; public string Modality { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty; public string Description { get; set; } = string.Empty;
public PacsType PacsTypeEnum { get; set; }
} }

View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace IRaCIS.Application.Contracts
{
public class SCUBasicInfo
{
public string? PatientID { get; set; }
public string? PatientName { get; set; }
public string? PatientSex { get; set; }
public string PatientBirthDate { get; set; }
public string? StudyID { get; set; }
public string? ModalitiesInStudy { get; set; }
public string? StudyDate { get; set; }
public string? StudyTime { get; set; }
public string? BodyPartExamined { get; set; }
public string? StudyDescription { get; set; }
public string? StudyInstanceUID { get; set; }
}
public class SCUQuery : SCUBasicInfo
{
[NotDefault]
public Guid PacsDicomAEId { get; set; }
}
public class SCUCmoveCommand
{
[NotDefault]
public Guid PacsDicomAEId { get; set; }
public List<string> StudyIDList { get; set; }
}
public class SCUStudyView : SCUBasicInfo
{
}
}

View File

@ -42,6 +42,10 @@ using IDistributedLockProvider = Medallion.Threading.IDistributedLockProvider;
using DocumentFormat.OpenXml.InkML; using DocumentFormat.OpenXml.InkML;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Infrastructure.Encryption; using IRaCIS.Core.Infrastructure.Encryption;
using FellowOakDicom.Network.Client;
using FellowOakDicom.Network;
using Microsoft.Extensions.Logging;
using DocumentFormat.OpenXml.Wordprocessing;
namespace IRaCIS.Application.Services namespace IRaCIS.Application.Services
{ {
@ -2694,6 +2698,8 @@ namespace IRaCIS.Application.Services
#endregion #endregion
#region 影像下载
/// <summary> /// <summary>
/// 获取下载的访视检查信息 /// 获取下载的访视检查信息
@ -2791,6 +2797,8 @@ namespace IRaCIS.Application.Services
return ResponseOutput.Ok(pageList); return ResponseOutput.Ok(pageList);
} }
#endregion
/// <summary> /// <summary>
/// scp 影像推送记录表 /// scp 影像推送记录表
@ -2817,7 +2825,154 @@ namespace IRaCIS.Application.Services
} }
#region 作为SCU C-find c-move 操作
#region 基础方法
public static DicomCFindRequest CreateStudyRequest(SCUQuery inQuery)
{
var request = new DicomCFindRequest(DicomQueryRetrieveLevel.Study);
// always add the encoding
request.Dataset.AddOrUpdate(new DicomTag(0x8, 0x5), "ISO_IR 100");
// add the dicom tags with empty values that should be included in the result of the QR Server
//病例号
request.Dataset.AddOrUpdate(DicomTag.PatientID, inQuery.PatientID.IsNullOrEmpty() ? "" : inQuery.PatientID);
request.Dataset.AddOrUpdate(DicomTag.PatientName, inQuery.PatientName.IsNullOrEmpty() ? "" : inQuery.PatientName);
request.Dataset.AddOrUpdate(DicomTag.PatientSex, inQuery.PatientSex.IsNullOrEmpty() ? "" : inQuery.PatientSex);
request.Dataset.AddOrUpdate(DicomTag.PatientBirthDate, inQuery.PatientBirthDate.IsNullOrEmpty() ? "" : inQuery.PatientBirthDate);
//检查号 设备类型
request.Dataset.AddOrUpdate(DicomTag.StudyID, inQuery.StudyID.IsNullOrEmpty() ? "" : inQuery.StudyID);
request.Dataset.AddOrUpdate(DicomTag.ModalitiesInStudy, inQuery.ModalitiesInStudy.IsNullOrEmpty() ? "" : inQuery.ModalitiesInStudy);
request.Dataset.AddOrUpdate(DicomTag.StudyDate, inQuery.StudyDate.IsNullOrEmpty() ? "" : inQuery.StudyDate);
request.Dataset.AddOrUpdate(DicomTag.StudyTime, inQuery.StudyTime.IsNullOrEmpty() ? "" : inQuery.StudyTime);
request.Dataset.AddOrUpdate(DicomTag.BodyPartExamined, inQuery.BodyPartExamined.IsNullOrEmpty() ? "" : inQuery.BodyPartExamined);
request.Dataset.AddOrUpdate(DicomTag.StudyDescription, inQuery.StudyDescription.IsNullOrEmpty() ? "" : inQuery.StudyDescription);
request.Dataset.AddOrUpdate(DicomTag.StudyInstanceUID, inQuery.StudyInstanceUID.IsNullOrEmpty() ? "" : inQuery.StudyInstanceUID);
// add the dicom tags that contain the filter criterias
return request;
}
public static void DebugStudyResponse(DicomCFindResponse response, ILogger _logger)
{
if (response.Status == DicomStatus.Pending)
{
// 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)} ");
}
if (response.Status == DicomStatus.Success)
{
Console.WriteLine(response.Status.ToString());
}
}
#endregion
/// <summary>
/// 获取 检查列表
/// </summary>
/// <param name="inQuery"></param>
/// <param name="_dicomAEReposiotry"></param>
/// <param name="_logger"></param>
/// <returns></returns>
public async Task<List<SCUStudyView>> GetCFindStudyList(SCUQuery inQuery,
[FromServices] IRepository<DicomAE> _dicomAEReposiotry,
[FromServices] ILogger<PatientService> _logger)
{
var result = new List<SCUStudyView>();
var find = await _dicomAEReposiotry.FirstOrDefaultAsync(t => t.Id == inQuery.PacsDicomAEId);
if (find != null)
{
var client = DicomClientFactory.Create(find.IP, find.Port, false, "HIRSCUAE", find.CalledAE);
client.NegotiateAsyncOps();
var request = CreateStudyRequest(inQuery);
request.OnResponseReceived += (req, response) =>
{
//DebugStudyResponse(response, _logger);
result.Add(new SCUStudyView()
{
PatientID = response.Dataset?.GetSingleValue<string>(DicomTag.PatientID),
PatientName = response.Dataset?.GetSingleValue<string>(DicomTag.PatientName),
PatientSex = response.Dataset?.GetSingleValue<string>(DicomTag.PatientSex),
PatientBirthDate = response.Dataset?.GetSingleValue<string>(DicomTag.PatientBirthDate),
StudyID = response.Dataset?.GetSingleValue<string>(DicomTag.StudyID),
ModalitiesInStudy = response.Dataset?.GetSingleValue<string>(DicomTag.ModalitiesInStudy),
StudyDate = response.Dataset?.GetSingleValue<string>(DicomTag.StudyDate),
StudyTime = response.Dataset?.GetSingleValue<string>(DicomTag.StudyTime),
BodyPartExamined = response.Dataset?.GetSingleValue<string>(DicomTag.BodyPartExamined),
StudyDescription = response.Dataset?.GetSingleValue<string>(DicomTag.StudyDescription),
StudyInstanceUID = response.Dataset?.GetSingleValue<string>(DicomTag.StudyInstanceUID)
});
};
await client.AddRequestAsync(request);
await client.SendAsync();
}
return result;
}
/// <summary>
/// 拉取影像
/// </summary>
/// <param name="inCommand"></param>
/// <param name="_dicomAEReposiotry"></param>
/// <returns></returns>
public async Task<IResponseOutput> CmoveStudyList(SCUCmoveCommand inCommand, [FromServices] IRepository<DicomAE> _dicomAEReposiotry)
{
var result = new List<SCUStudyView>();
var find = await _dicomAEReposiotry.FirstOrDefaultAsync(t => t.Id == inCommand.PacsDicomAEId);
var hirServer = await _dicomAEReposiotry.FirstOrDefaultAsync(t => t.PacsTypeEnum == PacsType.HIRServer);
if (hirServer == null)
{
return ResponseOutput.NotOk("未找到服务端AE配置请核查后再拉取");
}
if (find != null)
{
var client = DicomClientFactory.Create(find.IP, find.Port, false, "HIRSCUAE", find.CalledAE);
client.NegotiateAsyncOps();
var cmoveRequestList = new List<DicomCMoveRequest>();
foreach (var item in inCommand.StudyIDList)
{
cmoveRequestList.Add(new DicomCMoveRequest(hirServer.CalledAE, item));
}
await client.AddRequestsAsync(cmoveRequestList);
await client.SendAsync();
}
return ResponseOutput.Ok();
}
#endregion
} }

View File

@ -35,6 +35,18 @@ namespace IRaCIS.Core.Domain.Models
public bool IsTestOK { get; set; } public bool IsTestOK { get; set; }
public PacsType PacsTypeEnum { get; set; }
} }
public enum PacsType
{
HIRServer = 0,
//暂时不需要
HIRClient = 1,
PacsServer = 2,
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,51 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace IRaCIS.Core.Infra.EFCore.Migrations
{
/// <inheritdoc />
public partial class DicomAEAddField : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "PatientId",
table: "DicomStudy",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
comment: "废弃了用PatientIdStr",
oldClrType: typeof(string),
oldType: "nvarchar(400)",
oldMaxLength: 400);
migrationBuilder.AddColumn<int>(
name: "PacsTypeEnum",
table: "DicomAE",
type: "int",
nullable: false,
defaultValue: 0);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "PacsTypeEnum",
table: "DicomAE");
migrationBuilder.AlterColumn<string>(
name: "PatientId",
table: "DicomStudy",
type: "nvarchar(400)",
maxLength: 400,
nullable: false,
oldClrType: typeof(string),
oldType: "nvarchar(400)",
oldMaxLength: 400,
oldComment: "废弃了用PatientIdStr");
}
}
}

View File

@ -812,6 +812,9 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)");
b.Property<int>("PacsTypeEnum")
.HasColumnType("int");
b.Property<int>("Port") b.Property<int>("Port")
.HasColumnType("int"); .HasColumnType("int");
@ -1207,7 +1210,8 @@ namespace IRaCIS.Core.Infra.EFCore.Migrations
b.Property<string>("PatientId") b.Property<string>("PatientId")
.IsRequired() .IsRequired()
.HasMaxLength(400) .HasMaxLength(400)
.HasColumnType("nvarchar(400)"); .HasColumnType("nvarchar(400)")
.HasComment("废弃了用PatientIdStr");
b.Property<string>("PatientIdStr") b.Property<string>("PatientIdStr")
.IsRequired() .IsRequired()