拉取影像
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
959fa1c40c
commit
39e7218b52
|
@ -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>
|
||||||
|
|
|
@ -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; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
18651
IRaCIS.Core.Infra.EFCore/Migrations/20241212081432_DicomAEAddField.Designer.cs
generated
Normal file
18651
IRaCIS.Core.Infra.EFCore/Migrations/20241212081432_DicomAEAddField.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue