Compare commits
104 Commits
Test_IRC_N
...
EICS-V1.11
Author | SHA1 | Date |
---|---|---|
|
a47ac76729 | |
|
f86a88332c | |
|
f6be5e4355 | |
|
8deeb0290a | |
|
fb6231373b | |
|
a407313a95 | |
|
b1806d2eff | |
|
19351f34e1 | |
|
e0f708082d | |
|
44464a809d | |
|
c7c01b7ba3 | |
|
38b71d5267 | |
|
3950a3453a | |
|
7aa59da586 | |
|
9b2fbdb13f | |
|
c98b9e1bd4 | |
|
9522461508 | |
|
5bb99180b6 | |
|
62ec1e4955 | |
|
58e1af24c9 | |
|
a7394e7119 | |
|
a93d81de0d | |
|
6aafe02c6c | |
|
1511ef1608 | |
|
1141439c8e | |
|
559663082b | |
|
3a298518f9 | |
|
7f20232401 | |
|
20b0849b40 | |
|
db951e9195 | |
|
d5d78a99d2 | |
|
1609a7a88a | |
|
289831fce8 | |
|
dde058be18 | |
|
be8b730ee4 | |
|
28360861aa | |
|
3e097fa42b | |
|
b8a7cd6ebc | |
|
a9aefaf240 | |
|
266a0c5dd5 | |
|
54822ae038 | |
|
05203d6716 | |
|
2ce8edde80 | |
|
3c30f5dc14 | |
|
e4ad1c0653 | |
|
84df49ca07 | |
|
400edd0b70 | |
|
c4add1ecc8 | |
|
d5879e28d7 | |
|
37e083face | |
|
290506a060 | |
|
1b4bc3690a | |
|
6374781d26 | |
|
b28013a02f | |
|
fe429d2bdc | |
|
d63af2ed20 | |
|
cebf9875b1 | |
|
131681a0b3 | |
|
f833adc710 | |
|
df80d1e551 | |
|
82dc092247 | |
|
44894fcaa9 | |
|
083bebdc03 | |
|
e808764dd6 | |
|
77d198cb09 | |
|
180b02b28c | |
|
c49a74d742 | |
|
c76fc8f052 | |
|
14875dfacc | |
|
0a68788c0f | |
|
b17e5d9ff3 | |
|
05ce4b7155 | |
|
c8bbb3da48 | |
|
65de108ecd | |
|
d20c306219 | |
|
e69991ae37 | |
|
e1e2544ee3 | |
|
318333bae4 | |
|
d569de4dfe | |
|
05627ff126 | |
|
627618c854 | |
|
2711c5eb04 | |
|
a6982f79c3 | |
|
2a542949cd | |
|
a8ccbce76f | |
|
df7cf30aed | |
|
0664fbdfb7 | |
|
0a6ee05417 | |
|
f9bd8c3f5c | |
|
cb83c2a737 | |
|
fdd9afd4f0 | |
|
53d26c0445 | |
|
40d035e7a7 | |
|
a13807ae5f | |
|
9d5aaf1e26 | |
|
c347d08e2b | |
|
87f2d0e429 | |
|
89d009fcbf | |
|
7d65cf5051 | |
|
e74427c45c | |
|
e8825c7efa | |
|
628e0ad034 | |
|
2f3f639918 | |
|
87caf24dd1 |
|
@ -1,37 +0,0 @@
|
|||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
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;//标记当前异常已经被处理过了
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service.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(I18n.T("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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
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.Core.Application.Service;
|
||||
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 + typeof(BaseService).Assembly.GetName().Name+".dll");
|
||||
containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service"))
|
||||
.PropertiesAutowired().AsImplementedInterfaces();
|
||||
|
||||
|
||||
//containerBuilder.RegisterType<HttpContextAccessor>().As<IHttpContextAccessor>().SingleInstance();
|
||||
//containerBuilder.RegisterType<UserInfo>().As<IUserInfo>().InstancePerLifetimeScope();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
using EntityFramework.Exceptions.SqlServer;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using Medallion.Threading;
|
||||
using Medallion.Threading.SqlServer;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
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.AddHttpContextAccessor();
|
||||
services.AddScoped<IUserInfo, UserInfo>();
|
||||
services.AddScoped<ISaveChangesInterceptor, AuditEntityInterceptor>();
|
||||
|
||||
|
||||
//这个注入没有成功--注入是没问题的,构造函数也只是支持参数就好,错在注入的地方不能写DbContext
|
||||
//Web程序中通过重用池中DbContext实例可提高高并发场景下的吞吐量, 这在概念上类似于ADO.NET Provider原生的连接池操作方式,具有节省DbContext实例化成本的优点
|
||||
services.AddDbContext<IRaCISDBContext>((sp, options) =>
|
||||
{
|
||||
// 在控制台
|
||||
//public static readonly ILoggerFactory MyLoggerFactory = LoggerFactory.Create(builder => { builder.AddConsole(); });
|
||||
var logFactory = LoggerFactory.Create(builder => { builder.AddDebug(); });
|
||||
|
||||
options.UseSqlServer(configuration.GetSection("ConnectionStrings:RemoteNew").Value,
|
||||
contextOptionsBuilder => contextOptionsBuilder.EnableRetryOnFailure());
|
||||
|
||||
options.UseLoggerFactory(logFactory);
|
||||
|
||||
options.UseExceptionProcessor();
|
||||
|
||||
options.EnableSensitiveDataLogging();
|
||||
|
||||
options.AddInterceptors(new QueryWithNoLockDbCommandInterceptor());
|
||||
options.AddInterceptors(sp.GetServices<ISaveChangesInterceptor>());
|
||||
|
||||
options.UseProjectables();
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
//// Register an additional context factory as a Scoped service, which gets a pooled context from the Singleton factory we registered above,
|
||||
//services.AddScoped<IRaCISDBScopedFactory>();
|
||||
|
||||
//// Finally, arrange for a context to get injected from our Scoped factory:
|
||||
//services.AddScoped(sp => sp.GetRequiredService<IRaCISDBScopedFactory>().CreateDbContext());
|
||||
|
||||
//注意区分 easy caching 也有 IDistributedLockProvider
|
||||
services.AddSingleton<IDistributedLockProvider>(sp =>
|
||||
{
|
||||
//var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!);
|
||||
|
||||
return new SqlDistributedSynchronizationProvider(configuration.GetSection("ConnectionStrings:RemoteNew").Value);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.11" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.5" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="10.0.0" />
|
||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
||||
<PackageReference Include="AWSSDK.S3" Version="3.7.416.8" />
|
||||
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.401.81" />
|
||||
<PackageReference Include="DistributedLock.Core" Version="1.0.8" />
|
||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||
<PackageReference Include="fo-dicom" Version="5.2.1" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.1" />
|
||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
||||
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||
<PackageReference Include="Minio" Version="6.0.4" />
|
||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||
<TreatAsUsed>true</TreatAsUsed>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||
<PackageReference Include="Serilog.Enrichers.ClientInfo" Version="2.1.2" />
|
||||
<PackageReference Include="Serilog.Extensions.Hosting" Version="9.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj" />
|
||||
<ProjectReference Include="..\IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Helper\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,186 +0,0 @@
|
|||
|
||||
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 主机配置
|
||||
|
||||
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<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);
|
||||
|
||||
builder.Services.AddMediator(cfg =>
|
||||
{
|
||||
|
||||
});
|
||||
|
||||
|
||||
//转发头设置 获取真实IP
|
||||
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||||
{
|
||||
options.ForwardedHeaders =
|
||||
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||
});
|
||||
|
||||
|
||||
builder.Services.AddFellowOakDicom().AddTranscoderManager<NativeTranscoderManager>()
|
||||
//.AddTranscoderManager<FellowOakDicom.Imaging.NativeCodec.NativeTranscoderManager>()
|
||||
.AddImageManager<ImageSharpImageManager>();
|
||||
|
||||
|
||||
|
||||
#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.Warning)
|
||||
.WriteTo.Console()
|
||||
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day)
|
||||
.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
|
||||
|
||||
DicomSetupBuilder.UseServiceProvider(app.Services);
|
||||
|
||||
var logger = app.Services.GetService<Microsoft.Extensions.Logging.ILogger<Program>>();
|
||||
|
||||
var server = DicomServerFactory.Create<CStoreSCPService>(_configuration.GetSection("DicomSCPServiceConfig").GetValue<int>("ServerPort"), userState: app.Services, logger: logger);
|
||||
|
||||
|
||||
app.Run();
|
|
@ -1,31 +0,0 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:11224",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://localhost:5127",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
using AutoMapper;
|
||||
using IRaCIS.Core.Application.Service.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 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(_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(_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 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,376 +0,0 @@
|
|||
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, //1.2.840.10008.1.2.4.80
|
||||
DicomTransferSyntax.JPEG2000Lossless, //1.2.840.10008.1.2.4.90
|
||||
DicomTransferSyntax.JPEGProcess14SV1, //1.2.840.10008.1.2.4.70
|
||||
DicomTransferSyntax.JPEGProcess14, //1.2.840.10008.1.2.4.57 JPEG Lossless, Non-Hierarchical (Process 14)
|
||||
DicomTransferSyntax.RLELossless, //1.2.840.10008.1.2.5
|
||||
// Lossy
|
||||
DicomTransferSyntax.JPEGLSNearLossless,//1.2.840.10008.1.2.4.81"
|
||||
DicomTransferSyntax.JPEG2000Lossy, //1.2.840.10008.1.2.4.91
|
||||
DicomTransferSyntax.JPEGProcess1, //1.2.840.10008.1.2.4.50
|
||||
DicomTransferSyntax.JPEGProcess2_4, //1.2.840.10008.1.2.4.51
|
||||
// Uncompressed
|
||||
DicomTransferSyntax.ExplicitVRLittleEndian, //1.2.840.10008.1.2.1
|
||||
DicomTransferSyntax.ExplicitVRBigEndian, //1.2.840.10008.1.2.2
|
||||
DicomTransferSyntax.ImplicitVRLittleEndian //1.2.840.10008.1.2
|
||||
};
|
||||
|
||||
|
||||
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies, IServiceProvider injectServiceProvider)
|
||||
: base(stream, fallbackEncoding, log, dependencies)
|
||||
{
|
||||
_serviceProvider = injectServiceProvider.CreateScope().ServiceProvider;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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();
|
||||
|
||||
Log.Logger.Information("当前系统配置:", string.Join('|', trialDicomAEList));
|
||||
|
||||
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 && t.TrialId==_trialId).FirstOrDefault();
|
||||
|
||||
if (findTrialSiteAE != null)
|
||||
{
|
||||
_trialSiteId = findTrialSiteAE.TrialSiteId;
|
||||
|
||||
isCanReceiveIamge = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (association.CallingAE == "test-callingAE")
|
||||
{
|
||||
isCanReceiveIamge = true;
|
||||
}
|
||||
|
||||
if (!trialCalledAEList.Contains(association.CalledAE) || isCanReceiveIamge == false)
|
||||
{
|
||||
|
||||
Log.Logger.Warning($"拒绝CallingAE:{association.CallingAE} 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;
|
||||
_upload.TrialId = _trialId;
|
||||
_upload.TrialSiteId = _trialSiteId;
|
||||
|
||||
await _SCPImageUploadRepository.AddAsync(_upload, true);
|
||||
|
||||
|
||||
var _studyRepository = _serviceProvider.GetService<IRepository<SCPStudy>>();
|
||||
//将检查设置为传输结束
|
||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => _SCPStudyIdList.Contains(t.Id), u => new SCPStudy() { IsUploadFinished = true });
|
||||
|
||||
await _studyRepository.SaveChangesAndClearAllTrackingAsync();
|
||||
|
||||
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 studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
|
||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, _trialId.ToString());
|
||||
Guid instanceId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, sopInstanceUid, _trialId.ToString());
|
||||
|
||||
|
||||
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,fileSize);
|
||||
|
||||
if (!_SCPStudyIdList.Contains(scpStudyId))
|
||||
{
|
||||
_SCPStudyIdList.Add(scpStudyId);
|
||||
}
|
||||
|
||||
var series = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == 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));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,356 +0,0 @@
|
|||
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;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using Serilog.Sinks.File;
|
||||
|
||||
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,long fileSize)
|
||||
{
|
||||
string studyInstanceUid = dataset.GetString(DicomTag.StudyInstanceUID);
|
||||
string seriesInstanceUid = dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||
string sopInstanceUid = dataset.GetString(DicomTag.SOPInstanceUID);
|
||||
|
||||
string patientIdStr = dataset.GetSingleValueOrDefault(DicomTag.PatientID,string.Empty);
|
||||
|
||||
//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 && t.TrialSiteId==trialSiteId );
|
||||
var findStudy = await _studyRepository.FirstOrDefaultAsync(t=>t.Id== studyId);
|
||||
var findSerice = await _seriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
|
||||
var findInstance = await _instanceRepository.FirstOrDefaultAsync(t => t.Id == 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;
|
||||
|
||||
DateTime birthDate;
|
||||
|
||||
if (findPatient.PatientAge == string.Empty && studyTime.HasValue && DateTime.TryParse(findPatient.PatientBirthDate,out birthDate))
|
||||
{
|
||||
var patientAge = studyTime.Value.Year - birthDate.Year;
|
||||
// 如果生日还未到,年龄减去一岁
|
||||
if (studyTime.Value < birthDate.AddYears(patientAge))
|
||||
{
|
||||
patientAge--;
|
||||
}
|
||||
|
||||
findPatient.PatientAge = patientAge.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
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,
|
||||
|
||||
FileSize= fileSize,
|
||||
|
||||
};
|
||||
|
||||
++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,FileSize=fileSize });
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
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,long fileSize);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,770 +0,0 @@
|
|||
using AlibabaCloud.SDK.Sts20150401;
|
||||
using Aliyun.OSS;
|
||||
using Amazon;
|
||||
using Amazon.Runtime;
|
||||
using Amazon.S3;
|
||||
using Amazon.S3.Model;
|
||||
using Amazon.SecurityToken;
|
||||
using Amazon.SecurityToken.Model;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using IRaCIS.Core.Infrastructure.NewtonsoftJson;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Minio;
|
||||
using Minio.DataModel.Args;
|
||||
using System.Reactive.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace IRaCIS.Core.SCP;
|
||||
|
||||
#region 绑定和返回模型
|
||||
|
||||
[LowerCamelCaseJson]
|
||||
public class MinIOOptions : AWSOptions
|
||||
{
|
||||
public int Port { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class AWSOptions
|
||||
{
|
||||
public string EndPoint { get; set; }
|
||||
public bool UseSSL { get; set; }
|
||||
public string AccessKeyId { get; set; }
|
||||
public string RoleArn { get; set; }
|
||||
public string SecretAccessKey { get; set; }
|
||||
public string BucketName { get; set; }
|
||||
public string ViewEndpoint { get; set; }
|
||||
public int DurationSeconds { get; set; }
|
||||
public string Region { get; set; }
|
||||
}
|
||||
|
||||
public class AliyunOSSOptions
|
||||
{
|
||||
public string RegionId { get; set; }
|
||||
public string AccessKeyId { get; set; }
|
||||
public string AccessKeySecret { get; set; }
|
||||
|
||||
public string InternalEndpoint { 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 int DurationSeconds { 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 AliyunOSSTempToken AliyunOSS { get; set; }
|
||||
|
||||
public MinIOOptions MinIO { get; set; }
|
||||
|
||||
public AWSTempToken AWS { get; set; }
|
||||
|
||||
}
|
||||
|
||||
[LowerCamelCaseJson]
|
||||
public class AliyunOSSTempToken
|
||||
{
|
||||
public string AccessKeyId { get; set; }
|
||||
public string AccessKeySecret { get; set; }
|
||||
|
||||
public string EndPoint { get; set; }
|
||||
public string BucketName { get; set; }
|
||||
|
||||
public string Region { get; set; }
|
||||
|
||||
public string ViewEndpoint { get; set; }
|
||||
|
||||
public string SecurityToken { get; set; }
|
||||
public DateTime Expiration { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
[LowerCamelCaseJson]
|
||||
public class AWSTempToken
|
||||
{
|
||||
public string Region { get; set; }
|
||||
public string SessionToken { get; set; }
|
||||
public string EndPoint { get; set; }
|
||||
public string AccessKeyId { get; set; }
|
||||
public string SecretAccessKey { get; set; }
|
||||
public string BucketName { get; set; }
|
||||
public string ViewEndpoint { get; set; }
|
||||
public DateTime Expiration { get; set; }
|
||||
}
|
||||
|
||||
public enum ObjectStoreUse
|
||||
{
|
||||
AliyunOSS = 0,
|
||||
MinIO = 1,
|
||||
AWS = 2,
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// aws 参考链接 https://github.com/awsdocs/aws-doc-sdk-examples/tree/main/dotnetv3/S3/S3_Basics
|
||||
|
||||
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 Task DeleteFromPrefix(string prefix);
|
||||
|
||||
public ObjectStoreDTO GetObjectStoreTempToken();
|
||||
}
|
||||
|
||||
|
||||
public class OSSService : IOSSService
|
||||
{
|
||||
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
||||
|
||||
private AliyunOSSTempToken AliyunOSSTempToken { get; set; }
|
||||
|
||||
private AWSTempToken AWSTempToken { 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>
|
||||
/// <param name="isFileNameAddGuid"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
|
||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{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(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
|
||||
|
||||
// 上传文件
|
||||
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.AccessKeyId, minIOConfig.SecretAccessKey).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 awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||
|
||||
|
||||
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
|
||||
{
|
||||
BucketName = awsConfig.BucketName,
|
||||
InputStream = memoryStream,
|
||||
Key = ossRelativePath,
|
||||
};
|
||||
|
||||
await amazonS3Client.PutObjectAsync(putObjectRequest);
|
||||
}
|
||||
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>
|
||||
/// <param name="isFileNameAddGuid"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
|
||||
var localFileName = Path.GetFileName(localFilePath);
|
||||
|
||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{localFileName}" : $"{oosFolderPath}/{localFileName}";
|
||||
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
// 上传文件
|
||||
var result = _ossClient.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.AccessKeyId, minIOConfig.SecretAccessKey).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 awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
var putObjectRequest = new Amazon.S3.Model.PutObjectRequest()
|
||||
{
|
||||
BucketName = awsConfig.BucketName,
|
||||
FilePath = localFilePath,
|
||||
Key = ossRelativePath,
|
||||
};
|
||||
|
||||
await amazonS3Client.PutObjectAsync(putObjectRequest);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
return "/" + ossRelativePath;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
|
||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
// 上传文件
|
||||
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
||||
|
||||
// 将下载的文件流保存到本地文件
|
||||
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.AccessKeyId, minIOConfig.SecretAccessKey).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 awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
var getObjectArgs = new Amazon.S3.Model.GetObjectRequest()
|
||||
{
|
||||
BucketName = awsConfig.BucketName,
|
||||
Key = ossRelativePath,
|
||||
};
|
||||
|
||||
|
||||
await (await amazonS3Client.GetObjectAsync(getObjectArgs)).WriteResponseStreamToFileAsync(localFilePath, true, CancellationToken.None);
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
throw new BusinessValidationFailedException("oss下载失败!" + ex.Message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public async Task<string> GetSignedUrl(string ossRelativePath)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
|
||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
// 生成签名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.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||
.Build();
|
||||
|
||||
|
||||
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 awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
|
||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
var presignedUrl = await amazonS3Client.GetPreSignedURLAsync(new GetPreSignedUrlRequest()
|
||||
{
|
||||
BucketName = awsConfig.BucketName,
|
||||
Key = ossRelativePath,
|
||||
Expires = DateTime.UtcNow.AddMinutes(120)
|
||||
});
|
||||
|
||||
Uri uri = new Uri(presignedUrl);
|
||||
|
||||
string relativePath = uri.PathAndQuery;
|
||||
|
||||
|
||||
return relativePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
throw new BusinessValidationFailedException("oss授权url失败!" + ex.Message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除某个目录的文件
|
||||
/// </summary>
|
||||
/// <param name="prefix"></param>
|
||||
/// <returns></returns>
|
||||
public async Task DeleteFromPrefix(string prefix)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
ObjectListing objectListing = null;
|
||||
string nextMarker = null;
|
||||
do
|
||||
{
|
||||
// 使用 prefix 模拟目录结构,设置 MaxKeys 和 NextMarker
|
||||
objectListing = _ossClient.ListObjects(new Aliyun.OSS.ListObjectsRequest(aliConfig.BucketName)
|
||||
{
|
||||
Prefix = prefix,
|
||||
MaxKeys = 1000,
|
||||
Marker = nextMarker
|
||||
});
|
||||
|
||||
List<string> keys = objectListing.ObjectSummaries.Select(t => t.Key).ToList();
|
||||
|
||||
// 删除获取到的文件
|
||||
if (keys.Count > 0)
|
||||
{
|
||||
_ossClient.DeleteObjects(new Aliyun.OSS.DeleteObjectsRequest(aliConfig.BucketName, keys, false));
|
||||
}
|
||||
|
||||
// 设置 NextMarker 以获取下一页的数据
|
||||
nextMarker = objectListing.NextMarker;
|
||||
|
||||
} while (objectListing.IsTruncated);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error: {ex.Message}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||
|
||||
|
||||
var minioClient = new MinioClient().WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey).WithSSL(minIOConfig.UseSSL)
|
||||
.Build();
|
||||
|
||||
|
||||
var listArgs = new ListObjectsArgs().WithBucket(minIOConfig.BucketName).WithPrefix(prefix).WithRecursive(true);
|
||||
|
||||
|
||||
|
||||
// 创建一个空列表用于存储对象键
|
||||
var objects = new List<string>();
|
||||
|
||||
// 使用 await foreach 来异步迭代对象列表
|
||||
await foreach (var item in minioClient.ListObjectsEnumAsync(listArgs))
|
||||
{
|
||||
objects.Add(item.Key);
|
||||
}
|
||||
|
||||
|
||||
if (objects.Count > 0)
|
||||
{
|
||||
var objArgs = new RemoveObjectsArgs()
|
||||
.WithBucket(minIOConfig.BucketName)
|
||||
.WithObjects(objects);
|
||||
|
||||
// 删除对象
|
||||
await minioClient.RemoveObjectsAsync(objArgs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
|
||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
|
||||
// 提供awsAccessKeyId和awsSecretAccessKey构造凭证
|
||||
var credentials = new SessionAWSCredentials(AWSTempToken.AccessKeyId, AWSTempToken.SecretAccessKey, AWSTempToken.SessionToken);
|
||||
|
||||
//提供awsEndPoint(域名)进行访问配置
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
// 列出指定前缀下的所有对象
|
||||
var listObjectsRequest = new ListObjectsV2Request
|
||||
{
|
||||
BucketName = awsConfig.BucketName,
|
||||
Prefix = prefix
|
||||
};
|
||||
|
||||
var listObjectsResponse = await amazonS3Client.ListObjectsV2Async(listObjectsRequest);
|
||||
|
||||
if (listObjectsResponse.S3Objects.Count > 0)
|
||||
{
|
||||
// 准备删除请求
|
||||
var deleteObjectsRequest = new Amazon.S3.Model.DeleteObjectsRequest
|
||||
{
|
||||
BucketName = awsConfig.BucketName,
|
||||
Objects = new List<KeyVersion>()
|
||||
};
|
||||
|
||||
foreach (var s3Object in listObjectsResponse.S3Objects)
|
||||
{
|
||||
deleteObjectsRequest.Objects.Add(new KeyVersion
|
||||
{
|
||||
Key = s3Object.Key
|
||||
});
|
||||
}
|
||||
|
||||
// 批量删除对象
|
||||
var deleteObjectsResponse = await amazonS3Client.DeleteObjectsAsync(deleteObjectsRequest);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ObjectStoreDTO GetObjectStoreTempToken()
|
||||
{
|
||||
|
||||
var ossOptions = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var client = new Client(new AlibabaCloud.OpenApiClient.Models.Config()
|
||||
{
|
||||
AccessKeyId = ossOptions.AccessKeyId,
|
||||
AccessKeySecret = ossOptions.AccessKeySecret,
|
||||
//AccessKeyId = "LTAI5tJV76pYX5yPg1N9QVE8",
|
||||
//AccessKeySecret = "roRNLa9YG1of4pYruJGCNKBXEWTAWa",
|
||||
|
||||
Endpoint = "sts.cn-hangzhou.aliyuncs.com"
|
||||
});
|
||||
|
||||
var assumeRoleRequest = new AlibabaCloud.SDK.Sts20150401.Models.AssumeRoleRequest();
|
||||
// 将<YOUR_ROLE_SESSION_NAME>设置为自定义的会话名称,例如oss-role-session。
|
||||
assumeRoleRequest.RoleSessionName = $"session-name-{NewId.NextGuid()}";
|
||||
// 将<YOUR_ROLE_ARN>替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。
|
||||
assumeRoleRequest.RoleArn = ossOptions.RoleArn;
|
||||
//assumeRoleRequest.RoleArn = "acs:ram::1899121822495495:role/webdirect";
|
||||
assumeRoleRequest.DurationSeconds = ossOptions.DurationSeconds;
|
||||
var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions();
|
||||
var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime);
|
||||
var credentials = response.Body.Credentials;
|
||||
|
||||
var tempToken = new AliyunOSSTempToken()
|
||||
{
|
||||
AccessKeyId = credentials.AccessKeyId,
|
||||
AccessKeySecret = credentials.AccessKeySecret,
|
||||
|
||||
//转为服务器时区,最后统一转为客户端时区
|
||||
Expiration = TimeZoneInfo.ConvertTimeFromUtc(DateTime.Parse(credentials.Expiration), TimeZoneInfo.Local),
|
||||
SecurityToken = credentials.SecurityToken,
|
||||
|
||||
|
||||
Region = ossOptions.Region,
|
||||
BucketName = ossOptions.BucketName,
|
||||
EndPoint = ossOptions.EndPoint,
|
||||
ViewEndpoint = ossOptions.ViewEndpoint,
|
||||
|
||||
};
|
||||
|
||||
AliyunOSSTempToken = tempToken;
|
||||
|
||||
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, AliyunOSS = tempToken };
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||
{
|
||||
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, MinIO = ObjectStoreServiceOptions.MinIO };
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
var awsOptions = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
//aws 临时凭证
|
||||
// 创建 STS 客户端
|
||||
var stsClient = new AmazonSecurityTokenServiceClient(awsOptions.AccessKeyId, awsOptions.SecretAccessKey);
|
||||
|
||||
// 使用 AssumeRole 请求临时凭证
|
||||
var assumeRoleRequest = new AssumeRoleRequest
|
||||
{
|
||||
|
||||
RoleArn = awsOptions.RoleArn, // 角色 ARN
|
||||
RoleSessionName = $"session-name-{NewId.NextGuid()}",
|
||||
DurationSeconds = awsOptions.DurationSeconds // 临时凭证有效期
|
||||
};
|
||||
|
||||
var assumeRoleResponse = stsClient.AssumeRoleAsync(assumeRoleRequest).Result;
|
||||
|
||||
var credentials = assumeRoleResponse.Credentials;
|
||||
|
||||
var tempToken = new AWSTempToken()
|
||||
{
|
||||
AccessKeyId = credentials.AccessKeyId,
|
||||
SecretAccessKey = credentials.SecretAccessKey,
|
||||
SessionToken = credentials.SessionToken,
|
||||
Expiration = credentials.Expiration,
|
||||
Region = awsOptions.Region,
|
||||
BucketName = awsOptions.BucketName,
|
||||
EndPoint = awsOptions.EndPoint,
|
||||
ViewEndpoint = awsOptions.ViewEndpoint,
|
||||
|
||||
};
|
||||
|
||||
AWSTempToken = tempToken;
|
||||
return new ObjectStoreDTO() { ObjectStoreUse = ObjectStoreServiceOptions.ObjectStoreUse, AWS = tempToken };
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
|
@ -21,7 +21,6 @@ using FellowOakDicom.Imaging;
|
|||
using SharpCompress.Common;
|
||||
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
||||
namespace IRaCIS.Core.SCP.Service
|
||||
{
|
||||
|
@ -259,16 +258,9 @@ namespace IRaCIS.Core.SCP.Service
|
|||
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
|
||||
{
|
||||
|
||||
string studyInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID,string.Empty);
|
||||
string seriesInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty);
|
||||
string sopInstanceUid = request.Dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty);
|
||||
|
||||
if(studyInstanceUid.IsNullOrEmpty() || seriesInstanceUid.IsNullOrEmpty() || sopInstanceUid.IsNullOrEmpty())
|
||||
{
|
||||
Log.Logger.Error($"接收数据读取StudyInstanceUID:{studyInstanceUid}、SeriesInstanceUID:{seriesInstanceUid}、SOPInstanceUID:{sopInstanceUid}有空 ");
|
||||
|
||||
return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||
}
|
||||
string studyInstanceUid = request.Dataset.GetString(DicomTag.StudyInstanceUID);
|
||||
string seriesInstanceUid = request.Dataset.GetString(DicomTag.SeriesInstanceUID);
|
||||
string sopInstanceUid = request.Dataset.GetString(DicomTag.SOPInstanceUID);
|
||||
|
||||
//Guid studyId = IdentifierHelper.CreateGuid(studyInstanceUid, trialId.ToString());
|
||||
Guid seriesId = IdentifierHelper.CreateGuid(studyInstanceUid, seriesInstanceUid, _trialId.ToString());
|
||||
|
|
|
@ -19,8 +19,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure"
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRC.Core.SCP", "IRC.Core.SCP\IRC.Core.SCP.csproj", "{ECD08F47-DC1A-484E-BB91-6CDDC8823CC5}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IRC.Core.Dicom", "IRC.Core.Dicom\IRC.Core.Dicom.csproj", "{0545F0A5-D97B-4A47-92A6-A8A02A181322}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -59,10 +57,6 @@ Global
|
|||
{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
|
||||
{0545F0A5-D97B-4A47-92A6-A8A02A181322}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0545F0A5-D97B-4A47-92A6-A8A02A181322}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0545F0A5-D97B-4A47-92A6-A8A02A181322}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0545F0A5-D97B-4A47-92A6-A8A02A181322}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.BusinessFilter;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Contracts.DTO;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Application.Image.QA;
|
||||
using IRaCIS.Core.Application.Service;
|
||||
|
@ -35,31 +34,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||
) : ControllerBase
|
||||
{
|
||||
|
||||
|
||||
[HttpPost, Route("Inspection/NoneDicomStudy/UpdateNoneDicomStudy")]
|
||||
[TrialGlobalLimit("AfterStopCannNotOpt")]
|
||||
[UnitOfWork]
|
||||
|
||||
public async Task<IResponseOutput> UpdateNoneDicomStudy(DataInspectionDto<NoneDicomEdit> opt, [FromServices] INoneDicomStudyService _noneDicomStudyService)
|
||||
{
|
||||
var singId = await _inspectionService.RecordSing(opt.SignInfo);
|
||||
var result = await _noneDicomStudyService.UpdateNoneDicomStudy(opt.Data);
|
||||
await _inspectionService.CompletedSign(singId, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
[HttpPost, Route("Inspection/QCOperation/UpdateDicomStudyInfo")]
|
||||
[TrialGlobalLimit("AfterStopCannNotOpt")]
|
||||
[UnitOfWork]
|
||||
|
||||
public async Task<IResponseOutput> UpdateDicomStudyInfo(DataInspectionDto<DicomStudyEdit> opt, [FromServices] IQCOperationService _qcOperationService)
|
||||
{
|
||||
var singId = await _inspectionService.RecordSing(opt.SignInfo);
|
||||
var result = await _qcOperationService.UpdateDicomStudyInfo(opt.Data);
|
||||
await _inspectionService.CompletedSign(singId, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
#region 获取稽查数据
|
||||
/// <summary>
|
||||
/// 获取稽查数据
|
||||
|
|
|
@ -27,7 +27,6 @@ using Microsoft.AspNetCore.WebUtilities;
|
|||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using MiniExcelLibs;
|
||||
using Newtonsoft.Json;
|
||||
|
@ -39,7 +38,6 @@ using System.Data;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Path = System.IO.Path;
|
||||
|
||||
|
@ -584,9 +582,9 @@ namespace IRaCIS.Core.API.Controllers
|
|||
templateFileStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
|
||||
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/DataReconciliation", realFileName);
|
||||
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/Check", realFileName);
|
||||
|
||||
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
|
||||
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId });
|
||||
|
||||
return ossRelativePath;
|
||||
|
||||
|
@ -801,13 +799,12 @@ namespace IRaCIS.Core.API.Controllers
|
|||
|
||||
[HttpPost, Route("TrialSiteSurvey/UploadTrialSiteSurveyUser")]
|
||||
[DisableFormValueModelBinding]
|
||||
[UnitOfWork]
|
||||
public async Task<IResponseOutput> UploadTrialSiteSurveyUser(Guid trialId, string baseUrl, string routeUrl,
|
||||
[FromServices] IRepository<TrialSite> _trialSiteRepository,
|
||||
[FromServices] IRepository<UserType> _usertypeRepository,
|
||||
[FromServices] ITrialSiteSurveyService _trialSiteSurveyService,
|
||||
[FromServices] IOSSService oSSService,
|
||||
[FromServices] IOptionsMonitor<SystemEmailSendConfig> _systemEmailConfig,
|
||||
|
||||
[FromServices] IRepository<InspectionFile> _inspectionFileRepository)
|
||||
{
|
||||
var templateFileStream = new MemoryStream();
|
||||
|
@ -824,9 +821,9 @@ namespace IRaCIS.Core.API.Controllers
|
|||
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_TemplateUploadData"]);
|
||||
}
|
||||
|
||||
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, $"{trialId.ToString()}/InspectionUpload/SiteSurvey", realFileName);
|
||||
var ossRelativePath = await oSSService.UploadToOSSAsync(fileStream, "InspectionUpload/SiteSurvey", realFileName);
|
||||
|
||||
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId }, true);
|
||||
await _inspectionFileRepository.AddAsync(new InspectionFile() { FileName = realFileName, RelativePath = ossRelativePath, TrialId = trialId });
|
||||
|
||||
|
||||
|
||||
|
@ -839,26 +836,6 @@ namespace IRaCIS.Core.API.Controllers
|
|||
.Where(t => !(string.IsNullOrWhiteSpace(t.TrialSiteCode) && string.IsNullOrWhiteSpace(t.FirstName) && string.IsNullOrWhiteSpace(t.LastName) && string.IsNullOrWhiteSpace(t.Email)
|
||||
&& string.IsNullOrWhiteSpace(t.Phone) && string.IsNullOrWhiteSpace(t.UserTypeStr) && string.IsNullOrWhiteSpace(t.OrganizationName))).ToList();
|
||||
|
||||
//处理前后空格
|
||||
foreach (var excel in excelList)
|
||||
{
|
||||
excel.Email = excel.Email.Trim();
|
||||
excel.Phone = excel.Phone.Trim();
|
||||
excel.OrganizationName = excel.OrganizationName.Trim();
|
||||
excel.UserTypeStr = excel.UserTypeStr?.Trim();
|
||||
excel.TrialSiteCode = excel.TrialSiteCode.Trim();
|
||||
excel.FirstName = excel.FirstName.Trim();
|
||||
excel.LastName = excel.LastName.Trim();
|
||||
}
|
||||
|
||||
var emailRegexStr = _systemEmailConfig.CurrentValue.EmailRegexStr;
|
||||
if (excelList.Any(t => !Regex.IsMatch(t.Email, emailRegexStr)))
|
||||
{
|
||||
var errorList = excelList.Where(t => !Regex.IsMatch(t.Email, emailRegexStr)).Select(t => t.Email).ToList();
|
||||
//有邮箱不符合邮箱格式,请核查Excel数据
|
||||
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidEmail"] + string.Join(" | ", errorList));
|
||||
}
|
||||
|
||||
if (excelList.Any(t => string.IsNullOrWhiteSpace(t.TrialSiteCode) || string.IsNullOrWhiteSpace(t.FirstName) || string.IsNullOrWhiteSpace(t.LastName) || string.IsNullOrWhiteSpace(t.Email) || string.IsNullOrWhiteSpace(t.UserTypeStr)))
|
||||
{
|
||||
//请确保Excel中 每一行的 中心编号,姓名,邮箱,用户类型数据记录完整再进行上传
|
||||
|
@ -887,6 +864,11 @@ namespace IRaCIS.Core.API.Controllers
|
|||
}
|
||||
}
|
||||
|
||||
if (excelList.Any(t => !t.Email.Contains("@")))
|
||||
{
|
||||
//有邮箱不符合邮箱格式,请核查Excel数据
|
||||
throw new BusinessValidationFailedException(_localizer["UploadDownLoad_InvalidEmail"]);
|
||||
}
|
||||
var generateUserTypeList = new List<string>() { "CRC", "CRA" };
|
||||
|
||||
//if (excelList.Any(t => !generateUserTypeList.Contains(t.UserTypeStr.ToUpper())))
|
||||
|
|
|
@ -41,21 +41,6 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
|
|||
HangfireJobHelper.RemoveCronJob(jobId);
|
||||
}
|
||||
|
||||
// 清除所有可能存在的定时任务,防止类型加载错误
|
||||
var allJobIdList = JobStorage.Current.GetConnection().GetRecurringJobs().Select(t => t.Id).ToList();
|
||||
foreach (var jobId in allJobIdList)
|
||||
{
|
||||
try
|
||||
{
|
||||
HangfireJobHelper.RemoveCronJob(jobId);
|
||||
_logger.LogInformation($"已清除定时任务: {jobId}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning($"清除定时任务 {jobId} 时出错: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr == StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
|
||||
.Select(t => new { t.Id, t.Code, TrialCode = t.Trial.TrialCode, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
|
||||
|
@ -82,7 +67,7 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
|
|||
//利用主键作为任务Id
|
||||
var jobId = $"{task.Id}_({task.BusinessScenarioEnum})";
|
||||
|
||||
HangfireJobHelper.AddOrUpdateTimingCronJob(jobId, task.BusinessScenarioEnum, task.EmailCron);
|
||||
HangfireJobHelper.AddOrUpdateSystemCronJob(jobId, task.BusinessScenarioEnum, task.EmailCron);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -76,15 +76,16 @@
|
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="ConfigMapFileProvider" Version="2.0.1" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.20" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.18" />
|
||||
<PackageReference Include="Hangfire.Dashboard.BasicAuthorization" Version="1.0.2" />
|
||||
<PackageReference Include="Hangfire.InMemory" Version="1.0.0" />
|
||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.20" />
|
||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.18" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.10" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||
<PackageReference Include="Serilog.Formatting.Compact" Version="3.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.Email" Version="4.1.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="7.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.1" />
|
||||
<PackageReference Include="Serilog.Sinks.Email" Version="4.0.0" />
|
||||
<PackageReference Include="Serilog.Sinks.File" Version="6.0.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -22,10 +22,6 @@ namespace IRaCIS.Core.API
|
|||
var config = new LoggerConfiguration()
|
||||
.MinimumLevel.Information()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||
.MinimumLevel.Override("MassTransit", LogEventLevel.Warning)
|
||||
//https://github.com/ZiggyCreatures/FusionCache/blob/main/docs/Logging.md
|
||||
.MinimumLevel.Override("ZiggyCreatures.Caching.Fusion", LogEventLevel.Warning)
|
||||
|
||||
// Filter out ASP.NET Core infrastructre logs that are Information and below 日志太多了 一个请求 记录好几条
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting", LogEventLevel.Warning)
|
||||
|
@ -35,7 +31,7 @@ namespace IRaCIS.Core.API
|
|||
.Enrich.FromLogContext()
|
||||
.Filter.ByExcluding(logEvent => logEvent.Properties.ContainsKey("RequestPath") && logEvent.Properties["RequestPath"].ToString().Contains("/health"))
|
||||
.WriteTo.Console()
|
||||
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day,retainedFileCountLimit:60);
|
||||
.WriteTo.File($"{AppContext.BaseDirectory}Serilogs/.log", rollingInterval: RollingInterval.Day);
|
||||
|
||||
#region 根据环境配置是否打开错误发送邮件通知
|
||||
|
||||
|
|
|
@ -27,8 +27,7 @@ namespace IRaCIS.Core.API
|
|||
hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions()
|
||||
{
|
||||
SchemaName = "dbo",
|
||||
}).UseRecommendedSerializerSettings();
|
||||
// 移除 UseSimpleAssemblyNameTypeSerializer() 以避免类型加载问题
|
||||
}).UseRecommendedSerializerSettings().UseSimpleAssemblyNameTypeSerializer();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"RemoteNew": "Server=101.132.193.237,1434;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=101.132.193.237,1434;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
||||
//"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
||||
//"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
||||
//"RemoteNew": "Server=101.132.193.237,1434;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
||||
//"Hangfire": "Server=101.132.193.237,1434;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
||||
"RemoteNew": "Server=prod_mssql_standard,1433;Database=Prod_IRC;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true",
|
||||
"Hangfire": "Server=prod_mssql_standard,1433;Database=Prod_IRC_Hangfire;User ID=sa;Password=zhanying@2021;TrustServerCertificate=true"
|
||||
},
|
||||
"ObjectStoreService": {
|
||||
"ObjectStoreUse": "AliyunOSS",
|
||||
|
@ -60,7 +60,7 @@
|
|||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"FromEmail": "irc@extimaging.com",
|
||||
"FromName": "IRC Imaging System",
|
||||
"FromName": "irc",
|
||||
"AuthorizationCode": "ExtImg@2022",
|
||||
"SiteUrl": "http://irc.extimaging.com/login",
|
||||
"SystemShortName": "IRC",
|
||||
|
@ -72,7 +72,6 @@
|
|||
"CompanyShortNameCN": "展影医疗",
|
||||
"IsEnv_US": false,
|
||||
"IsOpenErrorNoticeEmail": false,
|
||||
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||
},
|
||||
"SystemPacsConfig": {
|
||||
|
|
|
@ -1,164 +1,104 @@
|
|||
{
|
||||
// 日志信息
|
||||
"Logging": {
|
||||
// 日志等级
|
||||
"LogLevel": {
|
||||
// 默认日志等级
|
||||
"Default": "Information",
|
||||
// 调试日志等级
|
||||
"Microsoft": "Warning",
|
||||
// ASP.NET Core 日志等级
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
// 数据库链接字符串
|
||||
"ConnectionStrings": {
|
||||
// 本地数据库链接字符串
|
||||
"RemoteNew": "Server=106.14.89.110,1435;Database=Test_IRC;User ID=sa;Password=xc@123456;TrustServerCertificate=true",
|
||||
// Hangfire 定时任务数据库链接字符串
|
||||
"Hangfire": "Server=106.14.89.110,1435;Database=Test_IRC_Hangfire;User ID=sa;Password=xc@123456;TrustServerCertificate=true"
|
||||
},
|
||||
// 对象存储服务配置
|
||||
|
||||
"ObjectStoreService": {
|
||||
// 使用的对象存储服务类型
|
||||
|
||||
"ObjectStoreUse": "AliyunOSS",
|
||||
// 阿里云对象存储服务的配置
|
||||
|
||||
"AliyunOSS": {
|
||||
// 阿里云 OSS 的 Region ID
|
||||
"RegionId": "cn-shanghai",
|
||||
// 阿里云 OSS 的内部访问端点
|
||||
"InternalEndpoint": "https://oss-cn-shanghai-internal.aliyuncs.com",
|
||||
// 阿里云 OSS 的外部访问端点
|
||||
"EndPoint": "https://oss-cn-shanghai.aliyuncs.com",
|
||||
// 阿里云 OSS 的访问密钥 ID
|
||||
"AccessKeyId": "LTAI5tRRZehUp2V9pyTPtAJm",
|
||||
// 阿里云 OSS 的访问密钥 Secret
|
||||
"AccessKeySecret": "FLizxkHsMm4CGYHtkV8E3PNJJZU7oV",
|
||||
// 阿里云 OSS 的角色 ARN
|
||||
"RoleArn": "acs:ram::1899121822495495:role/dev-oss-access",
|
||||
// 阿里云 OSS 的Bucket名称
|
||||
"BucketName": "zy-irc-test-store",
|
||||
// 阿里云 OSS 的访问端点
|
||||
//"ViewEndpoint": "https://zy-irc-test-store.oss-cn-shanghai.aliyuncs.com",
|
||||
"ViewEndpoint": "https://zy-irc-test-dev-cache.oss-cn-shanghai.aliyuncs.com",
|
||||
// 阿里云 OSS 的预览端点
|
||||
"Region": "oss-cn-shanghai",
|
||||
// 阿里云 OSS 的临时访问凭证有效时间(秒)
|
||||
"DurationSeconds": 7200,
|
||||
// 阿里云 OSS 的预览端点
|
||||
"PreviewEndpoint": "https://test-oss.test.extimaging.com"
|
||||
},
|
||||
// MinIO 对象存储服务的配置
|
||||
"MinIO": {
|
||||
// MinIO 的访问端点
|
||||
"EndPoint": "hir-oss.test.extimaging.com",
|
||||
// MinIO 的端口
|
||||
"Port": "443",
|
||||
// 是否使用 SSL
|
||||
"UseSSL": true,
|
||||
// MinIO 的角色 ARN
|
||||
"AccessKey": "fbStsVYCIPKHQneeqMwD",
|
||||
// MinIO 的访问密钥
|
||||
"SecretKey": "TzgvyA3zGXMUnpilJNUlyMYHfosl1hBMl6lxPmjy",
|
||||
// MinIO 的BucketName
|
||||
"BucketName": "irc-test",
|
||||
// MinIO 的访问端点
|
||||
"ViewEndpoint": "https://hir-oss.test.extimaging.com/irc-test"
|
||||
},
|
||||
// AWS S3 对象存储服务的配置
|
||||
"AWS": {
|
||||
// AWS S3 的Region
|
||||
"Region": "us-east-1",
|
||||
// AWS S3 的内部访问端点
|
||||
"EndPoint": "s3.us-east-1.amazonaws.com",
|
||||
// 是否使用 SSL
|
||||
"UseSSL": true,
|
||||
// AWS S3 的角色 ARN
|
||||
"RoleArn": "arn:aws:iam::471112624751:role/uat_s3_access",
|
||||
// AWS S3 的访问密钥 ID
|
||||
"AccessKeyId": "AKIAW3MEAFJX7IPXISP4",
|
||||
// AWS S3 的访问密钥 Secret
|
||||
"SecretAccessKey": "Pgrg3le5jPxZQ7MR1yYNS30J0XRyJeKVyIIjElXc",
|
||||
// AWS S3 的Bucket名称
|
||||
"BucketName": "ei-med-s3-lili-uat-store",
|
||||
// AWS S3 的访问端点
|
||||
"ViewEndpoint": "https://ei-med-s3-lili-uat-store.s3.amazonaws.com",
|
||||
// AWS S3 的持续数秒
|
||||
"DurationSeconds": 7200
|
||||
}
|
||||
},
|
||||
// 系统配置
|
||||
|
||||
"BasicSystemConfig": {
|
||||
// 打开用户复杂密码
|
||||
|
||||
"OpenUserComplexPassword": false,
|
||||
// 是否在开始工作前强制签署电子知情同意书
|
||||
"OpenSignDocumentBeforeWork": false,
|
||||
// 是否启用登录失败次数限制(防暴力破解)
|
||||
|
||||
"OpenLoginLimit": false,
|
||||
// 连续登录失败多少次后触发锁定
|
||||
"LoginMaxFailCount": 5,
|
||||
// 触发锁定后账号锁定时长(分钟)
|
||||
"LoginFailLockMinutes": 1,
|
||||
// 无操作自动登出的超时时间(分钟)
|
||||
"AutoLoginOutMinutes": 10,
|
||||
// 是否启用多因子登录认证(MFA)
|
||||
|
||||
"OpenLoginMFA": false,
|
||||
// 连续阅片的最长工作时间(分钟),超时后强制休息
|
||||
|
||||
"ContinuousReadingTimeMin": 120,
|
||||
// 强制休息时长(分钟)
|
||||
"ReadingRestTimeMin": 10,
|
||||
// 是否强制用户定期修改密码
|
||||
|
||||
"IsNeedChangePassWord": true,
|
||||
// 密码有效期(天),到期后必须修改
|
||||
"ChangePassWordDays": 90,
|
||||
|
||||
// 模板类型 1 Elevate 2 Extensive
|
||||
"TemplateType": 2,
|
||||
// 是否打开项目关联删除
|
||||
|
||||
"OpenTrialRelationDelete": true,
|
||||
// 转换PDF服务配置
|
||||
|
||||
"ThirdPdfUrl": "http://106.14.89.110:30088/api/v1/convert/file/pdf"
|
||||
},
|
||||
// 邮件服务配置(用于系统通知、找回密码、错误报警等)
|
||||
|
||||
"SystemEmailSendConfig": {
|
||||
// SMTP端口
|
||||
"Port": 465,
|
||||
// 企业邮箱SMTP服务器地址
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
// 发件人邮箱地址
|
||||
"FromEmail": "test@extimaging.com",
|
||||
// 发件人显示名称
|
||||
"FromName": "Test IRC Imaging System",
|
||||
// SMTP授权码
|
||||
"FromName": "Test_IRC",
|
||||
"AuthorizationCode": "SHzyyl2021",
|
||||
// 系统对外访问地址
|
||||
"SiteUrl": "http://irc.test.extimaging.com/login",
|
||||
// 系统简称
|
||||
|
||||
"SystemShortName": "IRC",
|
||||
// 组织英文名称
|
||||
"OrganizationName": "Extlmaging",
|
||||
// 组织中文名称
|
||||
"OrganizationNameCN": "Extlmaging",
|
||||
// 公司英文全称
|
||||
"CompanyName": "Extensive Imaging",
|
||||
// 公司中文全称
|
||||
"CompanyNameCN": "上海展影医疗科技有限公司",
|
||||
// 公司英文简称
|
||||
"CompanyShortName": "Extensive Imaging",
|
||||
// 公司中文简称
|
||||
"CompanyShortNameCN": "展影医疗",
|
||||
// 是否为国际版环境
|
||||
"IsEnv_US": false,
|
||||
// 是否开启系统异常邮件报警
|
||||
"IsOpenErrorNoticeEmail": false,
|
||||
// 邮箱格式校验正则表达式
|
||||
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
||||
// 接收系统异常报警的邮箱列表
|
||||
"ErrorNoticeEmailList": ["872297557@qq.com"]
|
||||
},
|
||||
// PACS 连接配置
|
||||
|
||||
"SystemPacsConfig": {
|
||||
// PACS服务器端口
|
||||
"Port": "11113",
|
||||
// PACS服务器IP地址
|
||||
"IP": "106.14.89.110"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
"Port": 587,
|
||||
"Host": "smtp-mail.outlook.com",
|
||||
"FromEmail": "donotreply@elevateimaging.ai",
|
||||
"FromName": "LiLi System",
|
||||
"FromName": "LiLi",
|
||||
"AuthorizationCode": "Q#669869497420ul",
|
||||
|
||||
"SystemShortName": "LiLi",
|
||||
|
@ -78,7 +78,6 @@
|
|||
"SiteUrl": "https://lili.elevateimaging.ai/login",
|
||||
"IsEnv_US": true,
|
||||
"IsOpenErrorNoticeEmail": false,
|
||||
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||
},
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
"Port": 587,
|
||||
"Host": "smtp-mail.outlook.com",
|
||||
"FromEmail": "donotreply@elevateimaging.ai",
|
||||
"FromName": "LiLi System",
|
||||
"FromName": "LiLi",
|
||||
"AuthorizationCode": "Q#669869497420ul",
|
||||
|
||||
"SystemShortName": "LiLi",
|
||||
|
|
|
@ -72,7 +72,7 @@
|
|||
"Port": 587,
|
||||
"Host": "smtp-mail.outlook.com",
|
||||
"FromEmail": "donotreply@elevateimaging.ai",
|
||||
"FromName": "LiLi System",
|
||||
"FromName": "LiLi",
|
||||
"AuthorizationCode": "Q#669869497420ul",
|
||||
|
||||
"SystemShortName": "LiLi",
|
||||
|
@ -85,7 +85,6 @@
|
|||
"SiteUrl": "https://lili.uat.elevateimaging.ai/login",
|
||||
"IsEnv_US": true,
|
||||
"IsOpenErrorNoticeEmail": false,
|
||||
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||
},
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
"Port": 465,
|
||||
"Host": "smtp.qiye.aliyun.com",
|
||||
"FromEmail": "uat@extimaging.com",
|
||||
"FromName": "Uat IRC Imaging System",
|
||||
"FromName": "UAT_IRC",
|
||||
"AuthorizationCode": "SHzyyl2021",
|
||||
"SiteUrl": "http://irc.uat.extimaging.com/login",
|
||||
|
||||
|
@ -92,7 +92,6 @@
|
|||
"CompanyShortNameCN": "展影医疗",
|
||||
"IsEnv_US": false,
|
||||
"IsOpenErrorNoticeEmail": false,
|
||||
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
|
||||
"ErrorNoticeEmailList": [ "872297557@qq.com" ]
|
||||
},
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service.BusinessFilter;
|
||||
|
||||
|
|
|
@ -70,8 +70,6 @@ public class SystemEmailSendConfig
|
|||
|
||||
public bool IsOpenErrorNoticeEmail { get; set; }
|
||||
|
||||
public string EmailRegexStr { get; set; }
|
||||
|
||||
public List<string> ErrorNoticeEmailList { get; set; } =new List<string>();
|
||||
}
|
||||
|
||||
|
@ -85,8 +83,6 @@ public class SystemEmailSendConfigView
|
|||
public string CompanyShortName { get; set; } = string.Empty;
|
||||
|
||||
public string CompanyShortNameCN { get; set; } = string.Empty;
|
||||
|
||||
public string EmailRegexStr { get; set; }
|
||||
}
|
||||
|
||||
public class SystemPacsConfig
|
||||
|
|
|
@ -11,6 +11,5 @@ global using AutoMapper;
|
|||
global using IRaCIS.Core.Domain.Share;
|
||||
global using IRaCIS.Core.Application.BusinessFilter;
|
||||
global using IdentityUser = IRaCIS.Core.Domain.Models.IdentityUser;
|
||||
global using Serilog;
|
||||
|
||||
|
||||
|
|
|
@ -1,190 +0,0 @@
|
|||
using FellowOakDicom;
|
||||
using FellowOakDicom.Media;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IRaCIS.Core.Application.Helper
|
||||
{
|
||||
|
||||
public class StudyDIRInfo
|
||||
{
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
// Study
|
||||
public Guid DicomStudyId { get; set; }
|
||||
|
||||
public string PatientId { get; set; }
|
||||
public string PatientName { get; set; }
|
||||
public string PatientBirthDate { get; set; }
|
||||
public string PatientSex { get; set; }
|
||||
|
||||
public string StudyInstanceUid { get; set; }
|
||||
public string StudyId { get; set; }
|
||||
public string DicomStudyDate { get; set; }
|
||||
public string DicomStudyTime { get; set; }
|
||||
public string AccessionNumber { get; set; }
|
||||
public string StudyDescription { get; set; }
|
||||
|
||||
// Series
|
||||
public string SeriesInstanceUid { get; set; }
|
||||
public string Modality { get; set; }
|
||||
public string DicomSeriesDate { get; set; }
|
||||
public string DicomSeriesTime { get; set; }
|
||||
public int SeriesNumber { get; set; }
|
||||
public string SeriesDescription { get; set; }
|
||||
|
||||
// Instance
|
||||
public Guid InstanceId { get; set; }
|
||||
public string SopInstanceUid { get; set; }
|
||||
public string SOPClassUID { get; set; }
|
||||
public int InstanceNumber { get; set; }
|
||||
public string MediaStorageSOPClassUID { get; set; }
|
||||
public string MediaStorageSOPInstanceUID { get; set; }
|
||||
public string TransferSytaxUID { get; set; }
|
||||
}
|
||||
public static class DicomDIRHelper
|
||||
{
|
||||
|
||||
public static async Task GenerateStudyDIRAndUploadAsync(List<StudyDIRInfo> list, Dictionary<string, string> dic, string ossFolder, IOSSService _oSSService)
|
||||
{
|
||||
var mappings = new List<string>();
|
||||
int index = 1;
|
||||
|
||||
|
||||
var dicomDir = new DicomDirectory();
|
||||
|
||||
foreach (var item in list.OrderBy(t => t.SeriesNumber).ThenBy(t => t.InstanceNumber))
|
||||
{
|
||||
var dicomUid = DicomUID.Enumerate().FirstOrDefault(uid => uid.UID == item.TransferSytaxUID);
|
||||
|
||||
if (dicomUid != null)
|
||||
{
|
||||
var ts = DicomTransferSyntax.Query(dicomUid);
|
||||
|
||||
var dataset = new DicomDataset(ts)
|
||||
{
|
||||
{ DicomTag.PatientID, item.PatientId ?? string.Empty },
|
||||
{ DicomTag.PatientName, item.PatientName ?? string.Empty },
|
||||
{ DicomTag.PatientBirthDate, item.PatientBirthDate ?? string.Empty },
|
||||
{ DicomTag.PatientSex, item.PatientSex ?? string.Empty },
|
||||
|
||||
{ DicomTag.StudyInstanceUID, item.StudyInstanceUid ?? string.Empty },
|
||||
{ DicomTag.StudyID, item.StudyId ?? string.Empty },
|
||||
{ DicomTag.StudyDate, item.DicomStudyDate ?? string.Empty },
|
||||
{ DicomTag.StudyTime, item.DicomStudyTime ?? string.Empty },
|
||||
{ DicomTag.AccessionNumber, item.AccessionNumber ?? string.Empty },
|
||||
{ DicomTag.StudyDescription, item.StudyDescription ?? string.Empty },
|
||||
|
||||
{ DicomTag.SeriesInstanceUID, item.SeriesInstanceUid ?? string.Empty },
|
||||
{ DicomTag.Modality, item.Modality ?? string.Empty },
|
||||
{ DicomTag.SeriesDate, item.DicomSeriesDate ?? string.Empty },
|
||||
{ DicomTag.SeriesTime, item.DicomSeriesTime ?? string.Empty },
|
||||
{ DicomTag.SeriesNumber, item.SeriesNumber.ToString() ?? string.Empty },
|
||||
{ DicomTag.SeriesDescription, item.SeriesDescription ?? string.Empty },
|
||||
|
||||
{ DicomTag.SOPInstanceUID, item.SopInstanceUid ?? string.Empty },
|
||||
{ DicomTag.SOPClassUID, item.SOPClassUID ?? string.Empty },
|
||||
{ DicomTag.InstanceNumber, item.InstanceNumber.ToString() ?? string.Empty },
|
||||
{ DicomTag.MediaStorageSOPClassUID, item.MediaStorageSOPClassUID ?? string.Empty },
|
||||
{ DicomTag.MediaStorageSOPInstanceUID, item.MediaStorageSOPInstanceUID ?? string.Empty },
|
||||
{ DicomTag.TransferSyntaxUID, item.TransferSytaxUID ?? string.Empty },
|
||||
};
|
||||
|
||||
var dicomFile = new DicomFile(dataset);
|
||||
|
||||
// 文件名递增格式:IM_00001, IM_00002, ...
|
||||
string filename = $@"IMAGE/IM_{index:D5}"; // :D5 表示补足5位
|
||||
|
||||
mappings.Add($"{filename} => {item.InstanceId}");
|
||||
|
||||
dic.Add(item.InstanceId.ToString(), Path.GetFileName(filename));
|
||||
|
||||
dicomDir.AddFile(dicomFile, filename);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
//有实际的文件
|
||||
if (mappings.Count > 0)
|
||||
{
|
||||
#region 写入临时路径
|
||||
var tempFilePath = Path.GetTempFileName();
|
||||
|
||||
// 保存 DICOMDIR 到临时文件 不能直接写入到流种
|
||||
await dicomDir.SaveAsync(tempFilePath);
|
||||
|
||||
using (var memoryStream = new MemoryStream(File.ReadAllBytes(tempFilePath)))
|
||||
{
|
||||
// 重置流位置
|
||||
memoryStream.Position = 0;
|
||||
|
||||
await _oSSService.UploadToOSSAsync(memoryStream, ossFolder, "DICOMDIR", false);
|
||||
}
|
||||
|
||||
//清理临时文件
|
||||
File.Delete(tempFilePath);
|
||||
|
||||
#endregion
|
||||
|
||||
#region 映射上传
|
||||
|
||||
// 将映射写入内存流
|
||||
var mappingText = string.Join(Environment.NewLine, mappings);
|
||||
await using var mappingStream = new MemoryStream(Encoding.UTF8.GetBytes(mappingText));
|
||||
|
||||
await _oSSService.UploadToOSSAsync(mappingStream, ossFolder, $"Download_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", false);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static StudyDIRInfo ReadDicomDIRInfo(DicomFile dicomFile)
|
||||
{
|
||||
var dataset = dicomFile.Dataset;
|
||||
|
||||
|
||||
var info = new StudyDIRInfo
|
||||
{
|
||||
PatientId = dataset.GetSingleValueOrDefault(DicomTag.PatientID, string.Empty),
|
||||
PatientName = dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty),
|
||||
PatientBirthDate = dataset.GetSingleValueOrDefault(DicomTag.PatientBirthDate, string.Empty),
|
||||
PatientSex = dataset.GetSingleValueOrDefault(DicomTag.PatientSex, string.Empty),
|
||||
|
||||
StudyInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty),
|
||||
StudyId = dataset.GetSingleValueOrDefault(DicomTag.StudyID, string.Empty),
|
||||
DicomStudyDate = dataset.GetSingleValueOrDefault(DicomTag.StudyDate, string.Empty),
|
||||
DicomStudyTime = dataset.GetSingleValueOrDefault(DicomTag.StudyTime, string.Empty),
|
||||
AccessionNumber = dataset.GetSingleValueOrDefault(DicomTag.AccessionNumber, string.Empty),
|
||||
StudyDescription = dataset.GetSingleValueOrDefault(DicomTag.StudyDescription, string.Empty),
|
||||
|
||||
SeriesInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SeriesInstanceUID, string.Empty),
|
||||
Modality = dataset.GetSingleValueOrDefault(DicomTag.Modality, string.Empty),
|
||||
DicomSeriesDate = dataset.GetSingleValueOrDefault(DicomTag.SeriesDate, string.Empty),
|
||||
DicomSeriesTime = dataset.GetSingleValueOrDefault(DicomTag.SeriesTime, string.Empty),
|
||||
SeriesNumber = dataset.GetSingleValueOrDefault(DicomTag.SeriesNumber, 1),
|
||||
SeriesDescription = dataset.GetSingleValueOrDefault(DicomTag.SeriesDescription, string.Empty),
|
||||
|
||||
SopInstanceUid = dataset.GetSingleValueOrDefault(DicomTag.SOPInstanceUID, string.Empty),
|
||||
SOPClassUID = dataset.GetSingleValueOrDefault(DicomTag.SOPClassUID, string.Empty),
|
||||
InstanceNumber = dataset.GetSingleValueOrDefault(DicomTag.InstanceNumber, 1),
|
||||
|
||||
MediaStorageSOPClassUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPClassUID, string.Empty),
|
||||
MediaStorageSOPInstanceUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.MediaStorageSOPInstanceUID, string.Empty),
|
||||
|
||||
TransferSytaxUID = dicomFile.FileMetaInfo.GetSingleValueOrDefault(DicomTag.TransferSyntaxUID, string.Empty)
|
||||
};
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,4 @@
|
|||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace IRaCIS.Core.Application.Helper;
|
||||
namespace IRaCIS.Core.Application.Helper;
|
||||
|
||||
public static class IRCEmailPasswordHelper
|
||||
{
|
||||
|
@ -77,56 +74,4 @@ public static class IRCEmailPasswordHelper
|
|||
// 随机打乱密码字符顺序
|
||||
return new string(password.OrderBy(_ => Random.Next()).ToArray());
|
||||
}
|
||||
|
||||
|
||||
|
||||
// https://learn.microsoft.com/zh-cn/dotnet/standard/base-types/how-to-verify-that-strings-are-in-valid-email-format
|
||||
/// <summary>
|
||||
/// 微软官方邮件验证 很宽松
|
||||
/// </summary>
|
||||
/// <param name="email"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidEmail(string email)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(email))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
// Normalize the domain
|
||||
email = Regex.Replace(email, @"(@)(.+)$", DomainMapper,
|
||||
RegexOptions.None, TimeSpan.FromMilliseconds(200));
|
||||
|
||||
// Examines the domain part of the email and normalizes it.
|
||||
string DomainMapper(Match match)
|
||||
{
|
||||
// Use IdnMapping class to convert Unicode domain names.
|
||||
var idn = new IdnMapping();
|
||||
|
||||
// Pull out and process domain name (throws ArgumentException on invalid)
|
||||
string domainName = idn.GetAscii(match.Groups[2].Value);
|
||||
|
||||
return match.Groups[1].Value + domainName;
|
||||
}
|
||||
}
|
||||
catch (RegexMatchTimeoutException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (ArgumentException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Regex.IsMatch(email,
|
||||
@"^[^@\s]+@[^@\s]+\.[^@\s]+$",
|
||||
RegexOptions.IgnoreCase, TimeSpan.FromMilliseconds(250));
|
||||
}
|
||||
catch (RegexMatchTimeoutException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,7 +243,6 @@ public static class ExcelExportHelper
|
|||
|
||||
}
|
||||
|
||||
|
||||
public class DynamicColumnConfig
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -261,9 +260,7 @@ public static class ExcelExportHelper
|
|||
/// </summary>
|
||||
public int TempalteLastColumnIndex { get; set; }
|
||||
|
||||
public bool IsCDISCExport { get; set; } = false;
|
||||
|
||||
//public List<string> CDISCList { get; set; } = new List<string>();
|
||||
public List<string> CDISCList { get; set; } = new List<string>();
|
||||
|
||||
/// <summary>
|
||||
/// 动态的列名 如果Id 重复,那么就按照名称填充,否则就按照Id 填充列数据
|
||||
|
@ -304,8 +301,6 @@ public static class ExcelExportHelper
|
|||
public Guid Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public string CDISCCode { get; set; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is not ColumItem other) return false;
|
||||
|
@ -494,9 +489,7 @@ public static class ExcelExportHelper
|
|||
|
||||
if (dynamicColumnConfig != null)
|
||||
{
|
||||
//var isCdics = dynamicColumnConfig.CDISCList.Count > 0;
|
||||
|
||||
var isCdics = dynamicColumnConfig.IsCDISCExport;
|
||||
var isCdics = dynamicColumnConfig.CDISCList.Count > 0;
|
||||
|
||||
var sheet = workbook.GetSheetAt(0);
|
||||
|
||||
|
@ -551,7 +544,7 @@ public static class ExcelExportHelper
|
|||
}
|
||||
|
||||
//创建新的列
|
||||
for (int i = originRemoveEndIndex; i < originRemoveEndIndex + needAddCount; i++)
|
||||
for (int i = originTotalEndIndex; i < originTotalEndIndex + needAddCount; i++)
|
||||
{
|
||||
|
||||
titelRow.CreateCell(i + 1);
|
||||
|
@ -572,11 +565,6 @@ public static class ExcelExportHelper
|
|||
titelRow.GetCell(i).SetCellValue(titelRow.GetCell(i - gap).StringCellValue);
|
||||
|
||||
templateRow.GetCell(i).SetCellValue(templateRow.GetCell(i - gap).StringCellValue);
|
||||
|
||||
if (isCdics)
|
||||
{
|
||||
cdicsRow.GetCell(i).SetCellValue(cdicsRow.GetCell(i - gap).StringCellValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -585,7 +573,6 @@ public static class ExcelExportHelper
|
|||
|
||||
for (int i = dynamicColunmStartIndex; i < dynamicColunmStartIndex + needAddCount; i++)
|
||||
{
|
||||
|
||||
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
|
||||
|
||||
titelRow.GetCell(i).SetCellValue(name);
|
||||
|
@ -593,15 +580,13 @@ public static class ExcelExportHelper
|
|||
|
||||
if (isCdics)
|
||||
{
|
||||
var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
|
||||
var cdicsCode = dynamicColumnConfig.CDISCList[i - dynamicColunmStartIndex];
|
||||
|
||||
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
using (var memoryStream2 = new MemoryStream())
|
||||
{
|
||||
workbook.Write(memoryStream2, true);
|
||||
|
@ -624,11 +609,8 @@ public static class ExcelExportHelper
|
|||
IgnoreTemplateParameterMissing = true,
|
||||
};
|
||||
|
||||
//await MiniExcel.SaveAsByTemplateAsync("testmini.xlsx", templateStream.ToArray(), translateData);
|
||||
|
||||
await MiniExcel.SaveAsByTemplateAsync(memoryStream, templateStream.ToArray(), translateData, config);
|
||||
|
||||
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
if (dynamicColumnConfig != null)
|
||||
|
@ -661,7 +643,7 @@ public static class ExcelExportHelper
|
|||
|
||||
var iteObjDic = itemObj.ToDictionary();
|
||||
|
||||
var itemDicName = iteObjDic.ContainsKey(dynamicColumnConfig.DynamicItemDicName) ? iteObjDic[dynamicColumnConfig.DynamicItemDicName]?.ToString() : "";
|
||||
var itemDicName = iteObjDic[dynamicColumnConfig.DynamicItemDicName]?.ToString();
|
||||
var itemValue = iteObjDic[dynamicColumnConfig.DynamicItemValueName]?.ToString();
|
||||
|
||||
//var writeIndex = itemList.IndexOf(itemObj) + dynamicColumnConfig.AutoColumnStartIndex;
|
||||
|
@ -925,7 +907,7 @@ public static class ExcelExportHelper
|
|||
{
|
||||
var name = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].Name;
|
||||
|
||||
var cdicsCode = dynamicColumnConfig.ColumnIdNameList[i - dynamicColunmStartIndex].CDISCCode;
|
||||
var cdicsCode = dynamicColumnConfig.CDISCList[i - dynamicColunmStartIndex];
|
||||
|
||||
cdicsRow.GetCell(i).SetCellValue(cdicsCode);
|
||||
titelRow.GetCell(i).SetCellValue(name);
|
||||
|
|
|
@ -69,15 +69,6 @@ public static class FileStoreHelper
|
|||
return rootFolder;
|
||||
}
|
||||
|
||||
public static string GetDonwnloadImageFolder(IWebHostEnvironment _hostEnvironment)
|
||||
{
|
||||
var rootPath = GetIRaCISRootPath(_hostEnvironment);
|
||||
|
||||
var rootFolder = Path.Combine(rootPath, StaticData.Folder.DownloadIamgeFolder);
|
||||
|
||||
return rootFolder;
|
||||
}
|
||||
|
||||
//根据相对路径 获取具体文件物理地址
|
||||
public static string GetPhysicalFilePath(IWebHostEnvironment _hostEnvironment, string relativePath)
|
||||
{
|
||||
|
|
|
@ -83,21 +83,15 @@ namespace IRaCIS.Core.Application.Helper
|
|||
|
||||
}
|
||||
|
||||
public static void AddOrUpdateTimingCronJob(string jobId, EmailBusinessScenario businessScenario, string emailCron)
|
||||
public static void AddOrUpdateSystemCronJob(string jobId, EmailBusinessScenario businessScenario, string emailCron)
|
||||
{
|
||||
switch (businessScenario)
|
||||
{
|
||||
|
||||
case EmailBusinessScenario.GeneralTraining_ExpirationNotification:
|
||||
|
||||
|
||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new SystemDocumentErverDayEvent() { }, default), emailCron);
|
||||
break;
|
||||
case EmailBusinessScenario.TrialTraining_ExpirationNotification:
|
||||
|
||||
Console.WriteLine("更新项目到期job");
|
||||
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new TrialDocumentErverDayEvent() { }, default), emailCron);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -18,7 +18,6 @@ using Minio.DataModel.Args;
|
|||
using Minio.Exceptions;
|
||||
using System.Reactive.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Web;
|
||||
|
||||
namespace IRaCIS.Core.Application.Helper;
|
||||
|
||||
|
@ -112,8 +111,6 @@ public class AliyunOSSTempToken
|
|||
|
||||
public string PreviewEndpoint { get; set; }
|
||||
|
||||
public string DownloadEndPoint => EndPoint.Insert(EndPoint.IndexOf("//") + 2, BucketName + ".");
|
||||
|
||||
}
|
||||
|
||||
[LowerCamelCaseJson]
|
||||
|
@ -126,7 +123,7 @@ public class AWSTempToken
|
|||
public string SecretAccessKey { get; set; }
|
||||
public string BucketName { get; set; }
|
||||
public string ViewEndpoint { get; set; }
|
||||
public DateTime? Expiration { get; set; }
|
||||
public DateTime Expiration { get; set; }
|
||||
}
|
||||
|
||||
public enum ObjectStoreUse
|
||||
|
@ -147,8 +144,6 @@ public interface IOSSService
|
|||
|
||||
public Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath);
|
||||
|
||||
public Task<Stream> GetStreamFromOSSAsync(string ossRelativePath);
|
||||
|
||||
public ObjectStoreServiceOptions ObjectStoreServiceOptions { get; set; }
|
||||
|
||||
public Task<string> GetSignedUrl(string ossRelativePath);
|
||||
|
@ -194,7 +189,7 @@ public class OSSService : IOSSService
|
|||
/// <returns></returns>
|
||||
public async Task<string> UploadToOSSAsync(Stream fileStream, string oosFolderPath, string fileRealName, bool isFileNameAddGuid = true)
|
||||
{
|
||||
BackBatchGetToken();
|
||||
GetObjectStoreTempToken();
|
||||
|
||||
var ossRelativePath = isFileNameAddGuid ? $"{oosFolderPath}/{Guid.NewGuid()}_{fileRealName}" : $"{oosFolderPath}/{fileRealName}";
|
||||
|
||||
|
@ -284,37 +279,6 @@ public class OSSService : IOSSService
|
|||
}
|
||||
|
||||
|
||||
//后端批量上传 或者下载,不每个文件获取临时token
|
||||
private void BackBatchGetToken()
|
||||
{
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
if (AliyunOSSTempToken == null)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
}
|
||||
//token 过期了
|
||||
else if (AliyunOSSTempToken.Expiration.AddSeconds(10) <= DateTime.Now)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
if (AWSTempToken == null)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
}
|
||||
//token 过期了
|
||||
else if (AWSTempToken.Expiration?.AddSeconds(10) <= DateTime.Now)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// oosFolderPath 不要 "/ "开头 应该: TempFolder/ChildFolder
|
||||
|
@ -326,7 +290,7 @@ public class OSSService : IOSSService
|
|||
/// <exception cref="BusinessValidationFailedException"></exception>
|
||||
public async Task<string> UploadToOSSAsync(string localFilePath, string oosFolderPath, bool isFileNameAddGuid = true)
|
||||
{
|
||||
BackBatchGetToken();
|
||||
GetObjectStoreTempToken();
|
||||
|
||||
var localFileName = Path.GetFileName(localFilePath);
|
||||
|
||||
|
@ -396,7 +360,7 @@ public class OSSService : IOSSService
|
|||
|
||||
public async Task DownLoadFromOSSAsync(string ossRelativePath, string localFilePath)
|
||||
{
|
||||
BackBatchGetToken();
|
||||
GetObjectStoreTempToken();
|
||||
|
||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||
try
|
||||
|
@ -409,12 +373,14 @@ public class OSSService : IOSSService
|
|||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
// 上传文件
|
||||
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
||||
|
||||
// 将下载的文件流保存到本地文件
|
||||
using (var fs = File.OpenWrite(localFilePath))
|
||||
{
|
||||
await result.Content.CopyToAsync(fs);
|
||||
result.Content.CopyTo(fs);
|
||||
fs.Close();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -478,96 +444,6 @@ public class OSSService : IOSSService
|
|||
|
||||
}
|
||||
|
||||
public async Task<Stream> GetStreamFromOSSAsync(string ossRelativePath)
|
||||
{
|
||||
BackBatchGetToken();
|
||||
ossRelativePath = ossRelativePath.TrimStart('/');
|
||||
|
||||
try
|
||||
{
|
||||
if (ObjectStoreServiceOptions.ObjectStoreUse == "AliyunOSS")
|
||||
{
|
||||
var aliConfig = ObjectStoreServiceOptions.AliyunOSS;
|
||||
|
||||
var _ossClient = new OssClient(
|
||||
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint,
|
||||
AliyunOSSTempToken.AccessKeyId,
|
||||
AliyunOSSTempToken.AccessKeySecret,
|
||||
AliyunOSSTempToken.SecurityToken
|
||||
);
|
||||
|
||||
var result = _ossClient.GetObject(aliConfig.BucketName, ossRelativePath);
|
||||
|
||||
// 将OSS返回的流复制到内存流中并返回
|
||||
var memoryStream = new MemoryStream();
|
||||
await result.Content.CopyToAsync(memoryStream);
|
||||
memoryStream.Position = 0; // 重置位置以便读取
|
||||
return memoryStream;
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "MinIO")
|
||||
{
|
||||
var minIOConfig = ObjectStoreServiceOptions.MinIO;
|
||||
|
||||
var minioClient = new MinioClient()
|
||||
.WithEndpoint($"{minIOConfig.EndPoint}:{minIOConfig.Port}")
|
||||
.WithCredentials(minIOConfig.AccessKeyId, minIOConfig.SecretAccessKey)
|
||||
.WithSSL(minIOConfig.UseSSL)
|
||||
.Build();
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
|
||||
var getObjectArgs = new GetObjectArgs()
|
||||
.WithBucket(minIOConfig.BucketName)
|
||||
.WithObject(ossRelativePath)
|
||||
.WithCallbackStream(stream => stream.CopyToAsync(memoryStream));
|
||||
|
||||
await minioClient.GetObjectAsync(getObjectArgs);
|
||||
memoryStream.Position = 0;
|
||||
return memoryStream;
|
||||
}
|
||||
else if (ObjectStoreServiceOptions.ObjectStoreUse == "AWS")
|
||||
{
|
||||
var awsConfig = ObjectStoreServiceOptions.AWS;
|
||||
|
||||
var credentials = new SessionAWSCredentials(
|
||||
AWSTempToken.AccessKeyId,
|
||||
AWSTempToken.SecretAccessKey,
|
||||
AWSTempToken.SessionToken
|
||||
);
|
||||
|
||||
var clientConfig = new AmazonS3Config
|
||||
{
|
||||
RegionEndpoint = RegionEndpoint.USEast1,
|
||||
UseHttp = true,
|
||||
};
|
||||
|
||||
var amazonS3Client = new AmazonS3Client(credentials, clientConfig);
|
||||
|
||||
var getObjectRequest = new Amazon.S3.Model.GetObjectRequest
|
||||
{
|
||||
BucketName = awsConfig.BucketName,
|
||||
Key = ossRelativePath
|
||||
};
|
||||
|
||||
var response = await amazonS3Client.GetObjectAsync(getObjectRequest);
|
||||
|
||||
var memoryStream = new MemoryStream();
|
||||
await response.ResponseStream.CopyToAsync(memoryStream);
|
||||
memoryStream.Position = 0;
|
||||
return memoryStream;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new BusinessValidationFailedException("未定义的存储介质类型");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new BusinessValidationFailedException("oss流获取失败! " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public async Task<string> GetSignedUrl(string ossRelativePath)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
|
@ -1124,9 +1000,14 @@ public class OSSService : IOSSService
|
|||
}
|
||||
}
|
||||
|
||||
private bool isFirstCall = true;
|
||||
public async Task<long> GetObjectSizeAsync(string sourcePath)
|
||||
{
|
||||
BackBatchGetToken();
|
||||
if (isFirstCall)
|
||||
{
|
||||
GetObjectStoreTempToken();
|
||||
isFirstCall = false;
|
||||
}
|
||||
|
||||
|
||||
var objectkey = sourcePath.Trim('/');
|
||||
|
@ -1137,10 +1018,9 @@ public class OSSService : IOSSService
|
|||
|
||||
var _ossClient = new OssClient(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? aliConfig.EndPoint : aliConfig.InternalEndpoint, AliyunOSSTempToken.AccessKeyId, AliyunOSSTempToken.AccessKeySecret, AliyunOSSTempToken.SecurityToken);
|
||||
|
||||
var key = HttpUtility.UrlDecode(objectkey);
|
||||
var metadata = _ossClient.GetObjectMetadata(aliConfig.BucketName, key);
|
||||
var metadata = _ossClient.GetObjectMetadata(aliConfig.BucketName, objectkey);
|
||||
|
||||
long fileSize = metadata?.ContentLength ?? 0; // 文件大小(字节)
|
||||
long fileSize = metadata.ContentLength; // 文件大小(字节)
|
||||
|
||||
return fileSize;
|
||||
}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IRaCIS.Core.Application.Helper
|
||||
{
|
||||
public static class SafeBussinessHelper
|
||||
{
|
||||
public static async Task<bool> RunAsync(Func<Task> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
await func();
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<(bool Success, T? Result)> RunAsync<T>(Func<Task<T>> func, [CallerMemberName] string caller = "", string errorMsgTitle = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await func();
|
||||
return (true, result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error($"【{errorMsgTitle}失败 - {caller}】: {ex.Message}");
|
||||
return (false, default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -33,38 +33,38 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="IdentityModel.OidcClient" Version="6.0.0" />
|
||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.6" />
|
||||
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.1.3" />
|
||||
<PackageReference Include="AlibabaCloud.SDK.Sts20150401" Version="1.1.5" />
|
||||
<PackageReference Include="AWSSDK.SecurityToken" Version="3.7.401.81" />
|
||||
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.14.1" />
|
||||
<PackageReference Include="AWSSDK.S3" Version="4.0.4.1" />
|
||||
<PackageReference Include="AWSSDK.S3" Version="3.7.416.8" />
|
||||
<PackageReference Include="DocX" Version="4.0.25105.5786" />
|
||||
<PackageReference Include="FreeSpire.Doc" Version="12.2.0" />
|
||||
<PackageReference Include="Hangfire.Core" Version="1.8.18" />
|
||||
<PackageReference Include="ExcelDataReader" Version="3.7.0" />
|
||||
<PackageReference Include="ExcelDataReader.DataSet" Version="3.7.0" />
|
||||
<PackageReference Include="DistributedLock.Redis" Version="1.0.3" />
|
||||
<PackageReference Include="DistributedLock.SqlServer" Version="1.0.6" />
|
||||
<PackageReference Include="fo-dicom" Version="5.2.2" />
|
||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.2" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.3" />
|
||||
<PackageReference Include="fo-dicom" Version="5.2.1" />
|
||||
<PackageReference Include="fo-dicom.Imaging.ImageSharp" Version="5.2.1" />
|
||||
<PackageReference Include="fo-dicom.Codecs" Version="5.16.1" />
|
||||
<PackageReference Include="IP2Region.Net" Version="2.0.2" />
|
||||
<PackageReference Include="MailKit" Version="4.11.0" />
|
||||
<PackageReference Include="Masa.Contrib.Service.MinimalAPIs" Version="1.0.0" />
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="5.3.0" />
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="5.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.10" />
|
||||
<PackageReference Include="MimeKit" Version="4.11.0" />
|
||||
<PackageReference Include="MiniExcel" Version="1.41.2" />
|
||||
<PackageReference Include="Minio" Version="6.0.5" />
|
||||
<PackageReference Include="MiniExcel" Version="1.41.3" />
|
||||
<PackageReference Include="Minio" Version="6.0.4" />
|
||||
<PackageReference Include="MiniWord" Version="0.9.2" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="9.0.0" />
|
||||
<PackageReference Include="My.Extensions.Localization.Json" Version="3.3.0">
|
||||
<TreatAsUsed>true</TreatAsUsed>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NPOI" Version="2.7.4" />
|
||||
<PackageReference Include="NPOI" Version="2.7.3" />
|
||||
<PackageReference Include="Panda.DynamicWebApi" Version="1.2.2" />
|
||||
<PackageReference Include="RestSharp" Version="112.1.0" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.10" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" />
|
||||
<PackageReference Include="ZiggyCreatures.FusionCache" Version="2.3.0" />
|
||||
<PackageReference Include="ZiggyCreatures.FusionCache" Version="2.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -363,7 +363,7 @@
|
|||
访视读片任务
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Allocation.VisitTaskService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskAllocationRule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadModule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTaskReReading},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskMedicalReview},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingClinicalData},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectCriteriaEvaluation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectCriteriaEvaluationVisitFilter},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomSeries},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectCanceDoctor},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableAnswerRowInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskInfluence},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialQCQuestionAnswer},Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.Application.Service.Allocation.VisitTaskService},IRaCIS.Core.Application.Service.IVisitTaskHelpeService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectCriteriaEvaluationVisitStudyFilter},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
|
||||
<member name="M:IRaCIS.Core.Application.Service.Allocation.VisitTaskService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskAllocationRule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadModule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTaskReReading},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskMedicalReview},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingClinicalData},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectCriteriaEvaluation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectCriteriaEvaluationVisitFilter},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomSeries},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectCanceDoctor},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableAnswerRowInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingCustomTag},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskInfluence},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialQCQuestionAnswer},Microsoft.Extensions.Logging.ILogger{IRaCIS.Core.Application.Service.Allocation.VisitTaskService},IRaCIS.Core.Application.Service.IVisitTaskHelpeService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectCriteriaEvaluationVisitStudyFilter},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
|
||||
<summary>
|
||||
访视读片任务
|
||||
</summary>
|
||||
|
@ -603,10 +603,11 @@
|
|||
<param name="addOrEditBasic"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.DictionaryService.GetChildList(IRaCIS.Application.Contracts.ChildInQuery)">
|
||||
<member name="M:IRaCIS.Core.Application.Service.DictionaryService.GetChildList(System.Guid)">
|
||||
<summary>
|
||||
获取子项数组
|
||||
</summary>
|
||||
<param name="parentId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.DictionaryService.DeleteDictionary(System.Guid)">
|
||||
|
@ -688,35 +689,6 @@
|
|||
<param name="eventId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Common.ExcelExportService.GetTrialQCQuestionAnserList_Export(IRaCIS.Core.Application.Contracts.GetQCQuestionAnswerQuery,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialQCQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialQCQuestion},IRaCIS.Application.Interfaces.IDictionaryService)">
|
||||
<summary>
|
||||
质控问题答案导出
|
||||
</summary>
|
||||
<param name="trialId"></param>
|
||||
<param name="_trialQCQuestionAnswerRepository"></param>
|
||||
<param name="_trialRepository"></param>
|
||||
<param name="_dictionaryService"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Common.ExcelExportService.GetReadingMedicineSystemQuestionList_Export(IRaCIS.Core.Application.ViewModel.ReadingMedicineSystemQuestionQuery,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingMedicineSystemQuestion},IRaCIS.Application.Interfaces.IDictionaryService)">
|
||||
<summary>
|
||||
医学审核问题导表
|
||||
</summary>
|
||||
<param name="inDto"></param>
|
||||
<param name="_readingMedicineSystemQuestionRepository"></param>
|
||||
<param name="_dictionaryService"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Common.ExcelExportService.GetTrialVisitImageStatList_Export(IRaCIS.Core.Application.Contracts.TrialVisitImageQuery,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Application.Interfaces.IDictionaryService)">
|
||||
<summary>
|
||||
访视影像统计
|
||||
</summary>
|
||||
<param name="inQuery"></param>
|
||||
<param name="_subjectVisitRepository"></param>
|
||||
<param name="_trialRepository"></param>
|
||||
<param name="_dictionaryService"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Common.ExcelExportService.TrialUserListExport(IRaCIS.Application.Contracts.TrialMaintenanceExportQuery,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CommonDocument},IRaCIS.Application.Interfaces.IDictionaryService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole})">
|
||||
<summary>
|
||||
项目参与人员导出
|
||||
|
@ -764,15 +736,6 @@
|
|||
<param name="_trialRepository"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Common.ExcelExportService.GetImageBackList_Export(IRaCIS.Core.Application.Contracts.ImageBackQueryDto,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisitImageBackRecord},IRaCIS.Application.Interfaces.IDictionaryService)">
|
||||
<summary>
|
||||
重传申请导表
|
||||
</summary>
|
||||
<param name="inQuery"></param>
|
||||
<param name="_subjectVisitImageBackRecordReposiotry"></param>
|
||||
<param name="_dictionaryService"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Common.ExcelExportService.GetSysDocumentConfirmList_Export(IRaCIS.Core.Application.Contracts.SystemDocQuery,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocument},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.IdentityUser},IRaCIS.Application.Interfaces.IDictionaryService)">
|
||||
getSysDocumentConfirmList 系统文档培训查询
|
||||
|
||||
|
@ -1090,34 +1053,6 @@
|
|||
PublishLogService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.TrialImageDownloadService">
|
||||
<summary>
|
||||
项目影像后台下载,不打包
|
||||
</summary>
|
||||
<param name="_trialRepository"></param>
|
||||
<param name="_oSSService"></param>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialImageDownloadService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Application.Helper.IOSSService,Microsoft.AspNetCore.Hosting.IWebHostEnvironment)">
|
||||
<summary>
|
||||
项目影像后台下载,不打包
|
||||
</summary>
|
||||
<param name="_trialRepository"></param>
|
||||
<param name="_oSSService"></param>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialImageDownloadService.DownloadTrialImage(System.Guid)">
|
||||
<summary>
|
||||
后端api swagger 下载项目影像
|
||||
</summary>
|
||||
<param name="trialId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialImageDownloadService.DownloadAndUploadTrialData(System.Guid,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomSeries})">
|
||||
<summary>
|
||||
下载影像 维护dir信息 并回传到OSS
|
||||
</summary>
|
||||
<param name="trialId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.AttachmentService">
|
||||
<summary>
|
||||
医生文档关联关系维护
|
||||
|
@ -1576,7 +1511,7 @@
|
|||
TrialEmailNoticeConfigService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialEmailNoticeConfig},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialEmailBlackUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.EmailNoticeConfig},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskMedicalReview},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingGlobalTaskInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialEmailNoticeUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadModule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig},IRaCIS.Application.Interfaces.IDictionaryService,IRaCIS.Core.Application.Service.IEmailSendService,AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer,Microsoft.AspNetCore.Hosting.IWebHostEnvironment)">
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialEmailNoticeConfig},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialEmailBlackUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.EmailNoticeConfig},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskMedicalReview},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingGlobalTaskInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialEmailNoticeUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadModule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig},IRaCIS.Core.Application.Service.IEmailSendService,AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer,Microsoft.AspNetCore.Hosting.IWebHostEnvironment)">
|
||||
<summary>
|
||||
TrialEmailNoticeConfigService
|
||||
</summary>
|
||||
|
@ -1595,7 +1530,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<!-- Badly formed XML comment ignored for member "M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.DealMedicalReviewTasKGenerateAndIsSendAsync(System.Guid,System.Nullable{System.Boolean},System.String,System.Collections.Generic.List{System.Guid},System.Collections.Generic.List{System.Guid})" -->
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.BaseBusinessScenarioSendEmailAsync(System.Guid,System.Nullable{System.Boolean},IRaCIS.Core.Domain.Share.Common.EmailStoreSendMode,System.String)">
|
||||
<summary>
|
||||
测试邮件 带附件 填充word
|
||||
|
@ -1622,19 +1556,9 @@
|
|||
<param name="sendFileRelativePath"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.DealEnrollAnswer(System.Guid,System.Guid,IRaCIS.Core.Domain.Share.CriterionType,System.Guid)">
|
||||
<summary>
|
||||
获取入组结果
|
||||
</summary>
|
||||
<param name="visitTaskId"></param>
|
||||
<param name="subjectVisitId"></param>
|
||||
<param name="criterionType"></param>
|
||||
<param name="trialReadingCriterionId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialEmailNoticeConfigService.TranslatePdStateAsync(System.Guid,IRaCIS.Core.Domain.Share.ReadingCategory,IRaCIS.Core.Domain.Share.CriterionType,System.Nullable{System.Boolean})">
|
||||
<summary>
|
||||
获取PD 结果
|
||||
|
||||
</summary>
|
||||
<param name="visitTaskId"> 任务Id</param>
|
||||
<param name="readingCategory"> 任务类型</param>
|
||||
|
@ -1777,44 +1701,6 @@
|
|||
<param name="trialFinalRecordId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.TrialHistoryRecordFileService">
|
||||
<summary>
|
||||
项目历史记录文件服务
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialHistoryRecordFileService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialHistoryRecordFile},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
|
||||
<summary>
|
||||
项目历史记录文件服务
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialHistoryRecordFileService.GetTrialHistoryRecordFileList(IRaCIS.Core.Application.Service.DTO.TrialHistoryRecordFileQuery)">
|
||||
<summary>
|
||||
获取稽查记录文件列表
|
||||
</summary>
|
||||
<param name="inQuery"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialHistoryRecordFileService.BatchAddTrialHistoryRecordFile(System.Collections.Generic.List{IRaCIS.Core.Application.Service.DTO.TrialHistoryRecordFileAddOrEdit})">
|
||||
<summary>
|
||||
批量新增稽查记录文件
|
||||
</summary>
|
||||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialHistoryRecordFileService.AddOrUpdateTrialHistoryRecordFile(IRaCIS.Core.Application.Service.DTO.TrialHistoryRecordFileAddOrEdit)">
|
||||
<summary>
|
||||
新增或修改稽查记录文件
|
||||
</summary>
|
||||
<param name="addOrEditTrialHistoryRecordFile"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.TrialHistoryRecordFileService.DeleteTrialHistoryRecordFile(System.Guid)">
|
||||
<summary>
|
||||
删除稽查记录文件
|
||||
</summary>
|
||||
<param name="trialHistoryRecordFileId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.TrialNormalRecordService">
|
||||
<summary>
|
||||
项目-一般文件记录
|
||||
|
@ -2116,14 +2002,6 @@
|
|||
<param name="inQuery"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.UpdateTaskStudyModality(System.Guid,System.String)">
|
||||
<summary>
|
||||
更新后处理上传的检查modality
|
||||
</summary>
|
||||
<param name="taskStudyId"></param>
|
||||
<param name="modality"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.DownloadImageSuccess(System.Guid)">
|
||||
<summary>
|
||||
影像下载成功回调
|
||||
|
@ -2138,18 +2016,12 @@
|
|||
<param name="inQuery"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.GetTrialVisitImageStatInfo(System.Guid)">
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.UpdateTaskStudyModality(System.Guid,System.String)">
|
||||
<summary>
|
||||
获取项目影像统计,有影像的subject 数量 访视数量
|
||||
更新后处理上传的检查modality
|
||||
</summary>
|
||||
<param name="trialId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.GetExportSubjectVisitImageList(IRaCIS.Core.Application.Contracts.TrialExportImageCommand)">
|
||||
<summary>
|
||||
批量勾选访视 进行下载
|
||||
</summary>
|
||||
<param name="inCommand"></param>
|
||||
<param name="taskStudyId"></param>
|
||||
<param name="modality"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.DownloadAndUploadService.GetSubejectOrVisitZipInfo(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Application.Contracts.SubejctZipInfoQuery)">
|
||||
|
@ -2197,14 +2069,14 @@
|
|||
<summary> 指定资源Id,渲染Dicom检查的Jpeg预览图像 </summary>
|
||||
<param name="studyId"> Dicom检查的Id </param>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.StudyService.GetAllRelationStudyList(System.Guid,System.Nullable{System.Boolean})">
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.StudyService.GetAllRelationStudyList(System.Guid)">
|
||||
<summary>
|
||||
获取某个检查的关联检查列表(该受试者在这个想项目下的所有检查)
|
||||
点击检查检查列表中的一个检查获取对应的序列列表(调用之前的接口:/series/list/,根据StudyId,获取访视的序列列表)
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.StudyService.Item(System.Guid,System.Nullable{System.Boolean})">
|
||||
<member name="M:IRaCIS.Core.Application.Service.ImageAndDoc.StudyService.Item(System.Guid)">
|
||||
<summary> 指定资源Id,获取Dicom检查信息 </summary>
|
||||
<param name="studyId"> Dicom检查的Id </param>
|
||||
</member>
|
||||
|
@ -2416,20 +2288,6 @@
|
|||
批次Id
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Inspection.InspectionService.SetTrialShowInspection(IRaCIS.Core.Application.Service.Inspection.DTO.SetTrialShowInspection)">
|
||||
<summary>
|
||||
设置项目稽查配置
|
||||
</summary>
|
||||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Inspection.InspectionService.GetTrialShowInspection(IRaCIS.Core.Application.Service.Inspection.DTO.GetTrialShowInspectionInDto)">
|
||||
<summary>
|
||||
获取项目稽查显示信息
|
||||
</summary>
|
||||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.Inspection.InspectionService.RecordSing(IRaCIS.Core.Application.Contracts.SignDTO)">
|
||||
<summary>
|
||||
传入参数记录ID
|
||||
|
@ -2456,7 +2314,7 @@
|
|||
FrontAuditConfigService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.FrontAuditConfigService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.FrontAuditConfig},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.QCChallengeDialog},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DataInspection},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.QCChallenge},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Dictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialAuditShow},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CheckChallengeDialog},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
|
||||
<member name="M:IRaCIS.Core.Application.Service.FrontAuditConfigService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.FrontAuditConfig},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.QCChallengeDialog},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DataInspection},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.QCChallenge},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Dictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.CheckChallengeDialog},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
|
||||
<summary>
|
||||
FrontAuditConfigService
|
||||
</summary>
|
||||
|
@ -2571,19 +2429,11 @@
|
|||
<param name="item"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.FrontAuditConfigService.GetModuleTypeList(IRaCIS.Core.Application.ViewModel.GetModuleTypeListInDto)">
|
||||
<summary>
|
||||
获取模块类型列表
|
||||
</summary>
|
||||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.FrontAuditConfigService.getModuleTypeDescriptionList(System.Guid,System.Guid)">
|
||||
<member name="M:IRaCIS.Core.Application.Service.FrontAuditConfigService.GetModuleTypeDescriptionList(System.Guid)">
|
||||
<summary>
|
||||
获取Description
|
||||
</summary>
|
||||
<param name="moduleTypeId"></param>
|
||||
<param name="trialId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.FrontAuditConfigService.GetFrontAuditConfigList(IRaCIS.Core.Application.ViewModel.FrontAuditConfigQuery)">
|
||||
|
@ -3082,12 +2932,6 @@
|
|||
标准和服务对应
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.ReadingCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.ReadingCalculateService.GetService(System.Guid)">
|
||||
<summary>
|
||||
获取Service
|
||||
|
@ -3156,12 +3000,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.IRECIST1Point1CalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.IRECIST1Point1CalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -3542,12 +3380,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.IVUSCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.IVUSCalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -3677,12 +3509,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.LuganoCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.LuganoCalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -4211,12 +4037,6 @@
|
|||
<param name="digitPlaces"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.LuganoWithoutPETCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.LuganoWithoutPETCalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -4745,12 +4565,6 @@
|
|||
<param name="digitPlaces"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.MRECISTHCCCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.MRECISTHCCCalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -5036,12 +4850,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.MRIPDFFCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.MRIPDFFCalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -5112,12 +4920,6 @@
|
|||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.OCTCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.OCTCalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -5289,12 +5091,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.PCWG3CalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.PCWG3CalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -5401,12 +5197,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.RECIST1Point1CalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.RECIST1Point1CalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -5658,12 +5448,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.RECIST1Point1_BMCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.RECIST1Point1_BMCalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -5975,12 +5759,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.SelfDefineCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingCalculate.SelfDefineCalculateService.GetReadingCalculationData(IRaCIS.Core.Application.Service.Reading.Dto.GetReadingCalculationDataInDto)">
|
||||
<summary>
|
||||
获取阅片的计算数据
|
||||
|
@ -6038,12 +5816,6 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ICriterionCalculateService.ReadingImport">
|
||||
<summary>
|
||||
阅片导入
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ICriterionCalculateService.VerifyVisitTaskQuestions(IRaCIS.Core.Application.Service.Reading.Dto.VerifyVisitTaskQuestionsInDto)">
|
||||
<summary>
|
||||
验证访视提交
|
||||
|
@ -6729,7 +6501,7 @@
|
|||
一致性分析临床数据签名
|
||||
</summary>
|
||||
<param name="inDto"></param>
|
||||
<returns></returns>kimjnyhujikljkljkl
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingClinicalDataService.SetTaskValid(IRaCIS.Core.Application.Service.Reading.Dto.SetTaskValidInDto)">
|
||||
<summary>
|
||||
|
@ -7272,11 +7044,6 @@
|
|||
自定义计算问题
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ClinicalQuestionBase.DefaultValue">
|
||||
<summary>
|
||||
默认值
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.Reading.Dto.ClinicalQuestionQueryBase">
|
||||
<summary>
|
||||
查询临床数据基类
|
||||
|
@ -7412,11 +7179,6 @@
|
|||
关联Value
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ClinicalTableQuestionBase.DefaultValue">
|
||||
<summary>
|
||||
默认值
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Service.Reading.Dto.TrialClinicalTableQuestionDto">
|
||||
<summary>
|
||||
项目临床数据问题
|
||||
|
@ -8522,11 +8284,6 @@
|
|||
保存表格问题标记
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.SaveTableQuestionMarkInDto.MarkId">
|
||||
<summary>
|
||||
标记的唯一标识符
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GetPreviousOtherPicturePathInDto.QuestionType">
|
||||
<summary>
|
||||
问题类型
|
||||
|
@ -8917,16 +8674,6 @@
|
|||
StudyId
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.QuestionMarkInfo.RowId">
|
||||
<summary>
|
||||
表格问题标记
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.QuestionMarkInfo.MarkId">
|
||||
<summary>
|
||||
标记的唯一标识符
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.GetReadingQuestionAndAnswerInDto.QuestionClassify">
|
||||
<summary>
|
||||
问题分类
|
||||
|
@ -10482,21 +10229,6 @@
|
|||
表格问题类型
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingTableQuestionTrialAddOrEdit.ImageMarkEnum">
|
||||
<summary>
|
||||
影像标记
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingTableQuestionTrialAddOrEdit.ImageTool">
|
||||
<summary>
|
||||
影像工具
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingTableQuestionTrialAddOrEdit.ImageToolAttribute">
|
||||
<summary>
|
||||
影像工具属性
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingTableQuestionTrialAddOrEdit.ClassifyType">
|
||||
<summary>
|
||||
分类问题类型
|
||||
|
@ -10858,21 +10590,6 @@
|
|||
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingQuestionTrialView.ImageMarkEnum">
|
||||
<summary>
|
||||
影像标记
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingQuestionTrialView.ImageTool">
|
||||
<summary>
|
||||
影像工具
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingQuestionTrialView.ImageToolAttribute">
|
||||
<summary>
|
||||
影像工具属性
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingQuestionTrialView.GroupName">
|
||||
<summary>
|
||||
分组
|
||||
|
@ -10923,11 +10640,6 @@
|
|||
Parent字典code
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingQuestionTrialView.ExcludeShowVisitList">
|
||||
<summary>
|
||||
排除显示的访视名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.ReadingQuestionTrialView.ReadingQuestionCriterionTrialId">
|
||||
<summary>
|
||||
系统标准Id
|
||||
|
@ -11763,21 +11475,6 @@
|
|||
问题英文分组
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.AddOrUpdateReadingQuestionTrialInDto.ImageMarkEnum">
|
||||
<summary>
|
||||
影像标记
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.AddOrUpdateReadingQuestionTrialInDto.ImageTool">
|
||||
<summary>
|
||||
影像工具
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.AddOrUpdateReadingQuestionTrialInDto.ImageToolAttribute">
|
||||
<summary>
|
||||
影像工具属性
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.AddOrUpdateReadingQuestionTrialInDto.Id">
|
||||
<summary>
|
||||
Id
|
||||
|
@ -11798,11 +11495,6 @@
|
|||
分类显示类型 是否显示
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.AddOrUpdateReadingQuestionTrialInDto.ExcludeShowVisitList">
|
||||
<summary>
|
||||
排除显示的访视名称
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Service.Reading.Dto.AddOrUpdateReadingQuestionTrialInDto.HighlightAnswer">
|
||||
<summary>
|
||||
高亮问题的答案
|
||||
|
@ -13066,7 +12758,7 @@
|
|||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingNoneDicomMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserLog},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingOncologyTaskInfo},IRaCIS.Core.Application.Service.IVisitTaskHelpeService,IRaCIS.Core.Application.Service.IVisitTaskService,IRaCIS.Core.Application.Contracts.IReadingClinicalDataService,IRaCIS.Core.Application.Service.IReadingCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserFeedBack},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingGlobalTaskInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingCriterionPage},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskRelation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingJudgeInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadModule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganTrialInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocument},IRaCIS.Core.Application.Service.ReadingCalculate.Interface.ILuganoCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTrialCriterionDictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableAnswerRowInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile},IRaCIS.Core.Application.Service.IGeneralCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskStudy},IRaCIS.Core.Application.Service.ImageAndDoc.IDownloadAndUploadService,IRaCIS.Core.Application.Interfaces.ITrialEmailNoticeConfigService,AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer,ZiggyCreatures.Caching.Fusion.IFusionCache)">
|
||||
<member name="M:IRaCIS.Core.Application.Service.ReadingImageTaskService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingNoneDicomMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserLog},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingOncologyTaskInfo},IRaCIS.Core.Application.Service.IVisitTaskHelpeService,IRaCIS.Core.Application.Service.IVisitTaskService,IRaCIS.Core.Application.Contracts.IReadingClinicalDataService,IRaCIS.Core.Application.Service.IReadingCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SubjectVisit},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Subject},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.UserFeedBack},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.ServiceVerifyConfigOption},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingGlobalTaskInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingCriterionPage},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskRelation},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingJudgeInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadModule},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.OrganTrialInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocument},IRaCIS.Core.Application.Service.ReadingCalculate.Interface.ILuganoCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingCustomTag},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionMark},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTrialCriterionDictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableAnswerRowInfo},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTableQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingTaskQuestionAnswer},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionSystem},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.NoneDicomStudyFile},IRaCIS.Core.Application.Service.IGeneralCalculateService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TaskStudy},IRaCIS.Core.Application.Service.ImageAndDoc.IDownloadAndUploadService,IRaCIS.Core.Application.Interfaces.ITrialEmailNoticeConfigService,AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer,ZiggyCreatures.Caching.Fusion.IFusionCache)">
|
||||
<summary>
|
||||
IR影像阅片
|
||||
</summary>
|
||||
|
@ -14108,13 +13800,6 @@
|
|||
计划外访视 获取受试者选择下拉框列表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.VisitPlanService.GetVisitStage(IRaCIS.Application.Contracts.GetVisitStageInDto)">
|
||||
<summary>
|
||||
获取项目访视计划
|
||||
</summary>
|
||||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Service.VisitPlanService.GetTrialVisitStageList(IRaCIS.Application.Contracts.VisitPlanQueryDTO)">
|
||||
暂时不用
|
||||
<summary> 获取项目访视计划</summary>
|
||||
|
@ -14332,13 +14017,6 @@
|
|||
<returns></returns>
|
||||
</member>
|
||||
<!-- Badly formed XML comment ignored for member "M:IRaCIS.Core.Application.Helper.IRCEmailPasswordHelper.GenerateRandomPassword(System.Int32)" -->
|
||||
<member name="M:IRaCIS.Core.Application.Helper.IRCEmailPasswordHelper.IsValidEmail(System.String)">
|
||||
<summary>
|
||||
微软官方邮件验证 很宽松
|
||||
</summary>
|
||||
<param name="email"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Helper.FileConvertHelper.ConvertWordToPdf(System.String,System.String)">
|
||||
<summary>
|
||||
镜像里面打入libreoffice 的方案
|
||||
|
@ -14760,17 +14438,6 @@
|
|||
如果为null或空,则发送给所有相关角色
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.TrialDocumentErverDayEvent">
|
||||
<summary>
|
||||
定时提醒
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.MassTransit.Consumer.TrialDocumentPublishEvent.NewUserTypeIds">
|
||||
<summary>
|
||||
新增的需要发送邮件的用户角色ID列表
|
||||
如果为null或空,则发送给所有相关角色
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.MassTransit.Consumer.QCImageQuestionRecurringSchedule">
|
||||
<summary>
|
||||
QC 影像质疑待处理
|
||||
|
@ -14816,26 +14483,6 @@
|
|||
生效通知
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.MassTransit.Recurring.TrialDocumentErverDayEventConsumer">
|
||||
<summary>
|
||||
定时过期提醒
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.MassTransit.Recurring.TrialDocumentErverDayEventConsumer.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocument},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.IdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocConfirmedIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Dictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocument},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Application.Contracts.ISystemDocumentService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocNeedConfirmedUserType},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocNeedConfirmedUserType},Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocConfirmedIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.EmailNoticeConfig},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig})">
|
||||
<summary>
|
||||
定时过期提醒
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.MassTransit.Recurring.TrialDocumentPublishEventConsumer">
|
||||
<summary>
|
||||
生效通知
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.MassTransit.Recurring.TrialDocumentPublishEventConsumer.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.VisitTask},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocument},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.IdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Dictionary},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.EmailNoticeConfig},Microsoft.Extensions.Options.IOptionsMonitor{IRaCIS.Core.Domain.Share.SystemEmailSendConfig})">
|
||||
<summary>
|
||||
生效通知
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.ViewModel.TaskAllocationRuleView">
|
||||
<summary> TaskAllocationRuleView 列表视图模型 </summary>
|
||||
</member>
|
||||
|
@ -15072,11 +14719,6 @@
|
|||
<member name="T:IRaCIS.Core.Application.ViewModel.FrontAuditConfigAddOrEdit">
|
||||
<summary> FrontAuditConfigAddOrEdit 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.ViewModel.FrontAuditConfigAddOrEdit.IsDefaultChoice">
|
||||
<summary>
|
||||
是否默认选择
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.ViewModel.FrontAuditConfigAddOrEdit.CodeEn">
|
||||
<summary>
|
||||
字段的英文值
|
||||
|
@ -16295,13 +15937,6 @@
|
|||
系统邮件配置表
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Contracts.EmailNoticeConfigService.BatchUpdateEmail(System.Collections.Generic.List{IRaCIS.Core.Application.Contracts.BatchUpdateEmailTopicCommand})">
|
||||
<summary>
|
||||
批量更新邮件主题中英文
|
||||
</summary>
|
||||
<param name="inCommandList"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Contracts.ISystemBasicDataService">
|
||||
<summary>
|
||||
ISystemBasicDataService
|
||||
|
@ -16383,21 +16018,6 @@
|
|||
<member name="T:IRaCIS.Core.Application.Contracts.TrialDocumentAddOrEdit">
|
||||
<summary> TrialDocumentAddOrEdit 列表查询参数模型</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Contracts.TrialDocumentAddOrEdit.CurrentStaffTrainDays">
|
||||
<summary>
|
||||
现有员工培训天数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Contracts.TrialDocumentAddOrEdit.NewStaffTrainDays">
|
||||
<summary>
|
||||
新员工培训天数
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Core.Application.Contracts.TrialDocumentAddOrEdit.IsPublish">
|
||||
<summary>
|
||||
是否发布
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Core.Application.Contracts.ISystemDocumentService">
|
||||
<summary>
|
||||
ISystemDocumentService
|
||||
|
@ -17568,44 +17188,11 @@
|
|||
TrialDocumentService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Services.TrialDocumentService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocument},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocumentAttachment},IRaCIS.Core.Application.Contracts.ISystemDocumentService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocConfirmedIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocNeedConfirmedUserType},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocNeedConfirmedUserType},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocument},Microsoft.Extensions.DependencyInjection.IServiceScopeFactory,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.IdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocConfirmedIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
|
||||
<member name="M:IRaCIS.Core.Application.Services.TrialDocumentService.#ctor(IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocument},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.Trial},IRaCIS.Core.Application.Contracts.ISystemDocumentService,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocConfirmedIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocNeedConfirmedUserType},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocNeedConfirmedUserType},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.SystemDocument},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialUserRole},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.IdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.TrialDocConfirmedIdentityUser},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.ReadingQuestionCriterionTrial},AutoMapper.IMapper,IRaCIS.Core.Domain.Share.IUserInfo,Microsoft.Extensions.Localization.IStringLocalizer)">
|
||||
<summary>
|
||||
TrialDocumentService
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Services.TrialDocumentService.GetTrialDocumentAttachmentList(IRaCIS.Core.Application.Contracts.TrialDocumentAttachmentQuery)">
|
||||
<summary>
|
||||
获取项目文档附件列表
|
||||
</summary>
|
||||
<param name="inQuery"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Services.TrialDocumentService.AddOrUpdateTrialDocumentAttachment(IRaCIS.Core.Application.Contracts.TrialDocumentAttachmentAddOrEdit)">
|
||||
<summary>
|
||||
添加或更新项目文档附件
|
||||
</summary>
|
||||
<param name="addOrEditTrialDocumentAttachment"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Services.TrialDocumentService.DeleteTrialDocumentAttachment(System.Guid)">
|
||||
<summary>
|
||||
删除项目文档附件
|
||||
</summary>
|
||||
<param name="trialDocumentAttachmentId"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Services.TrialDocumentService.PublishTrialDocument(IRaCIS.Core.Application.Contracts.PublishTrialDocumentInDto)">
|
||||
<summary>
|
||||
发布项目文档
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Services.TrialDocumentService.TestPush">
|
||||
<summary>
|
||||
测试定时发送
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Services.TrialDocumentService.GetTrialDocumentList(IRaCIS.Core.Application.Contracts.TrialDocumentQuery)">
|
||||
<summary>
|
||||
Setting 界面的 项目所有文档列表
|
||||
|
@ -17712,10 +17299,9 @@
|
|||
<param name="tpCode"></param>
|
||||
<param name="key"></param>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Services.SeriesService.List(System.Guid,System.Nullable{System.Boolean},System.Nullable{System.Boolean})">
|
||||
<member name="M:IRaCIS.Core.Application.Services.SeriesService.List(System.Guid)">
|
||||
<summary> 指定资源Id,获取Dicom检查所属序列信息列表 </summary>
|
||||
<param name="studyId"> Dicom检查的Id </param>
|
||||
<param name="isReading"></param>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Services.SeriesService.Preview(System.Guid)">
|
||||
<summary> 指定资源Id,渲染Dicom序列的Jpeg预览图像 </summary>
|
||||
|
@ -18101,7 +17687,7 @@
|
|||
<param name="trialId"></param>
|
||||
<returns></returns>SeriesCount
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Image.QA.QCOperationService.ReplaceQCTaskActionUser(System.Guid,System.Guid,System.Nullable{System.Guid})">
|
||||
<member name="M:IRaCIS.Core.Application.Image.QA.QCOperationService.ReplaceQCTaskActionUser(System.Guid,System.Guid)">
|
||||
<summary>替换当前领取人 </summary>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Image.QA.QCOperationService.CollectNextIQCQuality(IRaCIS.Core.Application.Contracts.GetNextIQCQualityInDto)">
|
||||
|
@ -18112,13 +17698,6 @@
|
|||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Image.QA.QCOperationService.GetNextIQCQuality(IRaCIS.Core.Application.Contracts.GetNextIQCQualityInDto)">
|
||||
<summary>
|
||||
因为不区分任务类型,按照同类型没找到,要自动切换到下一种类型,必须包一层
|
||||
</summary>
|
||||
<param name="inDto"></param>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:IRaCIS.Core.Application.Image.QA.QCOperationService.GetNextIQCTask(IRaCIS.Core.Application.Contracts.GetNextIQCQualityInDto,System.Boolean)">
|
||||
<summary>
|
||||
获取下一个质控任务
|
||||
</summary>
|
||||
|
@ -19262,11 +18841,6 @@
|
|||
读片数量分类统计
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:IRaCIS.Application.Contracts.TrialExtraConfig.IsOpenLostVistRead">
|
||||
<summary>
|
||||
打开失访可读
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:IRaCIS.Application.Contracts.ExportTemplateAsyncDto">
|
||||
<summary>
|
||||
导出文件
|
||||
|
|
|
@ -67,7 +67,7 @@ namespace IRaCIS.Core.Application.MassTransit.Consumer
|
|||
|
||||
//subjectVisitLambda2= subjectVisitLambda2.And(x => x.CheckState == CheckStateEnum.ToCheck && x.AuditState == AuditStateEnum.QCPassed || (x.CheckState == CheckStateEnum.CVIng && x.AuditState == AuditStateEnum.QCPassed));
|
||||
|
||||
Expression<Func<SubjectVisit, bool>> subjectVisitLambda = x => x.TrialId == trialId && x.Subject.IsSubjectQuit == false &&
|
||||
Expression<Func<SubjectVisit, bool>> subjectVisitLambda = x => x.TrialId == trialId &&
|
||||
(x.CheckState == CheckStateEnum.ToCheck && x.AuditState == AuditStateEnum.QCPassed || (x.CheckState == CheckStateEnum.CVIng && x.AuditState == AuditStateEnum.QCPassed));
|
||||
|
||||
var dicomQuery = from sv in _subjectVisitRepository.Where(subjectVisitLambda)
|
||||
|
|
|
@ -266,43 +266,57 @@ public class ImageConsumer(
|
|||
// 获取项目信息
|
||||
var trialInfo = await _trialRepository.FirstOrDefaultAsync(t => t.Id == inDto.TrialId);
|
||||
|
||||
List<UserTypeEnum> filterUserTypeList = new List<UserTypeEnum>()
|
||||
{
|
||||
UserTypeEnum.ClinicalResearchCoordinator,
|
||||
UserTypeEnum.CRA,
|
||||
};
|
||||
|
||||
// 根据不同场景获取不同角色的用户 先排除CRC和CRA
|
||||
var trialUserList = await _trialUseRoleRepository.Where(x => x.TrialId == inDto.TrialId && !x.TrialUser.IsDeleted && !filterUserTypeList.Contains(x.UserRole.UserTypeEnum) ).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||
|
||||
// CRC和CRA单独取
|
||||
var crcAndcraUserList = await _trialSiteRepository.Where(x => x.Id == inDto.SubjectVisit.TrialSiteId).SelectMany(x => x.CRCUserList.Select(y => y.UserRole)).ToListAsync();
|
||||
trialUserList.AddRange(crcAndcraUserList);
|
||||
// 根据不同场景获取不同角色的用户
|
||||
var trialUser = await _trialUseRoleRepository.Where(x => x.TrialId == inDto.TrialId && !x.TrialUser.IsDeleted).Include(x => x.UserRole).Select(x => x.UserRole).ToListAsync();
|
||||
|
||||
// 根据场景确定收件人
|
||||
List<UserRole> toUserList = new List<UserRole>();
|
||||
List<UserRole> ccUserList = new List<UserRole>();
|
||||
|
||||
var emailNoticeUserList = await _emailNoticeUserTypeRepository.Where(x => x.EmailNoticeConfigId == inDto.EmailNoticeConfig.Id).ToListAsync();
|
||||
var userTypeEnumList = emailNoticeUserList.Select(x => x.UserType).ToList();
|
||||
var userTypeEnum = emailNoticeUserList.Select(x => x.UserType).ToList();
|
||||
if (inDto.UserTypes != null)
|
||||
{
|
||||
userTypeEnumList = inDto.UserTypes;
|
||||
userTypeEnum = inDto.UserTypes;
|
||||
}
|
||||
var crcUserList = new List<UserRole>() { };
|
||||
if (userTypeEnum.Contains(UserTypeEnum.ClinicalResearchCoordinator))
|
||||
{
|
||||
crcUserList = await _trialSiteRepository.Where(x => x.Id == inDto.SubjectVisit.TrialSiteId).SelectMany(x => x.CRCUserList.Select(y => y.UserRole)).ToListAsync();
|
||||
}
|
||||
|
||||
if (inDto.UserTypes == null)
|
||||
{
|
||||
var toList = emailNoticeUserList.Where(x => x.EmailUserType == EmailUserType.To).Select(x => x.UserType).ToList();
|
||||
toUserList = trialUserList.Where(x => toList.Contains(x.UserTypeEnum)).ToList();
|
||||
var toList = emailNoticeUserList.Where(x => x.EmailUserType == EmailUserType.To && x.UserType != UserTypeEnum.ClinicalResearchCoordinator).Select(x => x.UserType).ToList();
|
||||
|
||||
toUserList = trialUser.Where(x => toList.Contains(x.UserTypeEnum)).ToList();
|
||||
|
||||
if (emailNoticeUserList.Any(x => x.EmailUserType == EmailUserType.To && x.UserType == UserTypeEnum.ClinicalResearchCoordinator))
|
||||
{
|
||||
toUserList.AddRange(crcUserList);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var toList = inDto.UserTypes;
|
||||
toUserList = trialUserList.Where(x => toList.Contains(x.UserTypeEnum)).ToList();
|
||||
var toList = inDto.UserTypes.Where(x => x != UserTypeEnum.ClinicalResearchCoordinator).ToList();
|
||||
|
||||
toUserList = trialUser.Where(x => toList.Contains(x.UserTypeEnum)).ToList();
|
||||
|
||||
if (inDto.UserTypes.Any(x => x == UserTypeEnum.ClinicalResearchCoordinator))
|
||||
{
|
||||
toUserList.AddRange(crcUserList);
|
||||
}
|
||||
}
|
||||
|
||||
var ccList = emailNoticeUserList.Where(x => x.EmailUserType == EmailUserType.Copy).Select(x => x.UserType).ToList();
|
||||
ccUserList = trialUserList.Where(x => ccList.Contains(x.UserTypeEnum)).ToList();
|
||||
|
||||
var ccList = emailNoticeUserList.Where(x => x.EmailUserType == EmailUserType.Copy && x.UserType != UserTypeEnum.ClinicalResearchCoordinator).Select(x => x.UserType).ToList();
|
||||
|
||||
ccUserList = trialUser.Where(x => ccList.Contains(x.UserTypeEnum)).ToList();
|
||||
|
||||
if (emailNoticeUserList.Any(x => x.EmailUserType == EmailUserType.Copy && x.UserType == UserTypeEnum.ClinicalResearchCoordinator))
|
||||
{
|
||||
ccUserList.AddRange(crcUserList);
|
||||
}
|
||||
|
||||
// 如果没有收件人,则不发送邮件
|
||||
if (toUserList.Count == 0)
|
||||
|
|
|
@ -28,10 +28,10 @@ public static class OldRecurringEmailHelper
|
|||
|
||||
Guid trialId, EmailBusinessScenario businessScenario,
|
||||
Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc,
|
||||
Guid? trialSiteId = null)
|
||||
Guid? trialSiteId = null, Guid? trialReadingCriterionId = null)
|
||||
{
|
||||
//找到配置
|
||||
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == businessScenario, ignoreQueryFilters: true)
|
||||
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.TrialReadingCriterionId == trialReadingCriterionId && t.BusinessScenarioEnum == businessScenario, ignoreQueryFilters: true)
|
||||
.Include(t => t.TrialEmailNoticeUserList).Include(t => t.TrialEmailBlackUserList).FirstOrDefaultAsync();
|
||||
|
||||
|
||||
|
|
|
@ -58,24 +58,3 @@ public class SystemDocumentPublishEvent : DomainEvent
|
|||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 定时提醒
|
||||
/// </summary>
|
||||
public class TrialDocumentErverDayEvent : DomainEvent
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class TrialDocumentPublishEvent : DomainEvent
|
||||
{
|
||||
public List<Guid> Ids { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 新增的需要发送邮件的用户角色ID列表
|
||||
/// 如果为null或空,则发送给所有相关角色
|
||||
/// </summary>
|
||||
public List<Guid> NewUserTypeIds { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,307 +0,0 @@
|
|||
using DocumentFormat.OpenXml;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using MassTransit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MimeKit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reactive.Joins;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IRaCIS.Core.Application.MassTransit.Recurring
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 定时过期提醒
|
||||
/// </summary>
|
||||
public class TrialDocumentErverDayEventConsumer(
|
||||
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
|
||||
IRepository<VisitTask> _visitTaskRepository,
|
||||
IRepository<SystemDocument> _systemDocumentRepository,
|
||||
IRepository<IdentityUser> _identityUserRepository,
|
||||
IRepository<SystemDocConfirmedIdentityUser> _systemDocConfirmedUserRepository,
|
||||
IRepository<Dictionary> _dictionaryRepository,
|
||||
IRepository<TrialUserRole> _trialUserRoleRepository, IRepository<TrialDocument> _trialDocumentRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
ISystemDocumentService _systemDocumentService,
|
||||
IRepository<SystemDocNeedConfirmedUserType> _systemDocNeedConfirmedUserTypeRepository,
|
||||
IRepository<TrialDocNeedConfirmedUserType> _trialDocNeedConfirmedUserTypeRepository,
|
||||
IServiceScopeFactory serviceScopeFactory,
|
||||
IRepository<TrialIdentityUser> _trialIdentityUserRepository,
|
||||
IRepository<TrialDocConfirmedIdentityUser> _trialDocConfirmedUserRepository,
|
||||
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
|
||||
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
||||
|
||||
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<TrialDocumentErverDayEvent>
|
||||
{
|
||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||
|
||||
public async Task Consume(ConsumeContext<TrialDocumentErverDayEvent> context)
|
||||
{
|
||||
|
||||
DateTime now = DateTime.Now;
|
||||
Console.WriteLine("发送定时项目过期提醒");
|
||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||
var trialDocQuery =
|
||||
from trialDoc in _trialDocumentRepository.AsQueryable(true)
|
||||
|
||||
join trialIdentityUser in _trialIdentityUserRepository.Where(x => x.IsDeleted == false) on trialDoc.TrialId equals trialIdentityUser.TrialId
|
||||
join trialUserRole in _trialUserRoleRepository.Where(x => x.IsDeleted == false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
|
||||
from identityUser in _identityUserRepository.AsQueryable(false)
|
||||
|
||||
.Where(t => t.Status == UserStateEnum.Enable &&
|
||||
t.Id == trialIdentityUser.IdentityUserId &&
|
||||
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
||||
.Any(t => trialDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
||||
|
||||
join confirm in _trialDocConfirmedUserRepository.Where() on
|
||||
new { trialIdentityUser.IdentityUserId, TrialDocumentId = trialDoc.Id } equals new { IdentityUserId = confirm.ConfirmUserId, confirm.TrialDocumentId } into cc
|
||||
|
||||
from confirm in cc.DefaultIfEmpty()
|
||||
select new TrialSignDocView()
|
||||
{
|
||||
TrialCode = trialDoc.Trial.TrialCode,
|
||||
ResearchProgramNo = trialDoc.Trial.ResearchProgramNo,
|
||||
ExperimentName = trialDoc.Trial.ExperimentName,
|
||||
CurrentStaffTrainDays = trialDoc.CurrentStaffTrainDays,
|
||||
NewStaffTrainDays = trialDoc.NewStaffTrainDays,
|
||||
Id = trialDoc.Id,
|
||||
IsSystemDoc = false,
|
||||
CreateTime = trialDoc.CreateTime,
|
||||
FullFilePath = trialDoc.Path,
|
||||
IsDeleted = trialDoc.IsDeleted,
|
||||
Name = trialDoc.Name,
|
||||
Path = trialDoc.Path,
|
||||
FileTypeId = trialDoc.FileTypeId,
|
||||
UpdateTime = trialDoc.UpdateTime,
|
||||
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
|
||||
//IsConfirmed = confirm.ConfirmTime != null,
|
||||
ConfirmUserId = identityUser.Id,
|
||||
ConfirmTime = confirm.ConfirmTime,
|
||||
RealName = trialIdentityUser.IdentityUser.FullName,
|
||||
UserName = trialIdentityUser.IdentityUser.UserName,
|
||||
UserCreateTime= trialIdentityUser.CreateTime,
|
||||
IdentityUserTypeList = trialIdentityUser.TrialUserRoleList.Select(t => t.UserRole.UserTypeRole.UserTypeShortName).ToList(),
|
||||
|
||||
DocNeedSignUserTypeList = trialDoc.NeedConfirmedUserTypeList.Select(t => t.UserTypeRole.UserTypeShortName).ToList(),
|
||||
};
|
||||
var datalist = await trialDocQuery.IgnoreQueryFilters().Where(t => t.IsDeleted == false && t.ConfirmTime == null&&t.ConfirmTime==null)
|
||||
.ToListAsync();
|
||||
datalist = datalist.Where(x => x.SuggestFinishTime != null && x.SuggestFinishTime.Value.Date == DateTime.Now.Date)
|
||||
.ToList();
|
||||
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
|
||||
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
||||
|
||||
Console.WriteLine("发送定时项目过期提醒:人员数量" + userinfoList.Count);
|
||||
int index = 1;
|
||||
foreach (var userinfo in userinfoList)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine($"{index}发送定时过期提醒,邮箱:{userinfo.EMail},姓名{userinfo.UserName}");
|
||||
index++;
|
||||
var messageToSend = new MimeMessage();
|
||||
//发件地址
|
||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||
|
||||
|
||||
|
||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||
{
|
||||
var topicStr = string.Format(input.topicStr, companyName);
|
||||
|
||||
var htmlBodyStr = string.Format(
|
||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||
userinfo.UserName, // 用户名 {0}
|
||||
_systemEmailConfig.SiteUrl
|
||||
);
|
||||
|
||||
return (topicStr, htmlBodyStr);
|
||||
};
|
||||
|
||||
var scenario = EmailBusinessScenario.TrialTraining_ExpirationNotification;
|
||||
|
||||
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsAutoSend && t.IsEnable).FirstOrDefault();
|
||||
|
||||
if (emailConfig != null)
|
||||
{
|
||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生效通知
|
||||
/// </summary>
|
||||
public class TrialDocumentPublishEventConsumer(
|
||||
IRepository<ReadingQuestionCriterionTrial> _trialReadingCriterionRepository,
|
||||
IRepository<VisitTask> _visitTaskRepository,
|
||||
IRepository<TrialDocument> _trialDocumentRepository,
|
||||
IRepository<IdentityUser> _identityUserRepository,
|
||||
IRepository<TrialIdentityUser> _trialIdentityUserRepository,
|
||||
IRepository<Dictionary> _dictionaryRepository,
|
||||
IRepository<TrialUserRole> _trialUserRoleRepository,
|
||||
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
|
||||
|
||||
IOptionsMonitor<SystemEmailSendConfig> systemEmailConfig) : IConsumer<TrialDocumentPublishEvent>
|
||||
{
|
||||
private readonly SystemEmailSendConfig _systemEmailConfig = systemEmailConfig.CurrentValue;
|
||||
|
||||
public async Task Consume(ConsumeContext<TrialDocumentPublishEvent> context)
|
||||
{
|
||||
var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US;
|
||||
|
||||
// 记录是否只发送给新增角色的日志
|
||||
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
|
||||
{
|
||||
Console.WriteLine($"只发送给新增项目的角色,角色数量: {context.Message.NewUserTypeIds.Count}");
|
||||
}
|
||||
// 构建查询
|
||||
IQueryable<UnionDocumentWithConfirmInfoView> systemDocQuery;
|
||||
|
||||
if (context.Message.NewUserTypeIds != null && context.Message.NewUserTypeIds.Any())
|
||||
{
|
||||
// 只查询新增角色的用户
|
||||
systemDocQuery =
|
||||
from trialDoc in _trialDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
|
||||
join trialIdentityUser in _trialIdentityUserRepository.Where(x=>x.IsDeleted==false) on trialDoc.TrialId equals trialIdentityUser.TrialId
|
||||
join trialUserRole in _trialUserRoleRepository.Where(x => x.IsDeleted == false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
|
||||
from identityUser in _identityUserRepository.AsQueryable(false)
|
||||
.Where(t => t.Status == UserStateEnum.Enable &&
|
||||
t.Id == trialIdentityUser.IdentityUserId &&
|
||||
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
||||
.Any(t => context.Message.NewUserTypeIds.Contains(t.UserTypeId) &&
|
||||
trialDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
||||
select new UnionDocumentWithConfirmInfoView()
|
||||
{
|
||||
IsSystemDoc = true,
|
||||
Id = trialDoc.Id,
|
||||
CreateTime = trialDoc.CreateTime,
|
||||
IsDeleted = trialDoc.IsDeleted,
|
||||
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
|
||||
Name = trialDoc.Name,
|
||||
Path = trialDoc.Path,
|
||||
FileTypeId = trialDoc.FileTypeId,
|
||||
UpdateTime = trialDoc.UpdateTime,
|
||||
ConfirmUserId = identityUser.Id,
|
||||
RealName = identityUser.FullName,
|
||||
UserName = identityUser.UserName,
|
||||
IsNeedSendEmial = identityUser.IsZhiZhun,
|
||||
FullFilePath = trialDoc.Path
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// 查询所有相关角色的用户
|
||||
systemDocQuery =
|
||||
from trialDoc in _trialDocumentRepository.AsQueryable(false).Where(x => context.Message.Ids.Contains(x.Id))
|
||||
join trialIdentityUser in _trialIdentityUserRepository.Where(x => x.IsDeleted == false) on trialDoc.TrialId equals trialIdentityUser.TrialId
|
||||
join trialUserRole in _trialUserRoleRepository.Where(x=>x.IsDeleted==false) on trialIdentityUser.Id equals trialUserRole.TrialUserId
|
||||
from identityUser in _identityUserRepository.AsQueryable(false)
|
||||
.Where(t => t.Status == UserStateEnum.Enable &&
|
||||
t.Id== trialIdentityUser.IdentityUserId&&
|
||||
t.UserRoleList.Where(t => t.IsUserRoleDisabled == false)
|
||||
.Any(t => trialDoc.NeedConfirmedUserTypeList.AsQueryable().Any(c => c.NeedConfirmUserTypeId == t.UserTypeId)))
|
||||
select new UnionDocumentWithConfirmInfoView()
|
||||
{
|
||||
IsSystemDoc = false,
|
||||
Id = trialDoc.Id,
|
||||
CreateTime = trialDoc.CreateTime,
|
||||
IsDeleted = trialDoc.IsDeleted,
|
||||
SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes,
|
||||
Name = trialDoc.Name,
|
||||
Path = trialDoc.Path,
|
||||
FileTypeId = trialDoc.FileTypeId,
|
||||
UpdateTime = trialDoc.UpdateTime,
|
||||
ConfirmUserId = identityUser.Id,
|
||||
RealName = identityUser.FullName,
|
||||
UserName = identityUser.UserName,
|
||||
IsNeedSendEmial = identityUser.IsZhiZhun ,
|
||||
FullFilePath = trialDoc.Path
|
||||
};
|
||||
}
|
||||
var datalist = await systemDocQuery.IgnoreQueryFilters().ToListAsync();
|
||||
|
||||
var confirmUserIdList = datalist.Select(t => t.ConfirmUserId).Distinct().ToList();
|
||||
var userinfoList = await _identityUserRepository.Where(x => confirmUserIdList.Contains(x.Id)).ToListAsync();
|
||||
int index = 1;
|
||||
foreach (var userinfo in userinfoList)
|
||||
{
|
||||
string msg = $"{index}项目生效通知,邮箱:{userinfo.EMail},姓名{userinfo.UserName},";
|
||||
index++;
|
||||
try
|
||||
{
|
||||
|
||||
var messageToSend = new MimeMessage();
|
||||
//发件地址
|
||||
messageToSend.From.Add(new MailboxAddress(_systemEmailConfig.FromName, _systemEmailConfig.FromEmail));
|
||||
messageToSend.To.Add(new MailboxAddress(String.Empty, userinfo.EMail));
|
||||
|
||||
|
||||
|
||||
var companyName = isEn_US ? _systemEmailConfig.CompanyShortName : _systemEmailConfig.CompanyShortNameCN;
|
||||
Func<(string topicStr, string htmlBodyStr), (string topicStr, string htmlBodyStr)> emailConfigFunc = input =>
|
||||
{
|
||||
var topicStr = string.Format(input.topicStr, companyName);
|
||||
|
||||
var htmlBodyStr = string.Format(
|
||||
CommonEmailHelper.ReplaceCompanyName(_systemEmailConfig, input.htmlBodyStr),
|
||||
userinfo.UserName, // 用户名 {0}
|
||||
_systemEmailConfig.SiteUrl
|
||||
);
|
||||
|
||||
return (topicStr, htmlBodyStr);
|
||||
};
|
||||
|
||||
var scenario = EmailBusinessScenario.TrialTraining_EffectiveNotification;
|
||||
|
||||
var emailConfig = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == scenario && t.IsEnable).FirstOrDefault();
|
||||
|
||||
if (emailConfig != null)
|
||||
{
|
||||
await CommonEmailHelper.GetEmailSubejctAndHtmlInfoAndBuildAsync(emailConfig, messageToSend, emailConfigFunc);
|
||||
|
||||
await SendEmailHelper.SendEmailAsync(messageToSend, _systemEmailConfig);
|
||||
msg += "发送成功";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
msg += "发送失败";
|
||||
|
||||
}
|
||||
|
||||
|
||||
Console.WriteLine(msg);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -71,8 +71,6 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||
|
||||
public bool IsPMSetBack { get; set; }
|
||||
|
||||
public bool IsSubjectQuit { get; set; }
|
||||
|
||||
#region 标准配置
|
||||
public Guid TrialReadingCriterionId { get; set; }
|
||||
|
||||
|
@ -240,7 +238,6 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||
//public string ReReadingOriginalTaskCode { get; set; }
|
||||
|
||||
|
||||
public string ApplicantName { get; set; }
|
||||
|
||||
public Guid Id { get; set; }
|
||||
|
||||
|
|
|
@ -125,7 +125,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
[HttpGet("{trialId:guid}")]
|
||||
public async Task<List<TrialDoctorUserSelectView>> GetDoctorUserSelectList(Guid trialId, [FromServices] IRepository<Enroll> _enrollRepository)
|
||||
{
|
||||
var query = from enroll in _enrollRepository.Where(t => t.TrialId == trialId /*&& t.TaskAllocationRule.IsEnable*/ && /*(t.EnrollStatus >= EnrollStatus.ConfirmIntoGroup ||*/ t.Trial.SubjectDoctorUserList.Any(v => v.DoctorUserId == t.DoctorUser.Id))
|
||||
var query = from enroll in _enrollRepository.Where(t => t.TrialId == trialId && t.EnrollStatus >= EnrollStatus.ConfirmIntoGroup)
|
||||
join user in _userRoleRepository.AsQueryable() on enroll.DoctorId equals user.DoctorId
|
||||
select new TrialDoctorUserSelectView()
|
||||
{
|
||||
|
|
|
@ -213,7 +213,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
//为防止脏数据 这里也多判断一次
|
||||
var existCurrentVisitTaskList = _visitTaskRepository.Where(t => t.TrialId == trialId && t.SubjectId == subjectVisit.SubjectId
|
||||
&& t.TrialReadingCriterionId == trialReadingCriterionConfig.TrialReadingCriterionId && t.TaskState == TaskState.Effect
|
||||
&& t.SourceSubjectVisitId == subjectVisit.Id && t.IsAnalysisCreate == false).ToList();
|
||||
&& t.SourceSubjectVisitId == subjectVisit.Id).ToList();
|
||||
|
||||
if (trialReadingCriterionConfig.ReadingType == ReadingMethod.Double)
|
||||
{
|
||||
|
@ -682,7 +682,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
var existCurrentVisitTaskList = _visitTaskRepository.Where(t => t.TrialId == trialId && t.SubjectId == subjectVisit.SubjectId
|
||||
&& t.TrialReadingCriterionId == trialReadingCriterionId && t.TaskState == TaskState.Effect
|
||||
/* && t.TaskAllocationState == TaskAllocationState.NotAllocate && t.DoctorUserId == null*/ && t.SourceSubjectVisitId == subjectVisit.Id && t.IsAnalysisCreate == false).ToList();
|
||||
/* && t.TaskAllocationState == TaskAllocationState.NotAllocate && t.DoctorUserId == null*/ && t.SourceSubjectVisitId == subjectVisit.Id).ToList();
|
||||
|
||||
VisitTask? task1 = existCurrentVisitTaskList.FirstOrDefault(t => t.ArmEnum == Arm.DoubleReadingArm1);
|
||||
VisitTask? task2 = existCurrentVisitTaskList.FirstOrDefault(t => t.ArmEnum == Arm.DoubleReadingArm2);
|
||||
|
@ -1084,7 +1084,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
|
||||
//该Subject 之前是否有已分配的 如果改变配置 可能会出现 一个Subject 分配的同一个医生 有的在Arm1 有的在Arm2
|
||||
var allocateSubjectArmList = _visitTaskRepository.Where(t => t.SubjectId == subjectVisit.SubjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.TrialId == trialId && t.DoctorUserId != null && t.ArmEnum != Arm.JudgeArm && t.IsAnalysisCreate == false)
|
||||
var allocateSubjectArmList = _visitTaskRepository.Where(t => t.SubjectId == subjectVisit.SubjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.TrialId == trialId && t.DoctorUserId != null && t.ArmEnum != Arm.JudgeArm)
|
||||
.Select(t => new { t.DoctorUserId, t.ArmEnum }).Distinct().ToList();
|
||||
|
||||
//不是初次分配
|
||||
|
@ -1105,7 +1105,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
if (trialReadingCriterionConfig.IsReadingTaskViewInOrder == ReadingOrder.InOrder)
|
||||
{
|
||||
//之前有回退到影像上传的访视 那么当前访视一致性核查通过的时候,当前访视生成但是不分配出去(排除失访的)
|
||||
var beforeBackVisitTask = await _visitTaskRepository.Where(t => t.TrialId == trialId && t.SubjectId == subjectVisit.SubjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.VisitTaskNum < subjectVisit.VisitNum && t.ReadingCategory == ReadingCategory.Visit && t.SourceSubjectVisit.CheckState != CheckStateEnum.CVPassed && t.SourceSubjectVisit.IsLostVisit == false && t.IsAnalysisCreate == false).OrderBy(t => t.VisitTaskNum).FirstOrDefaultAsync();
|
||||
var beforeBackVisitTask = await _visitTaskRepository.Where(t => t.TrialId == trialId && t.SubjectId == subjectVisit.SubjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.VisitTaskNum < subjectVisit.VisitNum && t.ReadingCategory == ReadingCategory.Visit && t.SourceSubjectVisit.CheckState != CheckStateEnum.CVPassed && t.SourceSubjectVisit.IsLostVisit == false).OrderBy(t => t.VisitTaskNum).FirstOrDefaultAsync();
|
||||
|
||||
|
||||
if (beforeBackVisitTask == null)
|
||||
|
@ -1130,7 +1130,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
#endregion
|
||||
|
||||
|
||||
var followBackVisitTask = await _visitTaskRepository.Where(t => t.TrialId == trialId && t.SubjectId == subjectVisit.SubjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.VisitTaskNum > subjectVisit.VisitNum && t.ReadingCategory == ReadingCategory.Visit && t.SourceSubjectVisit.CheckState != CheckStateEnum.CVPassed && t.SourceSubjectVisit.IsLostVisit == false && t.IsAnalysisCreate == false).OrderBy(t => t.VisitTaskNum).FirstOrDefaultAsync();
|
||||
var followBackVisitTask = await _visitTaskRepository.Where(t => t.TrialId == trialId && t.SubjectId == subjectVisit.SubjectId && t.TrialReadingCriterionId == trialReadingCriterionId && t.VisitTaskNum > subjectVisit.VisitNum && t.ReadingCategory == ReadingCategory.Visit && t.SourceSubjectVisit.CheckState != CheckStateEnum.CVPassed && t.SourceSubjectVisit.IsLostVisit == false).OrderBy(t => t.VisitTaskNum).FirstOrDefaultAsync();
|
||||
|
||||
//存在退回访视1 又退回基线 这种情况 生成任务 考虑基线先一致性核查通过,但是访视1还未通过时 生成任务
|
||||
var followVisitTaskList = await _visitTaskRepository
|
||||
|
@ -1409,9 +1409,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
.Where(x => x.ClinicalDataTrialSet.UploadRole == UploadRole.PM || x.FileCount > 0)
|
||||
.Include(t => t.ReadingClinicalDataPDFList).Include(t => t.ClinicalDataTrialSet).ToList();
|
||||
|
||||
//防止多标准重复插入
|
||||
if (!_readingConsistentClinicalDataRepository.Any(t => t.SubjectId == subjectId))
|
||||
{
|
||||
|
||||
foreach (var clinicalData in clinicalDataList)
|
||||
{
|
||||
var consistnentClinicalData = _mapper.Map<ReadingConsistentClinicalData>(clinicalData);
|
||||
|
@ -1435,8 +1433,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
await _readingConsistentClinicalDataRepository.AddAsync(consistnentClinicalData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (var task in generateTaskCommand.GenerataConsistentTaskList)
|
||||
{
|
||||
|
|
|
@ -46,7 +46,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
IRepository<SubjectCanceDoctor> _subjectCanceDoctorRepository,
|
||||
IRepository<ReadingTaskQuestionMark> _readingTaskQuestionMarkRepository,
|
||||
IRepository<ReadingTableAnswerRowInfo> _readingTableAnswerRowInfoRepository,
|
||||
//IRepository<ReadingCustomTag> _readingCustomTagRepository,
|
||||
IRepository<ReadingCustomTag> _readingCustomTagRepository,
|
||||
IRepository<TaskInfluence> _taskInfluenceRepository,
|
||||
IRepository<TrialQCQuestionAnswer> _trialQCQuestionAnswerRepository,
|
||||
ILogger<VisitTaskService> _logger,
|
||||
|
@ -965,7 +965,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
//随机阅片
|
||||
else
|
||||
{
|
||||
var taskQuery = _visitTaskRepository.Where(x => x.TrialId == inQuery.TrialId && x.DoctorUserId == _userInfo.UserRoleId && x.TaskState == TaskState.Effect && x.TrialReadingCriterionId == trialReadingCriterionId && x.Subject.IsSubjectQuit == false)
|
||||
var taskQuery = _visitTaskRepository.Where(x => x.TrialId == inQuery.TrialId && x.DoctorUserId == _userInfo.UserRoleId && x.TaskState == TaskState.Effect && x.TrialReadingCriterionId == trialReadingCriterionId)
|
||||
.Where(x => !x.Subject.IsDeleted).Where(x => (x.IsNeedClinicalDataSign && x.IsClinicalDataSign) || !x.IsNeedClinicalDataSign);
|
||||
|
||||
iRUnReadOut = new IRUnReadOutDto()
|
||||
|
@ -1013,7 +1013,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
|
||||
var extralConfig = JsonConvert.DeserializeObject<TrialExtraConfig>(extralObj?.TrialExtraConfigJsonStr) ?? new TrialExtraConfig();
|
||||
|
||||
var visitQuery = _visitTaskRepository.Where(x => x.TrialId == inQuery.TrialId && x.DoctorUserId == _userInfo.UserRoleId && x.TaskState == TaskState.Effect && x.Subject.IsSubjectQuit == false)
|
||||
var visitQuery = _visitTaskRepository.Where(x => x.TrialId == inQuery.TrialId && x.DoctorUserId == _userInfo.UserRoleId && x.TaskState == TaskState.Effect)
|
||||
|
||||
.WhereIf(inQuery.SubjectId != null, x => x.SubjectId == inQuery.SubjectId)
|
||||
//前序 不存在 未生成任务的访视
|
||||
|
@ -1404,12 +1404,6 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
|
||||
task.ReReadingApplyState = ReReadingApplyState.TrialGroupHaveApplyed;
|
||||
|
||||
if (!isSPMjoin)
|
||||
{
|
||||
task.ReReadingApplyState = ReReadingApplyState.Agree;
|
||||
task.PMBackReason = applyReReadingCommand.RequestReReadingReason;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -1621,7 +1615,13 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
var origenalTask = (await _visitTaskRepository.Where(t => item.OriginalReReadingTaskId == t.Id).FirstOrDefaultAsync()).IfNullThrowException();
|
||||
|
||||
|
||||
if ((origenalTask.TaskState != TaskState.Effect && origenalTask.TaskState != TaskState.Freeze))
|
||||
{
|
||||
await _visitTaskReReadingRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Id, u => new VisitTaskReReading() { RequestReReadingConfirmUserId = _userInfo.UserRoleId, RequestReReadingResultEnum = RequestReReadingResult.Invalid });
|
||||
|
||||
//---当前申请重阅任务的状态,已被其他任务重阅已影响,不允许对该状态下的任务进行重阅同意与否操作
|
||||
throw new BusinessValidationFailedException(_localizer["VisitTask_ReapplyStatusConflict"]);
|
||||
}
|
||||
|
||||
//更新申请信息
|
||||
var visitTaskReReadingAppply = await _visitTaskReReadingRepository.FirstOrDefaultAsync(t => t.Id == item.Id);
|
||||
|
@ -1634,13 +1634,6 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
|
||||
if (agreeReReadingCommand.RequestReReadingResultEnum == RequestReReadingResult.Agree)
|
||||
{
|
||||
if ((origenalTask.TaskState != TaskState.Effect && origenalTask.TaskState != TaskState.Freeze))
|
||||
{
|
||||
await _visitTaskReReadingRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Id, u => new VisitTaskReReading() { RequestReReadingConfirmUserId = _userInfo.UserRoleId, RequestReReadingResultEnum = RequestReReadingResult.Invalid });
|
||||
|
||||
//---当前申请重阅任务的状态,已被其他任务重阅已影响,不允许对该状态下的任务进行重阅同意与否操作
|
||||
throw new BusinessValidationFailedException(_localizer["VisitTask_ReapplyStatusConflict"]);
|
||||
}
|
||||
|
||||
await AgreeReReading(origenalTask.Id, visitTaskReReadingAppply.RequestReReadingType, visitTaskReReadingAppply);
|
||||
|
||||
|
@ -1717,12 +1710,12 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
if (criterionConfig.CriterionType == CriterionType.RECIST1Point1 && criterionConfig.IsAdditionalAssessment)
|
||||
{
|
||||
// PM申请 SPM / CPM审批
|
||||
//if (requestReReadingType == RequestReReadingType.TrialGroupApply)
|
||||
//{
|
||||
// filterExpression = filterExpression.And(t => t.TrialReadingCriterionId == origenalTask.TrialReadingCriterionId || t.TrialReadingCriterion.CriterionType == CriterionType.RECIST1Pointt1_MB);
|
||||
//}
|
||||
if (requestReReadingType == RequestReReadingType.TrialGroupApply)
|
||||
{
|
||||
filterExpression = filterExpression.And(t => t.TrialReadingCriterionId == origenalTask.TrialReadingCriterionId || t.TrialReadingCriterion.CriterionType == CriterionType.RECIST1Pointt1_MB);
|
||||
}
|
||||
//IR 申请 PM审批
|
||||
if (requestReReadingType != RequestReReadingType.TrialGroupApply)
|
||||
else
|
||||
{
|
||||
|
||||
// 1.1 基线任务影响BM任务
|
||||
|
@ -1740,13 +1733,10 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (requestReReadingType != RequestReReadingType.TrialGroupApply)
|
||||
{
|
||||
//默认影响的都是该标准的任务
|
||||
filterExpression = filterExpression.And(t => t.TrialReadingCriterionId == origenalTask.TrialReadingCriterionId);
|
||||
}
|
||||
}
|
||||
|
||||
//PM申请 SPM / CPM审批 回退访视,因此这里不生成访视任务 影响多个标准的任务
|
||||
if (requestReReadingType == RequestReReadingType.TrialGroupApply)
|
||||
|
@ -2216,16 +2206,16 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
{
|
||||
|
||||
//自定义
|
||||
//var readingCustomTagList = _readingCustomTagRepository.Where(t => t.VisitTaskId == origenalTask.Id).ToList();
|
||||
var readingCustomTagList = _readingCustomTagRepository.Where(t => t.VisitTaskId == origenalTask.Id).ToList();
|
||||
|
||||
//foreach (var item in readingCustomTagList)
|
||||
//{
|
||||
// item.Id = Guid.Empty;
|
||||
// item.VisitTaskId = newTask.Id;
|
||||
// item.MeasureData = item.MeasureData.Replace(origenalTask.Id.ToString(), newTask.Id.ToString());
|
||||
//}
|
||||
foreach (var item in readingCustomTagList)
|
||||
{
|
||||
item.Id = Guid.Empty;
|
||||
item.VisitTaskId = newTask.Id;
|
||||
item.MeasureData = item.MeasureData.Replace(origenalTask.Id.ToString(), newTask.Id.ToString());
|
||||
}
|
||||
|
||||
//_ = _readingCustomTagRepository.AddRangeAsync(readingCustomTagList).Result;
|
||||
_ = _readingCustomTagRepository.AddRangeAsync(readingCustomTagList).Result;
|
||||
|
||||
|
||||
|
||||
|
@ -2646,7 +2636,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
/// <param name="applyId"> 申请记录的Id</param>
|
||||
/// <returns></returns>
|
||||
[HttpGet("{taskId:guid}/{isReReading:bool}")]
|
||||
public async Task<IResponseOutput<List<InfluenceTaskInfo>>> GetReReadingOrBackInfluenceTaskList(Guid taskId, bool isReReading, Guid? applyId)
|
||||
public async Task<(List<InfluenceTaskInfo>, object)> GetReReadingOrBackInfluenceTaskList(Guid taskId, bool isReReading, Guid? applyId)
|
||||
{
|
||||
var isIRAppyTaskInfluenced = false;
|
||||
|
||||
|
@ -2664,16 +2654,13 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
//IR 申请1.1 基线重阅,影响附加评估所有的任务
|
||||
var isIR1Point1AdditionalAssessmentBaseline = false;
|
||||
|
||||
//是IR 申请 PM 审批流程
|
||||
var isIRApplyPMApprovalProcess = (IsPMOrAPm() && applyId != null && await _visitTaskReReadingRepository.AnyAsync(t => t.Id == applyId && t.CreateUserRole.UserTypeEnum == UserTypeEnum.IndependentReviewer))
|
||||
|| (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.IndependentReviewer && applyId == null);
|
||||
|
||||
//附加评估 IR 和PM 看到的影响列表不一样
|
||||
if (criterionConfig.CriterionType == CriterionType.RECIST1Point1 && criterionConfig.IsAdditionalAssessment)
|
||||
{
|
||||
|
||||
// IR 申请 PM 同意
|
||||
if (isIRApplyPMApprovalProcess)
|
||||
if (((IsPMOrAPm() && applyId != null && await _visitTaskReReadingRepository.AnyAsync(t => t.Id == applyId && t.CreateUserRole.UserTypeEnum == UserTypeEnum.IndependentReviewer))
|
||||
|| (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.IndependentReviewer && applyId == null)))
|
||||
{
|
||||
|
||||
// 1.1 基线任务影响BM任务
|
||||
|
@ -2692,20 +2679,18 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
}
|
||||
|
||||
}
|
||||
//(1、PM回退,PM申请重阅,SPM同意回退)--20250804-感觉这里没用,不用限制
|
||||
//else
|
||||
//{
|
||||
// filterExpression = filterExpression.And(t => t.TrialReadingCriterionId == filterObj.TrialReadingCriterionId || t.TrialReadingCriterion.CriterionType == CriterionType.RECIST1Pointt1_MB);
|
||||
//(1、PM回退,PM申请重阅,SPM同意回退)
|
||||
else
|
||||
{
|
||||
filterExpression = filterExpression.And(t => t.TrialReadingCriterionId == filterObj.TrialReadingCriterionId || t.TrialReadingCriterion.CriterionType == CriterionType.RECIST1Pointt1_MB);
|
||||
|
||||
//}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isReReading == true && isIRApplyPMApprovalProcess)
|
||||
{
|
||||
//默认影响的都是该标准的任务
|
||||
filterExpression = filterExpression.And(t => t.TrialReadingCriterionId == filterObj.TrialReadingCriterionId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -2946,8 +2931,8 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
|
|||
}
|
||||
#endregion
|
||||
|
||||
//IsIRAppyTaskInfluenced 列表中存在IR已申请重阅的任务!
|
||||
return ResponseOutput.Ok(list, new { IsIRAppyTaskInfluenced = isIRAppyTaskInfluenced });
|
||||
|
||||
return (list, new { IsIRAppyTaskInfluenced = isIRAppyTaskInfluenced });
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore.Migrations;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
|
@ -118,9 +117,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
.ForMember(o => o.IsReadingShowPreviousResults, t => t.MapFrom(u => u.TrialReadingCriterion.IsReadingShowPreviousResults))
|
||||
.ForMember(o => o.DigitPlaces, t => t.MapFrom(u => u.TrialReadingCriterion.DigitPlaces))
|
||||
.ForMember(o => o.IseCRFShowInDicomReading, t => t.MapFrom(u => u.TrialReadingCriterion.IseCRFShowInDicomReading))
|
||||
.ForMember(o => o.CriterionType, t => t.MapFrom(u => u.TrialReadingCriterion.CriterionType))
|
||||
.ForMember(o => o.IsSubjectQuit, t => t.MapFrom(u => u.Subject.IsSubjectQuit))
|
||||
;
|
||||
.ForMember(o => o.CriterionType, t => t.MapFrom(u => u.TrialReadingCriterion.CriterionType));
|
||||
|
||||
CreateMap<VisitTask, VisitTaskView>().IncludeBase<VisitTask, VisitTaskViewBasic>()
|
||||
|
||||
|
@ -163,10 +160,8 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
|
||||
CreateMap<VisitTaskReReading, ReReadingTaskView>()
|
||||
.ForMember(o => o.ApplicantName, t => t.MapFrom(u => u.CreateUserRole.IdentityUser.FullName))
|
||||
.ForMember(o => o.ReReadingNewTaskCode, t => t.MapFrom(u => u.NewReReadingTask.TaskCode))
|
||||
.ForMember(o => o.OriginalReReadingTask, t => t.MapFrom(u => u.OriginalReReadingTask))
|
||||
//.ForMember(o => o.IsSubjectQuit, t => t.MapFrom(u => u.OriginalReReadingTask.Subject.IsSubjectQuit))
|
||||
;
|
||||
|
||||
|
||||
|
@ -226,7 +221,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
.ForMember(o => o.IseCRFShowInDicomReading, t => t.MapFrom(u => u.VisitTask.TrialReadingCriterion.IseCRFShowInDicomReading))
|
||||
.ForMember(o => o.CriterionType, t => t.MapFrom(u => u.VisitTask.TrialReadingCriterion.CriterionType))
|
||||
|
||||
.ForMember(o => o.IsSubjectQuit, t => t.MapFrom(u => u.VisitTask.Subject.IsSubjectQuit))
|
||||
.ForMember(o => o.Id, t => t.MapFrom(u => u.Id))
|
||||
.ForMember(o => o.MedicalNo, t => t.MapFrom(u => u.VisitTask.Subject.MedicalNo))
|
||||
.ForMember(o => o.DoctorUser, t => t.MapFrom(u => u.VisitTask.DoctorUser))
|
||||
|
|
|
@ -36,14 +36,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
return await commonDocumentQueryable.ToPagedListAsync(queryCommonDocument);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public async Task<CommonDocument> GetCommonDocument(string code)
|
||||
{
|
||||
var find = await _commonDocumentRepository.Where(t => t.Code == code).FirstOrDefaultAsync();
|
||||
|
||||
return find;
|
||||
}
|
||||
|
||||
|
||||
public async Task<IResponseOutput> AddOrUpdateCommonDocument(CommonDocumentAddOrEdit addOrEditCommonDocument)
|
||||
{
|
||||
|
|
|
@ -39,10 +39,6 @@ namespace IRaCIS.Application.Contracts
|
|||
public string ValueCN { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class ChildInQuery:SortInput
|
||||
{
|
||||
public Guid ParentId { get; set; }
|
||||
}
|
||||
|
||||
public class AddOrEditBasicDic
|
||||
{
|
||||
|
|
|
@ -96,6 +96,9 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
public bool IsDeleted { get; set; }
|
||||
|
||||
|
||||
|
||||
public CriterionType? CriterionTypeEnum { get; set; }
|
||||
|
||||
/// <summary> 业务模块 /// </summary>
|
||||
public int BusinessModuleEnum { get; set; }
|
||||
|
||||
|
@ -137,24 +140,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
|
||||
public int? EmailDelaySeconds { get; set; }
|
||||
|
||||
|
||||
|
||||
[Comment("邮件配置的多个标准")]
|
||||
public List<CriterionType>? CriterionTypeList { get; set; }
|
||||
|
||||
//public CriterionType? CriterionTypeEnum { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class BatchUpdateEmailTopicCommand
|
||||
{
|
||||
[NotDefault]
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public string EmailTopic { get; set; } = string.Empty;
|
||||
|
||||
public string EmailTopicCN { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
// 生成时间 2022-03-28 16:43:52
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using DocumentFormat.OpenXml.Wordprocessing;
|
||||
using IRaCIS.Core.Infra.EFCore.Common;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
|
@ -64,26 +63,6 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||
|
||||
}
|
||||
|
||||
|
||||
public class ModuleTypeData
|
||||
{
|
||||
|
||||
public bool IsShow { get; set; }
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public Guid? ParentId { get; set; }
|
||||
public Guid DictionaryId { get; set; }
|
||||
|
||||
public int ShowOrder { get; set; }
|
||||
public string DictionaryValue { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class GetModuleTypeListInDto
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 复制其他对象到当前对象
|
||||
/// </summary>
|
||||
|
@ -169,11 +148,6 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||
public Guid UpdateUserId { get; set; }
|
||||
public string Code { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 是否默认选择
|
||||
/// </summary>
|
||||
public bool IsDefaultChoice { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 字段的英文值
|
||||
/// </summary>
|
||||
|
@ -329,7 +303,7 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||
public bool IsConfig { get; set; }
|
||||
public string DictionaryKey { get; set; } = string.Empty;
|
||||
|
||||
public bool IsBeforeModifyView { get; set; } = true;
|
||||
|
||||
|
||||
|
||||
//byzhouahng
|
||||
|
|
|
@ -182,12 +182,13 @@ namespace IRaCIS.Core.Application.Service
|
|||
/// <summary>
|
||||
/// 获取子项数组
|
||||
/// </summary>
|
||||
/// <param name="parentId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<List<BasicDicView>> GetChildList(ChildInQuery inQuery)
|
||||
[HttpGet("{parentId:guid}")]
|
||||
public async Task<List<BasicDicView>> GetChildList(Guid parentId)
|
||||
{
|
||||
return await _dicRepository.Where(t => t.ParentId == inQuery.ParentId)
|
||||
.ProjectTo<BasicDicView>(_mapper.ConfigurationProvider).SortToListAsync(inQuery);
|
||||
return await _dicRepository.Where(t => t.ParentId == parentId)
|
||||
.OrderBy(t => t.ShowOrder).ProjectTo<BasicDicView>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
.WhereIf(inQuery.SystemLevel != null, t => t.SystemLevel == inQuery.SystemLevel)
|
||||
.WhereIf(inQuery.IsDistinguishCriteria != null, t => t.IsDistinguishCriteria == inQuery.IsDistinguishCriteria)
|
||||
.WhereIf(inQuery.BusinessLevelEnum != null, t => t.BusinessLevelEnum == inQuery.BusinessLevelEnum)
|
||||
.WhereIf(inQuery.CriterionTypeEnum != null, t => t.CriterionTypeList.Any(t=>t==inQuery.CriterionTypeEnum))
|
||||
.WhereIf(inQuery.CriterionTypeEnum != null, t => t.CriterionTypeEnum == inQuery.CriterionTypeEnum)
|
||||
.WhereIf(inQuery.BusinessModuleEnum != null, t => t.BusinessModuleEnum == inQuery.BusinessModuleEnum)
|
||||
.WhereIf(inQuery.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == inQuery.BusinessScenarioEnum)
|
||||
.WhereIf(inQuery.IsReturnRequired != null, t => t.IsReturnRequired == inQuery.IsReturnRequired)
|
||||
|
@ -41,77 +41,16 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
return await emailNoticeConfigQueryable.ToPagedListAsync(inQuery);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量更新邮件主题中英文
|
||||
/// </summary>
|
||||
/// <param name="inCommandList"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IResponseOutput> BatchUpdateEmail(List<BatchUpdateEmailTopicCommand> inCommandList)
|
||||
{
|
||||
var findIdList = inCommandList.Select(x => x.Id).ToList();
|
||||
|
||||
var regex = new Regex(@"\{\s*\d+\s*\}");
|
||||
|
||||
foreach (var inCommand in inCommandList)
|
||||
{
|
||||
if (regex.Matches($"{inCommand.EmailTopic}{inCommand.EmailTopicCN}")
|
||||
.Any(t => t.Value.Contains(" ")))
|
||||
{
|
||||
//邮件模板占位符不允许有空格,请核查占位符的地方
|
||||
return ResponseOutput.NotOk(I18n.T("EmailNoticeConfig_ContainEmpty"));
|
||||
}
|
||||
}
|
||||
|
||||
var list = _emailNoticeConfigrepository.Where(t => findIdList.Contains(t.Id), true).ToList();
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
var exist = inCommandList.FirstOrDefault(t => t.Id == item.Id);
|
||||
if (exist != null)
|
||||
{
|
||||
item.EmailTopic = exist.EmailTopic;
|
||||
item.EmailTopicCN = exist.EmailTopicCN;
|
||||
}
|
||||
}
|
||||
|
||||
await _emailNoticeConfigrepository.SaveChangesAsync();
|
||||
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
public async Task<IResponseOutput> AddOrUpdateEmailNoticeConfig(EmailNoticeConfigAddOrEdit addOrEditEmailNoticeConfig)
|
||||
{
|
||||
//var verifyExp1 = new EntityVerifyExp<EmailNoticeConfig>()
|
||||
//{
|
||||
// VerifyExp = t => t.BusinessScenarioEnum == addOrEditEmailNoticeConfig.BusinessScenarioEnum && t.CriterionTypeEnum == addOrEditEmailNoticeConfig.CriterionTypeEnum,
|
||||
|
||||
// VerifyMsg = _localizer["EmailNoticeConfig_RepeatEmailScenario"]
|
||||
|
||||
//};
|
||||
|
||||
var criterionList = _emailNoticeConfigrepository.Where(t => t.BusinessScenarioEnum == addOrEditEmailNoticeConfig.BusinessScenarioEnum && t.IsEnable == true)
|
||||
.Where(t => t.CriterionTypeList != null)
|
||||
.WhereIf(addOrEditEmailNoticeConfig.Id != null, t => t.Id != addOrEditEmailNoticeConfig.Id)
|
||||
.Select(t => t.CriterionTypeList).ToList();//不能使用selectMany 会当成关联对象,不能当成字符串
|
||||
|
||||
|
||||
if (addOrEditEmailNoticeConfig.CriterionTypeList != null)
|
||||
var verifyExp1 = new EntityVerifyExp<EmailNoticeConfig>()
|
||||
{
|
||||
foreach (var item in addOrEditEmailNoticeConfig.CriterionTypeList)
|
||||
{
|
||||
foreach (var itemList in criterionList)
|
||||
{
|
||||
if (itemList.Any(t => t == item))
|
||||
{
|
||||
return ResponseOutput.NotOk(_localizer["EmailNoticeConfig_RepeatEmailScenario"]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
VerifyExp = t => t.BusinessScenarioEnum == addOrEditEmailNoticeConfig.BusinessScenarioEnum && t.CriterionTypeEnum == addOrEditEmailNoticeConfig.CriterionTypeEnum,
|
||||
|
||||
VerifyMsg = _localizer["EmailNoticeConfig_RepeatEmailScenario"]
|
||||
|
||||
};
|
||||
|
||||
var verifyExp2 = new EntityVerifyExp<EmailNoticeConfig>()
|
||||
{
|
||||
|
@ -155,7 +94,7 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
}
|
||||
|
||||
|
||||
await _emailNoticeConfigrepository.AddAsync(entity, true, verifyExp2);
|
||||
await _emailNoticeConfigrepository.AddAsync(entity, true, verifyExp1, verifyExp2);
|
||||
|
||||
|
||||
}
|
||||
|
@ -178,7 +117,7 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
}
|
||||
|
||||
|
||||
entity = await _emailNoticeConfigrepository.UpdateFromDTOAsync(addOrEditEmailNoticeConfig, true, false, verifyExp2);
|
||||
entity = await _emailNoticeConfigrepository.UpdateFromDTOAsync(addOrEditEmailNoticeConfig, true, false, verifyExp1, verifyExp2);
|
||||
|
||||
|
||||
|
||||
|
@ -186,16 +125,16 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
}
|
||||
|
||||
|
||||
if (addOrEditEmailNoticeConfig.EmailCron != string.Empty)
|
||||
if (entity.EmailCron != string.Empty)
|
||||
{
|
||||
var jobId = $"{entity.Id}_({addOrEditEmailNoticeConfig.BusinessScenarioEnum})";
|
||||
|
||||
HangfireJobHelper.RemoveCronJob(jobId);
|
||||
var jobId = $"{entity.Id}_({entity.BusinessScenarioEnum})";
|
||||
|
||||
//有的job 可能编辑控制直接不发,需要移除已存在的
|
||||
HangfireJobHelper.RemoveCronJob(jobId);
|
||||
|
||||
if (entity.IsAutoSend && entity.IsEnable)
|
||||
{
|
||||
HangfireJobHelper.AddOrUpdateTimingCronJob(jobId, addOrEditEmailNoticeConfig.BusinessScenarioEnum, addOrEditEmailNoticeConfig.EmailCron);
|
||||
HangfireJobHelper.AddOrUpdateSystemCronJob(jobId, entity.BusinessScenarioEnum, entity.EmailCron);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
IRepository<DicomStudy> _dicomStudyRepository,
|
||||
IRepository<QCChallenge> _qcChallengeRepository,
|
||||
IRepository<ReadModule> _readModuleRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
IRepository<NoneDicomStudy> _noneDicomStudyRepository,
|
||||
IRepository<StudyMonitor> _studyMonitorRepository,
|
||||
IRepository<CommonDocument> _commonDocumentRepository,
|
||||
|
@ -48,228 +47,8 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IWebHostEnvironment _hostEnvironment) : BaseService
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 质控问题答案导出
|
||||
/// </summary>
|
||||
/// <param name="trialId"></param>
|
||||
/// <param name="_trialQCQuestionAnswerRepository"></param>
|
||||
/// <param name="_trialRepository"></param>
|
||||
/// <param name="_dictionaryService"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> GetTrialQCQuestionAnserList_Export(GetQCQuestionAnswerQuery inQuery,
|
||||
[FromServices] IRepository<TrialQCQuestionAnswer> _trialQCQuestionAnswerRepository,
|
||||
[FromServices] IRepository<Trial> _trialRepository,
|
||||
[FromServices] IRepository<UserRole> _userRoleRepository,
|
||||
[FromServices] IRepository<TrialQCQuestion> _trialQCQuestionRepository,
|
||||
[FromServices] IDictionaryService _dictionaryService)
|
||||
{
|
||||
//var query = from sv in _subjectVisitRepository.Where(t => t.TrialId == trialId && t.AuditState == AuditStateEnum.QCPassed)
|
||||
|
||||
// join u in _userRoleRepository.AsQueryable() on sv.UpdateUserId equals u.Id
|
||||
// select new QCQuestionReusult_export()
|
||||
// {
|
||||
// TrialSiteCode = sv.TrialSite.TrialSiteCode,
|
||||
// SubjectCode = sv.Subject.Code,
|
||||
// VisitName = sv.VisitName,
|
||||
// SubjectVisitId = sv.Id,
|
||||
|
||||
// CurrentQCEnum = qa.CurrentQCEnum,
|
||||
// AuditTime = qa.UpdateTime,
|
||||
// SecondReviewTime = qa.SecondReviewTime,
|
||||
// AuditUserName = u.UserName,
|
||||
// AuditUserFullName = u.FullName,
|
||||
// QuesitonName = qa.TrialQCQuestionConfigure.QuestionName,
|
||||
|
||||
// ShowOrder = qa.TrialQCQuestionConfigure.ShowOrder,
|
||||
// Answer = qa.Answer
|
||||
|
||||
// }
|
||||
|
||||
var trialId = inQuery.TrialId;
|
||||
|
||||
var query = from qa in _trialQCQuestionAnswerRepository.Where(t => t.TrialId == trialId && t.SubjectVisit.IsDeleted == false &&
|
||||
((t.SubjectVisit.AuditState >= AuditStateEnum.PrimaryQCPassed && t.SecondReviewTime == null) ||
|
||||
(t.SubjectVisit.SecondReviewState == SecondReviewState.AuditPassed && t.SecondReviewTime <= t.SubjectVisit.Trial.QCQuestionConfirmedTime) ||
|
||||
(t.SubjectVisit.SecondReviewState == SecondReviewState.WaitAudit && t.SecondReviewTime < t.SubjectVisit.Trial.QCQuestionConfirmedTime)))
|
||||
join u in _userRoleRepository.AsQueryable() on qa.UpdateUserId equals u.Id
|
||||
select new QCQuestionAnswerResult_export()
|
||||
{
|
||||
SubjectVisitId = qa.SubjectVisitId,
|
||||
SecondReviewTime = qa.SecondReviewTime,
|
||||
|
||||
VisitNum = qa.SubjectVisit.VisitNum,
|
||||
|
||||
TrialSiteCode = qa.SubjectVisit.TrialSite.TrialSiteCode,
|
||||
SubjectCode = qa.SubjectVisit.Subject.Code,
|
||||
VisitName = qa.SubjectVisit.VisitName,
|
||||
CurrentQCEnum = qa.CurrentQCEnum,
|
||||
|
||||
AuditTime = qa.CurrentQCEnum == CurrentQC.First ? qa.SubjectVisit.PreliminaryAuditTime : (qa.CurrentQCEnum == CurrentQC.Second ? qa.SubjectVisit.ReviewAuditTime : qa.UpdateTime),
|
||||
AuditUserName = qa.CurrentQCEnum == CurrentQC.First ? qa.SubjectVisit.PreliminaryAuditUser.UserName : (qa.CurrentQCEnum == CurrentQC.Second ? qa.SubjectVisit.ReviewAuditUser.UserName : u.UserName),
|
||||
AuditUserFullName = qa.CurrentQCEnum == CurrentQC.First ? qa.SubjectVisit.PreliminaryAuditUser.FullName : (qa.CurrentQCEnum == CurrentQC.Second ? qa.SubjectVisit.ReviewAuditUser.FullName : u.FullName),
|
||||
|
||||
QuestionId = qa.TrialQCQuestionConfigure.Id,
|
||||
QuesitonName = qa.TrialQCQuestionConfigure.QuestionName,
|
||||
ShowOrder = qa.TrialQCQuestionConfigure.ShowOrder,
|
||||
Answer = qa.Answer,
|
||||
|
||||
|
||||
};
|
||||
|
||||
var result = query.OrderBy(t => t.TrialSiteCode).ThenBy(t => t.SubjectCode).ThenBy(t => t.VisitNum).ToList();
|
||||
|
||||
var list = result.Where(t => t.AuditTime != null).GroupBy(t => new { t.SubjectVisitId, t.SecondReviewTime, t.TrialSiteCode, t.VisitNum, t.SubjectCode, t.VisitName, t.CurrentQCEnum })
|
||||
.Select(g => new QCQuestionResult_Export()
|
||||
{
|
||||
TrialSiteCode = g.Key.TrialSiteCode,
|
||||
SubjectCode = g.Key.SubjectCode,
|
||||
VisitName = g.Key.VisitName,
|
||||
CurrentQCEnum = g.Key.CurrentQCEnum,
|
||||
VisitNum = g.Key.VisitNum,
|
||||
|
||||
AuditTime = g.Select(t => t.AuditTime).First(),
|
||||
AuditUserName = g.Select(t => t.AuditUserName).First(),
|
||||
AuditUserFullName = g.Select(t => t.AuditUserFullName).First(),
|
||||
|
||||
QuestionAnswerList = g.Select(t => new QCQuestionAnswerExport() { Answer = t.Answer, QuestionName = t.QuesitonName, ShowOrder = t.ShowOrder, QuestionId = t.QuestionId }).OrderBy(t => t.ShowOrder).ToList()
|
||||
|
||||
|
||||
}).OrderBy(t => t.TrialSiteCode).ThenBy(t => t.SubjectCode).ThenBy(t => t.VisitNum).ThenBy(t=>t.CurrentQCEnum).ThenBy(t=>t.AuditTime).ToList();
|
||||
|
||||
|
||||
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo<ExcelExportInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
|
||||
|
||||
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
|
||||
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
|
||||
|
||||
|
||||
var columNameList = _trialQCQuestionRepository.Where(t => t.TrialId == trialId).OrderBy(t => t.ShowOrder).Select(t => new { t.QuestionName, t.Id }).ToList();
|
||||
|
||||
|
||||
var dynamicColumnConfig = new DynamicColumnConfig()
|
||||
{
|
||||
AutoColumnTitleRowIndex = 2,
|
||||
AutoColumnStartIndex = 7,
|
||||
TempalteLastColumnIndex = 6,
|
||||
DynamicItemDicName = "TranslateDicName",
|
||||
DynamicItemValueName = "Answer",
|
||||
DynamicItemTitleName = "QuestionName",
|
||||
DynamicListName = "QuestionAnswerList",
|
||||
DynamicItemTitleId = "QuestionId",
|
||||
RemoveColunmIndexList = new List<int>() { },
|
||||
ColumnIdNameList = columNameList.Select(t => new DynamicColumnConfig.ColumItem() { Id = t.Id, Name = t.QuestionName }).ToList(),
|
||||
TranslateDicNameList = new List<string>()
|
||||
};
|
||||
|
||||
|
||||
var (memoryStream, fileName) = await ExcelExportHelper.DataExport_NpoiTestAsync(StaticData.Export.TrialQCResult_Export, exportInfo, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(QCQuestionResult_Export), dynamicColumnConfig: dynamicColumnConfig);
|
||||
|
||||
return new FileStreamResult(memoryStream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
{
|
||||
FileDownloadName = $"{exportInfo.ResearchProgramNo}_{exportInfo.CriterionName}_{fileName}_{DateTime.Now.ToString("yyyyMMddHHmmss")}.xlsx"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 医学审核问题导表
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <param name="_readingMedicineSystemQuestionRepository"></param>
|
||||
/// <param name="_dictionaryService"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> GetReadingMedicineSystemQuestionList_Export(ReadingMedicineSystemQuestionQuery inDto,
|
||||
[FromServices] IRepository<ReadingMedicineSystemQuestion> _readingMedicineSystemQuestionRepository,
|
||||
[FromServices] IDictionaryService _dictionaryService)
|
||||
{
|
||||
//避免前端遍历
|
||||
var criterionEnum = inDto.TrialReadingCriterionId != null ? _readingQuestionCriterionTrialRepository.Where(t => t.Id == inDto.TrialReadingCriterionId).Select(t => t.CriterionType).FirstOrDefault() : CriterionType.NoCriterion;
|
||||
|
||||
var query = _readingMedicineSystemQuestionRepository.AsQueryable()
|
||||
.WhereIf(!inDto.TypeValue.IsNullOrEmpty(), x => x.TypeValue.Contains(inDto.TypeValue))
|
||||
.WhereIf(!inDto.ParentTriggerValue.IsNullOrEmpty(), x => x.ParentTriggerValue.Contains(inDto.ParentTriggerValue))
|
||||
.WhereIf(!inDto.QuestionName.IsNullOrEmpty(), x => x.QuestionName.Contains(inDto.QuestionName))
|
||||
.WhereIf(!inDto.Type.IsNullOrEmpty(), x => x.Type.Contains(inDto.Type))
|
||||
.WhereIf(inDto.ReadingCategory != null, x => x.ReadingCategory == inDto.ReadingCategory)
|
||||
.WhereIf(inDto.CurrentCriterionType != null, x => x.CriterionTypeEnum == null || x.CriterionTypeEnum == inDto.CurrentCriterionType)
|
||||
.WhereIf(inDto.CriterionTypeEnum != null, x => x.CriterionTypeEnum == inDto.CriterionTypeEnum)
|
||||
.WhereIf(inDto.TrialReadingCriterionId != null, x => x.CriterionTypeEnum == criterionEnum || x.IsGeneral == true)
|
||||
.WhereIf(inDto.IsGeneral != null, x => x.IsGeneral == inDto.IsGeneral)
|
||||
.WhereIf(inDto.LanguageType != null, x => x.LanguageType == inDto.LanguageType!.Value)
|
||||
.ProjectTo<ReadingMedicineSystemQuestionView>(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder);
|
||||
|
||||
var defalutSortArray = new string[] { nameof(ReadingMedicineSystemQuestionView.LanguageType) + " desc", nameof(ReadingMedicineSystemQuestionView.ShowOrder) };
|
||||
|
||||
|
||||
var list = await query.SortToListAsync(inDto);
|
||||
|
||||
var exportInfo = new ExcelExportInfo();
|
||||
|
||||
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
|
||||
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
|
||||
|
||||
return await ExcelExportHelper.DataExportAsync(StaticData.Export.SystenMedicalQCQuestionsList_Export, exportInfo, exportInfo.TrialCode, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(ReadingMedicineSystemQuestionView));
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 访视影像统计
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <param name="_subjectVisitRepository"></param>
|
||||
/// <param name="_trialRepository"></param>
|
||||
/// <param name="_dictionaryService"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> GetTrialVisitImageStatList_Export(TrialVisitImageQuery inQuery,
|
||||
[FromServices] IRepository<SubjectVisit> _subjectVisitRepository,
|
||||
[FromServices] IRepository<Trial> _trialRepository,
|
||||
[FromServices] IDictionaryService _dictionaryService)
|
||||
{
|
||||
var query = _subjectVisitRepository.Where(t => t.TrialId == inQuery.TrialId)
|
||||
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
|
||||
.WhereIf(inQuery.SubjectCode.IsNotNullOrEmpty(), t => t.Subject.Code.Contains(inQuery.SubjectCode))
|
||||
.WhereIf(inQuery.BeginScanDate != null, t => t.LatestScanDate >= inQuery.BeginScanDate)
|
||||
.WhereIf(inQuery.EndScanDate != null, t => t.LatestScanDate == inQuery.EndScanDate)
|
||||
.Select(t => new TrialVisitImageStatView()
|
||||
{
|
||||
TrialId = t.TrialId,
|
||||
SubjectVisitId = t.Id,
|
||||
SubjectCode = t.Subject.Code,
|
||||
TrialSiteCode = t.TrialSite.TrialSiteCode,
|
||||
TrialSiteId = t.TrialSiteId,
|
||||
VisitName = t.VisitName,
|
||||
VisitNum = t.VisitNum,
|
||||
EarliestScanDate = t.EarliestScanDate,
|
||||
LatestScanDate = t.LatestScanDate,
|
||||
|
||||
IsHaveDicom = t.StudyList.Any(),
|
||||
|
||||
IsHaveNoneDicom = t.NoneDicomStudyList.Any(),
|
||||
|
||||
|
||||
TotalStudyCount = t.StudyList.Count() + t.NoneDicomStudyList.Count(),
|
||||
|
||||
TotalImageCount = t.StudyList.Sum(t => t.InstanceCount) + t.NoneDicomStudyList.Sum(t => t.FileCount),
|
||||
|
||||
TotalImageSize = t.StudyList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize) + t.NoneDicomStudyList.SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize),
|
||||
|
||||
});
|
||||
|
||||
|
||||
var list = await query.Where(t => t.TotalImageCount > 0).SortToListAsync(inQuery);
|
||||
|
||||
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo<ExcelExportInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
|
||||
|
||||
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
|
||||
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
|
||||
|
||||
return await ExcelExportHelper.DataExportAsync(StaticData.Export.TriaVisitImageStat_Export, exportInfo, exportInfo.TrialCode, _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(TrialMaintenanceDTO));
|
||||
|
||||
}
|
||||
|
||||
#region 后续需要移动过来
|
||||
|
||||
|
||||
|
||||
|
@ -563,6 +342,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
@ -570,46 +350,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
|
||||
#region 导表查询
|
||||
|
||||
/// <summary>
|
||||
/// 重传申请导表
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <param name="_subjectVisitImageBackRecordReposiotry"></param>
|
||||
/// <param name="_dictionaryService"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> GetImageBackList_Export(ImageBackQueryDto inQuery,
|
||||
[FromServices] IRepository<SubjectVisitImageBackRecord> _subjectVisitImageBackRecordReposiotry, [FromServices] IDictionaryService _dictionaryService)
|
||||
{
|
||||
var svExpression = QCCommon.GetSubjectVisitImageBackRecordFilter(inQuery.VisitPlanArray);
|
||||
|
||||
var query = _subjectVisitImageBackRecordReposiotry.Where(t => t.SubjectVisit.TrialId == inQuery.TrialId)
|
||||
.WhereIf(inQuery.TrialSiteId != null, t => t.SubjectVisit.TrialSiteId == inQuery.TrialSiteId)
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => t.SubjectVisit.Subject.Code.Contains(inQuery.SubjectCode))
|
||||
.WhereIf(!string.IsNullOrEmpty(inQuery.VisitName), t => t.SubjectVisit.VisitName.Contains(inQuery.VisitName))
|
||||
.WhereIf(inQuery.VisitPlanArray != null && inQuery.VisitPlanArray?.Length > 0, svExpression)
|
||||
.WhereIf(inQuery.CreateUserId != null, t => t.CreateUserId == inQuery.CreateUserId)
|
||||
.WhereIf(inQuery.ApplyUserRole != null, t => t.ApplyUserRole == inQuery.ApplyUserRole)
|
||||
.WhereIf(inQuery.ApplyBeginTime != null, t => t.CreateTime >= inQuery.ApplyBeginTime)
|
||||
.WhereIf(inQuery.ApplyEndTime != null, t => t.CreateTime <= inQuery.ApplyEndTime)
|
||||
.WhereIf(inQuery.ImageBackState != null, t => t.ImageBackState == inQuery.ImageBackState)
|
||||
.WhereIf(inQuery.AuditBeginTime != null, t => t.AuditTime >= inQuery.AuditBeginTime)
|
||||
.WhereIf(inQuery.AuditEndTime != null, t => t.AuditTime <= inQuery.AuditEndTime)
|
||||
.ProjectTo<ImageBackViewModel>(_mapper.ConfigurationProvider);
|
||||
|
||||
var defalutSortArray = new string[] { nameof(ImageBackViewModel.IsUrgent) + " desc", nameof(ImageBackViewModel.SubjectCode), nameof(ImageBackViewModel.VisitNum) };
|
||||
|
||||
var list = await query.OrderByDescending(t => t.IsUrgent).ThenBy(t => t.SubjectCode).ThenBy(t => t.VisitNum).ToListAsync();
|
||||
|
||||
var exportInfo = (await _trialRepository.Where(t => t.Id == inQuery.TrialId).IgnoreQueryFilters().ProjectTo<ExcelExportInfo>(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException();
|
||||
|
||||
exportInfo.List = ExportExcelConverterDate.ConvertToClientTimeInObject(list, _userInfo.TimeZoneId);
|
||||
exportInfo.CurrentTime = ExportExcelConverterDate.DateTimeInternationalToString(DateTime.Now, _userInfo.TimeZoneId);
|
||||
|
||||
return await ExcelExportHelper.DataExportAsync(StaticData.Export.TrialImageBackRecordList_Export, exportInfo, $"{exportInfo.ResearchProgramNo}", _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(ImageBackViewModel));
|
||||
|
||||
}
|
||||
|
||||
///getSysDocumentConfirmList 系统文档培训查询
|
||||
///
|
||||
[HttpPost]
|
||||
|
@ -976,8 +716,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
var svExpression = QCCommon.GetSubjectVisitFilter(inQuery.VisitPlanArray);
|
||||
|
||||
var query = _subjectVisitRepository.Where(x => x.TrialId == inQuery.TrialId)
|
||||
.Where(t => t.Subject.IsSubjectQuit == false || t.SubmitState >= SubmitStateEnum.ToSubmit)
|
||||
|
||||
.Where(t => t.Subject.FinalSubjectVisitId != null ? t.VisitNum <= t.Subject.FinalSubjectVisit.VisitNum : true)
|
||||
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
|
||||
.WhereIf(inQuery.SubjectId != null, t => t.Subject.Id == inQuery.SubjectId)
|
||||
|
@ -1025,9 +763,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
{
|
||||
var svExpression = QCCommon.GetSubjectVisitFilter(inQuery.VisitPlanArray);
|
||||
var query = _subjectVisitRepository.Where(x => x.TrialId == inQuery.TrialId)
|
||||
|
||||
.Where(t => t.Subject.IsSubjectQuit == false || t.AuditState > AuditStateEnum.ToAudit)
|
||||
|
||||
.WhereIf(inQuery.VisitId != null, t => t.Id == inQuery.VisitId)
|
||||
.WhereIf(inQuery.CurrentActionUserId != null, t => t.CurrentActionUserId == inQuery.CurrentActionUserId)
|
||||
.WhereIf(inQuery.ChallengeState != null, t => t.ChallengeState == inQuery.ChallengeState)
|
||||
|
@ -1438,9 +1173,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
var svExpression = QCCommon.GetDicomStudySubjectVisitFilter(studyQuery.VisitPlanArray);
|
||||
|
||||
var dicomStudyQuery = _dicomStudyRepository.Where(t => t.TrialId == studyQuery.TrialId)
|
||||
|
||||
.Where(t => t.Subject.IsSubjectQuit == false || t.SubjectVisit.CheckState >= CheckStateEnum.CVIng)
|
||||
|
||||
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.Subject.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.UserRoleId))
|
||||
.WhereIf(studyQuery.VisitPlanArray != null && studyQuery.VisitPlanArray?.Length > 0, svExpression)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo))
|
||||
|
@ -1463,17 +1195,12 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
//Uploader = t.Uploader.UserName,
|
||||
//UploadTime = t.CreateTime
|
||||
|
||||
SubjectStatus = t.Subject.Status
|
||||
|
||||
});
|
||||
|
||||
var svExpression2 = QCCommon.GetNoneDicomStudySubjectVisitFilter(studyQuery.VisitPlanArray);
|
||||
|
||||
|
||||
var nodeDicomStudyQuery = _noneDicomStudyRepository.Where(t => t.TrialId == studyQuery.TrialId)
|
||||
|
||||
.Where(t => t.Subject.IsSubjectQuit == false || t.SubjectVisit.CheckState >= CheckStateEnum.CVIng)
|
||||
|
||||
.WhereIf(_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.CRA, t => t.Subject.TrialSite.CRCUserList.Any(t => t.UserId == _userInfo.UserRoleId))
|
||||
.WhereIf(studyQuery.VisitPlanArray != null && studyQuery.VisitPlanArray?.Length > 0, svExpression2)
|
||||
.WhereIf(!string.IsNullOrWhiteSpace(studyQuery.SubjectInfo), t => t.Subject.Code.Contains(studyQuery.SubjectInfo))
|
||||
|
@ -1497,7 +1224,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
|
||||
//Uploader = t.CreateUser.UserName,
|
||||
//UploadTime = t.CreateTime
|
||||
SubjectStatus = t.Subject.Status
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
@ -1537,9 +1264,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
var svExpression = QCCommon.GetSubjectVisitFilter(inQuery.VisitPlanArray);
|
||||
|
||||
var query = _subjectVisitRepository.Where(x => x.TrialId == inQuery.TrialId)
|
||||
|
||||
.Where(t => t.Subject.IsSubjectQuit == false || t.CheckState >= CheckStateEnum.CVIng)
|
||||
|
||||
.Where(x => x.AuditState == AuditStateEnum.QCPassed) //一致性核查中的,或者还没一致性核查的
|
||||
.WhereIf(inQuery.CheckState != null, t => t.CheckState == inQuery.CheckState)
|
||||
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
|
||||
|
@ -1580,8 +1304,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
var list = await _visitTaskRepository.Where(t => t.TrialId == inQuery.TrialId && t.IsAnalysisCreate == false)
|
||||
//.Where(t => t.IsAnalysisCreate == false && t.DoctorUserId != null)
|
||||
|
||||
.Where(t => t.Subject.IsSubjectQuit == false || t.ReadingTaskState >= ReadingTaskState.Reading)
|
||||
|
||||
.WhereIf(inQuery.IsEffect == true, t => t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze)
|
||||
.WhereIf(inQuery.IsEffect == false, t => t.TaskState == TaskState.Adbandon || t.TaskState == TaskState.HaveReturned)
|
||||
|
||||
|
@ -1964,7 +1686,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
//.WhereIf(inQuery.SystemLevel == null, t => t.SystemLevel == SysEmailLevel.not_sys)
|
||||
.WhereIf(inQuery.SystemLevel != null, t => t.SystemLevel == inQuery.SystemLevel)
|
||||
.WhereIf(inQuery.IsDistinguishCriteria != null, t => t.IsDistinguishCriteria == inQuery.IsDistinguishCriteria)
|
||||
.WhereIf(inQuery.CriterionTypeEnum != null, t => t.CriterionTypeList.Any(c => c == inQuery.CriterionTypeEnum))
|
||||
.WhereIf(inQuery.CriterionTypeEnum != null, t => t.CriterionTypeEnum == inQuery.CriterionTypeEnum)
|
||||
.WhereIf(inQuery.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == inQuery.BusinessScenarioEnum)
|
||||
.WhereIf(inQuery.IsReturnRequired != null, t => t.IsReturnRequired == inQuery.IsReturnRequired)
|
||||
.WhereIf(inQuery.IsEnable != null, t => t.IsEnable == inQuery.IsEnable)
|
||||
|
@ -1981,7 +1703,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
return await ExcelExportHelper.DataExportAsync(StaticData.Export.EmailNoticeConfig_Export, exportInfo, $"{exportInfo.ResearchProgramNo}", _commonDocumentRepository, _hostEnvironment, _dictionaryService, typeof(EmailNoticeConfigExportDto));
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region 导表公用
|
||||
|
||||
|
@ -2105,7 +1827,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
{
|
||||
|
||||
//两个人都做了
|
||||
if (resultExceptJudgeList.Where(t => t.VisitTaskNum == item.VisitTaskNum && t.SubjectCode == item.SubjectCode).Select(t => t.ArmEnum).Distinct().Count() == 2)
|
||||
if (resultExceptJudgeList.Count(t => t.VisitTaskNum == item.VisitTaskNum && t.SubjectCode == item.SubjectCode) == 2)
|
||||
{
|
||||
//如果没有产生裁判,默认选择R1
|
||||
if (item.ArmEnum == Arm.DoubleReadingArm1)
|
||||
|
@ -2160,7 +1882,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
//已完成的全局数量
|
||||
finishedGlobalCount = resultExceptJudgeList.Where(t => t.SubjectCode == visitItem.SubjectCode && subjectReadingPeriondVisitNumList.Any(c => (c + addReadingPeriodNum) == t.VisitTaskNum)
|
||||
/*&& t.ReadingCategory == ReadingCategory.Global*/)
|
||||
.Select(t => new { t.VisitTaskNum, t.ArmEnum }).Distinct()
|
||||
.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).Count();
|
||||
}
|
||||
|
||||
|
@ -2174,7 +1895,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
|
||||
var subjectMaxFinishedGlobalTaskNum = resultExceptJudgeList.Where(t => t.SubjectCode == visitItem.SubjectCode && subjectReadingPeriondVisitNumList.Any(c => (c + addReadingPeriodNum) == t.VisitTaskNum)
|
||||
/*&& t.ReadingCategory == ReadingCategory.Global*/)
|
||||
.Select(t => new { t.VisitTaskNum, t.ArmEnum }).Distinct()
|
||||
.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).DefaultIfEmpty().Max();
|
||||
|
||||
//最大的完成的全局是否产生裁判
|
||||
|
@ -2307,7 +2027,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
#endregion
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region 通用阅片结果导出
|
||||
|
||||
|
@ -2429,24 +2149,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
else if (criterion.CriterionType == CriterionType.PCWG3)
|
||||
{
|
||||
|
||||
}
|
||||
else if (criterion.CriterionType == CriterionType.SelfDefine)
|
||||
{
|
||||
//自定义的又问题名称重复 所以统一加上组名
|
||||
|
||||
//有重复的就加,没有重复的就不加
|
||||
if (list.Any(t => t.QuestionAnswerList.Select(t => t.QuestionName).Count() != t.QuestionAnswerList.Select(t => t.QuestionName).Distinct().Count()))
|
||||
{
|
||||
foreach (var item in list)
|
||||
{
|
||||
foreach (var qs in item.QuestionAnswerList)
|
||||
{
|
||||
qs.QuestionName = qs.Group + "_" + qs.QuestionName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
@ -2803,10 +2505,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
// CDISC 导出 只管到 外层问题层级 和阅片结果表是保持一致
|
||||
else if (inQuery.ReadingExportType == ExportResult.CDISC)
|
||||
{
|
||||
|
||||
if (criterion.CriterionGroup == CriterionGroup.Tumor)
|
||||
{
|
||||
|
||||
list = await query.ProjectTo<CommonEvaluationExport>(_mapper.ConfigurationProvider,
|
||||
new
|
||||
{
|
||||
|
@ -2816,19 +2514,6 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
trialReadingCriterionId = inQuery.TrialReadingCriterionId,
|
||||
isEn_Us = _userInfo.IsEn_Us
|
||||
}).ToListAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
taskList = await query.ProjectTo<CommonLessionExport>(_mapper.ConfigurationProvider,
|
||||
new
|
||||
{
|
||||
readingExportType = inQuery.ReadingExportType,
|
||||
criterionType = criterion.CriterionType,
|
||||
arbitrationRule = criterion.ArbitrationRule,
|
||||
trialReadingCriterionId = inQuery.TrialReadingCriterionId,
|
||||
isEn_Us = _userInfo.IsEn_Us
|
||||
}).ToListAsync();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -3101,7 +2786,7 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
//多表格,增加的一列,就用Guid.Empty 标识
|
||||
var extralNameList = new List<DynamicColumnConfig.ColumItem>() { new DynamicColumnConfig.ColumItem() { Id = Guid.Empty, Name = _userInfo.IsEn_Us ? "Table Name" : "表格名称" } };
|
||||
|
||||
var tableQuestionNameList = trialConfigTableQuestionList.OrderBy(t => t.TableName).Select(t => new DynamicColumnConfig.ColumItem() { Id = t.QuestionId, Name = t.TableName + "_" + t.QuestionName }).ToList();
|
||||
var tableQuestionNameList = trialConfigTableQuestionList.Select(t => new DynamicColumnConfig.ColumItem() { Id = t.QuestionId, Name = t.TableName + "_" + t.QuestionName }).ToList();
|
||||
|
||||
configCoumNameList = fistLeveLNameList.Union(extralNameList).Union(tableQuestionNameList).ToList();
|
||||
}
|
||||
|
@ -3191,214 +2876,27 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
DynamicListName = "QuestionAnswerList",
|
||||
RemoveColunmIndexList = removeColumnIndexList,
|
||||
ColumnIdNameList = configCoumNameList,
|
||||
//CDISCList = new List<string>(),
|
||||
CDISCList = new List<string>(),
|
||||
TranslateDicNameList = translateDicNameList
|
||||
};
|
||||
|
||||
if (export_Template == StaticData.Export.ReadingLession_Export || export_Template == StaticData.Export.CommonJudgeReadingDetail_Export)
|
||||
{
|
||||
dynamicColumnConfig.TempalteLastColumnIndex = 8;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
|
||||
if (criterion.CriterionGroup == CriterionGroup.Nontumorous)
|
||||
{
|
||||
//最终EXCEL 列
|
||||
var configCoumNameList = new List<DynamicColumnConfig.ColumItem>();
|
||||
|
||||
//表格全问题名
|
||||
var trialConfigTableQuestionList = _trialReadingTableQuestionRepository.Where(t => t.TrialId == trialId && t.TrialCriterionId == trialReadingCriterionId).Where(t => t.ExportResultStr.Contains(((int)inQuery.ReadingExportType).ToString()))
|
||||
.Select(t => new ExportQuestionBasicInfo()
|
||||
{
|
||||
QuestionId = t.Id,
|
||||
TableName = _userInfo.IsEn_Us ? t.ReadingQuestionTrial.QuestionEnName : t.ReadingQuestionTrial.QuestionName,
|
||||
QuestionName = _userInfo.IsEn_Us ? t.QuestionEnName : t.QuestionName,
|
||||
CDISCCode = t.CDISCCode,
|
||||
TranslateDicName = t.DictionaryCode,
|
||||
ShowOrder = t.ShowOrder
|
||||
}).OrderBy(t => t.TableName).ThenBy(t => t.ShowOrder).ToList();
|
||||
|
||||
var isMutiTable = trialConfigTableQuestionList.Select(t => t.TableName).Distinct().Count() > 1;
|
||||
|
||||
|
||||
//外层问题处理
|
||||
var fistLeveLNameList = trialConfigQuestionList.Select(t => new DynamicColumnConfig.ColumItem()
|
||||
{
|
||||
Id = t.QuestionId,
|
||||
Name = t.QuestionName,
|
||||
CDISCCode = t.CDISCCode
|
||||
}).ToList();
|
||||
|
||||
var translateDicNameList = trialConfigQuestionList.Union(trialConfigTableQuestionList).Where(t => t.TranslateDicName.IsNotNullOrEmpty()).Select(t => t.TranslateDicName).Distinct().ToList();
|
||||
|
||||
//单表格问题(直接用表格问题名称) 或者没有表格问题
|
||||
if (isMutiTable == false)
|
||||
{
|
||||
//一个表格,或者没有表格
|
||||
var tableNameList = trialConfigTableQuestionList.Select(t => new DynamicColumnConfig.ColumItem() { Id = t.QuestionId, Name = t.QuestionName, CDISCCode = t.CDISCCode }).ToList();
|
||||
|
||||
configCoumNameList = fistLeveLNameList.Union(tableNameList).ToList();
|
||||
|
||||
//最终的病灶列表 要把裁判的也要加进去,需要处理裁判标记
|
||||
foreach (var item in taskList.OrderBy(t => t.SubjectCode).ThenBy(t => t.ArmEnum).ThenBy(t => t.VisitTaskNum))
|
||||
{
|
||||
//有病灶,并且至少配置了一个病灶问题
|
||||
if (item.LesionList.Count > 0 && item.LesionList.SelectMany(t => t.LessionAnswerList).Any())
|
||||
{
|
||||
foreach (var lession in item.LesionList.OrderBy(t => t.LessionType).ThenBy(t => t.LessionCode))
|
||||
{
|
||||
//病灶配置了问题 才进行导出
|
||||
if (lession.LessionAnswerList.Count > 0)
|
||||
{
|
||||
|
||||
var dynamicLessionInfoList = new List<CommonQuesionInfo>();
|
||||
|
||||
|
||||
var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId = t.TableQuesionId, QuestionName = t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode });
|
||||
|
||||
//两部分组成 外层问题+ 动态的表格问题
|
||||
dynamicLessionInfoList = item.QuestionAnswerList.Union(dynamicPartialLessionInfoList).ToList();
|
||||
|
||||
var cloneItem = item.Clone();
|
||||
cloneItem.QuestionAnswerList = dynamicLessionInfoList;
|
||||
list.Add(cloneItem);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//要把裁判任务加进去 裁判任务上没有病灶
|
||||
|
||||
list.Add(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dynamicColumnConfig = new DynamicColumnConfig()
|
||||
{
|
||||
AutoColumnTitleRowIndex = 1,
|
||||
AutoColumnStartIndex = 6,
|
||||
TempalteLastColumnIndex = 10,
|
||||
DynamicItemDicName = "TranslateDicName",
|
||||
DynamicItemValueName = "QuestionValue",
|
||||
DynamicItemTitleName = "QuestionName",
|
||||
DynamicItemTitleId = "QuestionId",
|
||||
DynamicListName = "QuestionAnswerList",
|
||||
RemoveColunmIndexList = removeColumnIndexList,
|
||||
ColumnIdNameList = configCoumNameList,
|
||||
IsCDISCExport = true,
|
||||
//CDISCList = cdiscCodeList,
|
||||
TranslateDicNameList = translateDicNameList
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
//多表格问题,需要用新的模板,并且用行的方式展示 (不是之前表格名称_表格子问题名的方式)
|
||||
|
||||
export_Template = StaticData.Export.CDISC_MutiTable_Reading_Export;
|
||||
|
||||
configCoumNameList = fistLeveLNameList.ToList();
|
||||
|
||||
var translateUnitList = await _dictionaryService.GetBasicDataSelect("ValueUnit");
|
||||
|
||||
|
||||
foreach (var item in taskList.OrderBy(t => t.SubjectCode).ThenBy(t => t.ArmEnum).ThenBy(t => t.VisitTaskNum))
|
||||
{
|
||||
//有病灶,并且至少配置了一个病灶问题
|
||||
if (item.LesionList.Count > 0 && item.LesionList.SelectMany(t => t.LessionAnswerList).Any())
|
||||
{
|
||||
foreach (var lession in item.LesionList.OrderBy(t => t.LessionType).ThenBy(t => t.LessionCode))
|
||||
{
|
||||
//病灶配置了问题 才进行导出
|
||||
if (lession.LessionAnswerList.Count > 0)
|
||||
{
|
||||
|
||||
//遍历病灶的每个问题
|
||||
foreach (var lessionItem in lession.LessionAnswerList.OrderBy(t => t.ShowOrder))
|
||||
{
|
||||
|
||||
var cloneItem = item.Clone();
|
||||
|
||||
|
||||
string unitText = lessionItem.Unit switch
|
||||
{
|
||||
ValueUnit.Custom => lessionItem.CustomUnit,
|
||||
null => "",
|
||||
_ => _userInfo.IsEn_Us ? translateUnitList.FirstOrDefault(t => t.Code == ((int)lessionItem.Unit).ToString())?.Value ?? ""
|
||||
: translateUnitList.FirstOrDefault(t => t.Code == ((int)lessionItem.Unit).ToString())?.ValueCN ?? ""
|
||||
};
|
||||
|
||||
|
||||
cloneItem.Group = lessionItem.TableName;
|
||||
cloneItem.TRLINKID = lessionItem.RowId.ToString();
|
||||
cloneItem.TRORRES = lessionItem.QuestionValue;
|
||||
cloneItem.TRTEST = lessionItem.CDISCCode;
|
||||
cloneItem.TRORRESU = unitText;
|
||||
|
||||
|
||||
list.Add(cloneItem);
|
||||
}
|
||||
|
||||
//var dynamicLessionInfoList = new List<CommonQuesionInfo>();
|
||||
|
||||
//var dynamicPartialLessionInfoList = lession.LessionAnswerList.Select(t => new CommonQuesionInfo() { QuestionId = t.TableQuesionId, QuestionName = t.QuestionName, QuestionValue = t.QuestionValue, TranslateDicName = t.TranslateDicName, CDISCCode = t.CDISCCode });
|
||||
|
||||
////两部分组成 外层问题+ 动态的表格问题
|
||||
//dynamicLessionInfoList = item.QuestionAnswerList.Union(dynamicPartialLessionInfoList).ToList();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//要把裁判任务加进去 裁判任务上没有病灶
|
||||
|
||||
list.Add(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dynamicColumnConfig = new DynamicColumnConfig()
|
||||
{
|
||||
AutoColumnTitleRowIndex = 1,
|
||||
AutoColumnStartIndex = 6,
|
||||
TempalteLastColumnIndex = 15,
|
||||
DynamicItemDicName = "TranslateDicName",
|
||||
DynamicItemValueName = "QuestionValue",
|
||||
DynamicItemTitleName = "QuestionName",
|
||||
DynamicItemTitleId = "QuestionId",
|
||||
DynamicListName = "QuestionAnswerList",
|
||||
RemoveColunmIndexList = removeColumnIndexList,
|
||||
ColumnIdNameList = configCoumNameList,
|
||||
IsCDISCExport = true,
|
||||
//CDISCList = cdiscCodeList,
|
||||
TranslateDicNameList = translateDicNameList
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//CDISC 导出 只到外层问题级别 使用Id 填充Excel
|
||||
|
||||
var totalConfigCoumNameList = trialConfigQuestionList.ToList();
|
||||
|
||||
var configCoumNameList = totalConfigCoumNameList.Select(t => new DynamicColumnConfig.ColumItem() { Id = t.QuestionId, Name = t.QuestionName, CDISCCode = t.CDISCCode }).ToList();
|
||||
var configCoumNameList = totalConfigCoumNameList.Select(t => new DynamicColumnConfig.ColumItem() { Id = t.QuestionId, Name = t.QuestionName }).ToList();
|
||||
|
||||
var translateDicList = totalConfigCoumNameList.Where(t => t.TranslateDicName.IsNotNullOrEmpty()).Select(t => t.TranslateDicName).Distinct().ToList();
|
||||
|
||||
var cdiscCodeList = totalConfigCoumNameList.Select(t => t.CDISCCode).ToList();
|
||||
|
||||
|
||||
dynamicColumnConfig = new DynamicColumnConfig()
|
||||
{
|
||||
AutoColumnTitleRowIndex = 1,
|
||||
|
@ -3411,16 +2909,9 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
DynamicListName = "QuestionAnswerList",
|
||||
RemoveColunmIndexList = removeColumnIndexList,
|
||||
ColumnIdNameList = configCoumNameList,
|
||||
IsCDISCExport = true,
|
||||
//CDISCList = cdiscCodeList,
|
||||
CDISCList = cdiscCodeList,
|
||||
TranslateDicNameList = translateDicList
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3803,7 +3294,5 @@ namespace IRaCIS.Core.Application.Service.Common
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,5 @@ namespace IRaCIS.Application.Interfaces
|
|||
|
||||
Task<Dictionary<string, List<BasicDicSelectCopy>>> GetBasicDataSelect(string[] searchArray);
|
||||
|
||||
Task<List<BasicDicSelect>> GetBasicDataSelect(string searchKey);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,41 +10,9 @@ using Microsoft.AspNetCore.Hosting;
|
|||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MimeKit;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
|
||||
public static class SafeMailHelper
|
||||
{
|
||||
public static async Task Run(Func<Task> func, [CallerMemberName] string caller = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
await func();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error($"【邮件失败 - {caller}】: {ex.Message}");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<T?> Run<T>(Func<Task<T>> func, [CallerMemberName] string caller = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
return await func();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error($"【邮件失败 - {caller}】: {ex.Message}");
|
||||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface IMailVerificationService
|
||||
{
|
||||
|
||||
|
@ -100,8 +68,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
if (configInfo == null)
|
||||
{
|
||||
Log.Logger.Error($"系统未找到当前场景:{scenario}邮件配置信息");
|
||||
|
||||
throw new BusinessValidationFailedException("系统未找到当前场景邮件配置信息,请联系运维人员核查");
|
||||
}
|
||||
|
||||
|
@ -115,7 +81,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Logger.Error($"邮件模板内容有误,填充内容出现问题,需要核查{scenario}场景邮件配置信息");
|
||||
|
||||
throw new BusinessValidationFailedException("邮件模板内容有误,填充内容出现问题,请联系运维人员核查");
|
||||
}
|
||||
|
@ -138,8 +103,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
if (configInfo == null)
|
||||
{
|
||||
Log.Logger.Error($"系统未找到当前场景:{scenario}邮件配置信息");
|
||||
|
||||
throw new BusinessValidationFailedException("系统未找到当前场景邮件配置信息,请联系运维人员核查");
|
||||
}
|
||||
|
||||
|
@ -262,10 +225,9 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
|
||||
|
||||
//中心调研 登陆 发送验证码
|
||||
//中心调研 登陆
|
||||
public async Task AnolymousSendEmail(string researchProgramNo, string emailAddress, int verificationCode)
|
||||
{
|
||||
//throw new BusinessValidationFailedException("模拟邮件取数据或者发送异常!!!");
|
||||
|
||||
var messageToSend = new MimeMessage();
|
||||
//发件地址
|
||||
|
@ -431,6 +393,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
}
|
||||
|
||||
|
||||
//不登录 通过邮箱重置密码
|
||||
public async Task AnolymousSendEmailForResetAccount(string emailAddress, int verificationCode)
|
||||
{
|
||||
|
|
|
@ -81,7 +81,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
public async Task<IResponseOutput<PublishLogView> > GetCurrentPublishInfo([FromServices] IOptionsMonitor<SystemEmailSendConfig> _sysEmialConfigOPtion)
|
||||
public async Task<PublishLogView> GetCurrentPublishInfo([FromServices] IOptionsMonitor<SystemEmailSendConfig> _sysEmialConfigOPtion)
|
||||
{
|
||||
var result = await _publishLogRepository.Where(t => t.IsCurrentVersion == true).ProjectTo<PublishLogView>(_mapper.ConfigurationProvider).FirstOrDefaultAsync();
|
||||
|
||||
|
@ -92,13 +92,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
|
||||
result.IsEnv_US = _sysEmialConfigOPtion.CurrentValue.IsEnv_US;
|
||||
|
||||
var emailConfig = _sysEmialConfigOPtion.CurrentValue;
|
||||
|
||||
var companyInfo = new SystemEmailSendConfigView() { CompanyName = emailConfig.CompanyName, CompanyNameCN = emailConfig.CompanyNameCN, CompanyShortName = emailConfig.CompanyShortName, CompanyShortNameCN = emailConfig.CompanyShortNameCN, SystemShortName = emailConfig.SystemShortName, EmailRegexStr = emailConfig.EmailRegexStr };
|
||||
|
||||
|
||||
return ResponseOutput.Ok(result, companyInfo) ;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,339 +0,0 @@
|
|||
using DocumentFormat.OpenXml.EMMA;
|
||||
using FellowOakDicom;
|
||||
using FellowOakDicom.Imaging;
|
||||
using FellowOakDicom.Imaging.Render;
|
||||
using FellowOakDicom.IO.Buffer;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using MassTransit;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SharpCompress.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using static IRaCIS.Core.Domain.Share.StaticData;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 项目影像后台下载,不打包
|
||||
/// </summary>
|
||||
/// <param name="_trialRepository"></param>
|
||||
/// <param name="_oSSService"></param>
|
||||
[ApiExplorerSettings(GroupName = "Common")]
|
||||
public class TrialImageDownloadService(IRepository<Trial> _trialRepository, IOSSService _oSSService, IWebHostEnvironment _hostEnvironment) : BaseService
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 后端api swagger 下载项目影像
|
||||
/// </summary>
|
||||
/// <param name="trialId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
public async Task<IResponseOutput> DownloadTrialImage(Guid trialId)
|
||||
{
|
||||
//var subjectCodeList = new List<string>() { "05002", "07006", "07026" };
|
||||
var downloadInfo = _trialRepository.Where(t => t.Id == trialId).Select(t => new
|
||||
{
|
||||
t.ResearchProgramNo,
|
||||
|
||||
VisitList = t.SubjectVisitList
|
||||
//.Where(t=>subjectCodeList.Contains(t.Subject.Code))
|
||||
.Select(sv => new
|
||||
{
|
||||
TrialSiteCode = sv.TrialSite.TrialSiteCode,
|
||||
SubjectCode = sv.Subject.Code,
|
||||
VisitName = sv.VisitName,
|
||||
StudyList = sv.StudyList.Select(u => new
|
||||
{
|
||||
u.PatientId,
|
||||
u.StudyTime,
|
||||
u.StudyCode,
|
||||
|
||||
SeriesList = u.SeriesList.Where(t => t.IsReading).Select(z => new
|
||||
{
|
||||
z.Modality,
|
||||
|
||||
InstancePathList = z.DicomInstanceList.Where(t => t.IsReading).Select(k => new
|
||||
{
|
||||
k.Path
|
||||
}).ToList()
|
||||
})
|
||||
|
||||
}).ToList(),
|
||||
|
||||
NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => t.IsReading).Select(nd => new
|
||||
{
|
||||
nd.Modality,
|
||||
nd.StudyCode,
|
||||
nd.ImageDate,
|
||||
|
||||
FileList = nd.NoneDicomFileList.Where(t => t.IsReading).Select(file => new
|
||||
{
|
||||
file.FileName,
|
||||
file.Path,
|
||||
file.FileType
|
||||
}).ToList()
|
||||
}).ToList()
|
||||
}).ToList()
|
||||
|
||||
}).FirstOrDefault();
|
||||
|
||||
|
||||
var count = downloadInfo.VisitList.SelectMany(t => t.NoneDicomStudyList).SelectMany(t => t.FileList).Count();
|
||||
var count2 = downloadInfo.VisitList.SelectMany(t => t.StudyList).SelectMany(t => t.SeriesList).SelectMany(t => t.InstancePathList).Count();
|
||||
|
||||
Console.WriteLine($"下载总数量:{count}+{count2}={count + count2}");
|
||||
|
||||
if (downloadInfo != null)
|
||||
{
|
||||
var downloadJobs = new List<Func<Task>>();
|
||||
|
||||
var rootFolder = @"E:\DownloadImage";
|
||||
|
||||
//var rootFolder = FileStoreHelper.GetDonwnloadImageFolder(_hostEnvironment);
|
||||
|
||||
// 获取无效字符(系统定义的)
|
||||
string invalidChars = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
|
||||
|
||||
// 用正则表达式替换所有非法字符为下划线或空字符
|
||||
string pattern = $"[{Regex.Escape(invalidChars)}]";
|
||||
|
||||
var regexNo = Regex.Replace(downloadInfo.ResearchProgramNo, pattern, "_");
|
||||
|
||||
// 创建一个临时文件夹来存放文件
|
||||
string trialFolderPath = Path.Combine(rootFolder, $"{regexNo}_{NewId.NextGuid()}");
|
||||
Directory.CreateDirectory(trialFolderPath);
|
||||
|
||||
foreach (var visitItem in downloadInfo.VisitList)
|
||||
{
|
||||
if (visitItem.StudyList.Count() == 0 && visitItem.NoneDicomStudyList.Count() == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#region 处理 中心,受试者dicom non-dicom 文件夹层级
|
||||
|
||||
var siteFolderPath = Path.Combine(trialFolderPath, visitItem.TrialSiteCode);
|
||||
if (!Directory.Exists(siteFolderPath))
|
||||
{
|
||||
Directory.CreateDirectory(siteFolderPath);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
foreach (var studyInfo in visitItem.StudyList)
|
||||
{
|
||||
// 遍历 Series
|
||||
foreach (var seriesInfo in studyInfo.SeriesList)
|
||||
{
|
||||
string studyDicomFolderPath = Path.Combine(siteFolderPath, $"{visitItem.SubjectCode}_{visitItem.VisitName}_DICOM", $"{studyInfo.StudyCode}_{studyInfo.StudyTime?.ToString("yyyy-MM-dd")}_{seriesInfo.Modality}");
|
||||
|
||||
// 创建 影像 文件夹
|
||||
Directory.CreateDirectory(studyDicomFolderPath);
|
||||
|
||||
// 遍历 InstancePathList
|
||||
foreach (var instanceInfo in seriesInfo.InstancePathList)
|
||||
{
|
||||
// 复制文件到相应的文件夹
|
||||
string destinationPath = Path.Combine(studyDicomFolderPath, Path.GetFileName(instanceInfo.Path));
|
||||
|
||||
|
||||
//加入到下载任务里
|
||||
downloadJobs.Add(() => _oSSService.DownLoadFromOSSAsync(instanceInfo.Path, destinationPath));
|
||||
|
||||
//下载到当前目录
|
||||
//await _oSSService.DownLoadFromOSSAsync(instanceInfo.Path, destinationPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
foreach (var noneDicomStudy in visitItem.NoneDicomStudyList)
|
||||
{
|
||||
string studyNoneDicomFolderPath = Path.Combine(siteFolderPath, $"{visitItem.SubjectCode}_{visitItem.VisitName}_Non-DICOM", $"{noneDicomStudy.StudyCode}_{noneDicomStudy.ImageDate.ToString("yyyy-MM-dd")}_{noneDicomStudy.Modality}");
|
||||
|
||||
Directory.CreateDirectory(studyNoneDicomFolderPath);
|
||||
|
||||
foreach (var file in noneDicomStudy.FileList)
|
||||
{
|
||||
string destinationPath = Path.Combine(studyNoneDicomFolderPath, Path.GetFileName(file.FileName));
|
||||
|
||||
//加入到下载任务里
|
||||
downloadJobs.Add(() => _oSSService.DownLoadFromOSSAsync(HttpUtility.UrlDecode(file.Path), destinationPath));
|
||||
//下载到当前目录
|
||||
//await _oSSService.DownLoadFromOSSAsync(HttpUtility.UrlDecode(file.Path), destinationPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#region 异步方式处理
|
||||
|
||||
int totalCount = downloadJobs.Count;
|
||||
int downloadedCount = 0;
|
||||
|
||||
foreach (var job in downloadJobs)
|
||||
{
|
||||
try
|
||||
{
|
||||
await job();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"下载失败: {ex.Message}");
|
||||
}
|
||||
|
||||
downloadedCount++;
|
||||
|
||||
// 每处理50个,输出一次进度(或最后一个时也输出)
|
||||
if (downloadedCount % 50 == 0 || downloadedCount == totalCount)
|
||||
{
|
||||
Console.WriteLine($"已下载 {downloadedCount} / {totalCount} 个文件,完成 {(downloadedCount * 100.0 / totalCount):F2}%");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 多线程测试
|
||||
|
||||
//const int batchSize = 15;
|
||||
//int totalCount = downloadJobs.Count;
|
||||
//int downloadedCount = 0;
|
||||
|
||||
//for (int i = 0; i < downloadJobs.Count; i += batchSize)
|
||||
//{
|
||||
// var batch = downloadJobs.Skip(i).Take(batchSize).Select(job => job());
|
||||
|
||||
// await Task.WhenAll(batch);
|
||||
|
||||
// downloadedCount += batch.Count();
|
||||
|
||||
// Console.WriteLine($"已下载 {downloadedCount} / {totalCount} 个文件,完成 {(downloadedCount * 100.0 / totalCount):F2}%");
|
||||
//}
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 下载影像 维护dir信息 并回传到OSS
|
||||
/// </summary>
|
||||
/// <param name="trialId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
[AllowAnonymous]
|
||||
public async Task<IResponseOutput> DownloadAndUploadTrialData(Guid trialId, [FromServices] IRepository<DicomInstance> _instanceRepository,
|
||||
[FromServices] IRepository<DicomStudy> _studyRepository,
|
||||
[FromServices] IRepository<DicomSeries> _seriesRepository)
|
||||
{
|
||||
var list = await _instanceRepository.Where(t => t.TrialId == trialId && t.SubjectVisitId == Guid.Parse("01000000-0a00-0242-bd20-08dcce543ded" ) && t.DicomStudy.ModalityForEdit == "IVUS")
|
||||
.Select(t => new { t.SeriesId, t.StudyId, t.Id, t.Path }).ToListAsync();
|
||||
|
||||
int totalCount = list.Count;
|
||||
int dealCount = 0;
|
||||
foreach (var item in list)
|
||||
{
|
||||
|
||||
var stream = await _oSSService.GetStreamFromOSSAsync(item.Path);
|
||||
|
||||
var dicomFile = DicomFile.Open(stream);
|
||||
|
||||
// 获取 Pixel Data 标签
|
||||
var pixelData = DicomPixelData.Create(dicomFile.Dataset);
|
||||
|
||||
//获取像素是否为封装形式
|
||||
var syntax = dicomFile.Dataset.InternalTransferSyntax;
|
||||
|
||||
//对于封装像素的文件做转换
|
||||
if (syntax.IsEncapsulated)
|
||||
{
|
||||
// 创建一个新的片段序列
|
||||
var newFragments = new DicomOtherByteFragment(DicomTag.PixelData);
|
||||
// 获取每帧数据并封装为单独的片段
|
||||
for (int n = 0; n < pixelData.NumberOfFrames; n++)
|
||||
{
|
||||
var frameData = pixelData.GetFrame(n);
|
||||
newFragments.Fragments.Add(new MemoryByteBuffer(frameData.Data));
|
||||
}
|
||||
// 替换原有的片段序列
|
||||
dicomFile.Dataset.AddOrUpdate(newFragments);
|
||||
}
|
||||
|
||||
|
||||
#region 获取dir信息 维护数据库三个表数据
|
||||
|
||||
var dirInfo = DicomDIRHelper.ReadDicomDIRInfo(dicomFile);
|
||||
|
||||
await _instanceRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Id,
|
||||
u => new DicomInstance()
|
||||
{
|
||||
IsEncapsulated= syntax.IsEncapsulated,
|
||||
TransferSytaxUID = dirInfo.TransferSytaxUID,
|
||||
SOPClassUID = dirInfo.SOPClassUID,
|
||||
MediaStorageSOPClassUID = dirInfo.MediaStorageSOPClassUID,
|
||||
MediaStorageSOPInstanceUID = dirInfo.MediaStorageSOPInstanceUID
|
||||
}, false);
|
||||
|
||||
await _seriesRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.SeriesId,
|
||||
u => new DicomSeries()
|
||||
{
|
||||
DicomSeriesDate = dirInfo.DicomSeriesDate,
|
||||
DicomSeriesTime = dirInfo.DicomSeriesTime,
|
||||
}, false);
|
||||
|
||||
await _studyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.StudyId,
|
||||
u => new DicomStudy()
|
||||
{
|
||||
DicomStudyDate = dirInfo.DicomStudyDate,
|
||||
DicomStudyTime = dirInfo.DicomStudyTime
|
||||
}, false);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
//保存到内存流
|
||||
using var memoryStream = new MemoryStream();
|
||||
dicomFile.Save(memoryStream);
|
||||
memoryStream.Position = 0;
|
||||
|
||||
//获取原始目录 和文件名
|
||||
var folder = item.Path.Substring(0, item.Path.LastIndexOf('/')).TrimStart('/');
|
||||
var fileName = Path.GetFileName(item.Path);
|
||||
|
||||
//dicomFile.Save($"download_{Guid.NewGuid()}");
|
||||
|
||||
await _oSSService.UploadToOSSAsync(memoryStream, folder, fileName, false);
|
||||
|
||||
dealCount++;
|
||||
|
||||
Console.WriteLine($"{DateTime.Now}已下载 {dealCount} / {totalCount} 个文件,完成 {(dealCount * 100.0 / totalCount):F2}%");
|
||||
}
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -242,8 +242,6 @@ namespace IRaCIS.Application.Contracts
|
|||
|
||||
public class ConfirmationReviewerDTO : DoctorOptDTO
|
||||
{
|
||||
public Guid DoctorId { get; set; }
|
||||
|
||||
public int DoctorTrialState { get; set; }
|
||||
public string OptUserName { get; set; } = string.Empty;
|
||||
|
||||
|
@ -251,11 +249,6 @@ namespace IRaCIS.Application.Contracts
|
|||
public DateTime? OptTime { get; set; }
|
||||
public string? OptTimeStr => OptTime?.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
public UserTypeEnum? AuditTypeEnum { get; set; }
|
||||
public DateTime? AuditTime { get; set; }
|
||||
public string AuditUserName { get; set; } = string.Empty;
|
||||
public string? AuditTimeStr => AuditTime?.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
//SPM 需要看到
|
||||
public DateTime? SubmmitTime { get; set; }
|
||||
public string SubmmitUserName { get; set; } = string.Empty;
|
||||
|
@ -275,8 +268,6 @@ namespace IRaCIS.Application.Contracts
|
|||
|
||||
public Guid? HospitalId { get; set; }
|
||||
|
||||
public Guid EnrollId { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -302,6 +302,8 @@ namespace IRaCIS.Core.Application.Service
|
|||
.Where(x => x.TrialId == inQuery.TrialId && x.EnrollStatus >= EnrollStatus.InviteIntoGroup);
|
||||
var enrollStateList = await query
|
||||
.ProjectTo<DoctorStateModelDTO>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
enrollStateList = enrollStateList.GroupBy(e => e.DoctorId)
|
||||
.Select(g => g.OrderByDescending(e => e.OptTime).FirstOrDefault()).ToList();
|
||||
|
||||
enrollStateList = enrollStateList
|
||||
.WhereIf(inQuery.OptStartTime != null, x => x.OptTime >= inQuery.OptStartTime)
|
||||
|
@ -335,29 +337,14 @@ namespace IRaCIS.Core.Application.Service
|
|||
doctorPageList.CurrentPageData.ToList().ForEach(u =>
|
||||
{
|
||||
u.DoctorTrialState = (int)EnrollStatus.InviteIntoGroup;
|
||||
|
||||
var lastState= enrollStateList.OrderByDescending(x=>x.OptTime).FirstOrDefault(t => t.DoctorId == u.Id);
|
||||
if (lastState != null)
|
||||
{
|
||||
u.DoctorTrialState = lastState.IntoGroupState;
|
||||
}
|
||||
var opt = enrollStateList.Where(x => x.IntoGroupState == 10).FirstOrDefault(t => t.DoctorId == u.Id);
|
||||
var opt = enrollStateList.OrderByDescending(x=>x.OptTime).FirstOrDefault(t => t.DoctorId == u.Id);
|
||||
if (opt != null)
|
||||
{
|
||||
|
||||
u.DoctorTrialState = opt.IntoGroupState;
|
||||
u.OptTime = opt.OptTime;
|
||||
u.UserTypeEnum = opt.UserTypeEnum;
|
||||
u.OptUserName = opt.OptUserName;
|
||||
}
|
||||
|
||||
var approved = enrollStateList.Where(x => x.IntoGroupState == 8).FirstOrDefault(t => t.DoctorId == u.Id);
|
||||
|
||||
if (approved != null)
|
||||
{
|
||||
u.AuditTime = approved.OptTime;
|
||||
u.AuditTypeEnum = approved.UserTypeEnum;
|
||||
u.AuditUserName = approved.OptUserName;
|
||||
}
|
||||
});
|
||||
|
||||
return doctorPageList;
|
||||
|
|
|
@ -3,7 +3,6 @@ using AutoMapper.EquivalencyExpression;
|
|||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Application.Contracts.Pay;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
|
||||
namespace IRaCIS.Core.Application.Service
|
||||
|
@ -213,8 +212,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
.ForMember(d => d.Code, u => u.MapFrom(s => s.DoctorUser.UserName))
|
||||
.ForMember(d => d.HospitalName, u => u.MapFrom(s => s.Doctor.HospitalName))
|
||||
.ForMember(d => d.HospitalNameCN, u => u.MapFrom(s => s.Doctor.HospitalNameCN))
|
||||
.ForMember(d => d.EnrollId, u => u.MapFrom(s => s.Id))
|
||||
|
||||
;
|
||||
CreateMap<Doctor, ConfirmationReviewerDTO>();
|
||||
CreateMap<Hospital, ConfirmationReviewerDTO>();
|
||||
|
|
|
@ -365,57 +365,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
public List<Guid> Ids { get; set; }
|
||||
}
|
||||
|
||||
public class PublishTrialDocumentInDto
|
||||
{
|
||||
public List<Guid> Ids { get; set; }
|
||||
}
|
||||
|
||||
public class TrialDocumentAttachmentView : TrialDocumentAttachmentAddOrEdit
|
||||
{
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class TrialDocumentAttachmentAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
public string FileFormat { get; set; }
|
||||
|
||||
public string FileName { get; set; }
|
||||
|
||||
public string FilePath { get; set; }
|
||||
|
||||
public decimal? FileSize { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public bool OffLine { get; set; }
|
||||
|
||||
public Guid TrialDocumentId { get; set; }
|
||||
}
|
||||
|
||||
public class TrialDocumentAttachmentQuery : PageInput
|
||||
{
|
||||
public string? FileFormat { get; set; }
|
||||
|
||||
public string? FileName { get; set; }
|
||||
|
||||
public string? FilePath { get; set; }
|
||||
|
||||
public decimal? FileSize { get; set; }
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public bool? OffLine { get; set; }
|
||||
|
||||
public Guid? TrialDocumentId { get; set; }
|
||||
}
|
||||
|
||||
public class AddOrEditSystemDocument : SystemDocumentAddOrEdit
|
||||
{
|
||||
|
||||
|
|
|
@ -13,7 +13,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
{
|
||||
public string FullFilePath { get; set; } = String.Empty;
|
||||
|
||||
public int AttachmentCount { get; set; }
|
||||
public bool IsSomeUserSigned { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
@ -61,24 +60,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
|
||||
public int SignViewMinimumMinutes { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 现有员工培训天数
|
||||
/// </summary>
|
||||
public int? CurrentStaffTrainDays { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 新员工培训天数
|
||||
/// </summary>
|
||||
public int? NewStaffTrainDays { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否发布
|
||||
/// </summary>
|
||||
|
||||
public bool IsPublish { get; set; } = true;
|
||||
|
||||
}
|
||||
|
||||
public class AddOrEditTrialDocument : TrialDocumentAddOrEdit
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||
public new List<UserTypeEnum> ToUserTypeList => TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(t => t.UserType).ToList();
|
||||
public new List<UserTypeEnum> CopyUserTypeList => TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(t => t.UserType).ToList();
|
||||
|
||||
public List<CriterionType>? SysCriterionTypeList { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||
|
||||
public EmailBusinessScenario? BusinessScenarioEnum { get; set; }
|
||||
|
||||
public CriterionType? CriterionTypeEnum { get; set; }
|
||||
//public CriterionType? CriterionTypeEnum { get; set; }
|
||||
|
||||
public Guid? TrialReadingCriterionId { get; set; }
|
||||
|
||||
|
@ -146,6 +146,9 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||
public Guid TrialId { get; set; }
|
||||
|
||||
|
||||
public CriterionType? CriterionTypeEnum { get; set; }
|
||||
|
||||
|
||||
public List<UserTypeEnum> ToUserTypeList { get; set; }
|
||||
public List<UserTypeEnum> CopyUserTypeList { get; set; }
|
||||
|
||||
|
@ -194,11 +197,6 @@ namespace IRaCIS.Core.Application.ViewModel
|
|||
|
||||
public int? EmailDelaySeconds { get; set; }
|
||||
|
||||
[Comment("邮件配置的多个标准")]
|
||||
public List<CriterionType>? CriterionTypeList { get; set; }
|
||||
|
||||
public bool IsDistinguishCriteria { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -14,8 +14,6 @@ namespace IRaCIS.Core.Application.ViewModel;
|
|||
|
||||
public class TrialFinalRecordView : TrialFinalRecordAddOrEdit
|
||||
{
|
||||
public int HistoryCount { get; set; }
|
||||
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-06-09 02:09:12Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using System.Collections.Generic;
|
||||
namespace IRaCIS.Core.Application.Service.DTO;
|
||||
|
||||
public class TrialHistoryRecordFileView : TrialHistoryRecordFileAddOrEdit
|
||||
{
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class TrialHistoryRecordFileAddOrEdit
|
||||
{
|
||||
public Guid? Id { get; set; }
|
||||
|
||||
public string FileFormat { get; set; }
|
||||
|
||||
public string FileName { get; set; }
|
||||
|
||||
public string FilePath { get; set; }
|
||||
|
||||
public string FileSize { get; set; }
|
||||
|
||||
public Guid TrialFileTypeId { get; set; }
|
||||
|
||||
public Guid TrialRecordId { get; set; }
|
||||
}
|
||||
|
||||
public class TrialHistoryRecordFileQuery:PageInput
|
||||
{
|
||||
public string? FileFormat { get; set; }
|
||||
|
||||
public string? FileName { get; set; }
|
||||
|
||||
public string? FilePath { get; set; }
|
||||
|
||||
public string? FileSize { get; set; }
|
||||
|
||||
public Guid? TrialFileTypeId { get; set; }
|
||||
|
||||
public Guid? TrialRecordId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ namespace IRaCIS.Core.Application.ViewModel;
|
|||
|
||||
public class TrialNormalRecordView : TrialNormalRecordAddOrEdit
|
||||
{
|
||||
public int HistoryCount { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace IRaCIS.Core.Application.ViewModel;
|
|||
|
||||
public class TrialTrianingRecordView : TrialTrianingRecordAddOrEdit
|
||||
{
|
||||
public int HistoryCount { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public DateTime UpdateTime { get; set; }
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
{
|
||||
Task SendEnrollOrPdEmail(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm);
|
||||
|
||||
Task<(TrialEmailNoticeConfig?, SMTPEmailConfig?)> BuildEmailConfig(Guid trialId, CriterionType criterionType, EmailBusinessScenario businessScenario, Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc, Guid? siteId = null);
|
||||
Task<(TrialEmailNoticeConfig?, SMTPEmailConfig?)> BuildEmailConfig(Guid trialId, EmailBusinessScenario businessScenario, Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc, Guid? siteId = null, Guid? trialReadingCriterionId = null);
|
||||
}
|
||||
|
||||
public class EmailSendService(IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
|
||||
|
@ -57,7 +57,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
t.Trial.Sponsor.SponsorName,
|
||||
t.SourceSubjectVisit.VisitName,
|
||||
t.TrialId,
|
||||
t.TrialReadingCriterion.CriterionType,
|
||||
|
||||
}).FirstNotNullAsync();
|
||||
|
||||
|
@ -78,7 +77,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
return (topicStr, htmlBodyStr, isEn_us, null);
|
||||
};
|
||||
|
||||
await SendTrialEmailAsync(taskInfo.TrialId, taskInfo.CriterionType, businessScenarioEnum, topicAndHtmlFunc, taskInfo.TrialSiteId);
|
||||
await SendTrialEmailAsync(taskInfo.TrialId, businessScenarioEnum, topicAndHtmlFunc, taskInfo.TrialSiteId);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -93,7 +92,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
return (topicStr, htmlBodyStr, isEn_us, null);
|
||||
};
|
||||
|
||||
await SendTrialEmailAsync(taskInfo.TrialId, taskInfo.CriterionType, businessScenarioEnum, topicAndHtmlFunc, taskInfo.TrialSiteId);
|
||||
await SendTrialEmailAsync(taskInfo.TrialId, businessScenarioEnum, topicAndHtmlFunc, taskInfo.TrialSiteId);
|
||||
}
|
||||
|
||||
|
||||
|
@ -103,9 +102,9 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
|
||||
|
||||
public async Task SendTrialEmailAsync(Guid trialId, CriterionType criterionType, EmailBusinessScenario businessScenario, Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc, Guid? trialSiteId = null, Func<TrialEmailNoticeConfig, SMTPEmailConfig, SMTPEmailConfig> emailAttachFunc = null)
|
||||
public async Task SendTrialEmailAsync(Guid trialId, EmailBusinessScenario businessScenario, Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc, Guid? trialSiteId = null, Guid? trialReadingCriterionId = null, Func<TrialEmailNoticeConfig, SMTPEmailConfig, SMTPEmailConfig> emailAttachFunc = null)
|
||||
{
|
||||
var (trialEmailConfig, sendEmailConfig) = await BuildEmailConfig(trialId, criterionType, businessScenario, topicAndHtmlFunc, trialSiteId);
|
||||
var (trialEmailConfig, sendEmailConfig) = await BuildEmailConfig(trialId, businessScenario, topicAndHtmlFunc, trialSiteId, trialReadingCriterionId);
|
||||
|
||||
if (sendEmailConfig != null)
|
||||
{
|
||||
|
@ -115,10 +114,10 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
|
||||
|
||||
public async Task<(TrialEmailNoticeConfig?, SMTPEmailConfig?)> BuildEmailConfig(Guid trialId, CriterionType criterionType, EmailBusinessScenario businessScenario, Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc, Guid? trialSiteId = null)
|
||||
public async Task<(TrialEmailNoticeConfig?, SMTPEmailConfig?)> BuildEmailConfig(Guid trialId, EmailBusinessScenario businessScenario, Func<TrialEmailNoticeConfig, (string topicStr, string htmlBodyStr, bool isEn_us, Guid? onlyToUserId)> topicAndHtmlFunc, Guid? trialSiteId = null, Guid? trialReadingCriterionId = null)
|
||||
{
|
||||
//找到配置
|
||||
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.BusinessScenarioEnum == businessScenario && t.CriterionTypeList.Any(t => t == criterionType), ignoreQueryFilters: true)
|
||||
var trialEmailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.TrialReadingCriterionId == trialReadingCriterionId && t.BusinessScenarioEnum == businessScenario, ignoreQueryFilters: true)
|
||||
.Include(t => t.TrialEmailNoticeUserList).Include(t => t.TrialEmailBlackUserList).FirstOrDefaultAsync();
|
||||
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-06-09 02:09:12Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Core.Application.Service.DTO;
|
||||
namespace IRaCIS.Core.Application.Interfaces;
|
||||
|
||||
public interface ITrialHistoryRecordFileService
|
||||
{
|
||||
|
||||
Task<PageOutput<TrialHistoryRecordFileView>> GetTrialHistoryRecordFileList(TrialHistoryRecordFileQuery inQuery);
|
||||
|
||||
Task<IResponseOutput> AddOrUpdateTrialHistoryRecordFile(TrialHistoryRecordFileAddOrEdit addOrEditTrialHistoryRecordFile);
|
||||
|
||||
Task<IResponseOutput> DeleteTrialHistoryRecordFile(Guid trialHistoryRecordFileId);
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ namespace IRaCIS.Core.Application.Services
|
|||
var beforeUserTypeIds = document.NeedConfirmedUserTypeList.Select(x => x.NeedConfirmUserTypeId).ToList();
|
||||
|
||||
_mapper.Map(addOrEditSystemDocument, document);
|
||||
document.UpdateTime = DateTime.Now;
|
||||
|
||||
#region 之前区分路径文件夹 现在不区分废弃
|
||||
|
||||
//if (document.FileTypeId != addOrEditSystemDocument.FileTypeId)
|
||||
|
|
|
@ -6,15 +6,11 @@
|
|||
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using MassTransit.Mediator;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using System.Linq;
|
||||
using System.Linq.Dynamic.Core;
|
||||
|
@ -27,13 +23,11 @@ namespace IRaCIS.Core.Application.Services
|
|||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
public class TrialDocumentService(IRepository<TrialDocument> _trialDocumentRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
IRepository<TrialDocumentAttachment> _trialDocumentAttachmentRepository,
|
||||
ISystemDocumentService _systemDocumentService,
|
||||
IRepository<SystemDocConfirmedIdentityUser> _systemDocConfirmedUserRepository,
|
||||
IRepository<SystemDocNeedConfirmedUserType> _systemDocNeedConfirmedUserTypeRepository,
|
||||
IRepository<TrialDocNeedConfirmedUserType> _trialDocNeedConfirmedUserTypeRepository,
|
||||
IRepository<SystemDocument> _systemDocumentRepository,
|
||||
IServiceScopeFactory serviceScopeFactory,
|
||||
IRepository<TrialIdentityUser> _trialIdentityUserRepository,
|
||||
IRepository<TrialUserRole> _trialUserRoleRepository,
|
||||
IRepository<IdentityUser> _identityUserRepository,
|
||||
|
@ -42,102 +36,7 @@ namespace IRaCIS.Core.Application.Services
|
|||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取项目文档附件列表
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<TrialDocumentAttachmentView>> GetTrialDocumentAttachmentList(TrialDocumentAttachmentQuery inQuery)
|
||||
{
|
||||
|
||||
var trialDocumentAttachmentQueryable = _trialDocumentAttachmentRepository
|
||||
.WhereIf(inQuery.TrialDocumentId != null, x => x.TrialDocumentId == inQuery.TrialDocumentId)
|
||||
.WhereIf(inQuery.Name != null, x => x.Name.Contains(inQuery.Name))
|
||||
.WhereIf(inQuery.FileFormat != null, x => x.FileFormat == inQuery.FileFormat)
|
||||
.ProjectTo<TrialDocumentAttachmentView>(_mapper.ConfigurationProvider);
|
||||
|
||||
var pageList = await trialDocumentAttachmentQueryable.ToPagedListAsync(inQuery);
|
||||
|
||||
return pageList;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 添加或更新项目文档附件
|
||||
/// </summary>
|
||||
/// <param name="addOrEditTrialDocumentAttachment"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IResponseOutput> AddOrUpdateTrialDocumentAttachment(TrialDocumentAttachmentAddOrEdit addOrEditTrialDocumentAttachment)
|
||||
{
|
||||
// 在此处拷贝automapper 映射
|
||||
|
||||
var entity = await _trialDocumentAttachmentRepository.InsertOrUpdateAsync(addOrEditTrialDocumentAttachment, true);
|
||||
|
||||
return ResponseOutput.Ok(entity.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除项目文档附件
|
||||
/// </summary>
|
||||
/// <param name="trialDocumentAttachmentId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{trialDocumentAttachmentId:guid}")]
|
||||
public async Task<IResponseOutput> DeleteTrialDocumentAttachment(Guid trialDocumentAttachmentId)
|
||||
{
|
||||
var success = await _trialDocumentAttachmentRepository.DeleteFromQueryAsync(t => t.Id == trialDocumentAttachmentId, true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布项目文档
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> PublishTrialDocument(PublishTrialDocumentInDto inDto)
|
||||
{
|
||||
await _trialDocumentRepository.UpdatePartialFromQueryAsync(x => inDto.Ids.Contains(x.Id), x => new TrialDocument()
|
||||
{
|
||||
IsPublish = true,
|
||||
IsDeleted = false,
|
||||
});
|
||||
await _trialDocumentRepository.SaveChangesAsync();
|
||||
Console.WriteLine("开始 发布项目文档");
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
// 创建独立作用域
|
||||
using (var scope = serviceScopeFactory.CreateScope())
|
||||
{
|
||||
// 从新作用域解析服务
|
||||
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
|
||||
await mediator.Publish(new TrialDocumentPublishEvent { Ids = inDto.Ids });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return ResponseOutput.Result(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试定时发送
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<IResponseOutput> TestPush()
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
// 创建独立作用域
|
||||
using (var scope = serviceScopeFactory.CreateScope())
|
||||
{
|
||||
// 从新作用域解析服务
|
||||
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
|
||||
await mediator.Publish(new TrialDocumentErverDayEvent { });
|
||||
}
|
||||
});
|
||||
return ResponseOutput.Result(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Setting 界面的 项目所有文档列表
|
||||
|
@ -175,8 +74,6 @@ namespace IRaCIS.Core.Application.Services
|
|||
TrialCode = trialDoc.Trial.TrialCode,
|
||||
ResearchProgramNo = trialDoc.Trial.ResearchProgramNo,
|
||||
ExperimentName = trialDoc.Trial.ExperimentName,
|
||||
CurrentStaffTrainDays = trialDoc.CurrentStaffTrainDays,
|
||||
NewStaffTrainDays = trialDoc.NewStaffTrainDays,
|
||||
Id = trialDoc.Id,
|
||||
IsSystemDoc = false,
|
||||
CreateTime = trialDoc.CreateTime,
|
||||
|
@ -510,35 +407,23 @@ namespace IRaCIS.Core.Application.Services
|
|||
.WhereIf(inQuery.IsSign == true, t => t.ConfirmTime != null)
|
||||
.WhereIf(inQuery.IsSign == false, t => t.ConfirmTime == null);
|
||||
|
||||
var defalutSortArray = new string[] { nameof(UnionDocumentWithConfirmInfoView.IsDeleted), nameof(UnionDocumentWithConfirmInfoView.CreateTime) + " desc", nameof(UnionDocumentWithConfirmInfoView.ConfirmTime) };
|
||||
|
||||
var result = await unionQuery.ToPagedListAsync(inQuery, defalutSortArray);
|
||||
|
||||
var result = await unionQuery.ToPagedListAsync(inQuery);
|
||||
|
||||
//Concat 不能用导航属性
|
||||
var sysids = result.CurrentPageData.Where(t => t.IsSystemDoc == true).Select(t => t.Id).ToList();
|
||||
|
||||
var sysDataList = await _systemDocumentRepository.Where(x => sysids.Contains(x.Id)).Include(x => x.SystemDocumentAttachmentList).ToListAsync();
|
||||
|
||||
|
||||
|
||||
result.CurrentPageData.ForEach(x =>
|
||||
{
|
||||
if (sysDataList.Any(y => y.Id == x.Id))
|
||||
{
|
||||
x.AttachmentCount = sysDataList.Where(y => y.Id == x.Id).Select(x => x.SystemDocumentAttachmentList.Where(z => !z.OffLine).Count()).FirstOrDefault();
|
||||
}
|
||||
});
|
||||
|
||||
var trialids = result.CurrentPageData.Where(t => t.IsSystemDoc == false).Select(t => t.Id).ToList();
|
||||
|
||||
var trialDataList = await _trialDocumentRepository.Where(x => trialids.Contains(x.Id)).Include(x => x.TrialDocumentAttachmentList).ToListAsync();
|
||||
|
||||
result.CurrentPageData.ForEach(x =>
|
||||
{
|
||||
if (trialDataList.Any(y => y.Id == x.Id))
|
||||
{
|
||||
x.AttachmentCount = trialDataList.Where(y => y.Id == x.Id).Select(x => x.TrialDocumentAttachmentList.Where(z => !z.OffLine).Count()).FirstOrDefault();
|
||||
}
|
||||
});
|
||||
#endregion
|
||||
|
||||
|
@ -1059,12 +944,10 @@ namespace IRaCIS.Core.Application.Services
|
|||
|
||||
var document = (await _trialDocumentRepository.Where(t => t.Id == addOrEditTrialDocument.Id, true).Include(t => t.NeedConfirmedUserTypeList).FirstOrDefaultAsync()).IfNullThrowException();
|
||||
|
||||
bool beforeIsPublish = document.IsPublish;
|
||||
bool beforeIsDeleted = document.IsDeleted;
|
||||
var beforeUserTypeIds = document.NeedConfirmedUserTypeList.Select(x => x.NeedConfirmUserTypeId).ToList();
|
||||
|
||||
|
||||
_mapper.Map(addOrEditTrialDocument, document);
|
||||
document.UpdateTime = DateTime.Now;
|
||||
|
||||
#region 不区分路径了
|
||||
|
||||
//if (document.FileTypeId != addOrEditTrialDocument.FileTypeId)
|
||||
|
@ -1090,37 +973,7 @@ namespace IRaCIS.Core.Application.Services
|
|||
|
||||
|
||||
var success = await _trialDocumentRepository.SaveChangesAsync();
|
||||
// 检查是否需要发送邮件给新增的角色
|
||||
if (beforeIsPublish && document.IsPublish && !beforeIsDeleted && !document.IsDeleted)
|
||||
{
|
||||
// 找出新增的用户角色ID
|
||||
var newUserTypeIds = addOrEditTrialDocument.NeedConfirmedUserTypeIdList
|
||||
.Where(id => !beforeUserTypeIds.Contains(id))
|
||||
.ToList();
|
||||
|
||||
if (newUserTypeIds.Any() && newUserTypeIds.Count() > 0)
|
||||
{
|
||||
// 发送邮件给新增的角色
|
||||
Console.WriteLine("开始 发送项目文档更新邮件给新增角色");
|
||||
Console.WriteLine(string.Join(",", newUserTypeIds));
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
// 创建独立作用域
|
||||
using (var scope = serviceScopeFactory.CreateScope())
|
||||
{
|
||||
// 从新作用域解析服务
|
||||
var mediator = scope.ServiceProvider.GetRequiredService<IMediator>();
|
||||
// 只发送给新增的角色
|
||||
await mediator.Publish(new TrialDocumentPublishEvent
|
||||
{
|
||||
Ids = new List<Guid> { document.Id },
|
||||
NewUserTypeIds = newUserTypeIds
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return ResponseOutput.Ok(document.Id.ToString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,11 @@
|
|||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
using Amazon.Runtime;
|
||||
using IRaCIS.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.MassTransit.Consumer;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Domain.Share.Common;
|
||||
|
@ -19,7 +16,6 @@ using IRaCIS.Core.Infra.EFCore.Common;
|
|||
using IRaCIS.Core.Infrastructure;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Spire.Doc;
|
||||
using System.Linq.Dynamic.Core;
|
||||
|
@ -47,7 +43,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
IRepository<ReadingTaskQuestionAnswer> _readingTaskQuestionAnswerRepository,
|
||||
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
|
||||
IOptionsMonitor<SystemEmailSendConfig> _systemEmailSendConfig,
|
||||
IDictionaryService _dictionaryService,
|
||||
IEmailSendService _emailSendService,
|
||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IWebHostEnvironment _hostEnvironment) : BaseService, ITrialEmailNoticeConfigService
|
||||
{
|
||||
|
@ -121,29 +116,21 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="trialId"></param>
|
||||
/// <param name="isHandSend">为空 代表 正常任务自动发送,为true 代表医学审核手动发送 为false 代表医学审核自动发送 </param></param>
|
||||
/// <param name="pdAnswer"></param>
|
||||
/// <param name="taskIdList"></param>
|
||||
/// <param name="minUserIdList"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<bool> DealMedicalReviewTasKGenerateAndIsSendAsync(Guid trialId, bool? isHandSend, string answer, List<Guid> taskIdList, List<Guid> minUserIdList)
|
||||
|
||||
private async Task<bool> DealMedicalReviewTasKGenerateAndIsSendAsync(Guid trialId, bool? isHandSend, string pdAnswer, List<Guid> taskIdList, List<Guid> minUserIdList)
|
||||
{
|
||||
|
||||
var isNeedSend = true;
|
||||
|
||||
//手动发送的时候,也有可能答案是是 此时是 这里不发送,发送已经生成的文件
|
||||
if (answer == "是" && isHandSend == null)
|
||||
if (pdAnswer == "是" && isHandSend == null)
|
||||
{
|
||||
isNeedSend = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//正常阅片自动发送,阅片为否的产生医学审核
|
||||
//正常阅片为否的
|
||||
if (isHandSend == null)
|
||||
{
|
||||
isNeedSend = false;
|
||||
|
@ -166,12 +153,12 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
else if (isHandSend == true)
|
||||
{
|
||||
//医学审核手动发送
|
||||
//手动发送
|
||||
isNeedSend = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 医学审核自动发送
|
||||
// 医学审核确认未否了 才发
|
||||
isNeedSend = true;
|
||||
}
|
||||
}
|
||||
|
@ -180,8 +167,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 测试邮件 带附件 填充word
|
||||
/// </summary>
|
||||
|
@ -196,9 +181,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
var isEn_us = _userInfo.IsEn_Us;
|
||||
EmailBusinessScenario businessScenarioEnum = EmailBusinessScenario.None;
|
||||
|
||||
var enrollReplace = "";
|
||||
var PdReplace = "";
|
||||
|
||||
#region 任务关联的项目配置 标准信息及配置,subject 信息
|
||||
var taskInfo = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => new
|
||||
{
|
||||
|
@ -237,8 +219,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
//单双中
|
||||
t.TrialReadingCriterion.ReadingType,
|
||||
|
||||
t.TrialReadingCriterion.IsGlobalReading,
|
||||
|
||||
t.TrialReadingCriterion.CriterionType,
|
||||
//有序与否
|
||||
t.TrialReadingCriterion.IsReadingTaskViewInOrder,
|
||||
|
@ -308,7 +288,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
};
|
||||
|
||||
|
||||
var (trialEmailConfig, sendEmailConfig) = await _emailSendService.BuildEmailConfig(taskInfo.TrialId, taskInfo.CriterionType, businessScenarioEnum, topicAndHtmlFunc, taskInfo.TrialSiteId);
|
||||
var (trialEmailConfig, sendEmailConfig) = await _emailSendService.BuildEmailConfig(taskInfo.TrialId, businessScenarioEnum, topicAndHtmlFunc, taskInfo.TrialSiteId, taskInfo.TrialReadingCriterionId);
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -318,7 +298,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
{
|
||||
#region 不同标准 不同项目配置 发送邮件的时机 处理具体逻辑
|
||||
|
||||
var answer = string.Empty;
|
||||
var answer = "否";
|
||||
var isNeedSend = true;
|
||||
var minUserIdList = _trialUserRoleRepository.Where(t => t.UserRole.UserTypeEnum == Domain.Share.UserTypeEnum.MIM && t.TrialId == taskInfo.TrialId).Select(t => t.UserId).ToList();
|
||||
|
||||
|
@ -327,9 +307,12 @@ namespace IRaCIS.Core.Application.Service
|
|||
//入组确认 根据每个标准配置的是否自动发送,发送邮件与否
|
||||
if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed)
|
||||
{
|
||||
var findItem = (await _dictionaryService.GetBasicDataSelect("Trial_Enroll_Report")).Where(t => t.Code == ((int)taskInfo.CriterionType).ToString()).FirstOrDefault();
|
||||
if (await _readingTableQuestionAnswerRepository.Where().AnyAsync(x => x.VisitTaskId == visitTaskId && x.Answer == TargetState.Exist.GetEnumInt() &&
|
||||
x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion))
|
||||
{
|
||||
answer = "是";
|
||||
}
|
||||
|
||||
enrollReplace = _userInfo.IsEn_Us ? findItem.Value : findItem.ValueCN;
|
||||
|
||||
//如果其他阅片人已经做了,说明发送了入组确认报告,第二个人做完就不发送了
|
||||
|
||||
|
@ -345,18 +328,27 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
else
|
||||
{
|
||||
bool isEnroll = false;
|
||||
|
||||
(answer, isEnroll) = await DealEnrollAnswer(visitTaskId, (Guid)taskInfo.SourceSubjectVisitId, taskInfo.CriterionType, taskInfo.TrialReadingCriterionId);
|
||||
|
||||
isNeedSend = await DealMedicalReviewTasKGenerateAndIsSendAsync(taskInfo.TrialId, isHandSend, answer, new List<Guid>() { visitTaskId }, minUserIdList);
|
||||
|
||||
|
||||
if (answer == "是")
|
||||
{
|
||||
//把另外一个人的任务设置为不加急(如果项目加急是否 subject 加急是否)
|
||||
var urgent = _subjectVisitRepository.Where(t => t.Id == taskInfo.SourceSubjectVisitId).Select(t => new { IsSubjectUrgent = t.Subject.IsUrgent, t.Trial.IsUrgent }).FirstOrDefault();
|
||||
|
||||
if (urgent?.IsUrgent == false || urgent?.IsSubjectUrgent == false)
|
||||
{
|
||||
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => t.SourceSubjectVisitId == taskInfo.SourceSubjectVisitId && t.TaskState == TaskState.Effect && t.IsAnalysisCreate == false &&
|
||||
t.Id != visitTaskId && t.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId, u => new VisitTask() { IsUrgent = false });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed)
|
||||
{
|
||||
var findItem = (await _dictionaryService.GetBasicDataSelect("Trial_PD_Report")).Where(t => t.Code == ((int)taskInfo.CriterionType).ToString()).FirstOrDefault();
|
||||
|
||||
PdReplace = _userInfo.IsEn_Us ? findItem.Value : findItem.ValueCN;
|
||||
|
||||
//有序
|
||||
|
||||
|
@ -371,7 +363,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
|
||||
//仲裁在访视上 就没有全局阅片 没有阅片期
|
||||
if (taskInfo.ArbitrationRule == ArbitrationRule.Visit || (taskInfo.ArbitrationRule == ArbitrationRule.Reading && taskInfo.IsGlobalReading == false))
|
||||
if (taskInfo.ArbitrationRule == ArbitrationRule.Visit)
|
||||
{
|
||||
//找到 访视,裁判 所有有效任务(不可能有全局的) 访视和裁判任务的SourceSubjectVisitId 一样
|
||||
var taskList = await _visitTaskRepository.Where(t => t.SourceSubjectVisitId == taskInfo.SourceSubjectVisitId && t.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect &&
|
||||
|
@ -408,8 +400,8 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
|
||||
}
|
||||
//仲裁在阅片期 并且有阅片期
|
||||
else if (taskInfo.ArbitrationRule == ArbitrationRule.Reading && taskInfo.IsGlobalReading)
|
||||
//仲裁在阅片期
|
||||
else if (taskInfo.ArbitrationRule == ArbitrationRule.Reading)
|
||||
{
|
||||
//是访视任务 不可能是裁判任务(访视上不会生成裁判),也不会是全局任务(全局任务 SourceSubjectVisitId=null )
|
||||
if (taskInfo.SourceSubjectVisitId != null)
|
||||
|
@ -625,8 +617,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
var value = new Dictionary<string, object>()
|
||||
{
|
||||
["Criterion_Enroll_Replace"] = enrollReplace,
|
||||
["Criterion_PD_Replace"] = PdReplace,
|
||||
["SponsorName"] = taskInfo.SponsorName,
|
||||
["ResearchProgramNo"] = taskInfo.ResearchProgramNo,
|
||||
["TrialSiteCode"] = taskInfo.TrialSiteCode,
|
||||
|
@ -640,7 +630,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
var path = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, _userInfo.IsEn_Us ? trialEmailConfig.AttachPath : trialEmailConfig.AttachCNPath);
|
||||
|
||||
//获取从word 到 PDF的路径
|
||||
var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetSubjectEnrollConfirmOrPDEmailPath(_hostEnvironment, Path.GetFileName(path), taskInfo.TrialId, taskInfo.TrialSiteId, taskInfo.SubjectId, true);
|
||||
|
||||
if (emailStoreMode == EmailStoreSendMode.StoreLocalSend || emailStoreMode == EmailStoreSendMode.OnlyStoreLocalNotSentEmail)
|
||||
|
@ -664,12 +653,10 @@ namespace IRaCIS.Core.Application.Service
|
|||
{
|
||||
var wordStoreServerPath = Path.Combine(Path.GetDirectoryName(serverFilePath), Path.GetFileNameWithoutExtension(serverFilePath) + ".docx");
|
||||
|
||||
//模板写入数据先放本地才能转换为pdf
|
||||
using (FileStream fileStream = new FileStream(wordStoreServerPath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
wordMemoryStream.WriteTo(fileStream);
|
||||
}
|
||||
|
||||
FileConvertHelper.ConvertWordToPdf(wordStoreServerPath, Path.GetDirectoryName(serverFilePath));
|
||||
|
||||
File.Delete(wordStoreServerPath);
|
||||
|
@ -709,7 +696,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
{
|
||||
var wordStoreServerPath = Path.Combine(Path.GetDirectoryName(serverFilePath), Path.GetFileNameWithoutExtension(serverFilePath) + ".docx");
|
||||
|
||||
//模板写入数据先放本地才能转换为pdf
|
||||
using (FileStream fileStream = new FileStream(wordStoreServerPath, FileMode.Create, FileAccess.Write))
|
||||
{
|
||||
wordMemoryStream.WriteTo(fileStream);
|
||||
|
@ -870,14 +856,13 @@ namespace IRaCIS.Core.Application.Service
|
|||
var currentLatestPdVisitId = pdSubjectVisitIdList.Last();
|
||||
//标准配置
|
||||
var trialReadingCriterionConfig = await _readingQuestionCriterionTrialRepository.Where(t => t.Id == trialReadingCriterionId).Select(t => new
|
||||
{ TrialReadingCriterionId = t.Id, t.ReadingType, t.IsReadingTaskViewInOrder, t.CriterionType, t.ArbitrationRule, t.IsGlobalReading }).FirstNotNullAsync();
|
||||
{ TrialReadingCriterionId = t.Id, t.ReadingType, t.IsReadingTaskViewInOrder, t.CriterionType, t.ArbitrationRule }).FirstNotNullAsync();
|
||||
|
||||
// 项目双重
|
||||
if (trialReadingCriterionConfig.ReadingType == ReadingMethod.Double && trialReadingCriterionConfig.IsReadingTaskViewInOrder == ReadingOrder.InOrder)
|
||||
{
|
||||
//仲裁在访视上面 或者有阅片期 但是没有全局任务
|
||||
if (trialReadingCriterionConfig.ArbitrationRule == ArbitrationRule.Visit ||
|
||||
(trialReadingCriterionConfig.ArbitrationRule == ArbitrationRule.Reading && trialReadingCriterionConfig.IsGlobalReading == false))
|
||||
//仲裁在访视上面
|
||||
if (trialReadingCriterionConfig.ArbitrationRule == ArbitrationRule.Visit)
|
||||
{
|
||||
//在两位阅片人读完访视后,如果有裁判者等裁判读完,如果无裁判则等第二个人的读完
|
||||
|
||||
|
@ -913,8 +898,8 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
|
||||
}
|
||||
//仲裁在阅片期上 并且有全局任务
|
||||
else if (trialReadingCriterionConfig.ArbitrationRule == ArbitrationRule.Reading && trialReadingCriterionConfig.IsGlobalReading)
|
||||
//仲裁在阅片期上
|
||||
else if (trialReadingCriterionConfig.ArbitrationRule == ArbitrationRule.Reading)
|
||||
{
|
||||
var existReadModule = await _readModuleRepository.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.SubjectVisitId == currentLatestPdVisitId && t.ReadingSetType == ReadingSetType.ImageReading)
|
||||
.FirstOrDefaultAsync();
|
||||
|
@ -926,7 +911,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
else
|
||||
{
|
||||
|
||||
var taskList = await _visitTaskRepository.Where(t => t.TrialReadingCriterionId == trialReadingCriterionId && t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect && t.SouceReadModuleId == existReadModule.Id
|
||||
&& (t.ReadingCategory == ReadingCategory.Global || t.ReadingCategory == ReadingCategory.Judge)).ToListAsync();
|
||||
|
||||
|
@ -1058,108 +1042,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取入组结果
|
||||
/// </summary>
|
||||
/// <param name="visitTaskId"></param>
|
||||
/// <param name="subjectVisitId"></param>
|
||||
/// <param name="criterionType"></param>
|
||||
/// <param name="trialReadingCriterionId"></param>
|
||||
/// <returns></returns>
|
||||
private async Task<(string enrollAnswer, bool isEnroll)> DealEnrollAnswer(Guid visitTaskId, Guid subjectVisitId, CriterionType criterionType, Guid trialReadingCriterionId)
|
||||
{
|
||||
|
||||
var enrollAnswer = _userInfo.IsEn_Us ? "No" : "否";
|
||||
var isEnroll = false;
|
||||
|
||||
switch (criterionType)
|
||||
{
|
||||
|
||||
case CriterionType.RECIST1Point1:
|
||||
case CriterionType.RECIST1Pointt1_MB:
|
||||
case CriterionType.IRECIST1Point1:
|
||||
case CriterionType.mRECISTHCC:
|
||||
|
||||
case CriterionType.Lugano2014:
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
|
||||
if (await _readingTableQuestionAnswerRepository.Where().AnyAsync(x => x.VisitTaskId == visitTaskId && x.Answer == TargetState.Exist.GetEnumInt() &&
|
||||
x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion))
|
||||
{
|
||||
enrollAnswer = _userInfo.IsEn_Us ? "Yes" : "是";
|
||||
isEnroll = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CriterionType.PCWG3:
|
||||
|
||||
var list = await _readingTableQuestionAnswerRepository.Where(x => x.VisitTaskId == visitTaskId &&
|
||||
x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.ReadingQuestionTrial.LesionType == LesionType.BaselineLesions).Select(t => t.Answer).ToListAsync();
|
||||
|
||||
bool exists = list.Any(s => int.TryParse(s, out var n) && n >= 1);
|
||||
if (exists)
|
||||
{
|
||||
enrollAnswer = _userInfo.IsEn_Us ? "Yes" : "是";
|
||||
isEnroll = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CriterionType.RANO_BM:
|
||||
break;
|
||||
case CriterionType.RANO:
|
||||
break;
|
||||
case CriterionType.IWCLL2018:
|
||||
break;
|
||||
|
||||
case CriterionType.Cheson2007:
|
||||
break;
|
||||
case CriterionType.IMWG2016:
|
||||
break;
|
||||
|
||||
case CriterionType.mRECISTMesothelioma:
|
||||
break;
|
||||
case CriterionType.RECIL:
|
||||
break;
|
||||
case CriterionType.RECIST1Point0:
|
||||
break;
|
||||
case CriterionType.WHO:
|
||||
break;
|
||||
case CriterionType.PERCIST:
|
||||
break;
|
||||
case CriterionType.Forrest:
|
||||
break;
|
||||
|
||||
case CriterionType.IVUS:
|
||||
break;
|
||||
case CriterionType.OCT:
|
||||
break;
|
||||
case CriterionType.MRIPDFF:
|
||||
break;
|
||||
case CriterionType.NoCriterion:
|
||||
break;
|
||||
case CriterionType.SelfDefine:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (enrollAnswer == "是" || enrollAnswer == "Yes")
|
||||
{
|
||||
//把另外一个人的任务设置为不加急(如果项目加急是否 subject 加急是否)
|
||||
var urgent = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { IsSubjectUrgent = t.Subject.IsUrgent, t.Trial.IsUrgent }).FirstOrDefault();
|
||||
|
||||
if (urgent?.IsUrgent == false || urgent?.IsSubjectUrgent == false)
|
||||
{
|
||||
await _visitTaskRepository.BatchUpdateNoTrackingAsync(t => t.SourceSubjectVisitId == subjectVisitId && t.TaskState == TaskState.Effect && t.IsAnalysisCreate == false &&
|
||||
t.Id != visitTaskId && t.TrialReadingCriterionId == trialReadingCriterionId, u => new VisitTask() { IsUrgent = false });
|
||||
}
|
||||
}
|
||||
return (enrollAnswer, isEnroll);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取PD 结果
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="visitTaskId"> 任务Id</param>
|
||||
/// <param name="readingCategory"> 任务类型</param>
|
||||
|
@ -1174,53 +1057,109 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi
|
|||
|
||||
ReadingTaskQuestionAnswer visitQuestionAnswer = null;
|
||||
|
||||
ReadingGlobalTaskInfo readingGlobalTaskInfo = null;
|
||||
ReadingTaskQuestionAnswer globalQuestionAnswer = null;
|
||||
|
||||
|
||||
|
||||
if (readingCategory == ReadingCategory.Visit)
|
||||
{
|
||||
|
||||
|
||||
switch (criterionType)
|
||||
{
|
||||
|
||||
|
||||
case CriterionType.RECIST1Point1:
|
||||
case CriterionType.RECIST1Pointt1_MB:
|
||||
case CriterionType.IRECIST1Point1:
|
||||
case CriterionType.mRECISTHCC:
|
||||
|
||||
if (readingCategory == ReadingCategory.Visit)
|
||||
{
|
||||
|
||||
visitQuestionAnswer = await _readingTaskQuestionAnswerRepository.Where(t => t.VisitTaskId == visitTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.Tumor).FirstNotNullAsync();
|
||||
|
||||
answer = visitQuestionAnswer.Answer;
|
||||
|
||||
break;
|
||||
|
||||
case CriterionType.Lugano2014:
|
||||
|
||||
visitQuestionAnswer = await _readingTaskQuestionAnswerRepository.Where(t => t.VisitTaskId == visitTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.ImgOncology).FirstNotNullAsync();
|
||||
|
||||
answer = visitQuestionAnswer.Answer;
|
||||
}
|
||||
else if (readingCategory == ReadingCategory.Global)
|
||||
{
|
||||
var questionAnsewer = await _readingGlobalTaskInfoRepository.Where(t => t.GlobalTaskId == visitTaskId && t.TrialReadingQuestion.QuestionType == QuestionType.Tumor).OrderByDescending(c => c.VisitTask.VisitTaskNum).FirstNotNullAsync();
|
||||
|
||||
break;
|
||||
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
answer = questionAnsewer.Answer;
|
||||
if (string.IsNullOrEmpty(questionAnsewer.Answer))
|
||||
{
|
||||
answer = await _readingTaskQuestionAnswerRepository.Where(t => questionAnsewer.TaskId == t.VisitTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.Tumor)
|
||||
.Select(t => t.Answer).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
visitQuestionAnswer = await _readingTaskQuestionAnswerRepository.Where(t => t.VisitTaskId == visitTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.CTandMRI).FirstNotNullAsync();
|
||||
}
|
||||
//else if (readingCategory == ReadingCategory.Judge)
|
||||
//{
|
||||
// var judgeResultTaskId = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => t.JudgeResultTaskId).FirstNotNullAsync();
|
||||
|
||||
answer = visitQuestionAnswer.Answer;
|
||||
// var questionAnsewer = await _readingTaskQuestionAnswerRepository.Where(t => t.VisitTaskId == judgeResultTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.Tumor).FirstNotNullAsync();
|
||||
|
||||
|
||||
// answer = questionAnsewer.Answer;
|
||||
//}
|
||||
else
|
||||
{
|
||||
//---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑
|
||||
throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidTaskTypeForEmailSending"]);
|
||||
}
|
||||
|
||||
if (answer == OverallAssessment.PD.GetEnumInt())
|
||||
{
|
||||
answer = "是";
|
||||
}
|
||||
else
|
||||
{
|
||||
answer = "否";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CriterionType.PCWG3:
|
||||
if (readingCategory == ReadingCategory.Visit)
|
||||
{
|
||||
|
||||
visitQuestionAnswer = await _readingTaskQuestionAnswerRepository.Where(t => t.VisitTaskId == visitTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.SiteVisitForTumorEvaluation).FirstNotNullAsync();
|
||||
|
||||
|
||||
answer = visitQuestionAnswer.Answer;
|
||||
}
|
||||
else if (readingCategory == ReadingCategory.Global)
|
||||
{
|
||||
var questionAnsewer = await _readingGlobalTaskInfoRepository.Where(t => t.TaskId == visitTaskId && t.TrialReadingQuestion.QuestionType == QuestionType.SiteVisitForTumorEvaluation).FirstNotNullAsync();
|
||||
|
||||
answer = questionAnsewer.Answer;
|
||||
}
|
||||
//else if (readingCategory == ReadingCategory.Judge)
|
||||
//{
|
||||
// //var judgeResultTaskId = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => t.JudgeResultTaskId).FirstNotNullAsync();
|
||||
|
||||
// var questionAnsewer = await _readingTaskQuestionAnswerRepository.Where(t => t.VisitTaskId == visitTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.SiteVisitForTumorEvaluation).FirstNotNullAsync();
|
||||
|
||||
// answer = questionAnsewer.Answer;
|
||||
//}
|
||||
else
|
||||
{
|
||||
//---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑
|
||||
throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidTaskTypeForEmailSending"]);
|
||||
}
|
||||
|
||||
if (answer == VisitTumorEvaluation.PD.GetEnumInt())
|
||||
{
|
||||
answer = "是";
|
||||
}
|
||||
if (answer == VisitTumorEvaluation.ND.GetEnumInt())
|
||||
{
|
||||
answer = "ND";
|
||||
}
|
||||
if (answer == VisitTumorEvaluation.NE.GetEnumInt())
|
||||
{
|
||||
answer = "NE";
|
||||
}
|
||||
else
|
||||
{
|
||||
answer = "否";
|
||||
}
|
||||
break;
|
||||
|
||||
case CriterionType.SelfDefine:
|
||||
case CriterionType.mRECISTMesothelioma:
|
||||
case CriterionType.RECIL:
|
||||
|
@ -1228,10 +1167,12 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi
|
|||
case CriterionType.WHO:
|
||||
case CriterionType.PERCIST:
|
||||
case CriterionType.Forrest:
|
||||
|
||||
case CriterionType.Lugano2014:
|
||||
case CriterionType.IRECIST1Point1:
|
||||
case CriterionType.RANO_BM:
|
||||
case CriterionType.RANO:
|
||||
case CriterionType.IWCLL2018:
|
||||
case CriterionType.mRECISTHCC:
|
||||
case CriterionType.Cheson2007:
|
||||
case CriterionType.IMWG2016:
|
||||
default:
|
||||
|
@ -1242,232 +1183,6 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi
|
|||
|
||||
|
||||
|
||||
}
|
||||
else if (readingCategory == ReadingCategory.Global)
|
||||
{
|
||||
switch (criterionType)
|
||||
{
|
||||
|
||||
case CriterionType.RECIST1Point1:
|
||||
case CriterionType.RECIST1Pointt1_MB:
|
||||
case CriterionType.IRECIST1Point1:
|
||||
case CriterionType.mRECISTHCC:
|
||||
|
||||
readingGlobalTaskInfo = await _readingGlobalTaskInfoRepository.Where(t => t.GlobalTaskId == visitTaskId && t.TrialReadingQuestion.QuestionType == QuestionType.Tumor).OrderByDescending(c => c.VisitTask.VisitTaskNum).FirstNotNullAsync();
|
||||
|
||||
answer = readingGlobalTaskInfo.Answer;
|
||||
if (string.IsNullOrEmpty(readingGlobalTaskInfo.Answer))
|
||||
{
|
||||
answer = await _readingTaskQuestionAnswerRepository.Where(t => readingGlobalTaskInfo.TaskId == t.VisitTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.Tumor)
|
||||
.Select(t => t.Answer).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CriterionType.Lugano2014:
|
||||
|
||||
readingGlobalTaskInfo = await _readingGlobalTaskInfoRepository.Where(t => t.GlobalTaskId == visitTaskId && t.TrialReadingQuestion.QuestionType == QuestionType.ImgOncology).OrderByDescending(c => c.VisitTask.VisitTaskNum).FirstNotNullAsync();
|
||||
|
||||
answer = readingGlobalTaskInfo.Answer;
|
||||
if (string.IsNullOrEmpty(readingGlobalTaskInfo.Answer))
|
||||
{
|
||||
answer = await _readingTaskQuestionAnswerRepository.Where(t => readingGlobalTaskInfo.TaskId == t.VisitTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.ImgOncology)
|
||||
.Select(t => t.Answer).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
break;
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
|
||||
readingGlobalTaskInfo = await _readingGlobalTaskInfoRepository.Where(t => t.GlobalTaskId == visitTaskId && t.TrialReadingQuestion.QuestionType == QuestionType.CTandMRI).OrderByDescending(c => c.VisitTask.VisitTaskNum).FirstNotNullAsync();
|
||||
|
||||
answer = readingGlobalTaskInfo.Answer;
|
||||
if (string.IsNullOrEmpty(readingGlobalTaskInfo.Answer))
|
||||
{
|
||||
answer = await _readingTaskQuestionAnswerRepository.Where(t => readingGlobalTaskInfo.TaskId == t.VisitTaskId && t.ReadingQuestionTrial.QuestionType == QuestionType.CTandMRI)
|
||||
.Select(t => t.Answer).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CriterionType.PCWG3:
|
||||
var questionAnsewer = await _readingGlobalTaskInfoRepository.Where(t => t.TaskId == visitTaskId && t.TrialReadingQuestion.QuestionType == QuestionType.SiteVisitForTumorEvaluation).FirstOrDefaultAsync();
|
||||
if (questionAnsewer != null && questionAnsewer.Answer.IsNotNullOrEmpty())
|
||||
{
|
||||
answer = questionAnsewer.Answer;
|
||||
}
|
||||
else
|
||||
{
|
||||
var visittaskList = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(x => x.RelatedVisitTaskIdList).FirstOrDefaultAsync();
|
||||
|
||||
var task = await _visitTaskRepository.Where(x => visittaskList.Contains(x.Id) && x.ReadingCategory == ReadingCategory.Visit).OrderByDescending(x => x.VisitTaskNum).FirstOrDefaultAsync();
|
||||
if (task != null)
|
||||
{
|
||||
answer = await _readingTaskQuestionAnswerRepository.Where(t => t.VisitTaskId == task.Id && t.ReadingQuestionTrial.QuestionType == QuestionType.SiteVisitForTumorEvaluation)
|
||||
.Select(t => t.Answer).FirstOrDefaultAsync();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case CriterionType.RANO_BM:
|
||||
break;
|
||||
case CriterionType.RANO:
|
||||
break;
|
||||
case CriterionType.IWCLL2018:
|
||||
break;
|
||||
case CriterionType.Cheson2007:
|
||||
break;
|
||||
case CriterionType.IMWG2016:
|
||||
break;
|
||||
|
||||
case CriterionType.mRECISTMesothelioma:
|
||||
break;
|
||||
case CriterionType.RECIL:
|
||||
break;
|
||||
case CriterionType.RECIST1Point0:
|
||||
break;
|
||||
case CriterionType.WHO:
|
||||
break;
|
||||
case CriterionType.PERCIST:
|
||||
break;
|
||||
case CriterionType.Forrest:
|
||||
break;
|
||||
|
||||
case CriterionType.IVUS:
|
||||
break;
|
||||
case CriterionType.OCT:
|
||||
break;
|
||||
case CriterionType.MRIPDFF:
|
||||
break;
|
||||
case CriterionType.NoCriterion:
|
||||
break;
|
||||
case CriterionType.SelfDefine:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑
|
||||
throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidTaskTypeForEmailSending"]);
|
||||
}
|
||||
|
||||
|
||||
switch (criterionType)
|
||||
{
|
||||
|
||||
case CriterionType.RECIST1Point1:
|
||||
case CriterionType.RECIST1Pointt1_MB:
|
||||
case CriterionType.mRECISTHCC:
|
||||
|
||||
|
||||
if (answer == OverallAssessment.PD.GetEnumInt())
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "Yes" : "是";
|
||||
}
|
||||
else
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "No" : "否";
|
||||
}
|
||||
|
||||
break;
|
||||
case CriterionType.IRECIST1Point1:
|
||||
|
||||
if (answer == OverallAssessment.iCPD.GetEnumInt())
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "Yes" : "是";
|
||||
}
|
||||
else
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "No" : "否";
|
||||
}
|
||||
|
||||
break;
|
||||
case CriterionType.Lugano2014WithoutPET:
|
||||
|
||||
if (answer == CTMRIOverallAssessment.PD.GetEnumInt())
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "Yes" : "是";
|
||||
}
|
||||
else
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "No" : "否";
|
||||
}
|
||||
|
||||
break;
|
||||
case CriterionType.Lugano2014:
|
||||
|
||||
if (answer == ImagingOverallAssessment_Lugano.PMDPD.GetEnumInt())
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "Yes" : "是";
|
||||
}
|
||||
else
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "No" : "否";
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
|
||||
|
||||
case CriterionType.PCWG3:
|
||||
|
||||
if (answer == VisitTumorEvaluation.PD.GetEnumInt())
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "Yes" : "是";
|
||||
}
|
||||
else
|
||||
{
|
||||
answer = _userInfo.IsEn_Us ? "No" : "否";
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case CriterionType.RANO_BM:
|
||||
break;
|
||||
case CriterionType.RANO:
|
||||
break;
|
||||
case CriterionType.IWCLL2018:
|
||||
break;
|
||||
|
||||
case CriterionType.Cheson2007:
|
||||
break;
|
||||
case CriterionType.IMWG2016:
|
||||
break;
|
||||
|
||||
case CriterionType.mRECISTMesothelioma:
|
||||
break;
|
||||
case CriterionType.RECIL:
|
||||
break;
|
||||
case CriterionType.RECIST1Point0:
|
||||
break;
|
||||
case CriterionType.WHO:
|
||||
break;
|
||||
case CriterionType.PERCIST:
|
||||
break;
|
||||
case CriterionType.Forrest:
|
||||
break;
|
||||
|
||||
case CriterionType.IVUS:
|
||||
break;
|
||||
case CriterionType.OCT:
|
||||
break;
|
||||
case CriterionType.MRIPDFF:
|
||||
break;
|
||||
case CriterionType.NoCriterion:
|
||||
break;
|
||||
case CriterionType.SelfDefine:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return answer;
|
||||
|
||||
|
||||
|
@ -1618,10 +1333,7 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi
|
|||
item.IsAutoSend = true;
|
||||
item.IsEnable = true;
|
||||
|
||||
//item.TrialReadingCriterionId = list.FirstOrDefault(t => t.CriterionType == item.CriterionTypeEnum)?.TrialReadingCriterionId;
|
||||
|
||||
item.CriterionTypeList = item.CriterionTypeList.Where(t => list.Any(c => c.CriterionType == t)).ToList();
|
||||
|
||||
item.TrialReadingCriterionId = list.FirstOrDefault(t => t.CriterionType == item.CriterionTypeEnum)?.TrialReadingCriterionId;
|
||||
|
||||
item.TrialEmailNoticeUserList.AddRange(batchAddList.Where(t => t.Id == item.SysEmailNoticeConfigId)
|
||||
.SelectMany(t => t.ToUserTypeList).Select(t => new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = t }));
|
||||
|
@ -1637,25 +1349,16 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi
|
|||
await _trialEmailNoticeConfigRepository.SaveChangesAsync();
|
||||
|
||||
//处理定时任务
|
||||
var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.EmailCron != string.Empty)
|
||||
.Select(t => new { t.Id, t.Code, TrialCode = t.Trial.TrialCode, t.EmailCron, t.BusinessScenarioEnum, t.TrialId, t.IsEnable, t.IsAutoSend })
|
||||
var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId== trialId && t.EmailCron != string.Empty && t.IsAutoSend)
|
||||
.Select(t => new { t.Id, t.Code, TrialCode = t.Trial.TrialCode, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var task in taskInfoList)
|
||||
{
|
||||
|
||||
//利用主键作为任务Id
|
||||
var jobId = $"{task.TrialId}({task.TrialCode})_({task.BusinessScenarioEnum})";
|
||||
|
||||
if (task.IsEnable && task.IsAutoSend)
|
||||
{
|
||||
HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, trialId, task.BusinessScenarioEnum, task.EmailCron);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
HangfireJobHelper.RemoveCronJob(jobId);
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
|
@ -1673,9 +1376,9 @@ x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.LesionNumber && x.Readi
|
|||
var trialConfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => new { t.IsEnrollementQualificationConfirm, t.IsPDProgressView }).First();
|
||||
|
||||
var trialEmailNoticeConfigQueryable = _trialEmailNoticeConfigRepository.Where(t => t.TrialId == inQuery.TrialId)
|
||||
.WhereIf(inQuery.IsDistinguishCriteria == false, t => t.IsDistinguishCriteria == false)
|
||||
.WhereIf(inQuery.IsDistinguishCriteria == true, t => t.IsDistinguishCriteria == true)
|
||||
.WhereIf(inQuery.CriterionTypeEnum != null, t => t.CriterionTypeList.Any(c => c == inQuery.CriterionTypeEnum))
|
||||
.WhereIf(inQuery.IsDistinguishCriteria == false, t => t.TrialReadingCriterionId == null)
|
||||
.WhereIf(inQuery.IsDistinguishCriteria == true, t => t.CriterionTypeEnum != null)
|
||||
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
|
||||
.WhereIf(inQuery.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == inQuery.BusinessScenarioEnum)
|
||||
.WhereIf(inQuery.EmailUrgentEnum != null, t => t.EmailUrgentEnum == inQuery.EmailUrgentEnum)
|
||||
.WhereIf(inQuery.IsEnable != null, t => t.IsEnable == inQuery.IsEnable)
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
|
||||
//--------------------------------------------------------------------
|
||||
// 此代码由liquid模板自动生成 byzhouhang 20240909
|
||||
// 生成时间 2025-06-09 02:09:09Z
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
using System.Threading.Tasks;
|
||||
using IRaCIS.Core.Infra.EFCore;
|
||||
using IRaCIS.Core.Application.Service.DTO;
|
||||
using IRaCIS.Core.Application.MassTransit.Command;
|
||||
namespace IRaCIS.Core.Application.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 项目历史记录文件服务
|
||||
/// </summary>
|
||||
[ApiExplorerSettings(GroupName = "FileRecord")]
|
||||
public class TrialHistoryRecordFileService(IRepository<TrialHistoryRecordFile> _trialHistoryRecordFileRepository,
|
||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer): BaseService, ITrialHistoryRecordFileService
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 获取稽查记录文件列表
|
||||
/// </summary>
|
||||
/// <param name="inQuery"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<PageOutput<TrialHistoryRecordFileView>> GetTrialHistoryRecordFileList(TrialHistoryRecordFileQuery inQuery)
|
||||
{
|
||||
|
||||
var trialHistoryRecordFileQueryable =_trialHistoryRecordFileRepository
|
||||
.WhereIf(inQuery.TrialRecordId!=null,x=>x.TrialRecordId==inQuery.TrialRecordId)
|
||||
.WhereIf(inQuery.TrialFileTypeId != null, x => x.TrialFileTypeId == inQuery.TrialFileTypeId)
|
||||
.WhereIf(inQuery.FileName.IsNotNullOrEmpty(), x => x.FileName.Contains(x.FileName))
|
||||
.ProjectTo<TrialHistoryRecordFileView>(_mapper.ConfigurationProvider);
|
||||
|
||||
var pageList= await trialHistoryRecordFileQueryable.ToPagedListAsync(inQuery);
|
||||
|
||||
return pageList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量新增稽查记录文件
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> BatchAddTrialHistoryRecordFile(List<TrialHistoryRecordFileAddOrEdit> inDto)
|
||||
{
|
||||
List<TrialHistoryRecordFile> entities = _mapper.Map<List<TrialHistoryRecordFile>>(inDto);
|
||||
await _trialHistoryRecordFileRepository.AddRangeAsync(entities);
|
||||
|
||||
await _trialHistoryRecordFileRepository.SaveChangesAsync();
|
||||
return ResponseOutput.Ok(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增或修改稽查记录文件
|
||||
/// </summary>
|
||||
/// <param name="addOrEditTrialHistoryRecordFile"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> AddOrUpdateTrialHistoryRecordFile(TrialHistoryRecordFileAddOrEdit addOrEditTrialHistoryRecordFile)
|
||||
{
|
||||
// 在此处拷贝automapper 映射
|
||||
|
||||
|
||||
|
||||
|
||||
var entity = await _trialHistoryRecordFileRepository.InsertOrUpdateAsync(addOrEditTrialHistoryRecordFile, true);
|
||||
|
||||
return ResponseOutput.Ok(entity.Id.ToString());
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除稽查记录文件
|
||||
/// </summary>
|
||||
/// <param name="trialHistoryRecordFileId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete("{trialHistoryRecordFileId:guid}")]
|
||||
public async Task<IResponseOutput> DeleteTrialHistoryRecordFile(Guid trialHistoryRecordFileId)
|
||||
{
|
||||
var success = await _trialHistoryRecordFileRepository.DeleteFromQueryAsync(t => t.Id == trialHistoryRecordFileId,true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
using AutoMapper.EquivalencyExpression;
|
||||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Service.DTO;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Infrastructure.Extention;
|
||||
|
||||
|
@ -17,8 +16,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
var isEn_Us = false;
|
||||
|
||||
// 在此处拷贝automapper 映射
|
||||
CreateMap<TrialDocumentAttachment, TrialDocumentAttachmentView>();
|
||||
CreateMap<TrialDocumentAttachment, TrialDocumentAttachmentAddOrEdit>().ReverseMap();
|
||||
|
||||
CreateMap<SystemDocumentAttachment, SystemDocumentAttachmentView>();
|
||||
CreateMap<SystemDocumentAttachment, SystemDocumentAttachmentAddOrEdit>().ReverseMap();
|
||||
|
@ -43,7 +40,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
.ForMember(dest => dest.CreateUserRole, opt => opt.Ignore());
|
||||
|
||||
CreateMap<TrialDocument, TrialDocumentView>()
|
||||
.ForMember(d => d.AttachmentCount, u => u.MapFrom(s =>s.TrialDocumentAttachmentList.Count()))
|
||||
.ForMember(d => d.FileType, u => u.MapFrom(s => isEn_Us ? s.FileType.Value : s.FileType.ValueCN))
|
||||
.ForMember(d => d.IsSomeUserSigned, u => u.MapFrom(s => s.TrialDocConfirmedUserList.Any(t => t.ConfirmTime != null)))
|
||||
.ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path));
|
||||
|
@ -100,7 +96,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
|
||||
CreateMap<TrialEmailNoticeConfig, TrialEmailNoticeConfigView>()
|
||||
.ForMember(d => d.SysCriterionTypeList, c => c.MapFrom(t => t.SysEmailNoticeConfig.CriterionTypeList))
|
||||
|
||||
.ForMember(d => d.TrialCriterionName, c => c.MapFrom(t => t.TrialReadingCriterion.CriterionName))
|
||||
.ForMember(d => d.TrialEmailNoticeUserList, c => c.MapFrom(t => t.TrialEmailNoticeUserList));
|
||||
|
||||
|
@ -125,8 +121,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
|
||||
CreateMap<TrialFileType, TrialFileTypeAddOrEdit>().ReverseMap();
|
||||
|
||||
CreateMap<TrialFinalRecord, TrialFinalRecordView>()
|
||||
.ForMember(d => d.HistoryCount, c => c.MapFrom(t => t.TrialHistoryRecordFileList.Count));
|
||||
CreateMap<TrialFinalRecord, TrialFinalRecordView>();
|
||||
CreateMap<TrialFinalRecordAddOrEdit, TrialFinalRecord>();
|
||||
//.ForMember(d => d.HistoryFileRecord.TrialFileTypeId, c => c.MapFrom(t => t.TrialFileTypeId))
|
||||
//.ForMember(d => d.SignFileRecord.TrialFileTypeId, c => c.MapFrom(t => t.TrialFileTypeId))
|
||||
|
@ -134,18 +129,15 @@ namespace IRaCIS.Core.Application.Service
|
|||
//.ForMember(d => d.PDFFileRecord.TrialFileTypeId, c => c.MapFrom(t => t.TrialFileTypeId));
|
||||
|
||||
CreateMap<TrialNormalRecord, TrialNormalRecordView>()
|
||||
.ForMember(d => d.HistoryCount, c => c.MapFrom(t => t.TrialHistoryRecordFileList.Count))
|
||||
.ForMember(d => d.FileName, c => c.MapFrom(t => t.TrialFileRecord.FileName));
|
||||
CreateMap<TrialNormalRecord, TrialNormalRecordAddOrEdit>().ReverseMap();
|
||||
|
||||
CreateMap<TrialTrianingRecord, TrialTrianingRecordView>()
|
||||
.ForMember(d => d.HistoryCount, c => c.MapFrom(t => t.TrialHistoryRecordFileList.Count))
|
||||
.ForMember(d => d.FileName, c => c.MapFrom(t => t.TrialFileRecord.FileName));
|
||||
CreateMap<TrialTrianingRecord, TrialTrianingRecordAddOrEdit>().ReverseMap();
|
||||
|
||||
|
||||
CreateMap<TrialHistoryRecordFile, TrialHistoryRecordFileView>();
|
||||
CreateMap<TrialHistoryRecordFile, TrialHistoryRecordFileAddOrEdit>().ReverseMap();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,10 +50,6 @@ namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
|||
public string? WindowWidth => InstanceInfoList.FirstOrDefault()?.WindowWidth;
|
||||
|
||||
public string ImageResizePath { get; set; }
|
||||
|
||||
public string VisitName { get; set; }
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
}
|
||||
|
||||
public class StudyInstanceInfo
|
||||
|
@ -70,12 +66,6 @@ namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
|||
public Guid? InstanceId { get; set; }
|
||||
|
||||
public int? NumberOfFrames { get; set; }
|
||||
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
public int? QuestionSort { get; set; }
|
||||
|
||||
public int? RowSort { get; set; }
|
||||
}
|
||||
public class InstanceBasicInfo
|
||||
{
|
||||
|
@ -108,8 +98,6 @@ namespace IRaCIS.Core.Application.Contracts.Dicom.DTO
|
|||
public string WindowCenter { get; set; }
|
||||
[JsonIgnore]
|
||||
public string WindowWidth { get; set; }
|
||||
|
||||
public DateTime? RowDate { get; set; }
|
||||
}
|
||||
|
||||
public class DicomSeriesWithLabelDTO : DicomSeriesDTO
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using FellowOakDicom;
|
||||
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
|
||||
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
@ -324,14 +323,9 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
|
||||
public string BodyPartExamined { get; set; } = string.Empty;
|
||||
|
||||
public string DicomStudyDate { get; set; }
|
||||
|
||||
public string DicomStudyTime { get; set; }
|
||||
|
||||
public List<AddOrUpdateSeriesDto> SeriesList { get; set; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class AddOrUpdateSeriesDto
|
||||
|
@ -357,12 +351,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
public string TriggerTime { get; set; } = string.Empty;
|
||||
|
||||
public string ImageResizePath { get; set; } = string.Empty;
|
||||
|
||||
public string DicomSeriesDate { get; set; }
|
||||
|
||||
public string DicomSeriesTime { get; set; }
|
||||
|
||||
|
||||
public List<AddInstanceDto> InstanceList { get; set; }
|
||||
|
||||
public Guid? VisitTaskId { get; set; }
|
||||
|
@ -397,17 +385,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
public string HtmlPath { get; set; } = string.Empty;
|
||||
|
||||
public long FileSize { get; set; }
|
||||
|
||||
public string SOPClassUID { get; set; }
|
||||
|
||||
public string MediaStorageSOPClassUID { get; set; }
|
||||
|
||||
public string TransferSytaxUID { get; set; }
|
||||
|
||||
public string MediaStorageSOPInstanceUID { get; set; }
|
||||
|
||||
public bool IsEncapsulated => DicomTransferSyntax.Lookup(DicomUID.Parse(TransferSytaxUID)).IsEncapsulated;
|
||||
|
||||
}
|
||||
|
||||
public class CRCUploadTaskQuery
|
||||
|
@ -525,69 +502,7 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
|
||||
}
|
||||
|
||||
#region 下载重新生成名字
|
||||
public class ImageDownloadDto
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
public Guid SubjectId { get; set; }
|
||||
public string SubjectCode { get; set; }
|
||||
public string TrialSiteCode { get; set; }
|
||||
public string VisitName { get; set; }
|
||||
|
||||
public string TaskBlindName { get; set; }
|
||||
|
||||
|
||||
public Guid VisitId { get; set; }
|
||||
|
||||
public List<DownloadDicomStudyDto> StudyList { get; set; }
|
||||
public List<DownloadNoneDicomStudyDto> NoneDicomStudyList { get; set; }
|
||||
}
|
||||
|
||||
public class DownloadDicomStudyDto
|
||||
{
|
||||
public string PatientId { get; set; }
|
||||
public DateTime? StudyTime { get; set; }
|
||||
public string StudyCode { get; set; }
|
||||
public string StudyInstanceUid { get; set; }
|
||||
public string StudyDIRPath { get; set; }
|
||||
|
||||
public List<DownloadDicomSeriesDto> SeriesList { get; set; }
|
||||
}
|
||||
|
||||
public class DownloadDicomSeriesDto
|
||||
{
|
||||
public string Modality { get; set; }
|
||||
|
||||
public List<DownloadDicomInstanceDto> InstanceList { get; set; }
|
||||
}
|
||||
|
||||
public class DownloadDicomInstanceDto
|
||||
{
|
||||
public bool IsEncapsulated { get; set; }
|
||||
public Guid InstanceId { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public string Path { get; set; }
|
||||
public long? FileSize { get; set; }
|
||||
}
|
||||
|
||||
public class DownloadNoneDicomStudyDto
|
||||
{
|
||||
public string Modality { get; set; }
|
||||
public string StudyCode { get; set; }
|
||||
public DateTime? ImageDate { get; set; }
|
||||
|
||||
public List<DownloadNoneDicomFileDto> FileList { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DownloadNoneDicomFileDto
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
public string Path { get; set; }
|
||||
public string FileType { get; set; }
|
||||
public long? FileSize { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public class CRCUploadedStudyQuqry
|
||||
{
|
||||
|
@ -631,179 +546,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
|
||||
}
|
||||
|
||||
public class TrialKeyImageExportDTO
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string ResearchProgramNo { get; set; }
|
||||
public string CriterionName { get; set; }
|
||||
public ArbitrationRule ArbitrationRule { get; set; }
|
||||
|
||||
public bool IsGlobalReading { get; set; }
|
||||
|
||||
public List<decimal> SubjectCriterionReadingPeriodVisitNumList { get; set; }
|
||||
|
||||
public string TrialSiteCode { get; set; }
|
||||
|
||||
public string VisitName { get; set; }
|
||||
|
||||
public Decimal VisitTaskNum { get; set; }
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
|
||||
public Arm ArmEnum { get; set; }
|
||||
|
||||
public Guid? JudgeResultTaskId { get; set; }
|
||||
|
||||
public bool? IsTrigerJudge { get; set; }
|
||||
public bool? IsJudgeSelect { get; set; }
|
||||
|
||||
public ReadingCategory ReadingCategory { get; set; }
|
||||
|
||||
public List<TrialKeyPicturePath> ReadingNoneDicomMarkPathList { get; set; }
|
||||
public List<TrialKeyPicturePath> QuestionMarkPictureList { get; set; }
|
||||
|
||||
public List<TrialKeyPicturePath> TableQuestionRowPictureList { get; set; }
|
||||
}
|
||||
public class TrialKeyPicturePath
|
||||
{
|
||||
public string PicturePath { get; set; }
|
||||
|
||||
public string OtherPicturePath { get; set; }
|
||||
}
|
||||
public class TrialExportImageCommand
|
||||
{
|
||||
[NotDefault]
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public List<Guid> SubjectVisitIdList { get; set; }
|
||||
|
||||
|
||||
public bool IsKeyImage { get; set; }
|
||||
|
||||
// true 导出阅片,null 就是所有影像
|
||||
public bool? IsExportReading { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class TrialVisitImageQuery : PageInput
|
||||
{
|
||||
[NotDefault]
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
|
||||
public Guid? TrialSiteId { get; set; }
|
||||
|
||||
public string? SubjectCode { get; set; }
|
||||
|
||||
public DateTime? BeginScanDate { get; set; }
|
||||
public DateTime? EndScanDate { get; set; }
|
||||
}
|
||||
public class TrialVisitImageStatView
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public Guid TrialSiteId { get; set; }
|
||||
|
||||
public string TrialSiteCode { get; set; }
|
||||
|
||||
public string SubjectCode { get; set; }
|
||||
|
||||
public string VisitName { get; set; }
|
||||
|
||||
public decimal VisitNum { get; set; }
|
||||
|
||||
public DateTime? EarliestScanDate { get; set; }
|
||||
public DateTime? LatestScanDate { get; set; }
|
||||
|
||||
|
||||
|
||||
public int TotalStudyCount { get; set; }
|
||||
|
||||
public int TotalImageCount { get; set; }
|
||||
|
||||
public long? TotalImageSize { get; set; }
|
||||
|
||||
public long? TotalReadingImageSize { get; set; }
|
||||
|
||||
public string TotalImageSizeStr => TotalImageSize.HasValue
|
||||
? $"{TotalImageSize.Value / 1024d / 1024d:F3} MB"
|
||||
: "0.000 MB";
|
||||
|
||||
public string TotalReadingImageSizeStr => TotalReadingImageSize.HasValue
|
||||
? $"{TotalReadingImageSize.Value / 1024d / 1024d:F3} MB"
|
||||
: "0.000 MB";
|
||||
|
||||
public string ImageTypeStr => $"{(IsHaveDicom ? "DICOM" : "")}{(IsHaveNoneDicom&&IsHaveDicom?" , ":"")}{(IsHaveNoneDicom ? "Non-DICOM" : "")}";
|
||||
|
||||
public bool IsHaveDicom { get; set; }
|
||||
|
||||
public bool IsHaveNoneDicom { get; set; }
|
||||
|
||||
#region 废弃,为了字段排序
|
||||
//public int TotalStudyCount => DicomStudyCount + NoneDicomStudyCount;
|
||||
|
||||
//public int TotalImageCount => DicomImageCount + NoneDicomImageCount;
|
||||
|
||||
//public long? TotalImageSize => DicomImageSize + NoneDicomImageSize;
|
||||
|
||||
//public int DicomStudyCount { get; set; }
|
||||
//public int DicomImageCount { get; set; }
|
||||
//public long? DicomImageSize { get; set; }
|
||||
|
||||
|
||||
//public int NoneDicomStudyCount { get; set; }
|
||||
//public int NoneDicomImageCount { get; set; }
|
||||
//public long? NoneDicomImageSize { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class TrialImageStatInfo
|
||||
{
|
||||
public int SubjectCount { get; set; }
|
||||
|
||||
public int SubjectVisitCount { get; set; }
|
||||
|
||||
public long? TotalImageSize { get; set; }
|
||||
|
||||
|
||||
public string TotalImageSizeStr => TotalImageSize.HasValue
|
||||
? $"{TotalImageSize.Value / 1024d / 1024d:F3} MB"
|
||||
: "0.000 MB";
|
||||
|
||||
|
||||
public string SubjectImageAVGSizeStr => TotalImageSize.HasValue
|
||||
? $"{TotalImageSize.Value / SubjectCount / 1024d / 1024d:F3} MB"
|
||||
: "0.000 MB";
|
||||
|
||||
|
||||
public string SubjectVisitImageAVGSizeStr => TotalImageSize.HasValue
|
||||
? $"{TotalImageSize.Value / SubjectVisitCount / 1024d / 1024d:F3} MB"
|
||||
: "0.000 MB";
|
||||
|
||||
public long? TotalReadingImageSize { get; set; }
|
||||
|
||||
|
||||
public string TotalReadingImageSizeStr => TotalReadingImageSize.HasValue
|
||||
? $"{TotalReadingImageSize.Value / 1024d / 1024d:F3} MB"
|
||||
: "0.000 MB";
|
||||
|
||||
|
||||
public string SubjectReadingImageAVGSizeStr => TotalReadingImageSize.HasValue
|
||||
? $"{TotalReadingImageSize.Value / SubjectCount / 1024d / 1024d:F3} MB"
|
||||
: "0.000 MB";
|
||||
|
||||
|
||||
public string SubjectVisitReadingImageAVGSizeStr => TotalReadingImageSize.HasValue
|
||||
? $"{TotalReadingImageSize.Value / SubjectVisitCount / 1024d / 1024d:F3} MB"
|
||||
: "0.000 MB";
|
||||
|
||||
}
|
||||
public class TrialImageDownloadView
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
|
|
|
@ -1,25 +1,20 @@
|
|||
using DocumentFormat.OpenXml.EMMA;
|
||||
using FellowOakDicom;
|
||||
using FellowOakDicom.Media;
|
||||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
|
||||
using IRaCIS.Core.Application.Filter;
|
||||
using IRaCIS.Core.Application.Helper;
|
||||
using IRaCIS.Core.Application.Service.ImageAndDoc.DTO;
|
||||
using IRaCIS.Core.Application.Service.Reading.Dto;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore.Common;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using MassTransit;
|
||||
using MassTransit.Initializers;
|
||||
using Medallion.Threading;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NetTopologySuite.Mathematics;
|
||||
using Newtonsoft.Json;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using System.Data;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
|
@ -35,7 +30,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
}
|
||||
|
||||
[ApiExplorerSettings(GroupName = "Trial")]
|
||||
public class DownloadAndUploadService(IRepository<SystemAnonymization> _systemAnonymizationRepository, IRepository<DicomStudy> _dicomStudyRepository,
|
||||
public class DownloadAndUploadService(IRepository<SystemAnonymization> _systemAnonymizationRepository,
|
||||
IRepository<VisitTask> _visitTaskRepository,
|
||||
IRepository<SubjectVisit> _subjectVisitRepository,
|
||||
IOSSService _oSSService,
|
||||
|
@ -197,9 +192,6 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
InstanceCount = t.InstanceCount,
|
||||
Modalities = t.Modalities,
|
||||
SeriesCount = t.SeriesCount,
|
||||
|
||||
ReadingInstanceCount = t.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading).Count(),
|
||||
ReadingSeriesCount = t.SeriesList.Where(t => t.IsReading).Count(),
|
||||
}).ToList(),
|
||||
|
||||
UploadStudyList = u.TaskStudyList.Select(t => new StudyBasicInfo()
|
||||
|
@ -219,9 +211,6 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
|
||||
SopInstanceUidList = t.InstanceList.Select(t => t.SopInstanceUid).ToList(),
|
||||
|
||||
ReadingInstanceCount = t.InstanceCount,
|
||||
ReadingSeriesCount = t.SeriesCount,
|
||||
|
||||
}).ToList()
|
||||
})
|
||||
;
|
||||
|
@ -732,9 +721,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
FileName = t.FileName,
|
||||
FileSize = t.FileSize,
|
||||
Path = t.Path
|
||||
}).ToList(),
|
||||
|
||||
ReadingFileCount = ns.FileCount,
|
||||
}).ToList()
|
||||
|
||||
};
|
||||
|
||||
|
@ -782,137 +769,58 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
|
||||
var imageType = (isQueryDicom && isQueryNoneDicom) ? ImageType.DicomAndNoneDicom : (isQueryDicom ? ImageType.Dicom : ImageType.NoneDicom);
|
||||
|
||||
var dirDic = new Dictionary<string, string>();
|
||||
#region DIR处理导出文件名,并将对应关系上传到OSS里面存储
|
||||
|
||||
//有传输语法值的导出 才生成DIR
|
||||
if (_subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId).SelectMany(t => t.StudyList.SelectMany(t => t.InstanceList)).All(c => c.TransferSytaxUID != string.Empty))
|
||||
{
|
||||
var list = _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId).SelectMany(t => t.StudyList)
|
||||
.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
|
||||
.SelectMany(t => t.InstanceList)
|
||||
.Select(t => new StudyDIRInfo()
|
||||
{
|
||||
|
||||
DicomStudyId = t.DicomStudy.Id,
|
||||
|
||||
PatientId = t.DicomStudy.PatientId,
|
||||
PatientName = t.DicomStudy.PatientName,
|
||||
PatientBirthDate = t.DicomStudy.PatientBirthDate,
|
||||
PatientSex = t.DicomStudy.PatientSex,
|
||||
|
||||
StudyInstanceUid = t.StudyInstanceUid,
|
||||
StudyId = t.DicomStudy.StudyId,
|
||||
DicomStudyDate = t.DicomStudy.DicomStudyDate,
|
||||
DicomStudyTime = t.DicomStudy.DicomStudyTime,
|
||||
AccessionNumber = t.DicomStudy.AccessionNumber,
|
||||
|
||||
StudyDescription = t.DicomStudy.Description,
|
||||
|
||||
SeriesInstanceUid = t.DicomSerie.SeriesInstanceUid,
|
||||
Modality = t.DicomSerie.Modality,
|
||||
DicomSeriesDate = t.DicomSerie.DicomSeriesDate,
|
||||
DicomSeriesTime = t.DicomSerie.DicomSeriesTime,
|
||||
SeriesNumber = t.DicomSerie.SeriesNumber,
|
||||
SeriesDescription = t.DicomSerie.Description,
|
||||
|
||||
InstanceId = t.Id,
|
||||
SopInstanceUid = t.SopInstanceUid,
|
||||
SOPClassUID = t.SOPClassUID,
|
||||
InstanceNumber = t.InstanceNumber,
|
||||
MediaStorageSOPClassUID = t.MediaStorageSOPClassUID,
|
||||
MediaStorageSOPInstanceUID = t.MediaStorageSOPInstanceUID,
|
||||
TransferSytaxUID = t.TransferSytaxUID,
|
||||
|
||||
}).ToList();
|
||||
|
||||
var pathInfo = await _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId).Select(t => new { t.TrialId, t.SubjectId, VisitId = t.Id }).FirstNotNullAsync();
|
||||
|
||||
foreach (var item in list.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId }))
|
||||
{
|
||||
var ossFolder = $"{pathInfo.TrialId}/Image/{pathInfo.SubjectId}/{pathInfo.VisitId}/{item.Key.StudyInstanceUid}";
|
||||
|
||||
var isSucess = await SafeBussinessHelper.RunAsync(async () => await DicomDIRHelper.GenerateStudyDIRAndUploadAsync(item.ToList(), dirDic, ossFolder, _oSSService));
|
||||
|
||||
|
||||
if (isSucess)
|
||||
{
|
||||
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/DICOMDIR" });
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
var query = from sv in _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId)
|
||||
|
||||
|
||||
select new ImageDownloadDto()
|
||||
select new
|
||||
{
|
||||
TrialId = sv.TrialId,
|
||||
SubjectId = sv.SubjectId,
|
||||
SubjectCode = sv.Subject.Code,
|
||||
TrialSiteCode = sv.TrialSite.TrialSiteCode,
|
||||
VisitName = sv.VisitName,
|
||||
VisitId = sv.Id,
|
||||
|
||||
StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
|
||||
|
||||
.Select(u => new DownloadDicomStudyDto()
|
||||
.Select(u => new
|
||||
{
|
||||
PatientId = u.PatientId,
|
||||
StudyTime = u.StudyTime,
|
||||
StudyCode = u.StudyCode,
|
||||
StudyInstanceUid = u.StudyInstanceUid,
|
||||
StudyDIRPath = u.StudyDIRPath,
|
||||
u.PatientId,
|
||||
u.StudyTime,
|
||||
u.StudyCode,
|
||||
|
||||
SeriesList = u.SeriesList.Select(z => new DownloadDicomSeriesDto()
|
||||
SeriesList = u.SeriesList.Select(z => new
|
||||
{
|
||||
Modality = z.Modality,
|
||||
z.Modality,
|
||||
|
||||
InstanceList = z.DicomInstanceList.Select(k => new DownloadDicomInstanceDto()
|
||||
InstanceList = z.DicomInstanceList.Select(k => new
|
||||
{
|
||||
IsEncapsulated = k.IsEncapsulated,
|
||||
InstanceId = k.Id,
|
||||
FileName = string.Empty,
|
||||
Path = k.Path,
|
||||
FileSize = k.FileSize
|
||||
}).ToList()
|
||||
}).ToList()
|
||||
k.Path,
|
||||
k.FileSize
|
||||
})
|
||||
})
|
||||
|
||||
}).ToList(),
|
||||
|
||||
NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)
|
||||
|
||||
.Select(nd => new DownloadNoneDicomStudyDto()
|
||||
.Select(nd => new
|
||||
{
|
||||
Modality = nd.Modality,
|
||||
StudyCode = nd.StudyCode,
|
||||
ImageDate = nd.ImageDate,
|
||||
nd.Modality,
|
||||
nd.StudyCode,
|
||||
nd.ImageDate,
|
||||
|
||||
FileList = nd.NoneDicomFileList.Select(file => new DownloadNoneDicomFileDto()
|
||||
FileList = nd.NoneDicomFileList.Select(file => new
|
||||
{
|
||||
FileName = file.FileName,
|
||||
Path = file.Path,
|
||||
FileType = file.FileType,
|
||||
FileSize = file.FileSize
|
||||
}).ToList()
|
||||
file.FileName,
|
||||
file.Path,
|
||||
file.FileType,
|
||||
file.FileSize,
|
||||
})
|
||||
}).ToList()
|
||||
};
|
||||
|
||||
var result = query.FirstOrDefault();
|
||||
|
||||
foreach (var item in result.StudyList.SelectMany(t => t.SeriesList).SelectMany(t => t.InstanceList))
|
||||
{
|
||||
var key = item.InstanceId.ToString();
|
||||
if (dirDic.ContainsKey(key))
|
||||
{
|
||||
item.FileName = dirDic[key];
|
||||
}
|
||||
}
|
||||
|
||||
var preDownloadInfo = new TrialImageDownload()
|
||||
{
|
||||
Id = NewId.NextSequentialGuid(),
|
||||
|
@ -1086,143 +994,59 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
|
||||
var trialSiteCode = _visitTaskRepository.Where(t => t.Id == taskIdList.FirstOrDefault()).Select(t => t.IsAnalysisCreate ? t.BlindTrialSiteCode : t.Subject.TrialSite.TrialSiteCode).FirstOrDefault() ?? string.Empty;
|
||||
|
||||
var dirDic = new Dictionary<string, string>();
|
||||
#region 在下载前先处理DIR文件
|
||||
|
||||
//有传输语法值的导出 才生成DIR
|
||||
if (_subjectVisitRepository.Where(t => t.SubjectId == inQuery.SubjectId).SelectMany(t => t.StudyList.SelectMany(t => t.InstanceList)).All(c => c.TransferSytaxUID != string.Empty))
|
||||
{
|
||||
var dirInfolist = _subjectRepository.Where(t => t.Id == inQuery.SubjectId).SelectMany(t => t.SubjectVisitList.Where(t => subjectVisitIdList.Contains(t.Id))).SelectMany(t => t.StudyList)
|
||||
.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
|
||||
.Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
|
||||
.SelectMany(t => t.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading))
|
||||
.Select(t => new StudyDIRInfo()
|
||||
{
|
||||
SubjectVisitId = t.SubjectVisitId,
|
||||
|
||||
DicomStudyId = t.DicomStudy.Id,
|
||||
|
||||
PatientId = t.DicomStudy.PatientId,
|
||||
PatientName = t.DicomStudy.PatientName,
|
||||
PatientBirthDate = t.DicomStudy.PatientBirthDate,
|
||||
PatientSex = t.DicomStudy.PatientSex,
|
||||
|
||||
StudyInstanceUid = t.StudyInstanceUid,
|
||||
StudyId = t.DicomStudy.StudyId,
|
||||
DicomStudyDate = t.DicomStudy.DicomStudyDate,
|
||||
DicomStudyTime = t.DicomStudy.DicomStudyTime,
|
||||
AccessionNumber = t.DicomStudy.AccessionNumber,
|
||||
|
||||
StudyDescription = t.DicomStudy.Description,
|
||||
|
||||
SeriesInstanceUid = t.DicomSerie.SeriesInstanceUid,
|
||||
Modality = t.DicomSerie.Modality,
|
||||
DicomSeriesDate = t.DicomSerie.DicomSeriesDate,
|
||||
DicomSeriesTime = t.DicomSerie.DicomSeriesTime,
|
||||
SeriesNumber = t.DicomSerie.SeriesNumber,
|
||||
SeriesDescription = t.DicomSerie.Description,
|
||||
|
||||
InstanceId = t.Id,
|
||||
SopInstanceUid = t.SopInstanceUid,
|
||||
SOPClassUID = t.SOPClassUID,
|
||||
InstanceNumber = t.InstanceNumber,
|
||||
MediaStorageSOPClassUID = t.MediaStorageSOPClassUID,
|
||||
MediaStorageSOPInstanceUID = t.MediaStorageSOPInstanceUID,
|
||||
TransferSytaxUID = t.TransferSytaxUID,
|
||||
|
||||
}).ToList();
|
||||
|
||||
var pathInfo = await _subjectRepository.Where(t => t.Id == inQuery.SubjectId).Select(t => new { t.TrialId, SubjectId = t.Id }).FirstNotNullAsync();
|
||||
|
||||
foreach (var item in dirInfolist.GroupBy(t => new { t.StudyInstanceUid, t.DicomStudyId }))
|
||||
{
|
||||
var visitId = item.First().SubjectVisitId;
|
||||
|
||||
var ossFolder = $"{pathInfo.TrialId}/Image/{pathInfo.SubjectId}/{visitId}/{item.Key.StudyInstanceUid}";
|
||||
|
||||
var isSucess = await SafeBussinessHelper.RunAsync(async () => await DicomDIRHelper.GenerateStudyDIRAndUploadAsync(item.ToList(), dirDic, ossFolder, _oSSService));
|
||||
|
||||
|
||||
if (isSucess)
|
||||
{
|
||||
await _dicomStudyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Key.DicomStudyId, u => new DicomStudy() { StudyDIRPath = $"/{ossFolder}/DICOMDIR" });
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubjectId).SelectMany(t => t.SubjectVisitList.Where(t => subjectVisitIdList.Contains(t.Id)))
|
||||
//一致性分析,导致查询出来两条数据
|
||||
join visitTask in _visitTaskRepository.Where(t => taskIdList.Contains(t.Id))
|
||||
|
||||
on sv.Id equals visitTask.SourceSubjectVisitId
|
||||
select new ImageDownloadDto()
|
||||
select new
|
||||
{
|
||||
SubjectCode = inQuery.SubjectCode,
|
||||
VisitName = sv.VisitName,
|
||||
TaskBlindName = visitTask.TaskBlindName,
|
||||
StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id) : false)
|
||||
.Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|") : true)
|
||||
.Select(u => new DownloadDicomStudyDto()
|
||||
.Select(u => new
|
||||
{
|
||||
PatientId = u.PatientId,
|
||||
StudyTime = u.StudyTime,
|
||||
StudyCode = u.StudyCode,
|
||||
StudyInstanceUid = u.StudyInstanceUid,
|
||||
StudyDIRPath = u.StudyDIRPath,
|
||||
u.PatientId,
|
||||
u.StudyTime,
|
||||
u.StudyCode,
|
||||
|
||||
SeriesList = u.SeriesList.Where(t => t.IsReading).Select(z => new DownloadDicomSeriesDto()
|
||||
SeriesList = u.SeriesList.Where(t => t.IsReading).Select(z => new
|
||||
{
|
||||
Modality = z.Modality,
|
||||
z.Modality,
|
||||
|
||||
InstanceList = z.DicomInstanceList.Where(t => t.IsReading).Select(k => new DownloadDicomInstanceDto()
|
||||
InstancePathList = z.DicomInstanceList.Where(t => t.IsReading).Select(k => new
|
||||
{
|
||||
IsEncapsulated = k.IsEncapsulated,
|
||||
InstanceId = k.Id,
|
||||
FileName = string.Empty,
|
||||
Path = k.Path,
|
||||
FileSize = k.FileSize
|
||||
}).ToList()
|
||||
}).ToList()
|
||||
}).ToList(),
|
||||
k.Path,
|
||||
k.FileSize
|
||||
})
|
||||
})
|
||||
|
||||
}),
|
||||
|
||||
NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isQueryNoneDicom ? inQuery.NoneDicomStudyIdList.Contains(t.Id) : false)
|
||||
.Where(t => info.IsImageFilter ? ("|" + info.CriterionModalitys + "|").Contains("|" + t.Modality + "|") : true)
|
||||
.Where(t => t.IsReading)
|
||||
.Select(nd => new DownloadNoneDicomStudyDto()
|
||||
.Select(nd => new
|
||||
{
|
||||
Modality = nd.Modality,
|
||||
StudyCode = nd.StudyCode,
|
||||
ImageDate = nd.ImageDate,
|
||||
nd.Modality,
|
||||
nd.StudyCode,
|
||||
nd.ImageDate,
|
||||
|
||||
FileList = nd.NoneDicomFileList.Where(t => t.IsReading).Select(file => new DownloadNoneDicomFileDto()
|
||||
FileList = nd.NoneDicomFileList.Where(t => t.IsReading).Select(file => new
|
||||
{
|
||||
FileName = file.FileName,
|
||||
Path = file.Path,
|
||||
FileType = file.FileType,
|
||||
FileSize = file.FileSize
|
||||
}).ToList()
|
||||
}).ToList()
|
||||
file.FileName,
|
||||
file.Path,
|
||||
file.FileType,
|
||||
file.FileSize
|
||||
})
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
|
||||
var list = await query.ToListAsync();
|
||||
|
||||
foreach (var result in list)
|
||||
{
|
||||
foreach (var item in result.StudyList.SelectMany(t => t.SeriesList).SelectMany(t => t.InstanceList))
|
||||
{
|
||||
var key = item.InstanceId.ToString();
|
||||
if (dirDic.ContainsKey(key))
|
||||
{
|
||||
item.FileName = dirDic[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var result = await query.ToListAsync();
|
||||
|
||||
|
||||
|
||||
|
@ -1237,17 +1061,17 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
DownloadStartTime = DateTime.Now,
|
||||
IsSuccess = false,
|
||||
ImageType = imageType,
|
||||
VisitName = string.Join(" | ", list.Select(t => t.VisitName).OrderBy(t => t).ToList()),
|
||||
NoneDicomStudyCount = list.Sum(t => t.NoneDicomStudyList.Count()),
|
||||
DicomStudyCount = list.Sum(t => t.StudyList.Count()),
|
||||
ImageCount = list.Sum(t => t.StudyList.Sum(s => s.SeriesList.Sum(s => s.InstanceList.Count())) + t.NoneDicomStudyList.Sum(s => s.FileList.Count())),
|
||||
ImageSize = list.Sum(t => t.StudyList.Sum(t => t.SeriesList.Sum(s => s.InstanceList.Sum(i => i.FileSize))) + t.NoneDicomStudyList.Sum(t => t.FileList.Sum(s => s.FileSize))
|
||||
VisitName = string.Join(" | ", result.Select(t => t.VisitName).OrderBy(t => t).ToList()),
|
||||
NoneDicomStudyCount = result.Sum(t => t.NoneDicomStudyList.Count()),
|
||||
DicomStudyCount = result.Sum(t => t.StudyList.Count()),
|
||||
ImageCount = result.Sum(t => t.StudyList.Sum(s => s.SeriesList.Sum(s => s.InstancePathList.Count())) + t.NoneDicomStudyList.Sum(s => s.FileList.Count())),
|
||||
ImageSize = result.Sum(t => t.StudyList.Sum(t => t.SeriesList.Sum(s => s.InstancePathList.Sum(i => i.FileSize))) + t.NoneDicomStudyList.Sum(t => t.FileList.Sum(s => s.FileSize))
|
||||
) ?? 0
|
||||
};
|
||||
|
||||
await _trialImageDownloadRepository.AddAsync(preDownloadInfo, true);
|
||||
|
||||
return ResponseOutput.Ok(list, new { PreDownloadId = preDownloadInfo.Id, info.IsReadingTaskViewInOrder });
|
||||
return ResponseOutput.Ok(result, new { PreDownloadId = preDownloadInfo.Id, info.IsReadingTaskViewInOrder });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1302,18 +1126,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新后处理上传的检查modality
|
||||
/// </summary>
|
||||
/// <param name="taskStudyId"></param>
|
||||
/// <param name="modality"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPut]
|
||||
public async Task<IResponseOutput> UpdateTaskStudyModality(Guid taskStudyId, string modality)
|
||||
{
|
||||
await _taskStudyRepository.UpdatePartialFromQueryAsync(t => t.Id == taskStudyId, u => new TaskStudy() { ModalityForEdit = modality }, true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 影像下载成功回调
|
||||
|
@ -1350,412 +1163,19 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
return await query.ToPagedListAsync(inQuery);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#region 影像汇总页面
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput<PageOutput<TrialVisitImageStatView>>> GetTrialVisitImageStatList(TrialVisitImageQuery inQuery)
|
||||
{
|
||||
var query = _subjectVisitRepository.Where(t => t.TrialId == inQuery.TrialId)
|
||||
.WhereIf(inQuery.TrialSiteId != null, t => t.TrialSiteId == inQuery.TrialSiteId)
|
||||
.WhereIf(inQuery.SubjectCode.IsNotNullOrEmpty(), t => t.Subject.Code.Contains(inQuery.SubjectCode))
|
||||
.WhereIf(inQuery.BeginScanDate != null, t => t.LatestScanDate >= inQuery.BeginScanDate)
|
||||
.WhereIf(inQuery.EndScanDate != null, t => t.LatestScanDate == inQuery.EndScanDate)
|
||||
.Select(t => new TrialVisitImageStatView()
|
||||
{
|
||||
TrialId = t.TrialId,
|
||||
SubjectVisitId = t.Id,
|
||||
SubjectCode = t.Subject.Code,
|
||||
TrialSiteCode = t.TrialSite.TrialSiteCode,
|
||||
TrialSiteId = t.TrialSiteId,
|
||||
VisitName = t.VisitName,
|
||||
VisitNum = t.VisitNum,
|
||||
EarliestScanDate = t.EarliestScanDate,
|
||||
LatestScanDate = t.LatestScanDate,
|
||||
|
||||
IsHaveDicom = t.StudyList.Any(),
|
||||
|
||||
IsHaveNoneDicom = t.NoneDicomStudyList.Any(),
|
||||
|
||||
|
||||
TotalStudyCount = t.StudyList.Count() + t.NoneDicomStudyList.Count(),
|
||||
|
||||
TotalImageCount = t.StudyList.Sum(t => t.InstanceCount) + t.NoneDicomStudyList.Sum(t => t.FileCount),
|
||||
|
||||
TotalImageSize = t.StudyList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize) + t.NoneDicomStudyList.SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize),
|
||||
|
||||
TotalReadingImageSize = t.StudyList.SelectMany(t => t.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading)).Sum(t => t.FileSize)
|
||||
+ t.NoneDicomStudyList.Where(t => t.IsReading).SelectMany(t => t.NoneDicomFileList.Where(t => t.IsReading)).Sum(t => t.FileSize),
|
||||
|
||||
|
||||
//DicomStudyCount = t.StudyList.Count(),
|
||||
//NoneDicomStudyCount = t.NoneDicomStudyList.Count(),
|
||||
|
||||
//DicomImageCount = t.StudyList.Sum(t => t.InstanceCount),
|
||||
//NoneDicomImageCount = t.NoneDicomStudyList.Sum(t => t.FileCount),
|
||||
|
||||
//DicomImageSize = t.StudyList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize),
|
||||
//NoneDicomImageSize = t.NoneDicomStudyList.SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize)
|
||||
});
|
||||
var defalutSortArray = new string[] { nameof(TrialVisitImageStatView.TrialSiteCode), nameof(QCCRCVisitViewModel.SubjectCode), nameof(QCCRCVisitViewModel.VisitNum) };
|
||||
|
||||
var pagelist = await query.Where(t => t.TotalImageCount > 0).ToPagedListAsync(inQuery, defalutSortArray);
|
||||
|
||||
return ResponseOutput.Ok(pagelist);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取项目影像统计,有影像的subject 数量 访视数量
|
||||
/// 更新后处理上传的检查modality
|
||||
/// </summary>
|
||||
/// <param name="trialId"></param>
|
||||
/// <param name="taskStudyId"></param>
|
||||
/// <param name="modality"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<IResponseOutput<TrialImageStatInfo>> GetTrialVisitImageStatInfo(Guid trialId)
|
||||
[HttpPut]
|
||||
public async Task<IResponseOutput> UpdateTaskStudyModality(Guid taskStudyId, string modality)
|
||||
{
|
||||
var subjectImageList = _subjectVisitRepository.Where(t => t.TrialId == trialId)
|
||||
.Where(t => t.StudyList.Sum(t => t.InstanceCount) > 0 || t.NoneDicomStudyList.Sum(t => t.FileCount) > 0)
|
||||
.GroupBy(t => t.SubjectId)
|
||||
.Select(g => new
|
||||
{
|
||||
SubjectId = g.Key,
|
||||
VisitCount = g.Count(),
|
||||
ReadingImageSize = g.SelectMany(t => t.NoneDicomStudyList.Where(t => t.IsReading)).SelectMany(t => t.NoneDicomFileList.Where(t => t.IsReading)).Sum(t => t.FileSize)
|
||||
|
||||
+ g.SelectMany(t => t.StudyList).SelectMany(t => t.InstanceList.Where(t => t.IsReading && t.DicomSerie.IsReading)).Sum(t => t.FileSize),
|
||||
|
||||
ImageSize = g.SelectMany(t => t.NoneDicomStudyList).SelectMany(t => t.NoneDicomFileList).Sum(t => t.FileSize)
|
||||
|
||||
+ g.SelectMany(t => t.StudyList).SelectMany(t => t.InstanceList).Sum(t => t.FileSize)
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var subjectCount = subjectImageList.Count;
|
||||
|
||||
var subjectVisitCount = subjectImageList.Sum(t => t.VisitCount);
|
||||
|
||||
var totalImageSize = subjectImageList.Sum(t => t.ImageSize);
|
||||
|
||||
var totalReadingImageSize = subjectImageList.Sum(t => t.ReadingImageSize);
|
||||
|
||||
return ResponseOutput.Ok(new TrialImageStatInfo { SubjectCount = subjectCount, SubjectVisitCount = subjectVisitCount, TotalImageSize = totalImageSize, TotalReadingImageSize = totalReadingImageSize });
|
||||
|
||||
|
||||
await _taskStudyRepository.UpdatePartialFromQueryAsync(t => t.Id == taskStudyId, u => new TaskStudy() { ModalityForEdit = modality }, true);
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量勾选访视 进行下载
|
||||
/// </summary>
|
||||
/// <param name="inCommand"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> GetExportSubjectVisitImageList(TrialExportImageCommand inCommand)
|
||||
{
|
||||
|
||||
var isExportReading = inCommand.IsExportReading == true;
|
||||
|
||||
if (inCommand.IsKeyImage)
|
||||
{
|
||||
var downloadInfoList = _visitTaskRepository.Where(t => t.TrialId == inCommand.TrialId && (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Global)
|
||||
&& t.ReadingTaskState == ReadingTaskState.HaveSigned && t.IsAnalysisCreate == false && (t.TaskState == TaskState.Effect || t.TaskState == TaskState.Freeze))
|
||||
.Where(t => inCommand.SubjectVisitIdList.Contains((Guid)t.SourceSubjectVisitId))
|
||||
.Select(t => new TrialKeyImageExportDTO()
|
||||
{
|
||||
ResearchProgramNo = t.Trial.ResearchProgramNo,
|
||||
CriterionName = t.TrialReadingCriterion.CriterionName,
|
||||
ArbitrationRule = t.TrialReadingCriterion.ArbitrationRule,
|
||||
IsGlobalReading = t.TrialReadingCriterion.IsGlobalReading,
|
||||
SubjectCriterionReadingPeriodVisitNumList = t.Subject.ReadModuleList
|
||||
.Where(u => u.TrialReadingCriterionId == t.TrialReadingCriterionId && u.ReadingSetType == ReadingSetType.ImageReading).Select(c => c.SubjectVisit.VisitNum).ToList(),
|
||||
|
||||
TrialSiteCode = t.Subject.TrialSite.TrialSiteCode,
|
||||
SubjectCode = t.Subject.Code,
|
||||
|
||||
ReadingCategory = t.ReadingCategory,
|
||||
|
||||
VisitName = t.ReadingCategory == ReadingCategory.Visit ? t.SourceSubjectVisit.VisitName : "",
|
||||
|
||||
VisitTaskNum = t.VisitTaskNum,
|
||||
|
||||
ArmEnum = t.ArmEnum,
|
||||
|
||||
ReadingNoneDicomMarkPathList = t.ReadingNoneDicomMarkList.Select(c => new TrialKeyPicturePath { PicturePath = c.Path, OtherPicturePath = string.Empty }).ToList(),
|
||||
|
||||
QuestionMarkPictureList = t.ReadingTaskQuestionMarkList.Select(c => new TrialKeyPicturePath { PicturePath = c.PicturePath, OtherPicturePath = c.OtherPicturePath }).ToList(),
|
||||
|
||||
TableQuestionRowPictureList = t.LesionList.Select(c => new TrialKeyPicturePath { PicturePath = c.PicturePath, OtherPicturePath = c.OtherPicturePath }).ToList(),
|
||||
|
||||
Id = t.Id,
|
||||
//裁判选择结果
|
||||
JudgeResultTaskId = t.JudgeVisitTask.JudgeResultTaskId,
|
||||
|
||||
//是否触发裁判
|
||||
IsTrigerJudge = t.JudgeVisitTaskId != null,
|
||||
|
||||
IsJudgeSelect = null
|
||||
|
||||
|
||||
}).ToList();
|
||||
|
||||
foreach (var subjectCriterionGroup in downloadInfoList.GroupBy(t => new { t.SubjectCode, t.CriterionName, t.ArbitrationRule, t.IsGlobalReading }))
|
||||
{
|
||||
var arbitrationRule = subjectCriterionGroup.Key.ArbitrationRule;
|
||||
var isGlobalReading = subjectCriterionGroup.Key.IsGlobalReading;
|
||||
|
||||
foreach (var item in subjectCriterionGroup)
|
||||
{
|
||||
if (arbitrationRule == ArbitrationRule.Visit)
|
||||
{
|
||||
//是否产生裁判
|
||||
|
||||
if (item.IsTrigerJudge == true)
|
||||
{
|
||||
//裁判做完了
|
||||
if (item.JudgeResultTaskId != null)
|
||||
{
|
||||
//裁判选择了自己,那么设置
|
||||
if (item.JudgeResultTaskId == item.Id)
|
||||
{
|
||||
item.IsJudgeSelect = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.IsJudgeSelect = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//没产生 且两个人做完了 默认R1
|
||||
|
||||
if (subjectCriterionGroup.Where(t => t.VisitTaskNum == item.VisitTaskNum && t.SubjectCode == item.SubjectCode).Select(t => t.ArmEnum).Distinct().Count() == 2)
|
||||
{
|
||||
if (item.ArmEnum == Arm.DoubleReadingArm1)
|
||||
{
|
||||
item.IsJudgeSelect = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.IsJudgeSelect = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if (arbitrationRule == ArbitrationRule.Reading)
|
||||
{
|
||||
|
||||
//阅片期访视号
|
||||
var subjectReadingPeriondVisitNumList = subjectCriterionGroup.FirstOrDefault()?.SubjectCriterionReadingPeriodVisitNumList;
|
||||
|
||||
//两个人完成最大得任务号(访视+全局)
|
||||
var subjectMaxFinishedTaskNum = subjectCriterionGroup.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).DefaultIfEmpty().Max();
|
||||
|
||||
var addReadingPeriodNum = isGlobalReading ? ReadingCommon.TaskNumDic[ReadingCategory.Global] : 0;
|
||||
|
||||
//可能没有配置阅片期 ,或者配置了 没有完成
|
||||
var finishedGlobalCount = 0;
|
||||
|
||||
var globalFinishedVisitTaskNumList = new List<decimal>();
|
||||
|
||||
//没有配置阅片期
|
||||
if (subjectReadingPeriondVisitNumList == null)
|
||||
{
|
||||
finishedGlobalCount = 0;
|
||||
}
|
||||
{
|
||||
globalFinishedVisitTaskNumList = subjectCriterionGroup.Where(t => subjectReadingPeriondVisitNumList.Any(c => (c + addReadingPeriodNum) == t.VisitTaskNum))
|
||||
.Select(t => new { t.VisitTaskNum, t.ArmEnum }).Distinct()
|
||||
.GroupBy(t => t.VisitTaskNum).Where(g => g.Count() == 2).Select(g => g.Key).ToList();
|
||||
|
||||
finishedGlobalCount = globalFinishedVisitTaskNumList.Count();
|
||||
|
||||
}
|
||||
|
||||
if (finishedGlobalCount != 0)
|
||||
{
|
||||
//最大的完成的全局是否产生裁判
|
||||
|
||||
var maxFinishedGlobalNum = globalFinishedVisitTaskNumList.Max();
|
||||
|
||||
var globalMaxTask = subjectCriterionGroup.FirstOrDefault(t => t.VisitTaskNum == maxFinishedGlobalNum);
|
||||
|
||||
// 触发了裁判
|
||||
if (globalMaxTask.IsTrigerJudge == true)
|
||||
{
|
||||
//最大裁判完成了
|
||||
|
||||
var maxJudgeVisitTaskNum = maxFinishedGlobalNum + ReadingCommon.TaskNumDic[ReadingCategory.Judge];
|
||||
|
||||
if (globalMaxTask.JudgeResultTaskId != null)
|
||||
{
|
||||
|
||||
var maxJudgeArmEnum = subjectCriterionGroup.Where(t => t.Id == globalMaxTask.JudgeResultTaskId).FirstOrDefault().ArmEnum;
|
||||
|
||||
if (item.VisitTaskNum < maxJudgeVisitTaskNum)
|
||||
{
|
||||
//触发裁判
|
||||
item.IsTrigerJudge = true;
|
||||
|
||||
if (item.ArmEnum == maxJudgeArmEnum)
|
||||
{
|
||||
item.IsJudgeSelect = true;
|
||||
}
|
||||
//裁判没选择的人设置为false
|
||||
else
|
||||
{
|
||||
item.IsJudgeSelect = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//最大的裁判未完成
|
||||
|
||||
//找到当前未阅最大裁判之前的已完成的最大裁判任务
|
||||
|
||||
var finishedGlobalFinishedMaxJudge = subjectCriterionGroup.Where(t => globalFinishedVisitTaskNumList.Contains(t.VisitTaskNum) && t.IsTrigerJudge == true && t.JudgeResultTaskId != null).OrderByDescending(t => t.VisitTaskNum).FirstOrDefault();
|
||||
|
||||
|
||||
//未完成裁判之前 没有已完成的全局裁判
|
||||
if (finishedGlobalFinishedMaxJudge == null)
|
||||
{
|
||||
if (item.VisitTaskNum < maxJudgeVisitTaskNum)
|
||||
{
|
||||
item.IsTrigerJudge = true;
|
||||
//item.IsJudgeSelect = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
var maxFinishedJudgeVisitTaskNum = finishedGlobalFinishedMaxJudge.VisitTaskNum + +ReadingCommon.TaskNumDic[ReadingCategory.Judge];
|
||||
|
||||
var maxFinishedJudgeArmEnum = subjectCriterionGroup.Where(t => t.Id == finishedGlobalFinishedMaxJudge.JudgeResultTaskId).FirstOrDefault().ArmEnum;
|
||||
|
||||
if (item.VisitTaskNum < maxFinishedJudgeVisitTaskNum)
|
||||
{
|
||||
item.IsTrigerJudge = true;
|
||||
|
||||
if (item.ArmEnum == maxFinishedJudgeArmEnum)
|
||||
{
|
||||
item.IsJudgeSelect = true;
|
||||
}
|
||||
//裁判没选择的人设置为false
|
||||
else
|
||||
{
|
||||
item.IsJudgeSelect = false;
|
||||
}
|
||||
}
|
||||
else if (item.VisitTaskNum > maxFinishedJudgeVisitTaskNum && item.VisitTaskNum < maxJudgeVisitTaskNum)
|
||||
{
|
||||
//完成裁判 和未完成裁判之间的 裁判选择标记默认是null
|
||||
|
||||
item.IsTrigerJudge = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
//在未完成全局裁判之后的访视 未知 都是null
|
||||
|
||||
item.IsTrigerJudge = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//最大的全局未产生裁判
|
||||
|
||||
if (item.VisitTaskNum <= maxFinishedGlobalNum)
|
||||
{
|
||||
item.IsTrigerJudge = false;
|
||||
|
||||
if (item.ArmEnum == Arm.DoubleReadingArm1)
|
||||
{
|
||||
item.IsJudgeSelect = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
item.IsJudgeSelect = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
downloadInfoList = downloadInfoList.Where(t => t.ReadingCategory == ReadingCategory.Visit).ToList();
|
||||
return ResponseOutput.Ok(downloadInfoList);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var downloadInfo = _trialRepository.Where(t => t.Id == inCommand.TrialId).Select(t => new
|
||||
{
|
||||
t.ResearchProgramNo,
|
||||
|
||||
VisitList = t.SubjectVisitList.Where(t => inCommand.SubjectVisitIdList.Contains(t.Id)).Select(sv => new
|
||||
{
|
||||
TrialSiteCode = sv.TrialSite.TrialSiteCode,
|
||||
SubjectCode = sv.Subject.Code,
|
||||
VisitName = sv.VisitName,
|
||||
StudyList = sv.StudyList.Select(u => new
|
||||
{
|
||||
u.PatientId,
|
||||
u.StudyTime,
|
||||
u.StudyCode,
|
||||
|
||||
SeriesList = u.SeriesList.Where(t => isExportReading ? t.IsReading : true).Select(z => new
|
||||
{
|
||||
z.Modality,
|
||||
|
||||
InstancePathList = z.DicomInstanceList.Where(t => isExportReading ? t.IsReading : true).Select(k => new
|
||||
{
|
||||
k.Path
|
||||
})
|
||||
})
|
||||
|
||||
}),
|
||||
|
||||
NoneDicomStudyList = sv.NoneDicomStudyList.Where(t => isExportReading ? t.IsReading : true).Select(nd => new
|
||||
{
|
||||
nd.Modality,
|
||||
nd.StudyCode,
|
||||
nd.ImageDate,
|
||||
|
||||
FileList = nd.NoneDicomFileList.Where(t => isExportReading ? t.IsReading : true).Select(file => new
|
||||
{
|
||||
file.FileName,
|
||||
file.Path,
|
||||
file.FileType
|
||||
})
|
||||
})
|
||||
}).ToList()
|
||||
|
||||
}).FirstOrDefault();
|
||||
|
||||
|
||||
return ResponseOutput.Ok(downloadInfo);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
|
||||
#region 之前后端下载废弃
|
||||
|
||||
|
|
|
@ -29,14 +29,7 @@ namespace IRaCIS.Core.Application.Services
|
|||
.OrderBy(s => s.InstanceNumber).ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
|
||||
.ProjectTo<DicomInstanceDTO>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
|
||||
var seriesInfo = await _instanceRepository.Where(s => s.SeriesId == seriesId).Select(t => new
|
||||
{
|
||||
t.DicomSerie.ImageResizePath,
|
||||
t.DicomSerie.IsDeleted,
|
||||
t.DicomSerie.IsReading,
|
||||
SubjectCode = t.DicomSerie.SubjectVisit.Subject.Code,
|
||||
t.DicomSerie.SubjectVisit.VisitName
|
||||
}).FirstOrDefaultAsync();
|
||||
var seriesInfo = await _instanceRepository.Where(s => s.SeriesId == seriesId).Select(t => new { t.DicomSerie.ImageResizePath,t.DicomSerie.IsDeleted,t.DicomSerie.IsReading }).FirstOrDefaultAsync();
|
||||
|
||||
return ResponseOutput.Ok(list, seriesInfo);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
Task<PageOutput<UnionStudyMonitorModel>> GetDicomAndNoneDicomStudyMonitorList(StudyQuery studyQuery);
|
||||
(List<string> SeriesInstanceUid, List<string> SopInstanceUid) GetHasUploadSeriesAndInstance(Guid studyId);
|
||||
DicomTrialSiteSubjectInfo GetSaveToDicomInfo(Guid subjectVisitId);
|
||||
IResponseOutput<DicomStudyDTO> Item(Guid studyId,bool? isPacs);
|
||||
IResponseOutput<DicomStudyDTO> Item(Guid studyId);
|
||||
Task<FileContentResult> Preview(Guid studyId);
|
||||
//IResponseOutput<List<VerifyStudyUploadResult>> VerifyStudyAllowUpload(VerifyUploadOrReupload verifyInfo);
|
||||
}
|
||||
|
|
|
@ -75,19 +75,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
}
|
||||
|
||||
|
||||
[HttpPut]
|
||||
public async Task<IResponseOutput> UpdateNoneDicomStudy(NoneDicomEdit noneDicomEdit)
|
||||
{
|
||||
if (_subjectVisitRepository.Any(t => t.Id == noneDicomEdit.SubjectVisitId && (t.PreliminaryAuditUserId == _userInfo.UserRoleId || t.ReviewAuditUserId == _userInfo.UserRoleId)))
|
||||
{
|
||||
await _noneDicomStudyRepository.UpdateFromDTOAsync(noneDicomEdit);
|
||||
await _noneDicomStudyRepository.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
[UnitOfWork]
|
||||
[TrialGlobalLimit("AfterStopCannNotOpt")]
|
||||
public async Task<IResponseOutput<NoneDicomStudyAddReturnDto>> AddOrUpdateNoneDicomStudy(NoneDicomStudyAddOrEdit addOrEditNoneDicomStudy)
|
||||
|
|
|
@ -11,8 +11,6 @@ namespace IRaCIS.Core.Application.Services
|
|||
[AllowAnonymous]
|
||||
public class SeriesService(IRepository<DicomSeries> _seriesRepository,
|
||||
IRepository<DicomInstance> _instanceRepository,
|
||||
IRepository<SCPSeries> _scpSeriesRepository,
|
||||
IRepository<SCPInstance> _scpInstanceRepository,
|
||||
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IWebHostEnvironment _hostEnvironment) : BaseService
|
||||
{
|
||||
|
||||
|
@ -24,44 +22,7 @@ namespace IRaCIS.Core.Application.Services
|
|||
/// <param name="studyId"> Dicom检查的Id </param>
|
||||
/// <param name="isReading"></param>
|
||||
[HttpGet, Route("{studyId:guid}")]
|
||||
public async Task<IResponseOutput<List<DicomSeriesDTO>>> List(Guid studyId, bool? isReading, bool? isPacs)
|
||||
{
|
||||
if (isPacs == true)
|
||||
{
|
||||
var seriesList = await _scpSeriesRepository.Where(s => s.StudyId == studyId).IgnoreQueryFilters()
|
||||
.OrderBy(s => s.SeriesNumber).ThenBy(s => s.SeriesTime).ThenBy(s => s.CreateTime)
|
||||
.ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
|
||||
|
||||
var instanceList = await _scpInstanceRepository.Where(s => s.StudyId == studyId).IgnoreQueryFilters()
|
||||
.OrderBy(t => t.SeriesId).ThenBy(t => t.InstanceNumber)
|
||||
.ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
|
||||
.Select(t => new { t.SeriesId, t.Id, t.Path, t.NumberOfFrames, t.InstanceNumber, t.FileSize }).ToListAsync();//.GroupBy(u => u.SeriesId);
|
||||
|
||||
|
||||
foreach (var series in seriesList)
|
||||
{
|
||||
|
||||
series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k =>
|
||||
new InstanceBasicInfo()
|
||||
{
|
||||
Id = k.Id,
|
||||
NumberOfFrames = k.NumberOfFrames,
|
||||
HtmlPath = string.Empty,
|
||||
Path = k.Path,
|
||||
InstanceNumber = k.InstanceNumber,
|
||||
IsReading = true,
|
||||
IsDeleted = false,
|
||||
FileSize = k.FileSize
|
||||
|
||||
}).ToList();
|
||||
|
||||
series.InstanceCount = series.InstanceInfoList.Count;
|
||||
}
|
||||
|
||||
return ResponseOutput.Ok(seriesList);
|
||||
|
||||
}
|
||||
else
|
||||
public async Task<IResponseOutput<List<DicomSeriesDTO>>> List(Guid studyId, bool? isReading)
|
||||
{
|
||||
//质控的时候,要标记序列,和instance 删除 ,所以要返回全部,但是 质控通过后,pm 进去看的时候要看过滤后的
|
||||
|
||||
|
@ -105,15 +66,60 @@ namespace IRaCIS.Core.Application.Services
|
|||
series.InstanceCount = series.InstanceInfoList.Count;
|
||||
}
|
||||
|
||||
#region 暂时废弃
|
||||
|
||||
//bool hasKeyInstance = false;
|
||||
//var SeriesIdList = _imageLabelRepository.Where(u => u.TpCode == tpCode).Select(s => s.SeriesId).Distinct().ToList();
|
||||
//var instanceIdList = _imageLabelRepository.Where(u => u.TpCode == tpCode).Select(s => s.InstanceId).Distinct().ToList();
|
||||
//foreach (var item in seriesList)
|
||||
//{
|
||||
// if (SeriesIdList.Contains(item.Id))
|
||||
// {
|
||||
// item.HasLabel = true;
|
||||
// hasKeyInstance = true;
|
||||
// }
|
||||
// else item.HasLabel = false;
|
||||
//}
|
||||
//if (hasKeyInstance)
|
||||
//{
|
||||
// seriesList.Add(new DicomSeriesWithLabelDTO
|
||||
// {
|
||||
// KeySeries = true,
|
||||
// Id = SeriesIdList[0],
|
||||
// InstanceCount = instanceIdList.Count,
|
||||
// HasLabel = true,
|
||||
// Modality = seriesList[0].Modality,
|
||||
// Description = "Key Series"
|
||||
// });
|
||||
//}
|
||||
|
||||
//var idList = await _instanceRepository.Where(s => s.StudyId == studyId).OrderBy(t => t.SeriesId).ThenBy(t => t.InstanceNumber)
|
||||
// .ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
|
||||
// .Select(t => new { t.SeriesId, t.Id, t.Path }).ToListAsync();//.GroupBy(u => u.SeriesId);
|
||||
|
||||
//foreach (var item in seriesList)
|
||||
//{
|
||||
// if (item.KeySeries)
|
||||
// {
|
||||
// item.InstanceList = instanceIdList;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //item.InstanceList = idList.Where(s => s.SeriesId == item.Id).OrderBy(t => t.InstanceNumber)
|
||||
// // .ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime).Select(u => u.Id).ToList();
|
||||
|
||||
// item.InstanceList = idList.Where(s => s.SeriesId == item.Id).Select(u => u.Id).ToList();
|
||||
|
||||
// item.InstancePathList = idList.Where(s => s.SeriesId == item.Id).Select(u => u.Path).ToList();
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
return ResponseOutput.Ok(seriesList);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,11 +15,11 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
public class StudyService(IRepository<SubjectVisit> _subjectVisitRepository,
|
||||
IRepository<DicomInstance> _dicomInstanceRepository,
|
||||
IRepository<DicomSeries> _dicomSeriesRepository,
|
||||
IRepository<DicomStudy> _dicomStudyRepository,
|
||||
IRepository<DicomStudy> _dicomstudyRepository,
|
||||
IRepository<Dictionary> _dictionaryRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
IRepository<VisitTask> _visitTaskRepository,
|
||||
IRepository<SCPStudy> _scpStudyRepository,
|
||||
IRepository<DicomStudy> _dicomStudyRepository,
|
||||
IRepository<Subject> _subjectRepository,
|
||||
IRepository<StudyMonitor> _studyMonitorRepository,
|
||||
IRepository<SystemAnonymization> _systemAnonymizationRepository,
|
||||
|
@ -159,7 +159,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
studyMonitor.FileSize = incommand.Study.SeriesList.SelectMany(t => t.InstanceList).Sum(t => t.FileSize);
|
||||
|
||||
var studyId = IdentifierHelper.CreateGuid(incommand.Study.StudyInstanceUid, incommand.TrialId.ToString());
|
||||
var findStudy = await _dicomStudyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
|
||||
var findStudy = await _dicomstudyRepository.FirstOrDefaultAsync(t => t.Id == studyId);
|
||||
|
||||
studyMonitor.StudyId = studyId;
|
||||
studyMonitor.StudyCode = findStudy?.StudyCode ?? "";
|
||||
|
@ -183,7 +183,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
using (await @lock.AcquireAsync())
|
||||
{
|
||||
//查询数据库获取最大的Code 没有记录则为0
|
||||
var dbStudyCodeIntMax = _dicomStudyRepository.Where(s => s.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max();
|
||||
var dbStudyCodeIntMax = _dicomstudyRepository.Where(s => s.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max();
|
||||
|
||||
//获取缓存中的值 并发的时候,需要记录,已被占用的值 这样其他线程在此占用的最大的值上递增
|
||||
var cacheMaxCodeInt = await _fusionCache.GetOrDefaultAsync<int>(CacheKeys.TrialStudyMaxCode(trialId));
|
||||
|
@ -213,7 +213,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
SpecialArchiveStudyDeal(addStudy);
|
||||
modalitys = addStudy.Modalities;
|
||||
|
||||
await _dicomStudyRepository.AddAsync(addStudy);
|
||||
await _dicomstudyRepository.AddAsync(addStudy);
|
||||
|
||||
|
||||
|
||||
|
@ -628,17 +628,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
|
|||
/// <param name="studyId"> Dicom检查的Id </param>
|
||||
[HttpGet, Route("{studyId:guid}")]
|
||||
[AllowAnonymous]
|
||||
public IResponseOutput<DicomStudyDTO> Item(Guid studyId,bool? isPacs)
|
||||
{
|
||||
if (isPacs == true)
|
||||
{
|
||||
return ResponseOutput.Ok(_mapper.Map<DicomStudyDTO>(_scpStudyRepository.Where().FirstOrDefault(s => s.Id == studyId)));
|
||||
}
|
||||
else
|
||||
public IResponseOutput<DicomStudyDTO> Item(Guid studyId)
|
||||
{
|
||||
return ResponseOutput.Ok(_mapper.Map<DicomStudyDTO>(_dicomStudyRepository.Where().FirstOrDefault(s => s.Id == studyId)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -89,9 +89,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
CreateMap<DicomInstance, DicomInstanceDTO>()
|
||||
.ForMember(o => o.SliceThickness, t => t.MapFrom(u => u.DicomSerie.SliceThickness));
|
||||
CreateMap<DicomStudy, DicomStudyDTO>();
|
||||
CreateMap<DicomSeries, DicomSeriesDTO>()
|
||||
.ForMember(o => o.SubjectCode, t => t.MapFrom(u => u.SubjectVisit.Subject.Code))
|
||||
.ForMember(o => o.VisitName, t => t.MapFrom(u => u.SubjectVisit.VisitName));
|
||||
CreateMap<DicomSeries, DicomSeriesDTO>();
|
||||
CreateMap<SCPSeries, DicomSeriesDTO>();
|
||||
|
||||
|
||||
|
@ -154,11 +152,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
.ForMember(d => d.TrialSiteCode, u => u.MapFrom(s => s.Subject.TrialSite.TrialSiteCode))
|
||||
;
|
||||
|
||||
CreateMap<SCPStudy, DicomStudyDTO>();
|
||||
CreateMap<SCPSeries, DicomSeriesDTO>();
|
||||
|
||||
CreateMap<NoneDicomEdit, NoneDicomStudy>();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -351,8 +351,6 @@ namespace IRaCIS.Core.Application.Service.Inspection.DTO
|
|||
|
||||
public class GetDataInspectionOutDto : DataInspection
|
||||
{
|
||||
public bool IsShow { get; set; }
|
||||
|
||||
public string TrialReadingCriterionName { get; set; }
|
||||
public string BlindName { get; set; }
|
||||
|
||||
|
@ -424,47 +422,11 @@ namespace IRaCIS.Core.Application.Service.Inspection.DTO
|
|||
public bool isAbandon { get; set; }
|
||||
}
|
||||
|
||||
public class GetTrialShowInspectionOutDto
|
||||
{
|
||||
public Guid FrontAuditConfigId { get; set; }
|
||||
|
||||
public Guid? ParentId { get; set; }
|
||||
|
||||
public int Sort { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
|
||||
public string DescriptionCN { get; set; }
|
||||
|
||||
public bool IsShow { get; set; }
|
||||
|
||||
public List<GetTrialShowInspectionOutDto> Children { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class SetTrialShowInspection
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
|
||||
public List<TrialShowInspection> TrialShowInspectionList { get; set; }
|
||||
}
|
||||
|
||||
public class TrialShowInspection
|
||||
{
|
||||
public Guid FrontAuditConfigId { get; set; }
|
||||
|
||||
public bool IsShow { get; set; }
|
||||
}
|
||||
|
||||
public class GetTrialShowInspectionInDto
|
||||
{
|
||||
public Guid TrialId { get; set; }
|
||||
}
|
||||
public class GetDataInspectionDto : PageInput
|
||||
{
|
||||
|
||||
|
||||
public Guid? FrontAuditConfigId { get; set; }
|
||||
/// <summary>
|
||||
/// 项目iD
|
||||
/// </summary>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
using IRaCIS.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Interfaces;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Domain.Models;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infra.EFCore.Common;
|
||||
using MassTransit;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -29,7 +29,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
IRepository<QCChallenge> _qCChallengeRepository,
|
||||
IRepository<Dictionary> _dictionaryRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
IRepository<TrialAuditShow> _trialAuditShowRepository,
|
||||
IRepository<UserRole> _userRoleRepository,
|
||||
|
||||
IRepository<CheckChallengeDialog> _checkChallengeDialogRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IFrontAuditConfigService
|
||||
|
@ -229,8 +228,8 @@ namespace IRaCIS.Core.Application.Service
|
|||
jsonDict.Add(nameof(InspectionJsonDetail.CommonData), new { });
|
||||
}
|
||||
|
||||
//查询关联父层级数据 现在都查询
|
||||
if (1==1)
|
||||
//查询关联父层级数据
|
||||
if (item.Id == currentInspectionId)
|
||||
{
|
||||
//把父层级的数据的 CommonData 数据合并(每一个层级把下面层级需要的数据放在CommonData 里面) 麻烦点是每个层级都需要记录一些信息,而且名称不能重复
|
||||
|
||||
|
@ -364,7 +363,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
var relationParentInspection = await _dataInspectionRepository.Where(t => t.GeneralId == objectRelationParentId && (t.CreateTime <= createTime || t.BatchId == batchId) && t.Id != id).OrderByDescending(x => x.CreateTime).Select(t => new { t.ObjectRelationParentId, t.CreateTime, t.JsonDetail, t.BatchId, t.ObjectRelationParentId2, t.ObjectRelationParentId3, t.EntityName, t.Id }).FirstOrDefaultAsync();
|
||||
|
||||
|
||||
if (relationParentInspection != null && relationParentInspection.EntityName!="UserRole")
|
||||
if (relationParentInspection != null)
|
||||
{
|
||||
|
||||
Dictionary<string, object> jsonDic = (JsonConvert.DeserializeObject<Dictionary<string, object>>(relationParentInspection.JsonDetail)).IfNullThrowConvertException();
|
||||
|
@ -400,7 +399,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
//用户的数据稽查没有 临时处理
|
||||
|
||||
|
||||
var userObj = await _userRoleRepository.Where(t => t.Id == objectRelationParentId).Select(t => new { UserRealName = t.IdentityUser.FullName, t.IdentityUser.Phone, t.IdentityUser.UserName, UserType = t.UserTypeRole.UserTypeShortName,t.UserTypeEnum, t.IdentityUser.EMail, t.IdentityUser.OrganizationName }).FirstOrDefaultAsync();
|
||||
var userObj = await _userRoleRepository.Where(t => t.Id == objectRelationParentId).Select(t => new { UserRealName = t.IdentityUser.FullName, t.IdentityUser.Phone, t.IdentityUser.UserName, UserType = t.UserTypeRole.UserTypeShortName, t.IdentityUser.EMail, t.IdentityUser.OrganizationName }).FirstOrDefaultAsync();
|
||||
|
||||
if (userObj != null)
|
||||
{
|
||||
|
@ -1135,82 +1134,18 @@ namespace IRaCIS.Core.Application.Service
|
|||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模块类型列表
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<object> GetModuleTypeList(GetModuleTypeListInDto inDto)
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
var allfront = await (from data in _frontAuditConfigRepository.Where(x=>x.IsEnable && x.ConfigType == "M")
|
||||
join dic in _dictionaryRepository.Where(x => x.Parent.Code == "ModuleType" && x.IsEnable) on data.ModuleTypeId equals dic.Id
|
||||
join trialshow in _trialAuditShowRepository.Where(x => x.TrialId == inDto.TrialId) on data.Id equals trialshow.FrontAuditConfigId into trialshowtemp
|
||||
from lefttrialshow in trialshowtemp.DefaultIfEmpty()
|
||||
select new ModuleTypeData()
|
||||
{
|
||||
IsShow = lefttrialshow == null ? data.IsDefaultChoice : lefttrialshow.IsShow,
|
||||
Id = data.Id,
|
||||
ParentId = data.ParentId,
|
||||
DictionaryId = dic.Id,
|
||||
ShowOrder= dic.ShowOrder,
|
||||
DictionaryValue = _userInfo.IsEn_Us ? dic.Value : dic.ValueCN,
|
||||
}).ToListAsync();
|
||||
|
||||
var result = allfront.Where(x => x.IsShow && x.ParentId!=null).ToList();
|
||||
FindParent(result, result.Select(x => x.ParentId).ToList());
|
||||
void FindParent(List<ModuleTypeData> re, List<Guid?> Parentids)
|
||||
{
|
||||
|
||||
var parentList = allfront.Where(x => Parentids.Contains(x.Id)).ToList();
|
||||
if (parentList.Count > 0)
|
||||
{
|
||||
re.AddRange(parentList);
|
||||
|
||||
FindParent(re, parentList.Select(x => x.ParentId).ToList());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result.OrderBy(x => x.ShowOrder).Select(x => new {
|
||||
|
||||
x.DictionaryId,
|
||||
x.DictionaryValue
|
||||
}).Distinct().ToList();
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取Description
|
||||
/// </summary>
|
||||
/// <param name="moduleTypeId"></param>
|
||||
/// <param name="trialId"></param>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public async Task<object> getModuleTypeDescriptionList(Guid moduleTypeId,Guid trialId)
|
||||
public async Task<List<string>> GetModuleTypeDescriptionList(Guid moduleTypeId)
|
||||
{
|
||||
|
||||
|
||||
var result = from data in _frontAuditConfigRepository.Where(x =>x.IsEnable && x.ModuleTypeId == moduleTypeId && x.ObjectTypeId != null && x.OptTypeId != null && x.Description.Length > 0)
|
||||
join trialshow in _trialAuditShowRepository.Where(x => x.TrialId == trialId) on data.Id equals trialshow.FrontAuditConfigId into trialshowtemp
|
||||
from lefttrialshow in trialshowtemp.DefaultIfEmpty()
|
||||
select new
|
||||
{
|
||||
IsShow= lefttrialshow==null? data.IsDefaultChoice : lefttrialshow.IsShow,
|
||||
FrontAuditConfigId = data.Id,
|
||||
data.Sort,
|
||||
Description = _userInfo.IsEn_Us ? data.Description : data.DescriptionCN
|
||||
};
|
||||
|
||||
return result.Where(x=>x.IsShow).Distinct().OrderBy(x=>x.Sort).ToList();
|
||||
var result = (await _frontAuditConfigRepository.Where(x => x.ModuleTypeId == moduleTypeId && x.ObjectTypeId != null && x.OptTypeId != null && x.Description.Length > 0).Select(x => new { x.Description, x.DescriptionCN, x.Sort }).OrderBy(t => t.Sort).ToListAsync()
|
||||
).Select(t => _userInfo.IsEn_Us ? t.Description : t.DescriptionCN).Distinct().ToList();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1257,7 +1192,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
Sort = data.Sort,
|
||||
ValueCN = data.ValueCN,
|
||||
ChildrenTypeValue = leftchildrenType.Value,
|
||||
IsDefaultChoice= data.IsDefaultChoice,
|
||||
|
||||
DictionaryKey = data.DictionaryKey,
|
||||
EnumType = data.EnumType,
|
||||
ObjectTypeId = data.ObjectTypeId,
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
using IRaCIS.Core.Application.Contracts;
|
||||
using IRaCIS.Core.Application.Service.Inspection.DTO;
|
||||
using IRaCIS.Core.Application.Service.Inspection.Interface;
|
||||
using IRaCIS.Core.Application.ViewModel;
|
||||
using IRaCIS.Core.Domain.Share;
|
||||
using IRaCIS.Core.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Panda.DynamicWebApi.Attributes;
|
||||
|
||||
|
||||
namespace IRaCIS.Core.Application.Service.Inspection
|
||||
{
|
||||
[ApiExplorerSettings(GroupName = "Reviewer")]
|
||||
[NonDynamicWebApi]
|
||||
public class InspectionService(IRepository<DataInspection> _dataInspectionRepository,
|
||||
IRepository<Dictionary> _dictionaryRepository,
|
||||
IRepository<TrialSign> _trialSignRepository,
|
||||
IRepository<IdentityUser> _identityUserRepository,
|
||||
IRepository<TrialAuditShow> _trialAuditShowRepository,
|
||||
IRepository<UserRole> _userRoleRepository,
|
||||
IRepository<TrialSite> _trialSiteRepository,
|
||||
IRepository<Trial> _trialRepository,
|
||||
|
@ -26,63 +23,7 @@ namespace IRaCIS.Core.Application.Service.Inspection
|
|||
IRepository<FrontAuditConfig> _frontAuditConfigRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IInspectionService
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 设置项目稽查配置
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<IResponseOutput> SetTrialShowInspection(SetTrialShowInspection inDto)
|
||||
{
|
||||
await _trialAuditShowRepository.BatchDeleteNoTrackingAsync(x => x.TrialId == inDto.TrialId);
|
||||
|
||||
List<TrialAuditShow> trialAuditShows = inDto.TrialShowInspectionList.Select(x => new TrialAuditShow()
|
||||
{
|
||||
FrontAuditConfigId = x.FrontAuditConfigId,
|
||||
TrialId = inDto.TrialId,
|
||||
IsShow = x.IsShow,
|
||||
|
||||
}).ToList();
|
||||
|
||||
await _trialAuditShowRepository.AddRangeAsync(trialAuditShows);
|
||||
|
||||
await _trialAuditShowRepository.SaveChangesAsync();
|
||||
|
||||
return ResponseOutput.Ok();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取项目稽查显示信息
|
||||
/// </summary>
|
||||
/// <param name="inDto"></param>
|
||||
/// <returns></returns>
|
||||
[HttpPost]
|
||||
public async Task<List<GetTrialShowInspectionOutDto>> GetTrialShowInspection(GetTrialShowInspectionInDto inDto)
|
||||
{
|
||||
var query = from data in _frontAuditConfigRepository.Where(x => x.IsEnable && x.ConfigType == "M")
|
||||
join trialdata in _trialAuditShowRepository.Where(x => x.TrialId == inDto.TrialId) on data.Id equals trialdata.FrontAuditConfigId into trialdatatemp
|
||||
from lefttrialdata in trialdatatemp.DefaultIfEmpty()
|
||||
select new GetTrialShowInspectionOutDto()
|
||||
{
|
||||
Description = data.Description,
|
||||
DescriptionCN = data.DescriptionCN,
|
||||
FrontAuditConfigId = data.Id,
|
||||
ParentId= data.ParentId,
|
||||
Sort=data.Sort,
|
||||
IsShow = lefttrialdata != null ? lefttrialdata.IsShow : data.IsDefaultChoice
|
||||
};
|
||||
var frontAuditList =await query.ToListAsync();
|
||||
|
||||
var result= frontAuditList.Where(x=>x.ParentId==default(Guid)).OrderBy(x=>x.Sort).ToList();
|
||||
result.ForEach(x =>
|
||||
{
|
||||
|
||||
x.Children = frontAuditList.Where(y => y.ParentId == x.FrontAuditConfigId).OrderBy(x => x.Sort).ToList();
|
||||
});
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public async Task<PageOutput<GetDataInspectionOutDto>> GetInspectionList(GetDataInspectionDto inQuery)
|
||||
|
@ -120,6 +61,26 @@ namespace IRaCIS.Core.Application.Service.Inspection
|
|||
|
||||
join visttask in _visitTaskRepository.Where().IgnoreQueryFilters() on data.VisitTaskId equals visttask.Id into visttasktemp
|
||||
from leftvisttask in visttasktemp.DefaultIfEmpty()
|
||||
|
||||
//join trialCriterion in _repository.GetQueryable<ReadingQuestionCriterionTrial>().IgnoreQueryFilters() on data.TrialReadingCriterionId equals trialCriterion.Id into criterion
|
||||
//from leftCriterion in criterion.DefaultIfEmpty()
|
||||
|
||||
//join moduleTyped in _dictionaryRepository.Where().Where(x => x.Code == "ModuleType") on 1 equals 1
|
||||
//join moduleTypec in _dictionaryRepository.Where() on new { ParentId = moduleTyped.Id, ModuleType = data.ModuleType } equals new { ParentId = moduleTypec.ParentId.Value, ModuleType = moduleTypec.Value } into moduleTypectemp
|
||||
|
||||
//join childrenTyped in _dictionaryRepository.Where().Where(x => x.Code == "ChildrenType") on 1 equals 1
|
||||
//join childrenTypec in _dictionaryRepository.Where() on new { ParentId = childrenTyped.Id, ModuleType = data.ChildrenType } equals new { ParentId = childrenTypec.ParentId.Value, ModuleType = childrenTypec.Value } into childrenTypectemp
|
||||
//from leftchildrenTypec in childrenTypectemp.DefaultIfEmpty()
|
||||
|
||||
//join ObjectTyped in _dictionaryRepository.Where().Where(x => x.Code == "ObjectType") on 1 equals 1
|
||||
//join ObjectTypec in _dictionaryRepository.Where() on new { ParentId = ObjectTyped.Id, ModuleType = data.ObjectType } equals new { ParentId = ObjectTypec.ParentId.Value, ModuleType = ObjectTypec.Value } into objectTypetemp
|
||||
//from leftObjectType in objectTypetemp.DefaultIfEmpty()
|
||||
|
||||
//join OptTyped in _dictionaryRepository.Where().Where(x => x.Code == "OptType") on 1 equals 1
|
||||
//join OptTypec in _dictionaryRepository.Where() on new { ParentId = OptTyped.Id, ModuleType = data.OptType } equals new { ParentId = OptTypec.ParentId.Value, ModuleType = OptTypec.Value } into optTypetemp
|
||||
//from leftOptType in optTypetemp.DefaultIfEmpty()
|
||||
|
||||
|
||||
join trialSign in _trialSignRepository.Where().IgnoreQueryFilters() on data.SignId equals trialSign.Id into trialSigntemp
|
||||
from lefttrialSign in trialSigntemp.DefaultIfEmpty()
|
||||
join leftfrontAuditConfig in _frontAuditConfigRepository.Where().Where(x => x.ConfigType == "M" && x.Identification != null && x.IsEnable == true) on
|
||||
|
@ -130,11 +91,9 @@ namespace IRaCIS.Core.Application.Service.Inspection
|
|||
from leftmoduleTypec in moduleTypectemp.DefaultIfEmpty()
|
||||
join OptTypec in _dictionaryRepository.Where() on new { ModuleType = leftfrontAuditConfig.OptTypeId!.Value } equals new { ModuleType = OptTypec.Id } into optTypetemp
|
||||
from leftOptType in optTypetemp.DefaultIfEmpty()
|
||||
join trialShow in _trialAuditShowRepository.Where(x => x.TrialId == inQuery.TrialId) on leftfrontAuditConfig.Id equals trialShow.FrontAuditConfigId into trialShowtemp
|
||||
from lefttrialShow in trialShowtemp.DefaultIfEmpty()
|
||||
|
||||
select new GetDataInspectionOutDto()
|
||||
{
|
||||
IsShow = lefttrialShow != null ? lefttrialShow.IsShow : leftfrontAuditConfig.IsDefaultChoice,
|
||||
CreateTime = data.CreateTime,
|
||||
CreateUserId = data.CreateUserId,
|
||||
ModuleTypeId = leftmoduleTypec.Id,
|
||||
|
@ -146,7 +105,7 @@ namespace IRaCIS.Core.Application.Service.Inspection
|
|||
SubjectVisitId = data.SubjectVisitId,
|
||||
//OptType = data.OptType,
|
||||
IP = data.IP,
|
||||
Reason = leftfrontAuditConfig.IsHaveReason? data.Reason:string.Empty,
|
||||
Reason = data.Reason,
|
||||
IsSign = leftfrontAuditConfig.IsHaveSign && lefttrialSign.SignText != null && lefttrialSign.SignText != string.Empty,
|
||||
SignId = data.SignId,
|
||||
ParentId = data.ParentId,
|
||||
|
@ -208,8 +167,7 @@ namespace IRaCIS.Core.Application.Service.Inspection
|
|||
query = query.WhereIf(inQuery.TrialSiteId != null, x => x.TrialSiteId == inQuery.TrialSiteId)
|
||||
//.Where(x => (x.TrialId == dto.TrialId) || (x.TrialId == null && x.CreateTime >= trialData.CreateTime && x.CreateTime <= trialData.TrialFinishTime))
|
||||
.Where(x => x.TrialId == inQuery.TrialId)
|
||||
.Where(x => x.IsShow)
|
||||
.WhereIf(inQuery.FrontAuditConfigId != null, x => x.FrontAuditConfigId == inQuery.FrontAuditConfigId)
|
||||
|
||||
#region 废弃
|
||||
// .WhereIf(dto.BatchId != null && dto.ObjectRelationParentId == null && dto.GeneralId == null, x => x.BatchId == dto.BatchId)
|
||||
// .WhereIf(dto.BatchId != null && dto.GeneralId != null && dto.ObjectRelationParentId == null, x => x.BatchId == dto.BatchId ||
|
||||
|
|
|
@ -350,8 +350,6 @@ namespace IRaCIS.Application.Contracts
|
|||
public string ResearchProgramNo { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
public int JoinedTrialCount { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
{
|
||||
|
||||
//检查手机或者邮箱是否有效
|
||||
if (!Regex.IsMatch(email, _systemEmailConfig.EmailRegexStr))
|
||||
if (!Regex.IsMatch(email, @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"))
|
||||
{
|
||||
//---Please input a legal email
|
||||
return ResponseOutput.NotOk(_localizer["User_LegalEmail"]);
|
||||
|
@ -325,7 +325,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
{
|
||||
|
||||
//检查手机或者邮箱是否有效
|
||||
if (!Regex.IsMatch(email, _systemEmailConfig.EmailRegexStr))
|
||||
if (!Regex.IsMatch(email, @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"))
|
||||
{
|
||||
|
||||
//---请输入一个正确的邮箱。
|
||||
|
@ -922,7 +922,7 @@ namespace IRaCIS.Core.Application.Service
|
|||
var password = loginDto.Password;
|
||||
|
||||
var emailConfig = _emailConfig.CurrentValue;
|
||||
var companyInfo = new SystemEmailSendConfigView() { CompanyName = emailConfig.CompanyName, CompanyNameCN = emailConfig.CompanyNameCN, CompanyShortName = emailConfig.CompanyShortName, CompanyShortNameCN = emailConfig.CompanyShortNameCN,SystemShortName=emailConfig.SystemShortName ,EmailRegexStr=emailConfig.EmailRegexStr};
|
||||
var companyInfo = new SystemEmailSendConfigView() { CompanyName = emailConfig.CompanyName, CompanyNameCN = emailConfig.CompanyNameCN, CompanyShortName = emailConfig.CompanyShortName, CompanyShortNameCN = emailConfig.CompanyShortNameCN,SystemShortName=emailConfig.SystemShortName };
|
||||
|
||||
|
||||
int maxFailures = _verifyConfig.CurrentValue.LoginMaxFailCount;
|
||||
|
@ -996,22 +996,11 @@ namespace IRaCIS.Core.Application.Service
|
|||
loginUser.NeedChangePassWord = true;
|
||||
}
|
||||
|
||||
List<UserOptType> userOptTypes = new List<UserOptType>() {
|
||||
UserOptType.Login,
|
||||
UserOptType.AccountOrPasswordError,
|
||||
UserOptType.LoginLockedAccount
|
||||
};
|
||||
|
||||
var actionUserName= loginUser!= null ? loginUser.UserName : userName;
|
||||
|
||||
var lastLoginIPRegion = await _userLogRepository.Where(t => t.ActionUserName == actionUserName && userOptTypes.Contains(t.OptType))
|
||||
.OrderByDescending(t => t.CreateTime).Select(t => t.IPRegion).FirstOrDefaultAsync();
|
||||
|
||||
if (lastLoginIPRegion != string.Empty)
|
||||
if (existUserLoginInfo.LastLoginIP != string.Empty)
|
||||
{
|
||||
// 与上一次区域不一致
|
||||
//if (SplitAndConcatenate(existUserLoginInfo.LastLoginIP) != SplitAndConcatenate(iPRegion))
|
||||
if (lastLoginIPRegion != iPRegion)
|
||||
if (existUserLoginInfo.LastLoginIP != iPRegion)
|
||||
{
|
||||
|
||||
isLoginUncommonly = true;
|
||||
|
|
|
@ -154,7 +154,6 @@ namespace IRaCIS.Core.Application.Service
|
|||
.ForMember(d => d.IdentityUserId, c => c.MapFrom(t => t.Id));
|
||||
CreateMap<IdentityUser, UserListDTO>()
|
||||
.ForMember(d => d.TrialCode, u => u.MapFrom(s => s.Trial.TrialCode))
|
||||
.ForMember(d => d.JoinedTrialCount, u => u.MapFrom(s => s.UserTrialList.Count()))
|
||||
.ForMember(d => d.ResearchProgramNo, u => u.MapFrom(s => s.Trial.ResearchProgramNo));
|
||||
|
||||
CreateMap<UserAddUserType, UserRole>().ReverseMap();
|
||||
|
|
|
@ -19,8 +19,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
public bool IsReading { get; set; }
|
||||
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
public DateTime? MarkTime { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
// 生成时间 2021-12-06 10:56:50
|
||||
// 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。
|
||||
//--------------------------------------------------------------------
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace IRaCIS.Core.Application.Contracts
|
||||
{
|
||||
/// <summary> NoneDicomStudyView 列表视图模型 </summary>
|
||||
|
@ -45,18 +43,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
|
||||
}
|
||||
|
||||
public class NoneDicomEdit
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
[NotDefault]
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
public string StudyName { get; set; }
|
||||
public string BodyPart { get; set; } = string.Empty;
|
||||
public string Modality { get; set; } = string.Empty;
|
||||
public DateTime ImageDate { get; set; }
|
||||
public string ModifyReason { get; set; }
|
||||
}
|
||||
|
||||
///<summary> NoneDicomStudyAddOrEdit 列表查询参数模型</summary>
|
||||
public class NoneDicomStudyAddOrEdit
|
||||
{
|
||||
|
@ -80,7 +66,6 @@ namespace IRaCIS.Core.Application.Contracts
|
|||
public DateTime? UploadVideoTime { get; set; }
|
||||
|
||||
public string VideoUrl { get; set; } = string.Empty;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,27 +1,12 @@
|
|||
using IRaCIS.Core.Domain.Share;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace IRaCIS.Core.Application.Contracts.DTO
|
||||
{
|
||||
|
||||
|
||||
|
||||
public class DicomStudyEdit
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
|
||||
[NotDefault]
|
||||
public Guid SubjectVisitId { get; set; }
|
||||
|
||||
public string StudyName { get; set; } = String.Empty;
|
||||
|
||||
public string Modality { get; set; } = String.Empty;
|
||||
|
||||
public string BodyPart { get; set; } = String.Empty;
|
||||
|
||||
public string ModifyReason { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -216,7 +201,6 @@ namespace IRaCIS.Core.Application.Contracts.DTO
|
|||
|
||||
public class QCChallengeWithUser : QCChallengeCommand
|
||||
{
|
||||
public SecondReviewState SecondReviewState { get; set; }
|
||||
public bool IsBaseLine { get; set; }
|
||||
public string VisitName { get; set; }
|
||||
public string BlindName { get; set; } = string.Empty;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue