Merge branch 'Test_IRC_Net8' of https://gitea.frp.extimaging.com/XCKJ/irc-netcore-api into Test_IRC_Net8
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
commit
1e5f01fdeb
|
@ -0,0 +1,37 @@
|
|||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
|
||||
namespace IRaCIS.Core.SCP.Filter
|
||||
{
|
||||
|
||||
|
||||
public class ModelActionFilter : ActionFilterAttribute, IActionFilter
|
||||
{
|
||||
public IStringLocalizer _localizer;
|
||||
public ModelActionFilter(IStringLocalizer localizer)
|
||||
{
|
||||
_localizer = localizer;
|
||||
}
|
||||
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
if (!context.ModelState.IsValid)
|
||||
{
|
||||
|
||||
var validationErrors = context.ModelState
|
||||
.Keys
|
||||
.SelectMany(k => context.ModelState[k]!.Errors)
|
||||
.Select(e => e.ErrorMessage)
|
||||
.ToArray();
|
||||
|
||||
//---提供给接口的参数无效。
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ModelAction_InvalidAPIParameter"] + JsonConvert.SerializeObject( validationErrors)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
|
||||
namespace IRaCIS.Core.SCP.Filter
|
||||
{
|
||||
#region snippet_DisableFormValueModelBindingAttribute
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
|
||||
{
|
||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||
{
|
||||
|
||||
|
||||
var factories = context.ValueProviderFactories;
|
||||
//factories.RemoveType<FormValueProviderFactory>();
|
||||
factories.RemoveType<FormFileValueProviderFactory>();
|
||||
factories.RemoveType<JQueryFormValueProviderFactory>();
|
||||
context.HttpContext.Request.EnableBuffering();
|
||||
}
|
||||
|
||||
public void OnResourceExecuted(ResourceExecutedContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
using IRaCIS.Core.Infrastructure;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace IRaCIS.Core.SCP.Filter
|
||||
{
|
||||
public class ProjectExceptionFilter : Attribute, IExceptionFilter
|
||||
{
|
||||
private readonly ILogger<ProjectExceptionFilter> _logger;
|
||||
|
||||
public IStringLocalizer _localizer;
|
||||
|
||||
public ProjectExceptionFilter(IStringLocalizer localizer, ILogger<ProjectExceptionFilter> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
_localizer = localizer;
|
||||
}
|
||||
public void OnException(ExceptionContext context)
|
||||
{
|
||||
//context.ExceptionHandled;//记录当前这个异常是否已经被处理过了
|
||||
|
||||
if (!context.ExceptionHandled)
|
||||
{
|
||||
if (context.Exception.GetType().Name == "DbUpdateConcurrencyException")
|
||||
{
|
||||
//---并发更新,当前不允许该操作
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["ProjectException_ConcurrentUpdateNotAllowed"] + context.Exception.Message));
|
||||
}
|
||||
|
||||
if (context.Exception.GetType() == typeof(BusinessValidationFailedException))
|
||||
{
|
||||
var error = context.Exception as BusinessValidationFailedException;
|
||||
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(context.Exception.Message, error!.Code));
|
||||
}
|
||||
else if(context.Exception.GetType() == typeof(QueryBusinessObjectNotExistException))
|
||||
{
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk( context.Exception.Message, ApiResponseCodeEnum.DataNotExist));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Result = new JsonResult(ResponseOutput.NotOk(_localizer["Project_ExceptionContactDeveloper"] + (context.Exception.InnerException is null ? (context.Exception.Message /*+ context.Exception.StackTrace*/)
|
||||
: (context.Exception.InnerException?.Message /*+ context.Exception.InnerException?.StackTrace*/)), ApiResponseCodeEnum.ProgramException));
|
||||
}
|
||||
|
||||
|
||||
_logger.LogError(context.Exception.InnerException is null ? (context.Exception.Message + context.Exception.StackTrace) : (context.Exception.InnerException?.Message + context.Exception.InnerException?.StackTrace));
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//继续
|
||||
}
|
||||
context.ExceptionHandled = true;//标记当前异常已经被处理过了
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
||||
namespace IRaCIS.Application.Services.BusinessFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// 统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码
|
||||
/// by zhouhang 2021.09.12 周末
|
||||
/// </summary>
|
||||
public class UnifiedApiResultFilter : Attribute, IAsyncResultFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// 异步版本
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="next"></param>
|
||||
/// <returns></returns>
|
||||
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
|
||||
{
|
||||
|
||||
if (context.Result is ObjectResult objectResult)
|
||||
{
|
||||
var statusCode = objectResult.StatusCode ?? context.HttpContext.Response.StatusCode;
|
||||
|
||||
//是200 并且没有包装 那么包装结果
|
||||
if (statusCode == 200 && !(objectResult.Value is IResponseOutput))
|
||||
{
|
||||
//if (objectResult.Value == null)
|
||||
//{
|
||||
// var apiResponse = ResponseOutput.DBNotExist();
|
||||
|
||||
// objectResult.Value = apiResponse;
|
||||
// objectResult.DeclaredType = apiResponse.GetType();
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
|
||||
var type = objectResult.Value?.GetType();
|
||||
|
||||
|
||||
if ( type!=null&& type.IsGenericType&&(type.GetGenericTypeDefinition()==typeof(ValueTuple<,>)|| type.GetGenericTypeDefinition()==typeof(Tuple<,>)))
|
||||
{
|
||||
|
||||
//报错
|
||||
//var tuple = (object, object))objectResult.Value;
|
||||
|
||||
//var (val1, val2) = ((dynamic, dynamic))objectResult.Value;
|
||||
//var apiResponse = ResponseOutput.Ok(val1, val2);
|
||||
|
||||
//OK
|
||||
var tuple = (dynamic)objectResult.Value;
|
||||
var apiResponse = ResponseOutput.Ok(tuple.Item1, tuple.Item2);
|
||||
|
||||
|
||||
objectResult.Value = apiResponse;
|
||||
objectResult.DeclaredType = apiResponse.GetType();
|
||||
}
|
||||
else
|
||||
{
|
||||
var apiResponse = ResponseOutput.Ok(objectResult.Value);
|
||||
|
||||
objectResult.Value = apiResponse;
|
||||
objectResult.DeclaredType = apiResponse.GetType();
|
||||
}
|
||||
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
//如果不是200 是IResponseOutput 不处理
|
||||
else if (statusCode != 200 && (objectResult.Value is IResponseOutput))
|
||||
{
|
||||
}
|
||||
|
||||
else if(statusCode != 200&&!(objectResult.Value is IResponseOutput))
|
||||
{
|
||||
//---程序错误,请联系开发人员。
|
||||
var apiResponse = ResponseOutput.NotOk(StaticData.International("UnifiedAPI_ProgramError"));
|
||||
|
||||
objectResult.Value = apiResponse;
|
||||
objectResult.DeclaredType = apiResponse.GetType();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
await next.Invoke();
|
||||
|
||||
}
|
||||
|
||||
public static bool IsTupleType(Type type, bool checkBaseTypes = false)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
|
||||
if (type == typeof(Tuple))
|
||||
return true;
|
||||
|
||||
while (type != null)
|
||||
{
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
var genType = type.GetGenericTypeDefinition();
|
||||
if (genType == typeof(Tuple<>)
|
||||
|| genType == typeof(Tuple<,>)
|
||||
|| genType == typeof(Tuple<,>))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!checkBaseTypes)
|
||||
break;
|
||||
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
using FellowOakDicom.Imaging;
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
using SixLabors.ImageSharp;
|
||||
using SixLabors.ImageSharp.Processing;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace IRaCIS.Core.Application.Helper;
|
||||
|
||||
public static class ImageHelper
|
||||
{
|
||||
|
||||
// 采用ImageSharp组件 跨平台,不依赖windows 平台图像处理组件,这里大坑(net 6 下,之前由于Dicom处理最新组件 依赖了这个库的一个旧版本,导致缩略图bug,单独升级依赖组件才解决)
|
||||
public static void ResizeSave(string filePath, string? fileStorePath)
|
||||
{
|
||||
|
||||
fileStorePath = fileStorePath ?? filePath + ".preview.jpeg";
|
||||
|
||||
using (var image = SixLabors.ImageSharp.Image.Load(filePath))
|
||||
{
|
||||
|
||||
image.Mutate(x => x.Resize(500, 500));
|
||||
|
||||
image.Save(fileStorePath);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static Stream RenderPreviewJpeg(string filePath)
|
||||
{
|
||||
string jpegPath = filePath + ".preview.jpg";
|
||||
|
||||
if (!File.Exists(jpegPath))
|
||||
{
|
||||
using (Stream stream = new FileStream(jpegPath, FileMode.Create))
|
||||
{
|
||||
DicomImage image = new DicomImage(filePath);
|
||||
|
||||
var sharpimage = image.RenderImage().AsSharpImage();
|
||||
|
||||
sharpimage.Save(stream, new JpegEncoder());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return new FileStream(jpegPath, FileMode.Open);
|
||||
}
|
||||
|
||||
public static void RemovePreviewJpeg(string filePath)
|
||||
{
|
||||
string jpegPath = filePath + ".preview.jpg";
|
||||
if (File.Exists(jpegPath)) File.Delete(jpegPath);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
using Autofac;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Panda.DynamicWebApi;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Application.Services;
|
||||
using AutoMapper;
|
||||
using IRaCIS.Core.SCP.Service;
|
||||
|
||||
namespace IRaCIS.Core.SCP
|
||||
{
|
||||
// ReSharper disable once IdentifierTypo
|
||||
public class AutofacModuleSetup : Autofac.Module
|
||||
{
|
||||
protected override void Load(ContainerBuilder containerBuilder)
|
||||
{
|
||||
|
||||
#region byzhouhang 20210917 此处注册泛型仓储 可以减少Domain层 和Infra.EFcore 两层 空的仓储接口定义和 仓储文件定义
|
||||
|
||||
containerBuilder.RegisterGeneric(typeof(Repository<>))
|
||||
.As(typeof(IRepository<>)).InstancePerLifetimeScope();//注册泛型仓储
|
||||
|
||||
containerBuilder.RegisterType<Repository>().As<IRepository>().InstancePerLifetimeScope();
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 指定控制器也由autofac 来进行实例获取 https://www.cnblogs.com/xwhqwer/p/15320838.html
|
||||
|
||||
//获取所有控制器类型并使用属性注入
|
||||
containerBuilder.RegisterAssemblyTypes(typeof(BaseService).Assembly)
|
||||
.Where(type => typeof(IDynamicWebApi).IsAssignableFrom(type))
|
||||
.PropertiesAutowired();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
Assembly application = Assembly.LoadFrom(AppDomain.CurrentDomain.BaseDirectory + "IRaCIS.Core.SCP.dll");
|
||||
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
|
||||
.PropertiesAutowired().AsImplementedInterfaces();
|
||||
|
||||
|
||||
containerBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
|
||||
containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using IRaCIS.Core.Infra.EFCore;
|
||||
using Medallion.Threading;
|
||||
using Medallion.Threading.SqlServer;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace IRaCIS.Core.SCP
|
||||
{
|
||||
public static class EFSetup
|
||||
{
|
||||
public static void AddEFSetup( this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
//services.AddScoped<DbContext, IRaCISDBContext>();
|
||||
|
||||
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
|
||||
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
|
||||
services.AddDbContext<IRaCISDBContext>(options =>
|
||||
{
|
||||
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
|
||||
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
||||
|
||||
options.EnableSensitiveDataLogging();
|
||||
|
||||
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
|
||||
|
||||
options.UseProjectables();
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
//注意区分 easy caching 也有 IDistributedLockProvider
|
||||
services.AddSingleton<IDistributedLockProvider>(sp =>
|
||||
{
|
||||
//var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
|
||||
|
||||
return new SqlDistributedSynchronizationProvider(configuration.GetSection("ConnectionStrings:RemoteNew").Value);
|
||||
});
|
||||
|
||||
//services.AddAssemblyTriggers(typeof(SubjectVisitImageDateTrigger).Assembly);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System;
|
||||
|
||||
namespace IRaCIS.Core.SCP
|
||||
{
|
||||
public static class NewtonsoftJsonSetup
|
||||
{
|
||||
public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder, IServiceCollection services)
|
||||
{
|
||||
services.AddHttpContextAccessor();
|
||||
services.AddScoped<IOSSService,OSSService>();
|
||||
|
||||
builder.AddNewtonsoftJson(options =>
|
||||
{
|
||||
//options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
|
||||
// 忽略循环引用
|
||||
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
//options.SerializerSettings.TypeNameHandling = TypeNameHandling.All;
|
||||
|
||||
//处理返回给前端 可空类型 给出默认值 比如in? 为null 设置 默认值0
|
||||
options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); //new DefaultContractResolver();// new NullToEmptyStringResolver();
|
||||
// 设置时间格式
|
||||
options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind;
|
||||
|
||||
//options.SerializerSettings.Converters.Add(new JSONCustomDateConverter()) ;
|
||||
|
||||
//options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService<JSONTimeZoneConverter>());
|
||||
|
||||
|
||||
|
||||
})
|
||||
.AddControllersAsServices()//动态webApi属性注入需要
|
||||
.ConfigureApiBehaviorOptions(o =>
|
||||
{
|
||||
o.SuppressModelStateInvalidFilter = true; //自己写验证
|
||||
|
||||
});
|
||||
|
||||
|
||||
Newtonsoft.Json.JsonSerializerSettings setting = new Newtonsoft.Json.JsonSerializerSettings();
|
||||
JsonConvert.DefaultSettings = new Func<JsonSerializerSettings>(() =>
|
||||
{
|
||||
//日期类型默认格式化处理
|
||||
setting.DateFormatString = "yyyy-MM-dd HH:mm:ss";
|
||||
setting.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||
|
||||
return setting;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace IRaCIS.Core.SCP
|
||||
{
|
||||
public class NullToEmptyStringResolver : DefaultContractResolver
|
||||
{
|
||||
|
||||
|
||||
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||
{
|
||||
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
|
||||
|
||||
var list= type.GetProperties()
|
||||
.Select(p =>
|
||||
{
|
||||
var jp = base.CreateProperty(p, memberSerialization);
|
||||
jp.ValueProvider = new NullToEmptyStringValueProvider(p);
|
||||
return jp;
|
||||
}).ToList();
|
||||
|
||||
var uu = list.Select(t => t.PropertyName).ToList();
|
||||
|
||||
//获取复杂对象属性
|
||||
properties = properties.TakeWhile(t => !uu.Contains(t.PropertyName)).ToList();
|
||||
|
||||
list.AddRange(properties);
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace IRaCIS.Core.SCP
|
||||
{
|
||||
|
||||
public class NullToEmptyStringValueProvider : IValueProvider
|
||||
{
|
||||
PropertyInfo _MemberInfo;
|
||||
public NullToEmptyStringValueProvider(PropertyInfo memberInfo)
|
||||
{
|
||||
_MemberInfo = memberInfo;
|
||||
}
|
||||
public object GetValue(object target)
|
||||
{
|
||||
object result = _MemberInfo.GetValue(target);
|
||||
if (_MemberInfo.PropertyType == typeof(string) && result == null) result = "";
|
||||
else if (_MemberInfo.PropertyType == typeof(String[]) && result == null) result = new string[] { };
|
||||
//else if (_MemberInfo.PropertyType == typeof(Nullable<Int32>) && result == null) result = 0;
|
||||
else if (_MemberInfo.PropertyType == typeof(Nullable<Decimal>) && result == null) result = 0.00M;
|
||||
|
||||
return result;
|
||||
}
|
||||
public void SetValue(object target, object value)
|
||||
{
|
||||
|
||||
if(_MemberInfo.PropertyType == typeof(string))
|
||||
{
|
||||
//去掉前后空格
|
||||
_MemberInfo.SetValue(target, value==null?string.Empty: value.ToString()==string.Empty? value:value.ToString().Trim());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
_MemberInfo.SetValue(target, value);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.13.0" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
|
||||
<PackageReference Include="DistributedLock.Core" Version="1.0.6" />
|
||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.4" />
|
||||
<PackageReference Include="fo-dicom" Version="5.1.2" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.12.0" />
|
||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.1.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="Minio" Version="6.0.2" />
|
||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||
<TreatAsUsed>true</TreatAsUsed>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NewId" Version="4.0.1" />
|
||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.0.3" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IRaCIS.Core.Domain\IRaCIS.Core.Domain.csproj" />
|
||||
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,208 @@
|
|||
|
||||
using Autofac;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using AutoMapper.EquivalencyExpression;
|
||||
using FellowOakDicom;
|
||||
using FellowOakDicom.Imaging;
|
||||
using FellowOakDicom.Imaging.NativeCodec;
|
||||
using FellowOakDicom.Network;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.SCP;
|
||||
using IRaCIS.Core.SCP.Filter;
|
||||
using IRaCIS.Core.SCP.Service;
|
||||
using MassTransit;
|
||||
using MassTransit.NewIdProviders;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Panda.DynamicWebApi;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
//以配置文件为准,否则 从url中取环境值(服务以命令行传递参数启动,配置文件配置了就不需要传递环境参数)
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddEnvironmentVariables()
|
||||
.Build();
|
||||
|
||||
var enviromentName = config["ASPNETCORE_ENVIRONMENT"];
|
||||
|
||||
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
|
||||
{
|
||||
EnvironmentName = enviromentName
|
||||
});
|
||||
|
||||
#region 兼容windows 服务命令行的方式
|
||||
|
||||
int urlsIndex = Array.FindIndex(args, arg => arg != null && arg.StartsWith("--port"));
|
||||
|
||||
if (urlsIndex > -1)
|
||||
{
|
||||
var port = args[urlsIndex].Substring("--port=".Length);
|
||||
Console.WriteLine(port);
|
||||
builder.WebHost.UseUrls($"http://0.0.0.0:{port}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 主机配置
|
||||
|
||||
NewId.SetProcessIdProvider(new CurrentProcessIdProvider());
|
||||
|
||||
builder.Configuration.AddJsonFile("appsettings.json", false, true)
|
||||
.AddJsonFile($"appsettings.{enviromentName}.json", false, true);
|
||||
builder.Host
|
||||
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||||
.ConfigureContainer<ContainerBuilder>(containerBuilder =>
|
||||
{
|
||||
containerBuilder.RegisterModule<AutofacModuleSetup>();
|
||||
})
|
||||
.UseSerilog();
|
||||
#endregion
|
||||
|
||||
#region 配置服务
|
||||
var _configuration = builder.Configuration;
|
||||
|
||||
//健康检查
|
||||
builder.Services.AddHealthChecks();
|
||||
|
||||
//本地化
|
||||
builder.Services.AddJsonLocalization(options => options.ResourcesPath = "Resources");
|
||||
|
||||
|
||||
// 异常、参数统一验证过滤器、Json序列化配置、字符串参数绑型统一Trim()
|
||||
builder.Services.AddControllers(options =>
|
||||
{
|
||||
//options.Filters.Add<LogActionFilter>();
|
||||
options.Filters.Add<ModelActionFilter>();
|
||||
options.Filters.Add<ProjectExceptionFilter>();
|
||||
options.Filters.Add<UnitOfWorkFilter>();
|
||||
|
||||
|
||||
})
|
||||
.AddNewtonsoftJsonSetup(builder.Services); // NewtonsoftJson 序列化 处理
|
||||
|
||||
|
||||
builder.Services.AddOptions().Configure<AliyunOSSOptions>(_configuration.GetSection("AliyunOSS"));
|
||||
builder.Services.AddOptions().Configure<ObjectStoreServiceOptions>(_configuration.GetSection("ObjectStoreService"));
|
||||
builder.Services.AddOptions().Configure<DicomSCPServiceOption>(_configuration.GetSection("DicomSCPServiceConfig"));
|
||||
|
||||
|
||||
//动态WebApi + UnifiedApiResultFilter 省掉控制器代码
|
||||
//动态webApi 目前存在的唯一小坑是生成api上服务上的动态代理AOP失效 间接掉用不影响
|
||||
builder.Services
|
||||
.AddDynamicWebApi(dynamicWebApiOption =>
|
||||
{
|
||||
//默认是 api
|
||||
dynamicWebApiOption.DefaultApiPrefix = "";
|
||||
//首字母小写
|
||||
dynamicWebApiOption.GetRestFulActionName = (actionName) => char.ToLower(actionName[0]) + actionName.Substring(1);
|
||||
//删除 Service后缀
|
||||
dynamicWebApiOption.RemoveControllerPostfixes.Add("Service");
|
||||
|
||||
});
|
||||
|
||||
//AutoMapper
|
||||
builder.Services.AddAutoMapper(automapper =>
|
||||
{
|
||||
|
||||
automapper.AddCollectionMappers();
|
||||
|
||||
|
||||
}, typeof(BaseService).Assembly);
|
||||
|
||||
//EF ORM QueryWithNoLock
|
||||
builder.Services.AddEFSetup(_configuration);
|
||||
|
||||
|
||||
//转发头设置 获取真实IP
|
||||
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||||
{
|
||||
options.ForwardedHeaders =
|
||||
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||
});
|
||||
|
||||
//Dicom影像渲染图片 跨平台
|
||||
//builder.Services.AddDicomSetup();
|
||||
new DicomSetupBuilder()
|
||||
.RegisterServices(s =>
|
||||
s.AddFellowOakDicom()
|
||||
.AddTranscoderManager<NativeTranscoderManager>()
|
||||
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||
.AddImageManager<ImageSharpImageManager>())
|
||||
.SkipValidation()
|
||||
.Build();
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
// Add services to the container.
|
||||
|
||||
builder.Services.AddControllers();
|
||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
//if (app.Environment.IsDevelopment())
|
||||
//{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
//}
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
#region 日志
|
||||
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Information()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||
// Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Hangfire", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("System.Net.Http.HttpClient.HttpReports", LogEventLevel.Warning)
|
||||
.Enrich.WithClientIp()
|
||||
|
||||
.Enrich.FromLogContext()
|
||||
|
||||
//控制台 方便调试 问题 我们显示记录日志 时 获取上下文的ip 和用户名 用户类型
|
||||
.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Warning,
|
||||
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext:l} || {Message} || {Exception} ||end {NewLine}")
|
||||
|
||||
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,
|
||||
outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {SourceContext:l} || {Message} || {Exception} ||end {NewLine}")
|
||||
.CreateLogger();
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region 运行环境 部署平台
|
||||
|
||||
Log.Logger.Warning($"当前环境:{enviromentName}");
|
||||
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
Log.Logger.Warning($"当前部署平台环境:windows");
|
||||
}
|
||||
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
{
|
||||
Log.Logger.Warning($"当前部署平台环境:linux");
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Logger.Warning($"当前部署平台环境:OSX or FreeBSD");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
var server = DicomServerFactory.Create<CStoreSCPService>(_configuration.GetSection("DicomSCPServiceConfig").GetValue<int>("ServerPort"), userState: app.Services);
|
||||
|
||||
|
||||
app.Run();
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:36358",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5243",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
using AutoMapper;
|
||||
using IRaCIS.Application.Services.BusinessFilter;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Panda.DynamicWebApi;
|
||||
using Panda.DynamicWebApi.Attributes;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
|
||||
namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
|
||||
#pragma warning disable CS8618
|
||||
|
||||
|
||||
#region 非泛型版本
|
||||
|
||||
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
|
||||
public class BaseService : IBaseService, IDynamicWebApi
|
||||
{
|
||||
public IMapper _mapper { get; set; }
|
||||
|
||||
public IUserInfo _userInfo { get; set; }
|
||||
|
||||
public IRepository _repository { get; set; }
|
||||
|
||||
public IStringLocalizer _localizer { get; set; }
|
||||
|
||||
public IWebHostEnvironment _hostEnvironment { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
||||
{
|
||||
return new ResponseOutput<string>()
|
||||
.NotOk($"The query object {typeof(TEntity).Name} does not exist , or was deleted by someone else, or an incorrect parameter query caused", code: ApiResponseCodeEnum.DataNotExist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface IBaseService
|
||||
{
|
||||
[MemberNotNull(nameof(_mapper))]
|
||||
public IMapper _mapper { get; set; }
|
||||
|
||||
[MemberNotNull(nameof(_userInfo))]
|
||||
public IUserInfo _userInfo { get; set; }
|
||||
|
||||
[MemberNotNull(nameof(_repository))]
|
||||
public IRepository _repository { get; set; }
|
||||
|
||||
[MemberNotNull(nameof(_localizer))]
|
||||
public IStringLocalizer _localizer { get; set; }
|
||||
|
||||
[MemberNotNull(nameof(_hostEnvironment))]
|
||||
public IWebHostEnvironment _hostEnvironment { get; set; }
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region 泛型版本测试
|
||||
|
||||
|
||||
public interface IBaseServiceTest<T> where T : Entity
|
||||
{
|
||||
[MemberNotNull(nameof(_mapper))]
|
||||
public IMapper _mapper { get; set; }
|
||||
|
||||
[MemberNotNull(nameof(_userInfo))]
|
||||
public IUserInfo _userInfo { get; set; }
|
||||
|
||||
[MemberNotNull(nameof(_repository))]
|
||||
public IRepository _repository { get; set; }
|
||||
|
||||
[MemberNotNull(nameof(_localizer))]
|
||||
public IStringLocalizer _localizer { get; set; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
[Authorize, DynamicWebApi, UnifiedApiResultFilter]
|
||||
public class BaseServiceTest<T> : IBaseServiceTest<T>, IDynamicWebApi where T : Entity
|
||||
{
|
||||
public IMapper _mapper { get; set; }
|
||||
|
||||
public IUserInfo _userInfo { get; set; }
|
||||
|
||||
public IRepository _repository { get; set; }
|
||||
|
||||
public IStringLocalizer _localizer { get; set; }
|
||||
|
||||
public static IResponseOutput Null404NotFound<TEntity>(TEntity? businessObject) where TEntity : class
|
||||
{
|
||||
return new ResponseOutput<string>()
|
||||
.NotOk($"The query object {typeof(TEntity).Name} does not exist , or was deleted by someone else, or an incorrect parameter query caused", code: ApiResponseCodeEnum.DataNotExist);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,358 @@
|
|||
using FellowOakDicom.Network;
|
||||
using FellowOakDicom;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using IRaCIS.Core.SCP.Service;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using Medallion.Threading;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using Serilog;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Data;
|
||||
using FellowOakDicom.Imaging;
|
||||
using SharpCompress.Common;
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
|
||||
namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
|
||||
public class DicomSCPServiceOption
|
||||
{
|
||||
public List<string> CalledAEList { get; set; }
|
||||
|
||||
public string ServerPort { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public class CStoreSCPService : DicomService, IDicomServiceProvider, IDicomCStoreProvider, IDicomCEchoProvider
|
||||
{
|
||||
private IServiceProvider _serviceProvider { get; set; }
|
||||
|
||||
private List<Guid> _SCPStudyIdList { get; set; } = new List<Guid>();
|
||||
|
||||
private SCPImageUpload _upload { get; set; }
|
||||
|
||||
private Guid _trialId { get; set; }
|
||||
|
||||
private Guid _trialSiteId { get; set; }
|
||||
|
||||
|
||||
|
||||
private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]
|
||||
{
|
||||
DicomTransferSyntax.ExplicitVRLittleEndian,
|
||||
DicomTransferSyntax.ExplicitVRBigEndian,
|
||||
DicomTransferSyntax.ImplicitVRLittleEndian
|
||||
};
|
||||
|
||||
private static readonly DicomTransferSyntax[] _acceptedImageTransferSyntaxes = new DicomTransferSyntax[]
|
||||
{
|
||||
// Lossless
|
||||
DicomTransferSyntax.JPEGLSLossless,
|
||||
DicomTransferSyntax.JPEG2000Lossless,
|
||||
DicomTransferSyntax.JPEGProcess14SV1,
|
||||
DicomTransferSyntax.JPEGProcess14,
|
||||
DicomTransferSyntax.RLELossless,
|
||||
// Lossy
|
||||
DicomTransferSyntax.JPEGLSNearLossless,
|
||||
DicomTransferSyntax.JPEG2000Lossy,
|
||||
DicomTransferSyntax.JPEGProcess1,
|
||||
DicomTransferSyntax.JPEGProcess2_4,
|
||||
// Uncompressed
|
||||
DicomTransferSyntax.ExplicitVRLittleEndian,
|
||||
DicomTransferSyntax.ExplicitVRBigEndian,
|
||||
DicomTransferSyntax.ImplicitVRLittleEndian
|
||||
};
|
||||
|
||||
|
||||
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies)
|
||||
: base(stream, fallbackEncoding, log, dependencies)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public Task OnReceiveAssociationRequestAsync(DicomAssociation association)
|
||||
{
|
||||
|
||||
_upload = new SCPImageUpload() { StartTime = DateTime.Now, CallingAE = association.CallingAE, CalledAE = association.CalledAE, CallingAEIP = association.RemoteHost };
|
||||
|
||||
|
||||
Log.Logger.Warning($"接收到来自{association.CallingAE}的连接");
|
||||
|
||||
_serviceProvider = (IServiceProvider)this.UserState;
|
||||
|
||||
|
||||
|
||||
var _trialDicomAERepository = _serviceProvider.GetService<IRepository<TrialDicomAE>>();
|
||||
|
||||
|
||||
var trialDicomAEList = _trialDicomAERepository.Select(t => new { t.CalledAE, t.TrialId }).ToList();
|
||||
var trialCalledAEList = trialDicomAEList.Select(t => t.CalledAE).ToList();
|
||||
|
||||
var findCalledAE = trialDicomAEList.Where(t => t.CalledAE == association.CalledAE).FirstOrDefault();
|
||||
|
||||
var isCanReceiveIamge = false;
|
||||
|
||||
if (findCalledAE!=null)
|
||||
{
|
||||
_trialId = findCalledAE.TrialId;
|
||||
|
||||
var _trialSiteDicomAERepository = _serviceProvider.GetService<IRepository<TrialSiteDicomAE>>();
|
||||
|
||||
|
||||
var findTrialSiteAE = _trialSiteDicomAERepository.Where(t=>t.CallingAE==association.CallingAE ).FirstOrDefault();
|
||||
|
||||
if (findTrialSiteAE!=null)
|
||||
{
|
||||
_trialSiteId= findTrialSiteAE.TrialSiteId;
|
||||
|
||||
isCanReceiveIamge = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!trialCalledAEList.Contains(association.CalledAE) || isCanReceiveIamge==false)
|
||||
{
|
||||
|
||||
Log.Logger.Warning($"拒绝CalledAE:{association.CalledAE}的连接");
|
||||
|
||||
return SendAssociationRejectAsync(
|
||||
DicomRejectResult.Permanent,
|
||||
DicomRejectSource.ServiceUser,
|
||||
DicomRejectReason.CalledAENotRecognized);
|
||||
}
|
||||
|
||||
foreach (var pc in association.PresentationContexts)
|
||||
{
|
||||
if (pc.AbstractSyntax == DicomUID.Verification)
|
||||
{
|
||||
pc.AcceptTransferSyntaxes(_acceptedTransferSyntaxes);
|
||||
}
|
||||
else if (pc.AbstractSyntax.StorageCategory != DicomStorageCategory.None)
|
||||
{
|
||||
pc.AcceptTransferSyntaxes(_acceptedImageTransferSyntaxes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return SendAssociationAcceptAsync(association);
|
||||
}
|
||||
|
||||
|
||||
public async Task OnReceiveAssociationReleaseRequestAsync()
|
||||
{
|
||||
await DataMaintenanceAsaync();
|
||||
|
||||
//记录监控
|
||||
|
||||
var _SCPImageUploadRepository = _serviceProvider.GetService<IRepository<SCPImageUpload>>();
|
||||
|
||||
_upload.EndTime = DateTime.Now;
|
||||
_upload.StudyCount = _SCPStudyIdList.Count;
|
||||
|
||||
await _SCPImageUploadRepository.AddAsync(_upload, true);
|
||||
|
||||
await SendAssociationReleaseResponseAsync();
|
||||
}
|
||||
|
||||
|
||||
private async Task DataMaintenanceAsaync()
|
||||
{
|
||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}传输结束:开始维护数据,处理检查Modality");
|
||||
|
||||
|
||||
|
||||
//处理检查Modality
|
||||
var _dictionaryRepository = _serviceProvider.GetService<IRepository<Dictionary>>();
|
||||
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
|
||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||
|
||||
var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList();
|
||||
var seriesModalityList = _seriesRepository.Where(t => _SCPStudyIdList.Contains(t.StudyId)).Select(t => new { SCPStudyId = t.StudyId, t.Modality }).ToList();
|
||||
|
||||
foreach (var g in seriesModalityList.GroupBy(t => t.SCPStudyId))
|
||||
{
|
||||
var modality = string.Join('、', g.Select(t => t.Modality).Distinct().ToList());
|
||||
|
||||
//特殊逻辑
|
||||
var modalityForEdit = dicModalityList.Contains(modality) ? modality : String.Empty;
|
||||
|
||||
if (modality == "MR")
|
||||
{
|
||||
modalityForEdit = "MRI";
|
||||
}
|
||||
|
||||
if (modality == "PT")
|
||||
{
|
||||
modalityForEdit = "PET";
|
||||
}
|
||||
if (modality == "PT、CT" || modality == "CT、PT")
|
||||
{
|
||||
modalityForEdit = "PET-CT";
|
||||
}
|
||||
|
||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == g.Key, u => new SCPStudy() { Modalities = modality, ModalityForEdit = modalityForEdit });
|
||||
|
||||
}
|
||||
|
||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}维护数据结束");
|
||||
}
|
||||
|
||||
public void OnReceiveAbort(DicomAbortSource source, DicomAbortReason reason)
|
||||
{
|
||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE}接收中断,中断原因:{source.ToString() + reason.ToString()}");
|
||||
/* nothing to do here */
|
||||
}
|
||||
|
||||
|
||||
public async void OnConnectionClosed(Exception exception)
|
||||
{
|
||||
/* nothing to do here */
|
||||
|
||||
//奇怪的bug 上传的时候,用王捷修改的影像,会关闭,重新连接,导致检查id 丢失,然后状态不一致
|
||||
if (exception == null)
|
||||
{
|
||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||
//将检查设置为传输结束
|
||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||
|
||||
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||
}
|
||||
|
||||
Log.Logger.Warning($"连接关闭 {exception?.Message} {exception?.InnerException?.Message}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
|
||||
{
|
||||
|
||||
string studyInstanceUid = request.Dataset.GetString(DicomTag.StudyInstanceUID);
|
||||
string seriesInstanceUid = request.Dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||
string sopInstanceUid = request.Dataset.GetString(DicomTag.SOPInstanceUID);
|
||||
|
||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid);
|
||||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid);
|
||||
|
||||
|
||||
var ossService = _serviceProvider.GetService<IOSSService>();
|
||||
var dicomArchiveService = _serviceProvider.GetService<IDicomArchiveService>();
|
||||
var _seriesRepository = _serviceProvider.GetService<IRepository<SCPSeries>>();
|
||||
|
||||
var _distributedLockProvider = _serviceProvider.GetService<IDistributedLockProvider>();
|
||||
|
||||
var storeRelativePath = string.Empty;
|
||||
var ossFolderPath = $"{_trialId}/Image/PACS/{_trialSiteId}{studyInstanceUid}";
|
||||
|
||||
|
||||
long fileSize = 0;
|
||||
try
|
||||
{
|
||||
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
await request.File.SaveAsync(ms);
|
||||
|
||||
//irc 从路径最后一截取Guid
|
||||
storeRelativePath = await ossService.UploadToOSSAsync(ms, ossFolderPath, instanceId.ToString(), false);
|
||||
|
||||
fileSize = ms.Length;
|
||||
}
|
||||
|
||||
Log.Logger.Information($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} {request.SOPInstanceUID} 上传完成 ");
|
||||
|
||||
}
|
||||
catch (Exception ec)
|
||||
{
|
||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 上传异常 {ec.Message}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
|
||||
|
||||
using (await @lock.AcquireAsync())
|
||||
{
|
||||
try
|
||||
{
|
||||
var scpStudyId = await dicomArchiveService.ArchiveDicomFileAsync(request.Dataset,_trialId,_trialSiteId, storeRelativePath, Association.CallingAE, Association.CalledAE);
|
||||
|
||||
if (!_SCPStudyIdList.Contains(scpStudyId))
|
||||
{
|
||||
_SCPStudyIdList.Add(scpStudyId);
|
||||
}
|
||||
|
||||
var series = await _seriesRepository.FindAsync(seriesId);
|
||||
|
||||
//没有缩略图
|
||||
if (series != null && string.IsNullOrEmpty(series.ImageResizePath))
|
||||
{
|
||||
|
||||
// 生成缩略图
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
DicomImage image = new DicomImage(request.Dataset);
|
||||
|
||||
var sharpimage = image.RenderImage().AsSharpImage();
|
||||
sharpimage.Save(memoryStream, new JpegEncoder());
|
||||
|
||||
// 上传缩略图到 OSS
|
||||
|
||||
var seriesPath = await ossService.UploadToOSSAsync(memoryStream, ossFolderPath, seriesId.ToString() + ".preview.jpg", false);
|
||||
|
||||
Console.WriteLine(seriesPath + " Id: " + seriesId);
|
||||
|
||||
series.ImageResizePath = seriesPath;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
await _seriesRepository.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
Log.Logger.Warning($"CallingAE:{Association.CallingAE} CalledAE:{Association.CalledAE} 传输处理异常:{ex.ToString()}");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//监控信息设置
|
||||
_upload.FileCount++;
|
||||
_upload.FileSize = _upload.FileSize + fileSize;
|
||||
return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||
}
|
||||
|
||||
|
||||
public Task OnCStoreRequestExceptionAsync(string tempFileName, Exception e)
|
||||
{
|
||||
// let library handle logging and error response
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public Task<DicomCEchoResponse> OnCEchoRequestAsync(DicomCEchoRequest request)
|
||||
{
|
||||
return Task.FromResult(new DicomCEchoResponse(request, DicomStatus.Success));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,337 @@
|
|||
using IRaCIS.Core.Domain.Share;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using Medallion.Threading;
|
||||
using FellowOakDicom;
|
||||
using FellowOakDicom.Imaging.Codec;
|
||||
using System.Data;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using FellowOakDicom.Network;
|
||||
using IRaCIS.Core.SCP.Service;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using MassTransit;
|
||||
|
||||
namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
public class DicomArchiveService : BaseService, IDicomArchiveService
|
||||
{
|
||||
private readonly IRepository<SCPPatient> _patientRepository;
|
||||
private readonly IRepository<SCPStudy> _studyRepository;
|
||||
private readonly IRepository<SCPSeries> _seriesRepository;
|
||||
private readonly IRepository<SCPInstance> _instanceRepository;
|
||||
private readonly IRepository<Dictionary> _dictionaryRepository;
|
||||
private readonly IDistributedLockProvider _distributedLockProvider;
|
||||
|
||||
|
||||
private List<Guid> _instanceIdList = new List<Guid>();
|
||||
|
||||
public DicomArchiveService(IRepository<SCPPatient> patientRepository, IRepository<SCPStudy> studyRepository,
|
||||
IRepository<SCPSeries> seriesRepository,
|
||||
IRepository<SCPInstance> instanceRepository,
|
||||
IRepository<Dictionary> dictionaryRepository,
|
||||
IDistributedLockProvider distributedLockProvider)
|
||||
{
|
||||
_distributedLockProvider = distributedLockProvider;
|
||||
_studyRepository = studyRepository;
|
||||
_patientRepository = patientRepository;
|
||||
_seriesRepository = seriesRepository;
|
||||
_instanceRepository = instanceRepository;
|
||||
_dictionaryRepository = dictionaryRepository;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 单个文件接收 归档
|
||||
/// </summary>
|
||||
/// <param name="dataset"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="NotImplementedException"></exception>
|
||||
public async Task<Guid> ArchiveDicomFileAsync(DicomDataset dataset, Guid trialId, Guid trialSiteId, string fileRelativePath, string callingAE, string calledAE)
|
||||
{
|
||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||||
|
||||
string patientIdStr = dataset.GetString(DicomTag.PatientID);
|
||||
|
||||
//Guid patientId= IdentifierHelper.CreateGuid(patientIdStr);
|
||||
Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid,trialId.ToString());
|
||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, trialId.ToString());
|
||||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, trialId.ToString());
|
||||
|
||||
var isStudyNeedAdd = false;
|
||||
var isSeriesNeedAdd = false;
|
||||
var isInstanceNeedAdd = false;
|
||||
var isPatientNeedAdd = false;
|
||||
|
||||
//var @lock = _distributedLockProvider.CreateLock($"{studyInstanceUid}");
|
||||
|
||||
//using (@lock.Acquire())
|
||||
{
|
||||
var findPatient = await _patientRepository.FirstOrDefaultAsync(t => t.PatientIdStr == patientIdStr);
|
||||
var findStudy = await _studyRepository.FindAsync(studyId);
|
||||
var findSerice = await _seriesRepository.FindAsync(seriesId);
|
||||
var findInstance = await _instanceRepository.FindAsync(instanceId);
|
||||
|
||||
DateTime? studyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty) == string.Empty ? null : dataset.GetSingleValue<DateTime>(DicomTag.StudyDate).Add(dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty) == string.Empty ? TimeSpan.Zero : dataset.GetSingleValue<DateTime>(DicomTag.StudyTime).TimeOfDay);
|
||||
|
||||
//先传输了修改了患者编号的,又传输了没有修改患者编号的,导致后传输的没有修改患者编号的下面的检查为0
|
||||
if (findPatient == null && findStudy==null)
|
||||
{
|
||||
isPatientNeedAdd = true;
|
||||
|
||||
|
||||
findPatient = new SCPPatient()
|
||||
{
|
||||
Id = NewId.NextSequentialGuid(),
|
||||
TrialId=trialId,
|
||||
TrialSiteId=trialSiteId,
|
||||
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||||
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||||
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
||||
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
|
||||
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
|
||||
|
||||
EarliestStudyTime = studyTime,
|
||||
LatestStudyTime = studyTime,
|
||||
LatestPushTime = DateTime.Now,
|
||||
};
|
||||
|
||||
if (findPatient.PatientBirthDate.Length == 8)
|
||||
{
|
||||
var birthDateStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}-{findPatient.PatientBirthDate[4]}{findPatient.PatientBirthDate[5]}-{findPatient.PatientBirthDate[6]}{findPatient.PatientBirthDate[7]}";
|
||||
|
||||
var yearStr = $"{findPatient.PatientBirthDate[0]}{findPatient.PatientBirthDate[1]}{findPatient.PatientBirthDate[2]}{findPatient.PatientBirthDate[3]}";
|
||||
|
||||
int year = 0;
|
||||
|
||||
var canParse = int.TryParse(yearStr, out year);
|
||||
|
||||
if (canParse && year > 1900)
|
||||
{
|
||||
findPatient.PatientBirthDate = birthDateStr;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
findPatient.PatientBirthDate = string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (studyTime < findPatient.EarliestStudyTime)
|
||||
{
|
||||
findPatient.EarliestStudyTime = studyTime;
|
||||
}
|
||||
if (studyTime > findPatient.LatestStudyTime)
|
||||
{
|
||||
findPatient.LatestStudyTime = studyTime;
|
||||
}
|
||||
|
||||
findPatient.LatestPushTime = DateTime.Now;
|
||||
}
|
||||
|
||||
if (findStudy == null)
|
||||
{
|
||||
isStudyNeedAdd = true;
|
||||
findStudy = new SCPStudy
|
||||
{
|
||||
CalledAE = calledAE,
|
||||
CallingAE = callingAE,
|
||||
|
||||
PatientId = findPatient.Id,
|
||||
Id = studyId,
|
||||
TrialId = trialId,
|
||||
TrialSiteId = trialSiteId,
|
||||
StudyInstanceUid = studyInstanceUid,
|
||||
StudyTime = studyTime,
|
||||
Modalities = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
//ModalityForEdit = modalityForEdit,
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||
InstitutionName = dataset.GetSingleValueOrDefault(DicomTag.InstitutionName, string.Empty),
|
||||
PatientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||||
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||||
PatientAge = dataset.GetSingleValueOrDefault(DicomTag.PatientAge, string.Empty),
|
||||
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
|
||||
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
|
||||
|
||||
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
|
||||
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
|
||||
|
||||
//需要特殊处理
|
||||
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
|
||||
|
||||
|
||||
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
|
||||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
||||
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
|
||||
|
||||
|
||||
|
||||
//IsDoubleReview = addtionalInfo.IsDoubleReview,
|
||||
SeriesCount = 0,
|
||||
InstanceCount = 0
|
||||
};
|
||||
|
||||
|
||||
if (findStudy.PatientBirthDate.Length == 8)
|
||||
{
|
||||
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]}";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (findSerice == null)
|
||||
{
|
||||
isSeriesNeedAdd = true;
|
||||
|
||||
findSerice = new SCPSeries
|
||||
{
|
||||
Id = seriesId,
|
||||
StudyId = findStudy.Id,
|
||||
|
||||
StudyInstanceUid = findStudy.StudyInstanceUid,
|
||||
SeriesInstanceUid = seriesInstanceUid,
|
||||
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
|
||||
//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 = 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),
|
||||
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
Description = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||
|
||||
ImagePositionPatient = dataset.GetSingleValueOrDefault(DicomTag.ImagePositionPatient, string.Empty),
|
||||
ImageOrientationPatient = dataset.GetSingleValueOrDefault(DicomTag.ImageOrientationPatient, string.Empty),
|
||||
BodyPartExamined = dataset.GetSingleValueOrDefault(DicomTag.BodyPartExamined, string.Empty),
|
||||
SequenceName = dataset.GetSingleValueOrDefault(DicomTag.SequenceName, string.Empty),
|
||||
ProtocolName = dataset.GetSingleValueOrDefault(DicomTag.ProtocolName, string.Empty),
|
||||
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||
|
||||
AcquisitionTime = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionTime, string.Empty),
|
||||
AcquisitionNumber = dataset.GetSingleValueOrDefault(DicomTag.AcquisitionNumber, string.Empty),
|
||||
TriggerTime = dataset.GetSingleValueOrDefault(DicomTag.TriggerTime, string.Empty),
|
||||
|
||||
|
||||
InstanceCount = 0
|
||||
};
|
||||
|
||||
++findStudy.SeriesCount;
|
||||
}
|
||||
|
||||
|
||||
if (findInstance == null)
|
||||
{
|
||||
isInstanceNeedAdd = true;
|
||||
findInstance = new SCPInstance
|
||||
{
|
||||
Id = instanceId,
|
||||
StudyId = findStudy.Id,
|
||||
SeriesId = findSerice.Id,
|
||||
StudyInstanceUid = findStudy.StudyInstanceUid,
|
||||
SeriesInstanceUid = findSerice.SeriesInstanceUid,
|
||||
|
||||
SopInstanceUid = sopInstanceUid,
|
||||
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 = DateTime.TryParse(dataset.GetSingleValue<string>(DicomTag.ContentDate) + dataset.GetSingleValue<string>(DicomTag.ContentTime), out DateTime dt) ? dt : null,
|
||||
//InstanceTime = dataset.GetSingleValueOrDefault(DicomTag.ContentDate,(DateTime?)null)?.Add(dataset.GetSingleValueOrDefault(DicomTag.ContentTime, TimeSpan.Zero)),
|
||||
//dataset.GetSingleValueOrDefault(DicomTag.ContentDate,DateTime.Now);//, DicomTag.ContentTime)
|
||||
CPIStatus = false,
|
||||
ImageRows = dataset.GetSingleValueOrDefault(DicomTag.Rows, 0),
|
||||
ImageColumns = dataset.GetSingleValueOrDefault(DicomTag.Columns, 0),
|
||||
SliceLocation = dataset.GetSingleValueOrDefault(DicomTag.SliceLocation, 0),
|
||||
|
||||
SliceThickness = dataset.GetSingleValueOrDefault(DicomTag.SliceThickness, string.Empty),
|
||||
NumberOfFrames = dataset.GetSingleValueOrDefault(DicomTag.NumberOfFrames, 0),
|
||||
PixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.PixelSpacing, string.Empty),
|
||||
ImagerPixelSpacing = dataset.GetSingleValueOrDefault(DicomTag.ImagerPixelSpacing, string.Empty),
|
||||
FrameOfReferenceUID = dataset.GetSingleValueOrDefault(DicomTag.FrameOfReferenceUID, string.Empty),
|
||||
WindowCenter = dataset.GetSingleValueOrDefault(DicomTag.WindowCenter, string.Empty),
|
||||
WindowWidth = dataset.GetSingleValueOrDefault(DicomTag.WindowWidth, string.Empty),
|
||||
|
||||
Path = fileRelativePath
|
||||
};
|
||||
|
||||
++findStudy.InstanceCount;
|
||||
++findSerice.InstanceCount;
|
||||
}
|
||||
|
||||
if (isPatientNeedAdd)
|
||||
{
|
||||
var ss = await _patientRepository.AddAsync(findPatient);
|
||||
}
|
||||
if (isStudyNeedAdd)
|
||||
{
|
||||
var dd = await _studyRepository.AddAsync(findStudy);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == findStudy.Id, t => new SCPStudy() { IsUploadFinished = false });
|
||||
}
|
||||
|
||||
if (isSeriesNeedAdd)
|
||||
{
|
||||
await _seriesRepository.AddAsync(findSerice);
|
||||
}
|
||||
if (isInstanceNeedAdd)
|
||||
{
|
||||
await _instanceRepository.AddAsync(findInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == instanceId, u => new SCPInstance() { Path = fileRelativePath });
|
||||
}
|
||||
|
||||
//await _studyRepository.SaveChangesAsync();
|
||||
|
||||
return findStudy.Id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 从DICOM文件中获取使用的字符集
|
||||
private string GetEncodingVaulueFromDicomFile(DicomDataset dataset, DicomTag dicomTag)
|
||||
{
|
||||
|
||||
// 获取DICOM文件的特定元素,通常用于指示使用的字符集
|
||||
var charset = dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
|
||||
|
||||
var dicomEncoding = DicomEncoding.GetEncoding(charset);
|
||||
|
||||
|
||||
var dicomStringElement = dataset.GetDicomItem<DicomStringElement>(dicomTag);
|
||||
|
||||
var bytes = dicomStringElement.Buffer.Data;
|
||||
|
||||
|
||||
return dicomEncoding.GetString(bytes);
|
||||
|
||||
|
||||
//// 从DICOM文件中获取使用的字符集
|
||||
//string filePath = "C:\\Users\\hang\\Documents\\WeChat Files\\wxid_r2imdzb7j3q922\\FileStorage\\File\\2024-05\\1.2.840.113619.2.80.169103990.5390.1271401378.4.dcm";
|
||||
//DicomFile dicomFile = DicomFile.Open(filePath);
|
||||
|
||||
//// 获取DICOM文件的特定元素,通常用于指示使用的字符集
|
||||
//var charset = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.SpecificCharacterSet, string.Empty);
|
||||
|
||||
//var dicomEncoding = DicomEncoding.GetEncoding(charset);
|
||||
|
||||
//var value = dicomFile.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty);
|
||||
|
||||
//var dicomStringElement = dicomFile.Dataset.GetDicomItem<DicomStringElement>(DicomTag.PatientName);
|
||||
|
||||
//var bytes = dicomStringElement.Buffer.Data;
|
||||
|
||||
//var aa= dicomEncoding.GetString(bytes);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
using FellowOakDicom;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
|
||||
|
||||
namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
public interface IDicomArchiveService
|
||||
{
|
||||
Task<Guid> ArchiveDicomFileAsync(DicomDataset dicomDataset,Guid trialId,Guid trialSiteId, string fileRelativePath,string callingAE,string calledAE);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,427 @@
|
|||
using Aliyun.OSS;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Minio.DataModel.Args;
|
||||
using Minio;
|
||||
using SharpCompress.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.AccessControl;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IRaCIS.Core.SCP
|
||||
{
|
||||
public class MinIOOptions : AWSOptions
|
||||
{
|
||||
public int port { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class AWSOptions
|
||||
{
|
||||
public string endPoint { get; set; }
|
||||
public bool useSSL { get; set; }
|
||||
public string accessKey { get; set; }
|
||||
public string secretKey { get; set; }
|
||||
public string bucketName { get; set; }
|
||||
public string viewEndpoint { get; set; }
|
||||
}
|
||||
|
||||
public class AliyunOSSOptions
|
||||
{
|
||||
public string regionId { get; set; }
|
||||
public string accessKeyId { get; set; }
|
||||
public string accessKeySecret { get; set; }
|
||||
public string endPoint { get; set; }
|
||||
public string bucketName { get; set; }
|
||||
|
||||
public string roleArn { get; set; }
|
||||
|
||||
public string region { get; set; }
|
||||
|
||||
public string viewEndpoint { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ObjectStoreServiceOptions
|
||||
{
|
||||
public string ObjectStoreUse { get; set; }
|
||||
public AliyunOSSOptions AliyunOSS { get; set; }
|
||||
public MinIOOptions MinIO { get; set; }
|
||||
|
||||
public AWSOptions AWS { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class ObjectStoreDTO
|
||||
{
|
||||
public string ObjectStoreUse { get; set; }
|
||||
|
||||
public AliyunOSSOptions AliyunOSS { get; set; }
|
||||
|
||||
public MinIOOptions MinIO { get; set; }
|
||||
|
||||
public AWSOptions AWS { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class AliyunOSSTempToken
|
||||
{
|
||||
public string AccessKeyId { get; set; }
|
||||
public string AccessKeySecret { get; set; }
|
||||
public string SecurityToken { get; set; }
|
||||
public string Expiration { get; set; }
|
||||
|
||||
public string Region { get; set; }
|
||||
public string BucketName { get; set; }
|
||||
public string ViewEndpoint { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public enum ObjectStoreUse
|
||||
{
|
||||
AliyunOSS = 0,
|
||||
MinIO = 1,
|
||||
AWS = 2,
|
||||
}
|
||||
|
||||
public interface IOSSService
|
||||
{
|
||||
public Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName,bool isFileNameAddGuid=true);
|
||||
public Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true);
|
||||
|
||||
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
|
||||
|
||||
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
||||
|
||||
public Task<string> GetSignedUrl(string ossRelativePath);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class OSSService : IOSSService
|
||||
{
|
||||
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
||||
|
||||
|
||||
public OSSService(IOptionsMonitor<ObjectStoreServiceOptions> options)
|
||||
{
|
||||
ObjectStoreServiceOptions = options.CurrentValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||
/// </summary>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <param name="oosFolderPath"></param>
|
||||
/// <param name="fileRealName"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
||||
{
|
||||
|
||||
|
||||
var ossRelativePath = isFileNameAddGuid? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}": $"{oosFolderPath}/{fileRealName}";
|
||||
//var ossRelativePath = oosFolderPath + "/" + fileRealName;
|
||||
|
||||
try
|
||||
{
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
fileStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
fileStream.CopyTo(memoryStream);
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(aliConfig.endPoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||
|
||||
|
||||
|
||||
// 上传文件
|
||||
var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, memoryStream);
|
||||
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||
|
||||
|
||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||
.Build();
|
||||
|
||||
var putObjectArgs = new PutObjectArgs()
|
||||
.WithBucket(minIOConfig.bucketName)
|
||||
.WithObject(ossRelativePath)
|
||||
.WithStreamData(memoryStream)
|
||||
.WithObjectSize(memoryStream.Length);
|
||||
|
||||
await minioClient.PutObjectAsync(putObjectArgs);
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
|
||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||
.Build();
|
||||
|
||||
var putObjectArgs = new PutObjectArgs()
|
||||
.WithBucket(minIOConfig.bucketName)
|
||||
.WithObject(ossRelativePath)
|
||||
.WithStreamData(memoryStream)
|
||||
.WithObjectSize(memoryStream.Length);
|
||||
|
||||
await minioClient.PutObjectAsync(putObjectArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
throw new BusinessValidationFailedException($"上传发生异常:{ex.Message}"); ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return "/" + ossRelativePath;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||
/// </summary>
|
||||
/// <param name="localFilePath"></param>
|
||||
/// <param name="oosFolderPath"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
||||
{
|
||||
var localFileName = Path.GetFileName(localFilePath);
|
||||
|
||||
var ossRelativePath = isFileNameAddGuid? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
|
||||
|
||||
//var ossRelativePath = oosFolderPath + "/" + localFileName;
|
||||
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(aliConfig.endPoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||
|
||||
// 上传文件
|
||||
var result = _ossClient.PutObject(aliConfig.bucketName, ossRelativePath, localFilePath);
|
||||
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||
|
||||
|
||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||
.Build();
|
||||
|
||||
var putObjectArgs = new PutObjectArgs()
|
||||
.WithBucket(minIOConfig.bucketName)
|
||||
.WithObject(ossRelativePath)
|
||||
.WithFileName(localFilePath);
|
||||
|
||||
await minioClient.PutObjectAsync(putObjectArgs);
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
|
||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||
.Build();
|
||||
|
||||
var putObjectArgs = new PutObjectArgs()
|
||||
.WithBucket(minIOConfig.bucketName)
|
||||
.WithObject(ossRelativePath)
|
||||
.WithFileName(localFilePath);
|
||||
|
||||
await minioClient.PutObjectAsync(putObjectArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
return "/" + ossRelativePath;
|
||||
|
||||
}
|
||||
|
||||
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
||||
{
|
||||
|
||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(aliConfig.endPoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||
|
||||
// 上传文件
|
||||
var result = _ossClient.GetObject(aliConfig.bucketName, ossRelativePath);
|
||||
|
||||
// 将下载的文件流保存到本地文件
|
||||
using (var fs = File.OpenWrite(localFilePath))
|
||||
{
|
||||
result.Content.CopyTo(fs);
|
||||
fs.Close();
|
||||
}
|
||||
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||
|
||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||
.Build();
|
||||
|
||||
var getObjectArgs = new GetObjectArgs()
|
||||
.WithBucket(minIOConfig.bucketName)
|
||||
.WithObject(ossRelativePath)
|
||||
.WithFile(localFilePath);
|
||||
|
||||
await minioClient.GetObjectAsync(getObjectArgs);
|
||||
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||
.Build();
|
||||
|
||||
var getObjectArgs = new GetObjectArgs()
|
||||
.WithBucket(minIOConfig.bucketName)
|
||||
.WithObject(ossRelativePath)
|
||||
.WithFile(localFilePath);
|
||||
|
||||
await minioClient.GetObjectAsync(getObjectArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
throw new BusinessValidationFailedException("oss下载失败!" + ex.Message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public async Task<string> GetSignedUrl(string ossRelativePath)
|
||||
{
|
||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(aliConfig.endPoint, aliConfig.accessKeyId, aliConfig.accessKeySecret);
|
||||
|
||||
// 生成签名URL。
|
||||
var req = new GeneratePresignedUriRequest(aliConfig.bucketName, ossRelativePath, SignHttpMethod.Get)
|
||||
{
|
||||
// 设置签名URL过期时间,默认值为3600秒。
|
||||
Expiration = DateTime.Now.AddHours(1),
|
||||
};
|
||||
var uri = _ossClient.GeneratePresignedUri(req);
|
||||
|
||||
return uri.PathAndQuery;
|
||||
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||
|
||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}:{minIOConfig.port}")
|
||||
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||
.Build();
|
||||
|
||||
//var reqParams = new Dictionary<string, string>(StringComparer.Ordinal)
|
||||
// {
|
||||
// { "response-content-type", "application/json" }
|
||||
// };
|
||||
|
||||
var args = new PresignedGetObjectArgs()
|
||||
.WithBucket(minIOConfig.bucketName)
|
||||
.WithObject(ossRelativePath)
|
||||
.WithExpiry(3600)
|
||||
/*.WithHeaders(reqParams)*/;
|
||||
|
||||
var presignedUrl = await minioClient.PresignedGetObjectAsync(args);
|
||||
|
||||
Uri uri = new Uri(presignedUrl);
|
||||
|
||||
string relativePath = uri.PathAndQuery;
|
||||
|
||||
|
||||
return relativePath;
|
||||
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.endPoint}")
|
||||
.WithCredentials(minIOConfig.accessKey, minIOConfig.secretKey).WithSSL(minIOConfig.useSSL)
|
||||
.Build();
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
throw new BusinessValidationFailedException("oss授权url失败!" + ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ObjectStoreService": {
|
||||
"ObjectStoreUse": "AliyunOSS",
|
||||
"AliyunOSS": {
|
||||
"regionId": "cn-shanghai",
|
||||
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||
"bucketName": "zy-irc-store",
|
||||
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||
"viewEndpoint": "https://zy-irc-cache.oss-cn-shanghai.aliyuncs.com",
|
||||
"region": "oss-cn-shanghai"
|
||||
},
|
||||
|
||||
"MinIO": {
|
||||
"endpoint": "http://192.168.3.68",
|
||||
"port": "8001",
|
||||
"useSSL": false,
|
||||
"accessKey": "IDFkwEpWej0b4DtiuThL",
|
||||
"secretKey": "Lhuu83yMhVwu7c1SnjvGY6lq74jzpYqifK6Qtj4h",
|
||||
"bucketName": "test"
|
||||
}
|
||||
},
|
||||
|
||||
"ConnectionStrings": {
|
||||
//"RemoteNew": "Server=47.117.165.18,1434;Database=Prod_Study;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
||||
//"Hangfire": "Server=47.117.165.18,1434;Database=Prod_Study_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
||||
"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_Study;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_Study_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
||||
},
|
||||
|
||||
"BasicSystemConfig": {
|
||||
|
||||
"OpenUserComplexPassword": true,
|
||||
|
||||
"OpenSignDocumentBeforeWork": true,
|
||||
|
||||
"OpenTrialRelationDelete": true,
|
||||
|
||||
"OpenLoginLimit": true,
|
||||
"LoginMaxFailCount": 5,
|
||||
|
||||
"LoginFailLockMinutes": 30
|
||||
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"FromEmail": "study@extimaging.com",
|
||||
"FromName": "研究单位阅片系统",
|
||||
"AuthorizationCode": "zhanying123",
|
||||
"SiteUrl": "https://study.extimaging.com/login"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ObjectStoreService": {
|
||||
"ObjectStoreUse": "AliyunOSS",
|
||||
"AliyunOSS": {
|
||||
"regionId": "cn-shanghai",
|
||||
"endPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||
"bucketName": "zy-irc-test-store",
|
||||
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||
"viewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
||||
"region": "oss-cn-shanghai"
|
||||
},
|
||||
|
||||
"MinIO": {
|
||||
"endPoint": "106.14.89.110",
|
||||
"port": "9001",
|
||||
"useSSL": false,
|
||||
"accessKey": "fbStsVYCIPKHQneeqMwD",
|
||||
"secretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
||||
"bucketName": "hir-test",
|
||||
"viewEndpoint": "http://106.14.89.110:9001/hir-test/"
|
||||
},
|
||||
|
||||
"AWS": {
|
||||
"endPoint": "s3.us-east-1.amazonaws.com",
|
||||
"useSSL": false,
|
||||
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
|
||||
"secretKey": "l+yjtvV7Z4jiwm/7xCYv30UeUj/SvuqqYzAwjJHf",
|
||||
"bucketName": "ei-irc-test-store",
|
||||
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
|
||||
}
|
||||
},
|
||||
|
||||
"ConnectionStrings": {
|
||||
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_HIR;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=106.14.89.110,1435;Database=Test_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
"BasicSystemConfig": {
|
||||
|
||||
"OpenUserComplexPassword": false,
|
||||
|
||||
"OpenSignDocumentBeforeWork": false,
|
||||
|
||||
"OpenTrialRelationDelete": true,
|
||||
|
||||
"OpenLoginLimit": false,
|
||||
"LoginMaxFailCount": 5,
|
||||
|
||||
"LoginFailLockMinutes": 30
|
||||
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"FromEmail": "test-study@extimaging.com",
|
||||
"FromName": "Test_Study",
|
||||
"AuthorizationCode": "zhanying123",
|
||||
|
||||
"SiteUrl": "http://study.test.extimaging.com/login"
|
||||
},
|
||||
"DicomSCPServiceConfig": {
|
||||
"CalledAEList": [
|
||||
"STORESCP",
|
||||
"Value1",
|
||||
"Value2",
|
||||
"Value3"
|
||||
],
|
||||
"ServerPort": 11112
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ObjectStoreService": {
|
||||
"ObjectStoreUse": "MinIO",
|
||||
"AliyunOSS": {
|
||||
"regionId": "cn-shanghai",
|
||||
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||
"bucketName": "zy-sir-test-store",
|
||||
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||
"viewEndpoint": "https://zy-sir-test-store.oss-cn-shanghai.aliyuncs.com",
|
||||
"region": "oss-cn-shanghai"
|
||||
},
|
||||
|
||||
"MinIO": {
|
||||
"endPoint": "44.218.11.19",
|
||||
"port": "9001",
|
||||
"useSSL": false,
|
||||
"accessKey": "lH8DkKskLuDqPaiubuSQ",
|
||||
"secretKey": "pdPdicvvLeH7xAC5yFUrI7odMyBfOXxvVWMvKYV4",
|
||||
"bucketName": "hir-us",
|
||||
"viewEndpoint": "http://hir.us.extimaging.com/oss/hir-us"
|
||||
},
|
||||
|
||||
"AWS": {
|
||||
"endPoint": "s3.us-east-1.amazonaws.com",
|
||||
"useSSL": false,
|
||||
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
|
||||
"secretKey": "l+yjtvV7Z4jiwm/7xCYv30UeUj/SvuqqYzAwjJHf",
|
||||
"bucketName": "ei-irc-test-store",
|
||||
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"RemoteNew": "Server=44.218.11.19,1435;Database=US_HIR;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=44.218.11.19,1435;Database=US_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
"BasicSystemConfig": {
|
||||
|
||||
"OpenUserComplexPassword": false,
|
||||
|
||||
"OpenSignDocumentBeforeWork": false,
|
||||
|
||||
"OpenTrialRelationDelete": true,
|
||||
|
||||
"OpenLoginLimit": false,
|
||||
"LoginMaxFailCount": 5,
|
||||
|
||||
"LoginFailLockMinutes": 30
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"FromEmail": "uat-study@extimaging.com",
|
||||
"FromName": "Uat_Study",
|
||||
"AuthorizationCode": "zhanying123",
|
||||
"SiteUrl": "http://study.uat.extimaging.com/login"
|
||||
},
|
||||
"DicomSCPServiceConfig": {
|
||||
"CalledAEList": [
|
||||
"STORESCP",
|
||||
"Value1",
|
||||
"Value2",
|
||||
"Value3"
|
||||
],
|
||||
"ServerPort": 11112
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ObjectStoreService": {
|
||||
"ObjectStoreUse": "MinIO",
|
||||
"AliyunOSS": {
|
||||
"regionId": "cn-shanghai",
|
||||
"endpoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||
"accessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ",
|
||||
"accessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio",
|
||||
"bucketName": "zy-irc-uat-store",
|
||||
"roleArn": "acs:ram::1899121822495495:role/oss-upload",
|
||||
"viewEndpoint": "https://zy-irc-uat-store.oss-cn-shanghai.aliyuncs.com",
|
||||
"region": "oss-cn-shanghai"
|
||||
},
|
||||
|
||||
"MinIO": {
|
||||
"endPoint": "47.117.164.182",
|
||||
"port": "9001",
|
||||
"useSSL": false,
|
||||
"accessKey": "b9Ul0e98xPzt6PwRXA1Q",
|
||||
"secretKey": "DzMaU2L4OXl90uytwOmDXF2encN0Jf4Nxu2XkYqQ",
|
||||
"bucketName": "hir-uat",
|
||||
"viewEndpoint": "http://hir.uat.extimaging.com/oss/hir-uat"
|
||||
},
|
||||
|
||||
"AWS": {
|
||||
"endPoint": "s3.us-east-1.amazonaws.com",
|
||||
"useSSL": false,
|
||||
"accessKey": "AKIAZQ3DRSOHFPJJ6FEU",
|
||||
"secretKey": "l+yjtvV7Z4jiwm/7xCYv30UeUj/SvuqqYzAwjJHf",
|
||||
"bucketName": "ei-irc-test-store",
|
||||
"viewEndpoint": "https://ei-irc-test-store.s3.amazonaws.com/"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"RemoteNew": "Server=47.117.164.182,1434;Database=Uat_HIR;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=47.117.164.182,1434;Database=Uat_HIR_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
"BasicSystemConfig": {
|
||||
|
||||
"OpenUserComplexPassword": false,
|
||||
|
||||
"OpenSignDocumentBeforeWork": false,
|
||||
|
||||
"OpenTrialRelationDelete": true,
|
||||
|
||||
"OpenLoginLimit": false,
|
||||
"LoginMaxFailCount": 5,
|
||||
|
||||
"LoginFailLockMinutes": 30
|
||||
},
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"FromEmail": "uat-study@extimaging.com",
|
||||
"FromName": "Uat_Study",
|
||||
"AuthorizationCode": "zhanying123",
|
||||
"SiteUrl": "http://study.uat.extimaging.com/login"
|
||||
},
|
||||
"DicomSCPServiceConfig": {
|
||||
"CalledAEList": [
|
||||
"STORESCP",
|
||||
"Value1",
|
||||
"Value2",
|
||||
"Value3"
|
||||
],
|
||||
"ServerPort": 11112
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
|
@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infra.EFCore",
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure", "IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj", "{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IRC.Core.SCP", "IRC.Core.SCP\IRC.Core.SCP.csproj", "{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -51,6 +53,10 @@ Global
|
|||
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -402,6 +402,19 @@ namespace IRaCIS.Core.API.Controllers
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
[HttpPost, Route("Inspection/configTrialBasicInfo/ConfigTrialPACSInfoConfirm")]
|
||||
[UnitOfWork]
|
||||
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt" })]
|
||||
public async Task<IResponseOutput> ConfigTrialPACSInfoConfirm(DataInspectionDto<TrialPACSConfig> opt)
|
||||
{
|
||||
opt.Data.IsTrialPACSConfirmed = true;
|
||||
var singid = await _inspectionService.RecordSing(opt.SignInfo);
|
||||
var result = await _trialConfigService.ConfigTrialPACSInfo(opt.Data);
|
||||
await _inspectionService.CompletedSign(singid, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 签名确认
|
||||
/// </summary>
|
||||
|
|
|
@ -64,22 +64,21 @@
|
|||
<PackageReference Include="aliyun-net-sdk-sts" Version="3.1.2" />
|
||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="9.0.0" />
|
||||
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
|
||||
<PackageReference Include="EasyCaching.Interceptor.Castle" Version="1.9.2" />
|
||||
<PackageReference Include="EasyCaching.Serialization.MessagePack" Version="1.9.2">
|
||||
<TreatAsUsed>true</TreatAsUsed>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.12" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.14" />
|
||||
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
|
||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.12" />
|
||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.14" />
|
||||
<PackageReference Include="Invio.Extensions.Authentication.JwtBearer" Version="2.0.1" />
|
||||
<PackageReference Include="LogDashboard" Version="1.4.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.5" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" />
|
||||
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.0.3" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -707,6 +707,11 @@
|
|||
<param name="_trialRepository"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.ExploreRecommendService">
|
||||
<summary>
|
||||
ExploreRecommendService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.InternationalizationService">
|
||||
<summary>
|
||||
InternationalizationService
|
||||
|
@ -9808,6 +9813,24 @@
|
|||
<param name="_dicomInstanceRepository"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.TrialDicomAEService">
|
||||
<summary>
|
||||
DicomAEService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialDicomAEService.GetTrialDicomAE(System.Guid)">
|
||||
<summary>
|
||||
获取项目dicom AE 配置信息,otherinfo里面有IsPACSConnect IsTrialPACSConfirmed
|
||||
</summary>
|
||||
<param name="trialId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialDicomAEService.TestSCPServerConnect(System.Guid)">
|
||||
<summary>
|
||||
测试scp server 是否可以连接
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.TrialExternalUserService">
|
||||
<summary>
|
||||
项目外部人员 录入流程相关
|
||||
|
@ -9820,6 +9843,11 @@
|
|||
<param name="addOrEditTrialExternalUser"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.TrialSiteDicomAEService">
|
||||
<summary>
|
||||
TrialSiteDicomAEService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.TaskAllocationRuleView">
|
||||
<summary> TaskAllocationRuleView 列表视图模型 </summary>
|
||||
</member>
|
||||
|
@ -9960,6 +9988,15 @@
|
|||
<member name="T:IRaCIS.Core.Application.ViewModel.CommonDocumentAddOrEdit">
|
||||
<summary> CommonDocumentAddOrEdit 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.ExploreRecommendView">
|
||||
<summary> ExploreRecommendView 列表视图模型 </summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.ExploreRecommendQuery">
|
||||
<summary>ExploreRecommendQuery 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.ExploreRecommendAddOrEdit">
|
||||
<summary> ExploreRecommendAddOrEdit 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.FrontAuditConfigView">
|
||||
<summary> FrontAuditConfigView 列表视图模型 </summary>
|
||||
</member>
|
||||
|
@ -10959,6 +10996,15 @@
|
|||
<member name="T:IRaCIS.Core.Application.ViewModel.UserWLTemplateAddOrEdit">
|
||||
<summary> UserWLTemplateAddOrEdit 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.DicomAEView">
|
||||
<summary> DicomAEView 列表视图模型 </summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.DicomAEQuery">
|
||||
<summary>DicomAEQuery 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.DicomAEAddOrEdit">
|
||||
<summary> DicomAEAddOrEdit 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.TrialExternalUserView">
|
||||
<summary> TrialExternalUserView 列表视图模型 </summary>
|
||||
</member>
|
||||
|
@ -10968,6 +11014,15 @@
|
|||
<member name="T:IRaCIS.Core.Application.ViewModel.TrialExternalUserAddOrEdit">
|
||||
<summary> TrialExternalUserAddOrEdit 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.TrialSiteDicomAEView">
|
||||
<summary> TrialSiteDicomAEView 列表视图模型 </summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.TrialSiteDicomAEQuery">
|
||||
<summary>TrialSiteDicomAEQuery 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.TrialSiteDicomAEAddOrEdit">
|
||||
<summary> TrialSiteDicomAEAddOrEdit 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.TrialUserPreparationView">
|
||||
<summary> TrialUserPreparation View 列表视图模型 </summary>
|
||||
</member>
|
||||
|
@ -11002,6 +11057,11 @@
|
|||
ICommonDocumentService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Interfaces.IExploreRecommendService">
|
||||
<summary>
|
||||
IExploreRecommendService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Interfaces.IFrontAuditConfigService">
|
||||
<summary>
|
||||
IFrontAuditConfigService
|
||||
|
@ -11052,11 +11112,21 @@
|
|||
IOrganInfoService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Interfaces.IDicomAEService">
|
||||
<summary>
|
||||
IDicomAEService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Interfaces.ITrialExternalUserService">
|
||||
<summary>
|
||||
ITrialExternalUserService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Interfaces.ITrialSiteDicomAEService">
|
||||
<summary>
|
||||
ITrialSiteDicomAEService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Contracts.EmailNoticeConfigView">
|
||||
<summary> EmailNoticeConfigView 列表视图模型 </summary>
|
||||
</member>
|
||||
|
@ -13040,6 +13110,13 @@
|
|||
<param name="trialConfig"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.TrialConfigService.ConfigTrialPACSInfo(IRaCIS.Core.Application.Contracts.TrialPACSConfig)">
|
||||
<summary>
|
||||
配置pacs信息
|
||||
</summary>
|
||||
<param name="trialConfig"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.TrialConfigService.UpdateTrialState(System.Guid,System.String,System.String)">
|
||||
<summary>
|
||||
更新项目状态
|
||||
|
@ -14971,6 +15048,41 @@
|
|||
<param name="status">9-拒绝入组,10-确认入组</param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Application.Services.PatientService.GetSCPImageUploadList(IRaCIS.Application.Contracts.SCPImageUploadQuery)">
|
||||
<summary>
|
||||
scp 影像推送记录表
|
||||
</summary>
|
||||
<param name="inQuery"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Application.Services.PatientService.GetPatientList(IRaCIS.Application.Contracts.PatientTrialQuery)">
|
||||
<summary>
|
||||
影像检查列表-患者为维度组织
|
||||
</summary>
|
||||
<param name="inQuery"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Application.Services.PatientService.GetPatientStudyList(IRaCIS.Application.Contracts.PatientStudyInfoQuery)">
|
||||
<summary>
|
||||
影像检查列表-> 获取患者的检查列表
|
||||
</summary>
|
||||
<param name="inQuery"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Application.Services.PatientService.GetVisitPatientStudyFilterList(IRaCIS.Application.Contracts.VisitPatientStudyFilterQuery)">
|
||||
<summary>
|
||||
影像访视上传 检查列表
|
||||
</summary>
|
||||
<param name="inQuery"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Application.Services.PatientService.SubmitVisitStudyBinding(IRaCIS.Application.Contracts.SubmitVisitStudyBindingCommand)">
|
||||
<summary>
|
||||
提交 患者检查和访视的绑定
|
||||
</summary>
|
||||
<param name="inCommand"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Application.Services.SubjectService.AddOrUpdateSubject(IRaCIS.Application.Contracts.SubjectCommand)">
|
||||
<summary>
|
||||
添加或更新受试者信息[New]
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-07-02 09:29:36
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.Collections.Generic;
|
||||
namespace IRaCIS.Core.Application.ViewModel
|
||||
{
|
||||
/// <summary> ExploreRecommendView 列表视图模型 </summary>
|
||||
public class ExploreRecommendView: ExploreRecommendAddOrEdit
|
||||
{
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
public Guid CreateUserId { get; set; }
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
public DateTime? DeleteTime { get; set; }
|
||||
public Guid? DeleteUserId { get; set; }
|
||||
}
|
||||
|
||||
///<summary>ExploreRecommendQuery 列表查询参数模型</summary>
|
||||
public class ExploreRecommendQuery:PageInput
|
||||
{
|
||||
|
||||
public string? Version { get; set; }
|
||||
|
||||
|
||||
public string? Title { get; set; }
|
||||
|
||||
|
||||
public string? DownloadUrl { get; set; }
|
||||
|
||||
|
||||
public string? FileName { get; set; }
|
||||
|
||||
public bool? IsDeleted { get; set; }
|
||||
|
||||
}
|
||||
|
||||
///<summary> ExploreRecommendAddOrEdit 列表查询参数模型</summary>
|
||||
public class ExploreRecommendAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public string ExploreType { get; set; }
|
||||
|
||||
public string Version { get; set; }
|
||||
public string Title { get; set; }
|
||||
|
||||
public bool IsDeleted { get; set; }
|
||||
public string DownloadUrl { get; set; }
|
||||
public string Path { get; set; }
|
||||
public string FileName { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-07-02 09:26:59
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// ExploreRecommendService
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(GroupName = "Common")]
|
||||
public class ExploreRecommendService : BaseService, IExploreRecommendService
|
||||
{
|
||||
|
||||
private readonly IRepository<ExploreRecommend> _exploreRecommendRepository;
|
||||
|
||||
public ExploreRecommendService(IRepository<ExploreRecommend> exploreRecommendRepository)
|
||||
{
|
||||
_exploreRecommendRepository = exploreRecommendRepository;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<ExploreRecommendView>> GetExploreRecommendList(ExploreRecommendQuery inQuery)
|
||||
{
|
||||
|
||||
var exploreRecommendQueryable =
|
||||
|
||||
_exploreRecommendRepository.Where().IgnoreQueryFilters()
|
||||
.WhereIf(string.IsNullOrEmpty(inQuery.Title), t => t.Title.Contains(inQuery.Title))
|
||||
.WhereIf(string.IsNullOrEmpty(inQuery.FileName), t => t.Title.Contains(inQuery.FileName))
|
||||
.WhereIf(string.IsNullOrEmpty(inQuery.DownloadUrl), t => t.Title.Contains(inQuery.DownloadUrl))
|
||||
.WhereIf(string.IsNullOrEmpty(inQuery.Version), t => t.Title.Contains(inQuery.Version))
|
||||
.WhereIf(inQuery.IsDeleted != null, t => t.IsDeleted == t.IsDeleted)
|
||||
.ProjectTo<ExploreRecommendView>(_mapper.ConfigurationProvider);
|
||||
|
||||
var pageList = await exploreRecommendQueryable
|
||||
.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, string.IsNullOrWhiteSpace(inQuery.SortField) ? nameof(ExploreRecommendView.Id) : inQuery.SortField,
|
||||
inQuery.Asc);
|
||||
|
||||
return pageList;
|
||||
}
|
||||
|
||||
|
||||
public async Task<IResponseOutput> AddOrUpdateExploreRecommend(ExploreRecommendAddOrEdit addOrEditExploreRecommend)
|
||||
{
|
||||
var verifyExp2 = new EntityVerifyExp<ExploreRecommend>()
|
||||
{
|
||||
VerifyExp = u => u.IsDeleted == addOrEditExploreRecommend.IsDeleted && u.ExploreType == addOrEditExploreRecommend.ExploreType,
|
||||
|
||||
VerifyMsg = "当前浏览器启用版本只允许有一个",
|
||||
|
||||
IsVerify = addOrEditExploreRecommend.IsDeleted == false
|
||||
};
|
||||
|
||||
var entity = await _exploreRecommendRepository.InsertOrUpdateAsync(addOrEditExploreRecommend, true, verifyExp2);
|
||||
|
||||
return ResponseOutput.Ok(entity.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpDelete("{exploreRecommendId:guid}")]
|
||||
public async Task<IResponseOutput> DeleteExploreRecommend(Guid exploreRecommendId)
|
||||
{
|
||||
var success = await _exploreRecommendRepository.DeleteFromQueryAsync(t => t.Id == exploreRecommendId, true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public async Task<List<ExploreRecommendView> > GetExploreRecommentInfo()
|
||||
{
|
||||
|
||||
|
||||
var result = await _exploreRecommendRepository.Where(t => t.IsDeleted == false).ProjectTo<ExploreRecommendView>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
|
||||
if (result .Count==0)
|
||||
{
|
||||
throw new QueryBusinessObjectNotExistException("系统浏览器版本推荐未维护,请联系维护人员");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-07-02 09:27:36
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
namespace IRaCIS.Core.Application.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// IExploreRecommendService
|
||||
/// </summary>
|
||||
public interface IExploreRecommendService
|
||||
{
|
||||
|
||||
Task<PageOutput<ExploreRecommendView>> GetExploreRecommendList(ExploreRecommendQuery inQuery);
|
||||
|
||||
Task<IResponseOutput> AddOrUpdateExploreRecommend(ExploreRecommendAddOrEdit addOrEditExploreRecommend);
|
||||
|
||||
Task<IResponseOutput> DeleteExploreRecommend(Guid exploreRecommendId);
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -80,8 +80,9 @@ namespace IRaCIS.Core.Application.Service
|
|||
CreateMap<PublishLog, PublishLogAddOrEdit>().ReverseMap();
|
||||
|
||||
CreateMap<PublishLog, PublishVersionSelect>();
|
||||
|
||||
|
||||
CreateMap<ExploreRecommend, ExploreRecommendView>();
|
||||
CreateMap<ExploreRecommend, ExploreRecommendAddOrEdit>().ReverseMap();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -506,6 +506,39 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
}
|
||||
|
||||
|
||||
|
||||
public async Task<IResponseOutput> GetSubejectVisitPathInfo(Guid subjectVisitId)
|
||||
{
|
||||
var query = from sv in _subjectVisitRepository.Where(t => t.Id == subjectVisitId)
|
||||
|
||||
select new
|
||||
{
|
||||
SubjectCode = sv.Subject.Code,
|
||||
VisitName = sv.VisitName,
|
||||
StudyList = sv.StudyList.Select(u => new
|
||||
{
|
||||
u.PatientId,
|
||||
u.StudyTime,
|
||||
u.StudyCode,
|
||||
|
||||
SeriesList = u.SeriesList.Select(z => new
|
||||
{
|
||||
z.Modality,
|
||||
|
||||
InstancePathList = z.DicomInstanceList.Select(k => new
|
||||
{
|
||||
k.Path
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
};
|
||||
|
||||
var info = query.FirstOrDefault();
|
||||
|
||||
return ResponseOutput.Ok(info);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 后台任务调用,前端忽略该接口
|
||||
/// </summary>
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-03-22 15:44:37
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
namespace IRaCIS.Core.Application.ViewModel
|
||||
{
|
||||
/// <summary> DicomAEView 列表视图模型 </summary>
|
||||
public class DicomAEView : DicomAEAddOrEdit
|
||||
{
|
||||
public DateTime CreateTime { get; set; }
|
||||
public Guid CreateUserId { get; set; }
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
public DateTime? LatestTestTime { get; set; }
|
||||
|
||||
public bool IsTestOK { get; set; }
|
||||
|
||||
public bool IsPACSConnect { get; set; }
|
||||
|
||||
public bool IsTrialPACSConfirmed { get; set; }
|
||||
|
||||
}
|
||||
|
||||
///<summary>DicomAEQuery 列表查询参数模型</summary>
|
||||
public class DicomAEQuery : PageInput
|
||||
{
|
||||
public Guid? TrialId { get; set; }
|
||||
|
||||
public string? CalledAE { get; set; }
|
||||
|
||||
public string? IP { get; set; }
|
||||
|
||||
|
||||
public int? Port { get; set; }
|
||||
|
||||
|
||||
public string? Modality { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
}
|
||||
|
||||
///<summary> DicomAEAddOrEdit 列表查询参数模型</summary>
|
||||
public class DicomAEAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
[NotDefault]
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public string CalledAE { get; set; }
|
||||
public string IP { get; set; }
|
||||
public int Port { get; set; }
|
||||
public string Modality { get; set; } = string.Empty;
|
||||
public string Description { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -313,6 +313,16 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
|
||||
}
|
||||
|
||||
public class TrialPACSConfig
|
||||
{
|
||||
[NotDefault]
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public bool IsPACSConnect { get; set; }
|
||||
|
||||
public bool IsTrialPACSConfirmed { get; set; } = true;
|
||||
}
|
||||
|
||||
public class TrialStateChangeDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-07-02 16:53:52
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
namespace IRaCIS.Core.Application.ViewModel
|
||||
{
|
||||
/// <summary> TrialSiteDicomAEView 列表视图模型 </summary>
|
||||
public class TrialSiteDicomAEView : TrialSiteDicomAEAddOrEdit
|
||||
{
|
||||
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public Guid? DeleteUserId { get; set; }
|
||||
public DateTime CreateTime { get; set; }
|
||||
public Guid CreateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
///<summary>TrialSiteDicomAEQuery 列表查询参数模型</summary>
|
||||
public class TrialSiteDicomAEQuery /*: PageInput*/
|
||||
{
|
||||
[NotDefault]
|
||||
|
||||
public Guid TrialSiteId { get; set; }
|
||||
|
||||
public string? CallingAE { get; set; }
|
||||
|
||||
public string? IP { get; set; }
|
||||
|
||||
public string? Port { get; set; }
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
}
|
||||
|
||||
///<summary> TrialSiteDicomAEAddOrEdit 列表查询参数模型</summary>
|
||||
public class TrialSiteDicomAEAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
|
||||
public Guid TrialSiteId { get; set; }
|
||||
public string CallingAE { get; set; }
|
||||
public string IP { get; set; }
|
||||
public string Port { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
||||
//public bool IsDeleted { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -259,7 +259,7 @@ namespace IRaCIS.Application.Contracts
|
|||
//public string ContactPhone { get; set; } = String.Empty;
|
||||
//public string Address { get; set; } = String.Empty;
|
||||
|
||||
|
||||
public List<string> CallingAEList { get; set; }
|
||||
public List<string> UserNameList { get; set; } = new List<string>();
|
||||
|
||||
public int? VisitCount { get; set; }
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-03-22 15:44:27
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
namespace IRaCIS.Core.Application.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// IDicomAEService
|
||||
/// </summary>
|
||||
public interface IDicomAEService
|
||||
{
|
||||
|
||||
Task<IResponseOutput<PageOutput<DicomAEView>>> GetDicomAEList(DicomAEQuery inQuery);
|
||||
|
||||
Task<IResponseOutput> AddOrUpdateDicomAE(DicomAEAddOrEdit addOrEditDicomAE);
|
||||
|
||||
Task<IResponseOutput> DeleteDicomAE(Guid dicomAEId);
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace IRaCIS.Application.Interfaces
|
|||
|
||||
Task<IResponseOutput> ConfigTrialUrgentInfo(TrialUrgentConfig trialConfig);
|
||||
|
||||
|
||||
Task<IResponseOutput> ConfigTrialPACSInfo(TrialPACSConfig trialConfig);
|
||||
Task<IResponseOutput> TrialConfigSignatureConfirm(SignConfirmDTO signConfirmDTO);
|
||||
|
||||
Task<IResponseOutput> AsyncTrialCriterionDictionary(AsyncTrialCriterionDictionaryInDto inDto);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-07-02 16:53:55
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
namespace IRaCIS.Core.Application.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// ITrialSiteDicomAEService
|
||||
/// </summary>
|
||||
public interface ITrialSiteDicomAEService
|
||||
{
|
||||
|
||||
Task<List<TrialSiteDicomAEView>> GetTrialSiteDicomAEList(TrialSiteDicomAEQuery inQuery);
|
||||
|
||||
Task<IResponseOutput> AddOrUpdateTrialSiteDicomAE(TrialSiteDicomAEAddOrEdit addOrEditTrialSiteDicomAE);
|
||||
|
||||
Task<IResponseOutput> DeleteTrialSiteDicomAE(Guid trialSiteDicomAEId);
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -604,7 +604,7 @@ namespace IRaCIS.Core.Application
|
|||
|
||||
await _readingQuestionCriterionTrialRepository.UpdatePartialFromQueryAsync(inDto.TrialReadingCriterionId, x => new ReadingQuestionCriterionTrial()
|
||||
{
|
||||
IsImageFilter=inDto.IsImageFilter,
|
||||
IsImageFilter = inDto.IsImageFilter,
|
||||
ImageDownloadEnum = inDto.ImageDownloadEnum,
|
||||
ImageUploadEnum = inDto.ImageUploadEnum,
|
||||
CriterionModalitys = inDto.CriterionModalitys,
|
||||
|
@ -954,7 +954,7 @@ namespace IRaCIS.Core.Application
|
|||
trialInfo.UpdateTime = DateTime.Now;
|
||||
|
||||
|
||||
//await _readingQuestionCriterionTrialRepository.BatchUpdateNoTrackingAsync(t => t.TrialId == trialConfig.TrialId && t.IsSigned == false, u => new ReadingQuestionCriterionTrial() { CriterionModalitys = trialConfig.Modalitys });
|
||||
//await _readingQuestionCriterionTrialRepository.BatchUpdateNoTrackingAsync(t => t.TrialId == trialConfig.TrialId && t.IsSigned == false, u => new ReadingQuestionCriterionTrial() { CriterionModalitys = trialConfig.Modalitys });
|
||||
|
||||
return ResponseOutput.Ok(await _repository.SaveChangesAsync());
|
||||
}
|
||||
|
@ -1151,6 +1151,25 @@ namespace IRaCIS.Core.Application
|
|||
return ResponseOutput.Ok(await _repository.SaveChangesAsync());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 配置pacs信息
|
||||
/// </summary>
|
||||
/// <param name="trialConfig"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPut]
|
||||
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "BeforeOngoingCantOpt", "AfterStopCannNotOpt" })]
|
||||
public async Task<IResponseOutput> ConfigTrialPACSInfo(TrialPACSConfig trialConfig)
|
||||
{
|
||||
var trialInfo = (await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialConfig.TrialId)).IfNullThrowException();
|
||||
trialInfo.IsPACSConnect = trialConfig.IsPACSConnect;
|
||||
trialConfig.IsTrialPACSConfirmed = trialConfig.IsTrialPACSConfirmed;
|
||||
trialInfo.UpdateTime = DateTime.Now;
|
||||
await _trialRepository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok(await _repository.SaveChangesAsync());
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{trialId:guid}")]
|
||||
public async Task<IResponseOutput> IfTrialCanOngoing(Guid trialId)
|
||||
{
|
||||
|
@ -1318,7 +1337,7 @@ namespace IRaCIS.Core.Application
|
|||
|
||||
public async Task<IResponseOutput<List<TrialBodyPartView>>> GetTrialBodyPartList(Guid trialId)
|
||||
{
|
||||
var list = await _trialRepository.Where(t => t.Id == trialId).SelectMany(t => t.TrialBodyPartList).Select(t => new TrialBodyPartView() { Code = t.Code, Name = _userInfo.IsEn_Us ? t.Name : t.NameCN ,Id=t.Id,IsHandAdd=t.IsHandAdd}).ToListAsync();
|
||||
var list = await _trialRepository.Where(t => t.Id == trialId).SelectMany(t => t.TrialBodyPartList).Select(t => new TrialBodyPartView() { Code = t.Code, Name = _userInfo.IsEn_Us ? t.Name : t.NameCN, Id = t.Id, IsHandAdd = t.IsHandAdd }).ToListAsync();
|
||||
|
||||
return ResponseOutput.Ok(list);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-03-22 15:44:31
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using FellowOakDicom.Network.Client;
|
||||
using FellowOakDicom.Network;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// DicomAEService
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
public class TrialDicomAEService : BaseService, IDicomAEService
|
||||
{
|
||||
|
||||
private readonly IRepository<TrialDicomAE> _dicomAERepository;
|
||||
private readonly IRepository<Trial> _trialRepository;
|
||||
|
||||
public TrialDicomAEService(IRepository<TrialDicomAE> dicomAERepository, IRepository<Trial> trialRepository)
|
||||
{
|
||||
_trialRepository = trialRepository;
|
||||
_dicomAERepository = dicomAERepository;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput<PageOutput<DicomAEView>>> GetDicomAEList(DicomAEQuery inQuery)
|
||||
{
|
||||
|
||||
var dicomAEQueryable = _dicomAERepository
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.IP), t => t.IP.Contains(inQuery.IP))
|
||||
.WhereIf(inQuery.Port != null, t => t.Port == inQuery.Port)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CalledAE), t => t.CalledAE.Contains(inQuery.CalledAE))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Description), t => t.Description.Contains(inQuery.Description))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Modality), t => t.Modality.Contains(inQuery.Modality))
|
||||
.ProjectTo<DicomAEView>(_mapper.ConfigurationProvider);
|
||||
|
||||
|
||||
|
||||
|
||||
var pageList = await dicomAEQueryable.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, inQuery.SortField == string.Empty ? nameof(DicomAEView.CalledAE) : inQuery.SortField, inQuery.Asc);
|
||||
|
||||
|
||||
return ResponseOutput.Ok(pageList);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取项目dicom AE 配置信息,otherinfo里面有IsPACSConnect IsTrialPACSConfirmed
|
||||
/// </summary>
|
||||
/// <param name="trialId"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IResponseOutput<DicomAEView>> GetTrialDicomAE(Guid trialId)
|
||||
{
|
||||
var dicomAE = _dicomAERepository.Where(t => t.TrialId == trialId).ProjectTo<DicomAEView>(_mapper.ConfigurationProvider).FirstOrDefault();
|
||||
var trialConfig = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.IsPACSConnect, t.IsTrialPACSConfirmed });
|
||||
return ResponseOutput.Ok(dicomAE, trialConfig);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<IResponseOutput> AddOrUpdateDicomAE(DicomAEAddOrEdit addOrEditDicomAE)
|
||||
{
|
||||
var verifyExp1 = new EntityVerifyExp<TrialDicomAE>()
|
||||
{
|
||||
VerifyExp = u => u.IP == addOrEditDicomAE.IP && u.Port == addOrEditDicomAE.Port && u.TrialId == addOrEditDicomAE.TrialId,
|
||||
|
||||
VerifyMsg = "不允许添加相同的IP和端口的记录"
|
||||
};
|
||||
|
||||
//var verifyExp2 = new EntityVerifyExp<TrialDicomAE>()
|
||||
//{
|
||||
// VerifyExp = u => u.TrialId == addOrEditDicomAE.TrialId,
|
||||
|
||||
// VerifyMsg = "只允许配置一条记录",
|
||||
// IsVerify=addOrEditDicomAE.Id==null
|
||||
//};
|
||||
|
||||
// 在此处拷贝automapper 映射
|
||||
var entity = await _dicomAERepository.InsertOrUpdateAsync(addOrEditDicomAE, true, verifyExp1);
|
||||
|
||||
return ResponseOutput.Ok(entity.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpDelete("{dicomAEId:guid}")]
|
||||
public async Task<IResponseOutput> DeleteDicomAE(Guid dicomAEId)
|
||||
{
|
||||
var success = await _dicomAERepository.DeleteFromQueryAsync(t => t.Id == dicomAEId, true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 测试scp server 是否可以连接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{dicomAEId:guid}")]
|
||||
public async Task<bool> TestSCPServerConnect(Guid dicomAEId)
|
||||
{
|
||||
var find = await _dicomAERepository.FirstOrDefaultAsync(t => t.Id == dicomAEId);
|
||||
|
||||
if (find == null)
|
||||
{
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
find.LatestTestTime = DateTime.Now;
|
||||
|
||||
try
|
||||
{
|
||||
var client = DicomClientFactory.Create(find.IP, find.Port, false, "test-callingAE", find.CalledAE);
|
||||
|
||||
client.NegotiateAsyncOps();
|
||||
|
||||
await client.AddRequestAsync(new DicomCEchoRequest());
|
||||
|
||||
await client.SendAsync();
|
||||
|
||||
find.IsTestOK = true;
|
||||
await _dicomAERepository.SaveChangesAsync();
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
find.IsTestOK = false;
|
||||
await _dicomAERepository.SaveChangesAsync();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-07-02 16:53:58
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
/// <summary>
|
||||
/// TrialSiteDicomAEService
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
public class TrialSiteDicomAEService : BaseService, ITrialSiteDicomAEService
|
||||
{
|
||||
|
||||
private readonly IRepository<TrialSiteDicomAE> _trialSiteDicomAERepository;
|
||||
|
||||
public TrialSiteDicomAEService(IRepository<TrialSiteDicomAE> trialSiteDicomAERepository)
|
||||
{
|
||||
_trialSiteDicomAERepository = trialSiteDicomAERepository;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<List<TrialSiteDicomAEView>> GetTrialSiteDicomAEList(TrialSiteDicomAEQuery inQuery)
|
||||
{
|
||||
|
||||
var trialSiteDicomAEQueryable =
|
||||
|
||||
_trialSiteDicomAERepository.Where(t=>t.TrialSiteId==inQuery.TrialSiteId)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.IP), t => t.IP.Contains(inQuery.IP))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Port), t => t.Port.Contains(inQuery.Port))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Description), t => t.Description.Contains(inQuery.Description))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.CallingAE.Contains(inQuery.CallingAE))
|
||||
.ProjectTo<TrialSiteDicomAEView>(_mapper.ConfigurationProvider);
|
||||
|
||||
//var pageList = await trialSiteDicomAEQueryable
|
||||
//.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, string.IsNullOrWhiteSpace(inQuery.SortField) ? nameof(TrialSiteDicomAEView.Id) : inQuery.SortField,
|
||||
//inQuery.Asc);
|
||||
|
||||
var list = await trialSiteDicomAEQueryable.ToListAsync();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
public async Task<IResponseOutput> AddOrUpdateTrialSiteDicomAE(TrialSiteDicomAEAddOrEdit addOrEditTrialSiteDicomAE)
|
||||
{
|
||||
var verifyExp1 = new EntityVerifyExp<TrialSiteDicomAE>()
|
||||
{
|
||||
VerifyExp = u => u.IP == addOrEditTrialSiteDicomAE.IP && u.Port == addOrEditTrialSiteDicomAE.Port &&u.CallingAE==addOrEditTrialSiteDicomAE.CallingAE && u.TrialId == addOrEditTrialSiteDicomAE.TrialId,
|
||||
|
||||
VerifyMsg = "不允许添加相同的IP和端口的记录"
|
||||
};
|
||||
|
||||
|
||||
var entity = await _trialSiteDicomAERepository.InsertOrUpdateAsync(addOrEditTrialSiteDicomAE, true, verifyExp1);
|
||||
|
||||
return ResponseOutput.Ok(entity.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
[HttpDelete("{trialSiteDicomAEId:guid}")]
|
||||
public async Task<IResponseOutput> DeleteTrialSiteDicomAE(Guid trialSiteDicomAEId)
|
||||
{
|
||||
var success = await _trialSiteDicomAERepository.DeleteFromQueryAsync(t => t.Id == trialSiteDicomAEId, true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -141,7 +141,8 @@ namespace IRaCIS.Core.Application.Service
|
|||
.ForMember(d => d.UserCount, u => u.MapFrom(s => s.CRCUserList.Count()))
|
||||
.ForMember(d => d.VisitCount, u => u.MapFrom(s => s.SubjectVisitList.Count()))
|
||||
.ForMember(d => d.SubjectCount, u => u.MapFrom(s => s.SubjectList.Count()))
|
||||
.ForMember(d => d.UserNameList, u => u.MapFrom(s => s.CRCUserList.Where(t => t.IsDeleted == false).Select(u => u.User.FullName)));
|
||||
.ForMember(d => d.UserNameList, u => u.MapFrom(s => s.CRCUserList.Where(t => t.IsDeleted == false).Select(u => u.User.FullName)))
|
||||
.ForMember(d => d.CallingAEList, u => u.MapFrom(s => s.TrialSiteDicomAEList.Select(u => u.CallingAE)));
|
||||
//CreateMap<Site, SiteStatSimpleDTO>();
|
||||
|
||||
|
||||
|
|
|
@ -45,7 +45,11 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
CreateMap<AddOrUpdateTrialBodyPartCommand, TrialBodyPart>();
|
||||
|
||||
|
||||
|
||||
CreateMap<TrialSiteDicomAE, TrialSiteDicomAEView>();
|
||||
CreateMap<TrialSiteDicomAE, TrialSiteDicomAEAddOrEdit>().ReverseMap();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,374 @@
|
|||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using IRaCIS.Core.Application.Auth;
|
||||
using MassTransit;
|
||||
using Panda.DynamicWebApi.Attributes;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using AutoMapper.EntityFrameworkCore;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Configuration.Json;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using SharpCompress.Common;
|
||||
using System.Reactive.Subjects;
|
||||
using Subject = IRaCIS.Core.Domain.Models.Subject;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using Medallion.Threading;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using EasyCaching.Core;
|
||||
using Pipelines.Sockets.Unofficial.Arenas;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using MailKit.Search;
|
||||
using DocumentFormat.OpenXml.Office2010.Excel;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
using System.Text;
|
||||
using DocumentFormat.OpenXml.EMMA;
|
||||
using Azure;
|
||||
using System.IO.Compression;
|
||||
using static IRaCIS.Core.Domain.Share.StaticData;
|
||||
using FellowOakDicom;
|
||||
using DocumentFormat.OpenXml.Office2010.Drawing;
|
||||
using EasyCaching.Core.DistributedLock;
|
||||
using IDistributedLockProvider = Medallion.Threading.IDistributedLockProvider;
|
||||
using DocumentFormat.OpenXml.InkML;
|
||||
|
||||
namespace IRaCIS.Application.Services
|
||||
{
|
||||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
public class PatientService : BaseService
|
||||
{
|
||||
|
||||
private readonly IRepository<Trial> _trialRepository;
|
||||
private readonly IRepository<SCPPatient> _patientRepository;
|
||||
private readonly IRepository<SCPStudy> _scpStudyRepository;
|
||||
private readonly IRepository<Subject> _subjectRepository;
|
||||
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
|
||||
private readonly IDistributedLockProvider _distributedLockProvider;
|
||||
|
||||
public PatientService(IRepository<SCPStudy> studyRepository, IRepository<Trial> trialRepository, IRepository<SCPPatient> patientRepository, IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository, IDistributedLockProvider distributedLockProvider)
|
||||
{
|
||||
_scpStudyRepository = studyRepository;
|
||||
_trialRepository = trialRepository;
|
||||
_patientRepository = patientRepository;
|
||||
_subjectRepository = subjectRepository;
|
||||
_subjectVisitRepository = subjectVisitRepository;
|
||||
_distributedLockProvider = distributedLockProvider;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// scp 影像推送记录表
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput<PageOutput<SCPImageUploadView>>> GetSCPImageUploadList(SCPImageUploadQuery inQuery)
|
||||
{
|
||||
var query = _repository.Where<SCPImageUpload>()
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CalledAE), t => t.CalledAE.Contains(inQuery.CalledAE))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAEIP), t => t.CallingAEIP.Contains(inQuery.CallingAEIP))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.CallingAE.Contains(inQuery.CallingAE))
|
||||
.WhereIf(inQuery.StartTime != null, t => t.StartTime >= inQuery.StartTime)
|
||||
.WhereIf(inQuery.EndTime != null, t => t.EndTime <= inQuery.EndTime)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.TrialSiteKeyInfo), t => t.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteKeyInfo)
|
||||
|| t.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteKeyInfo) || t.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteKeyInfo))
|
||||
.ProjectTo<SCPImageUploadView>(_mapper.ConfigurationProvider);
|
||||
|
||||
|
||||
var pageList = await query.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, inQuery.SortField == string.Empty ? nameof(SCPImageUploadView.CallingAE) : inQuery.SortField, inQuery.Asc);
|
||||
|
||||
|
||||
return ResponseOutput.Ok(pageList);
|
||||
}
|
||||
|
||||
|
||||
#region 患者检查管理
|
||||
|
||||
/// <summary>
|
||||
///影像检查列表-患者为维度组织
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput<PageOutput<PatientSubjectView>>> GetPatientList(PatientTrialQuery inQuery)
|
||||
{
|
||||
|
||||
|
||||
#region new ok
|
||||
var query = _patientRepository
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.PatientIdStr.Contains(inQuery.PatientIdStr))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.PatientName.Contains(inQuery.PatientName))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubejctCode), t => t.Subject.Code.Contains(inQuery.SubejctCode))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.TrialSiteKeyInfo), t => t.TrialSite.TrialSiteCode.Contains(inQuery.TrialSiteKeyInfo)
|
||||
|| t.TrialSite.TrialSiteAliasName.Contains(inQuery.TrialSiteKeyInfo)|| t.TrialSite.TrialSiteName.Contains(inQuery.TrialSiteKeyInfo))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.SCPStudyList.Any(t => t.CallingAE == inQuery.CallingAE))
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CalledAE), t => t.SCPStudyList.Any(t => t.CalledAE == inQuery.CalledAE))
|
||||
.WhereIf(inQuery.BeginPushTime != null, t => t.LatestPushTime >= inQuery.BeginPushTime)
|
||||
.WhereIf(inQuery.EndPushTime != null, t => t.LatestPushTime <= inQuery.EndPushTime);
|
||||
|
||||
//foreach (var calledAE in inQuery.CalledAEList)
|
||||
//{
|
||||
// query = query.Where(t => t.SCPStudyList.Select(c => c.CalledAE).Contains(calledAE));
|
||||
//}
|
||||
|
||||
|
||||
var resultQuery = from patient in query
|
||||
|
||||
select new PatientSubjectView()
|
||||
{
|
||||
PatientId = patient.Id,
|
||||
PatientBirthDate = patient.PatientBirthDate,
|
||||
CreateTime = patient.CreateTime,
|
||||
CalledAEList = patient.SCPStudyList.Select(t => t.CalledAE).Distinct().ToList(),
|
||||
CallingAEList = patient.SCPStudyList.Select(t => t.CallingAE).Distinct().ToList(),
|
||||
CreateUserId = patient.CreateUserId,
|
||||
UpdateTime = patient.UpdateTime,
|
||||
UpdateUserId = patient.UpdateUserId,
|
||||
|
||||
EarliestStudyTime = patient.EarliestStudyTime,
|
||||
LatestStudyTime = patient.LatestStudyTime,
|
||||
LatestPushTime = patient.LatestPushTime,
|
||||
PatientAge = patient.PatientAge,
|
||||
PatientName = patient.PatientName,
|
||||
PatientIdStr = patient.PatientIdStr,
|
||||
PatientSex = patient.PatientSex,
|
||||
|
||||
StudyCount = patient.SCPStudyList.Count(),
|
||||
|
||||
TrialId=patient.TrialId,
|
||||
SubejctId=patient.SubjectId,
|
||||
SubjectCode=patient.Subject.Code,
|
||||
TrialSiteAliasName=patient.TrialSite.TrialSiteAliasName,
|
||||
TrialSiteCode=patient.TrialSite.TrialSiteCode,
|
||||
TrialSiteName=patient.TrialSite.TrialSiteName
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
var pageList = await resultQuery.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, inQuery.SortField == string.Empty ? nameof(PatientQueryView.PatientIdStr) : inQuery.SortField, inQuery.Asc);
|
||||
#endregion
|
||||
|
||||
|
||||
return ResponseOutput.Ok(pageList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 影像检查列表-> 获取患者的检查列表
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<PatientStudySimpleView>> GetPatientStudyList(PatientStudyInfoQuery inQuery)
|
||||
{
|
||||
var query = from scpStudy in _scpStudyRepository.Where(t => t.PatientId == inQuery.PatientId)
|
||||
.WhereIf(inQuery.EarliestStudyTime != null, t => t.StudyTime >= inQuery.EarliestStudyTime)
|
||||
.WhereIf(inQuery.LatestStudyTime != null, t => t.StudyTime <= inQuery.LatestStudyTime)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Modalities), t => t.Modalities.Contains(inQuery.Modalities))
|
||||
select new PatientStudySimpleView()
|
||||
{
|
||||
Description = scpStudy.Description,
|
||||
CalledAE = scpStudy.CalledAE,
|
||||
CallingAE = scpStudy.CallingAE,
|
||||
InstanceCount = scpStudy.InstanceCount,
|
||||
Modalities = scpStudy.Modalities,
|
||||
PatientId = scpStudy.PatientId,
|
||||
SCPStudyId = scpStudy.Id,
|
||||
SeriesCount = scpStudy.SeriesCount,
|
||||
StudyTime = scpStudy.StudyTime,
|
||||
|
||||
SubjectVisitId= scpStudy.SubjectVisitId,
|
||||
VisitName=scpStudy.SubjectVisit.VisitName,
|
||||
BlindName=scpStudy.SubjectVisit.BlindName
|
||||
};
|
||||
|
||||
|
||||
//var sortField = string.IsNullOrWhiteSpace(inQuery.SortField) ? nameof(PatientStudySimpleView.StudyTime) : inQuery.SortField;
|
||||
//var orderQuery = inQuery.Asc ? query.OrderBy(sortField) : query.OrderBy(sortField + " desc");
|
||||
|
||||
//var list = await orderQuery.ToListAsync();
|
||||
|
||||
var pageList = await query.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, inQuery.SortField == string.Empty ? nameof(PatientStudySimpleView.StudyTime) : inQuery.SortField, inQuery.Asc);
|
||||
|
||||
return pageList;
|
||||
}
|
||||
|
||||
|
||||
public async Task<List<string>> GetDicomCalledAEList()
|
||||
{
|
||||
var list = await _scpStudyRepository.Select(t => t.CalledAE).Distinct().ToListAsync();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public async Task<List<string>> GetDicomCallingAEList()
|
||||
{
|
||||
var list = await _scpStudyRepository.Select(t => t.CallingAE).Distinct().ToListAsync();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 影像访视上传 检查列表
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<VisitPatientStudyFilterView>> GetVisitPatientStudyFilterList(VisitPatientStudyFilterQuery inQuery)
|
||||
{
|
||||
|
||||
var trialSiteId=_subjectRepository.Where(t=>t.Id==inQuery.SubjectId).Select(t=>t.TrialSiteId).FirstOrDefault();
|
||||
|
||||
var query = from scpStudy in _scpStudyRepository
|
||||
//未绑定的患者,或者自己已绑定但是未绑定访视的
|
||||
.Where(t => t.Patient.SubjectId == null|| (t.Patient.SubjectId == inQuery.SubjectId && t.SubjectVisitId==null))
|
||||
//中心
|
||||
.Where(t=>t.TrialSiteId==trialSiteId)
|
||||
.WhereIf(inQuery.EarliestStudyTime != null, t => t.StudyTime >= inQuery.EarliestStudyTime)
|
||||
.WhereIf(inQuery.LatestStudyTime != null, t => t.StudyTime <= inQuery.LatestStudyTime)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Modalities), t => t.Modalities.Contains(inQuery.Modalities))
|
||||
select new VisitPatientStudyFilterView()
|
||||
{
|
||||
Description = scpStudy.Description,
|
||||
CalledAE = scpStudy.CalledAE,
|
||||
CallingAE = scpStudy.CallingAE,
|
||||
InstanceCount = scpStudy.InstanceCount,
|
||||
Modalities = scpStudy.Modalities,
|
||||
PatientId = scpStudy.PatientId,
|
||||
SCPStudyId = scpStudy.Id,
|
||||
SeriesCount = scpStudy.SeriesCount,
|
||||
StudyTime = scpStudy.StudyTime,
|
||||
};
|
||||
|
||||
|
||||
var pageList = await query.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, inQuery.SortField == string.Empty ? nameof(PatientStudySimpleView.StudyTime) : inQuery.SortField, inQuery.Asc);
|
||||
|
||||
return pageList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 提交 患者检查和访视的绑定
|
||||
/// </summary>
|
||||
/// <param name="inCommand"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[UnitOfWork]
|
||||
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
|
||||
public async Task<IResponseOutput> SubmitVisitStudyBinding(SubmitVisitStudyBindingCommand inCommand)
|
||||
{
|
||||
|
||||
var subjectId = inCommand.SubjectId;
|
||||
var subjectVisitId=inCommand.SubjectVisitId;
|
||||
var trialId = inCommand.TrialId;
|
||||
|
||||
|
||||
|
||||
var @lock = _distributedLockProvider.CreateLock($"StudyCode");
|
||||
|
||||
using (await @lock.AcquireAsync())
|
||||
{
|
||||
var dbStudyCodeIntMax = _repository.Where<DicomStudy>(s => s.TrialId == inCommand.TrialId).Select(t => t.Code).DefaultIfEmpty().Max();
|
||||
|
||||
int currentNextCodeInt = dbStudyCodeIntMax + 1;
|
||||
|
||||
foreach (var scpStudyId in inCommand.SCPStudyIdList)
|
||||
{
|
||||
|
||||
var find = _scpStudyRepository.Where(t => t.Id == scpStudyId).Include(t => t.SeriesList).Include(t => t.InstanceList).FirstOrDefault();
|
||||
|
||||
if (find != null)
|
||||
{
|
||||
|
||||
var newStuty = _mapper.Map<DicomStudy>(find);
|
||||
|
||||
await _repository.AddAsync(newStuty);
|
||||
|
||||
newStuty.SeqId = Guid.Empty;
|
||||
newStuty.Code = currentNextCodeInt;
|
||||
newStuty.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(DicomStudy));
|
||||
newStuty.IsFromPACS = true;
|
||||
newStuty.TrialId = trialId;
|
||||
newStuty.SubjectId = subjectId;
|
||||
newStuty.SubjectVisitId = subjectVisitId;
|
||||
|
||||
var newSeriesList = _mapper.Map<List<DicomSeries>>(find.SeriesList);
|
||||
|
||||
foreach (var series in newSeriesList)
|
||||
{
|
||||
|
||||
series.SeqId = Guid.Empty;
|
||||
series.TrialId = trialId;
|
||||
series.SubjectId = subjectId;
|
||||
series.SubjectVisitId = subjectVisitId;
|
||||
}
|
||||
|
||||
await _repository.AddRangeAsync(newSeriesList);
|
||||
|
||||
var newInstanceList = _mapper.Map<List<DicomInstance>>(find.InstanceList);
|
||||
|
||||
foreach (var instance in newInstanceList)
|
||||
{
|
||||
|
||||
|
||||
instance.SeqId = Guid.Empty;
|
||||
instance.TrialId = trialId;
|
||||
instance.SubjectId = subjectId;
|
||||
instance.SubjectVisitId = subjectVisitId;
|
||||
|
||||
}
|
||||
await _repository.AddRangeAsync(newInstanceList);
|
||||
}
|
||||
|
||||
currentNextCodeInt++;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
await _repository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -112,6 +112,14 @@ namespace IRaCIS.Core.Application.Service
|
|||
.ForMember(d => d.InstanceInfoList, u => u.MapFrom(s => s.InstanceList));
|
||||
|
||||
CreateMap<TaskInstance, InstanceBasicInfo>();
|
||||
|
||||
|
||||
CreateMap<SCPImageUpload, SCPImageUploadView>()
|
||||
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.TrialSite.TrialSiteCode))
|
||||
.ForMember(d => d.TrialSiteAliasName, u => u.MapFrom(s => s.TrialSite.TrialSiteAliasName))
|
||||
.ForMember(d => d.TrialSiteName, u => u.MapFrom(s => s.TrialSite.TrialSiteName))
|
||||
;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -213,7 +213,7 @@ namespace IRaCIS.Core.Application.MediatR.Handlers
|
|||
else
|
||||
{
|
||||
//"Problems are as follows:
|
||||
dialogMsg.AppendLine($"<br/><div style='color: yellow'>{_localizer["ConsistencyVerification_Prob"]}</div>");
|
||||
dialogMsg.AppendLine($"<br/><div style='color: red'>{_localizer["ConsistencyVerification_Prob"]}</div>");
|
||||
|
||||
num = 0;
|
||||
foreach (var item in dbExceptExcel)
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-07-02 09:26:43
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
namespace IRaCIS.Core.Domain.Models
|
||||
{
|
||||
///<summary>
|
||||
///ExploreRecommend
|
||||
///</summary>
|
||||
[Table("ExploreRecommend")]
|
||||
public class ExploreRecommend : Entity, IAuditUpdate, IAuditAdd,ISoftDelete
|
||||
{
|
||||
public string ExploreType { get; set; } = string.Empty;
|
||||
|
||||
|
||||
public string Version { get; set; }=string.Empty;
|
||||
|
||||
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
|
||||
public Guid CreateUserId { get; set; }
|
||||
|
||||
|
||||
public Guid UpdateUserId { get; set; }
|
||||
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
|
||||
public string DownloadUrl { get; set; } = string.Empty;
|
||||
|
||||
|
||||
public string Path { get; set; } = string.Empty;
|
||||
|
||||
public string FileName { get; set; } = string.Empty;
|
||||
|
||||
public DateTime? DeletedTime { get; set; }
|
||||
|
||||
public Guid? DeleteUserId { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -99,5 +99,8 @@ namespace IRaCIS.Core.Domain.Models
|
|||
public Guid? DeleteUserId { get; set; }
|
||||
|
||||
|
||||
public bool IsFromPACS { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-05-24 14:31:45
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Collections.Generic;
|
||||
namespace IRaCIS.Core.Domain.Models
|
||||
{
|
||||
///<summary>
|
||||
///SCPImageUpload
|
||||
///</summary>
|
||||
[Table("SCPImageUpload")]
|
||||
public class SCPImageUpload : Entity, IAuditAdd
|
||||
{
|
||||
|
||||
|
||||
|
||||
[Required]
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
|
||||
[Required]
|
||||
public Guid CreateUserId { get; set; }
|
||||
|
||||
|
||||
[Required]
|
||||
public string CallingAE { get; set; }=string.Empty;
|
||||
|
||||
[Required]
|
||||
public string CalledAE { get; set; } = string.Empty;
|
||||
|
||||
|
||||
[Required]
|
||||
public string CallingAEIP { get; set; } = string.Empty;
|
||||
|
||||
|
||||
[Required]
|
||||
public DateTime StartTime { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime EndTime { get; set; }
|
||||
|
||||
|
||||
[Required]
|
||||
public int FileCount { get; set; }
|
||||
|
||||
|
||||
[Required]
|
||||
public long FileSize { get; set; }
|
||||
|
||||
|
||||
public int StudyCount { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid TrialSiteId { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
|
||||
public Trial Trial { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public TrialSite TrialSite { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace IRaCIS.Core.Domain.Models
|
||||
{
|
||||
[Table("SCPInstance")]
|
||||
public class SCPInstance : Entity, IAuditAdd, IAuditUpdate
|
||||
{
|
||||
[JsonIgnore]
|
||||
[ForeignKey("SeriesId")]
|
||||
public SCPSeries SCPSeries { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[ForeignKey("StudyId")]
|
||||
public SCPStudy SCPStudy { get; set; }
|
||||
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
|
||||
public Guid SeqId { get; set; }
|
||||
public Guid StudyId { get; set; }
|
||||
public Guid SeriesId { get; set; }
|
||||
public string StudyInstanceUid { get; set; }
|
||||
public string SeriesInstanceUid { get; set; }
|
||||
public string SopInstanceUid { get; set; }
|
||||
public int InstanceNumber { get; set; }
|
||||
public DateTime? InstanceTime { get; set; }
|
||||
public bool CPIStatus { get; set; }
|
||||
public int ImageRows { get; set; }
|
||||
public int ImageColumns { get; set; }
|
||||
public int SliceLocation { get; set; }
|
||||
|
||||
|
||||
public string SliceThickness { get; set; }
|
||||
public int NumberOfFrames { get; set; }
|
||||
public string PixelSpacing { get; set; }
|
||||
|
||||
public string ImagerPixelSpacing { get; set; }
|
||||
public string FrameOfReferenceUID { get; set; }
|
||||
public string WindowCenter { get; set; }
|
||||
public string WindowWidth { get; set; }
|
||||
|
||||
public bool Anonymize { get; set; }
|
||||
public string Path { get; set; } = string.Empty;
|
||||
|
||||
public Guid CreateUserId { get; set; }
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; } = DateTime.Now;
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace IRaCIS.Core.Domain.Models
|
||||
{
|
||||
[Table("SCPPatient")]
|
||||
public class SCPPatient : Entity, IAuditUpdate, IAuditAdd
|
||||
{
|
||||
public List<SCPStudy> SCPStudyList { get; set; }
|
||||
|
||||
public string PatientIdStr { get; set; } = string.Empty;
|
||||
public string PatientName { get; set; } = string.Empty;
|
||||
public string PatientAge { get; set; } = string.Empty;
|
||||
public string PatientSex { get; set; } = string.Empty;
|
||||
public string PatientBirthDate { get; set; } = string.Empty;
|
||||
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; } = DateTime.Now;
|
||||
public Guid CreateUserId { get; set; }
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
|
||||
|
||||
public DateTime? EarliestStudyTime { get; set; }
|
||||
|
||||
public DateTime? LatestStudyTime { get; set; }
|
||||
|
||||
public DateTime LatestPushTime { get; set; }
|
||||
|
||||
|
||||
public Guid? SubjectId { get; set; }
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid TrialSiteId { get; set; }
|
||||
|
||||
|
||||
[JsonIgnore]
|
||||
public Subject Subject { get; set; }
|
||||
[JsonIgnore]
|
||||
public Trial Trial { get; set; }
|
||||
[JsonIgnore]
|
||||
public TrialSite TrialSite { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace IRaCIS.Core.Domain.Models
|
||||
{
|
||||
[Table("SCPSeries")]
|
||||
public class SCPSeries : Entity, IAuditAdd, IAuditUpdate, ISoftDelete
|
||||
{
|
||||
[JsonIgnore]
|
||||
[ForeignKey("StudyId")]
|
||||
public SCPStudy SCPStudy { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<SCPInstance> SCPInstanceList { get; set; }
|
||||
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid SeqId { get; set; }
|
||||
public Guid StudyId { get; set; }
|
||||
public string StudyInstanceUid { get; set; }
|
||||
public string SeriesInstanceUid { get; set; }
|
||||
public int SeriesNumber { get; set; }
|
||||
public DateTime? SeriesTime { get; set; }
|
||||
public string Modality { get; set; }
|
||||
public string Description { get; set; }
|
||||
public int InstanceCount { get; set; }
|
||||
public string SliceThickness { get; set; }
|
||||
|
||||
public string ImagePositionPatient { get; set; }
|
||||
public string ImageOrientationPatient { get; set; }
|
||||
public string BodyPartExamined { get; set; }
|
||||
public string SequenceName { get; set; }
|
||||
public string ProtocolName { get; set; }
|
||||
public string ImagerPixelSpacing { get; set; }
|
||||
|
||||
public string AcquisitionTime { get; set; } = string.Empty;
|
||||
public string AcquisitionNumber { get; set; } = string.Empty;
|
||||
public string TriggerTime { get; set; } = string.Empty;
|
||||
|
||||
public string BodyPartForEdit { get; set; } = string.Empty;
|
||||
|
||||
public Guid CreateUserId { get; set; }
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; } = DateTime.Now;
|
||||
|
||||
public DateTime? DeletedTime { get; set; }
|
||||
|
||||
public Guid? DeleteUserId { get; set; }
|
||||
public bool IsDeleted {get;set;}
|
||||
public bool IsReading { get; set; } = true;
|
||||
|
||||
public string ImageResizePath { get; set; }=string.Empty;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace IRaCIS.Core.Domain.Models
|
||||
{
|
||||
[Table("SCPStudy")]
|
||||
public class SCPStudy : Entity, IAuditUpdate, IAuditAdd, ISoftDelete
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//0 未知 1 单重 2 双重
|
||||
public bool IsDoubleReview { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<SCPInstance> InstanceList { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public List<SCPSeries> SeriesList { get; set; }
|
||||
|
||||
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public Guid SeqId { get; set; }
|
||||
|
||||
[ForeignKey("PatientId")]
|
||||
[JsonIgnore]
|
||||
public SCPPatient Patient { get; set; }
|
||||
public Guid PatientId { get; set; }
|
||||
|
||||
|
||||
|
||||
|
||||
public string StudyInstanceUid { get; set; } = string.Empty;
|
||||
public DateTime? StudyTime { get; set; }
|
||||
public string Modalities { get; set; } = string.Empty;
|
||||
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public int SeriesCount { get; set; } = 0;
|
||||
public int InstanceCount { get; set; } = 0;
|
||||
|
||||
|
||||
public string InstitutionName { get; set; } = string.Empty;
|
||||
public string PatientIdStr { get; set; } = string.Empty;
|
||||
public string PatientName { get; set; } = string.Empty;
|
||||
public string PatientAge { get; set; } = string.Empty;
|
||||
public string PatientSex { get; set; } = string.Empty;
|
||||
|
||||
public string StudyId { get; set; } = string.Empty;
|
||||
public string AccessionNumber { get; set; } = string.Empty;
|
||||
public string PatientBirthDate { get; set; } = string.Empty;
|
||||
public string AcquisitionTime { get; set; } = string.Empty;
|
||||
public string AcquisitionNumber { get; set; } = string.Empty;
|
||||
public string TriggerTime { get; set; } = string.Empty;
|
||||
|
||||
public string BodyPartExamined { get; set; } = string.Empty;
|
||||
|
||||
public string BodyPartForEdit { get; set; } = string.Empty;
|
||||
|
||||
public string ModalityForEdit { get; set; } = string.Empty;
|
||||
|
||||
|
||||
|
||||
public Guid UpdateUserId { get; set; }
|
||||
public DateTime UpdateTime { get; set; } = DateTime.Now;
|
||||
public Guid CreateUserId { get; set; }
|
||||
public DateTime CreateTime { get; set; } = DateTime.Now;
|
||||
|
||||
|
||||
//软删除
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
public DateTime? DeletedTime { get; set; }
|
||||
|
||||
public Guid? DeleteUserId { get; set; }
|
||||
|
||||
public string CallingAE { get; set; } = string.Empty;
|
||||
|
||||
public string CalledAE { get; set; } = string.Empty;
|
||||
|
||||
public bool IsUploadFinished { get; set; }
|
||||
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid TrialSiteId { get; set; }
|
||||
|
||||
public Guid? SubjectVisitId { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public SubjectVisit SubjectVisit { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
|
||||
public Trial Trial { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public TrialSite TrialSite { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-03-22 15:44:11
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
namespace IRaCIS.Core.Domain.Models
|
||||
{
|
||||
///<summary>
|
||||
///DicomAE
|
||||
///</summary>
|
||||
[Table("TrialDicomAE")]
|
||||
public class TrialDicomAE : Entity, IAuditUpdate, IAuditAdd
|
||||
{
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
|
||||
public Guid CreateUserId { get; set; }
|
||||
|
||||
|
||||
public Guid UpdateUserId { get; set; }
|
||||
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
public string CalledAE { get; set; } = string.Empty;
|
||||
|
||||
public string IP { get; set; }
|
||||
|
||||
|
||||
public int Port { get; set; }
|
||||
|
||||
|
||||
public string Modality { get; set; } = string.Empty;
|
||||
|
||||
|
||||
public string Description { get; set; }=string.Empty;
|
||||
|
||||
|
||||
public DateTime? LatestTestTime { get; set; }
|
||||
|
||||
public bool IsTestOK { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -401,7 +401,9 @@ namespace IRaCIS.Core.Domain.Models
|
|||
#endregion
|
||||
|
||||
|
||||
public bool IsPACSConnect { get; set; }
|
||||
|
||||
public bool IsTrialPACSConfirmed { get; set; }
|
||||
|
||||
///// <summary>
|
||||
///// 图像是否有标注
|
||||
|
|
|
@ -55,7 +55,9 @@ namespace IRaCIS.Core.Domain.Models
|
|||
[JsonIgnore]
|
||||
public List<Subject> SubjectList { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
|
||||
public List<TrialSiteDicomAE> TrialSiteDicomAEList { get; set; }
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由T4模板自动生成 byzhouhang 20210918
|
||||
// 生成时间 2024-07-02 16:53:49
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
namespace IRaCIS.Core.Domain.Models
|
||||
{
|
||||
///<summary>
|
||||
///TrialSiteDicomAE
|
||||
///</summary>
|
||||
[Table("TrialSiteDicomAE")]
|
||||
public class TrialSiteDicomAE : Entity, IAuditUpdate, IAuditAdd
|
||||
{
|
||||
|
||||
|
||||
|
||||
public DateTime? DeletedTime { get; set; }
|
||||
|
||||
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
|
||||
public Guid UpdateUserId { get; set; }
|
||||
|
||||
|
||||
public Guid? DeleteUserId { get; set; }
|
||||
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
|
||||
public Guid CreateUserId { get; set; }
|
||||
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
|
||||
public Guid TrialSiteId { get; set; }
|
||||
|
||||
|
||||
public string CallingAE { get; set; }
|
||||
|
||||
|
||||
public string IP { get; set; }
|
||||
|
||||
|
||||
public string Port { get; set; }
|
||||
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
|
||||
|
||||
public TrialSite TrialSite { get; set; }
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -481,6 +481,21 @@ namespace IRaCIS.Core.Infra.EFCore
|
|||
|
||||
public virtual DbSet<TrialBodyPart> TrialBodyPart { get; set; }
|
||||
|
||||
public virtual DbSet<ExploreRecommend> ExploreRecommend { get; set; }
|
||||
|
||||
public virtual DbSet<SCPPatient> SCPPatient { get; set; }
|
||||
public virtual DbSet<SCPStudy> SCPStudy { get; set; }
|
||||
public virtual DbSet<SCPSeries> SCPSeries { get; set; }
|
||||
public virtual DbSet<SCPInstance> SCPInstance { get; set; }
|
||||
public virtual DbSet<TrialDicomAE> TrialDicomAE { get; set; }
|
||||
|
||||
|
||||
public virtual DbSet<TrialSiteDicomAE> TrialSiteDicomAE { get; set; }
|
||||
|
||||
|
||||
public virtual DbSet<SCPImageUpload> SCPImageUpload { get; set; }
|
||||
|
||||
|
||||
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
|
||||
{
|
||||
// 采用触发器的方式 设置 CreateUserId CreateTime UpdateTime UpdateUserId 稽查实体里面没有这四个字段的值 因为先后顺序的原因
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="12.0.1" />
|
||||
<PackageReference Include="AutoMapper.Collection.EntityFrameworkCore" Version="9.0.0" />
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="AutoMapper.Collection.EntityFrameworkCore" Version="10.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.35.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
|
||||
<PackageReference Include="SharpCompress" Version="0.37.2" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.3.7" />
|
||||
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
public static readonly string ConnectionString = "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true";
|
||||
public static readonly string DbDatabase = "Test_IRC";
|
||||
//表名称用字符串,拼接
|
||||
public static readonly string TableName = "TrialBodyPart";
|
||||
public static readonly string TableName = "TrialSiteDicomAE";
|
||||
//具体文件里面 例如service 可以配置是否分页
|
||||
}
|
||||
#>
|
||||
|
|
|
@ -65,6 +65,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
|
||||
<# if(isPage){#>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<<#=tableName#>View>> Get<#=tableName#>List(<#=tableName#>Query inQuery)
|
||||
{
|
||||
|
||||
|
@ -74,13 +75,13 @@ namespace IRaCIS.Core.Application.Service
|
|||
.ProjectTo<<#=tableName#>View>(_mapper.ConfigurationProvider);
|
||||
|
||||
var pageList= await <#=char.ToLower(tableName[0]) + tableName.Substring(1)#>Queryable
|
||||
.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, string.IsNullOrWhiteSpace(inQuery.SortField) ? "Id" : inQuery.SortField,
|
||||
.ToPagedListAsync(inQuery.PageIndex, inQuery.PageSize, string.IsNullOrWhiteSpace(inQuery.SortField) ? nameof(<#=tableName#>View.Id) : inQuery.SortField,
|
||||
inQuery.Asc);
|
||||
|
||||
return pageList;
|
||||
}
|
||||
<# } else {#>
|
||||
|
||||
[HttpPost]
|
||||
public async Task<List<<#=tableName#>View>> Get<#=tableName#>List(<#=tableName#>Query inQuery)
|
||||
{
|
||||
|
||||
|
|
Loading…
Reference in New Issue