diff --git a/IRaCIS.Core.API.sln b/IRaCIS.Core.API.sln index cb23da7dd..d5afa55fa 100644 --- a/IRaCIS.Core.API.sln +++ b/IRaCIS.Core.API.sln @@ -11,25 +11,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Application", " EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Domain.Share", "IRaCIS.Core.Domain.Share\IRaCIS.Core.Domain.Share.csproj", "{7CBC76F5-3817-46B7-8D9D-79253A89B578}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.JWT.RS256", "ZhiZhunAuthenticationCenter\IRaCIS.JWT.RS256.csproj", "{3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Test", "IRaCIS.Core.Test\IRaCIS.Core.Test.csproj", "{3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infra.EFCore", "IRaCIS.Core.Infra.EFCore\IRaCIS.Core.Infra.EFCore.csproj", "{6D8115E5-84D6-424B-8F8D-0C2D40347A8C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.Infrastructure", "IRaCIS.Core.Infrastructure\IRaCIS.Core.Infrastructure.csproj", "{07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "IRaCIS.AuthenticationCenter", "IRaCIS.AuthenticationCenter", "{481329D6-B8A0-491F-A398-1DF66A0FBB62}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.IdentityServer4", "IRaCIS.Core.IdentityServer4\IRaCIS.Core.IdentityServer4.csproj", "{C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IRaCIS.Core.IdentityServer4.MVC", "IRaCIS.Core.IdentityServer4.MVC\IRaCIS.Core.IdentityServer4.MVC.csproj", "{F621ADD6-94E8-4A4B-998E-25B8EF15D39C}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F852ABFB-88AC-48BE-B876-2228BE2373D6}" - ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - EndProjectSection -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -52,10 +39,6 @@ Global {7CBC76F5-3817-46B7-8D9D-79253A89B578}.Debug|Any CPU.Build.0 = Debug|Any CPU {7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|Any CPU.ActiveCfg = Release|Any CPU {7CBC76F5-3817-46B7-8D9D-79253A89B578}.Release|Any CPU.Build.0 = Release|Any CPU - {3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39}.Release|Any CPU.Build.0 = Release|Any CPU {3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Debug|Any CPU.Build.0 = Debug|Any CPU {3292B2B4-6E8A-43AA-84C0-AB4A391E8A2A}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -68,23 +51,10 @@ Global {07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Debug|Any CPU.Build.0 = Debug|Any CPU {07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.ActiveCfg = Release|Any CPU {07EED0F8-08E6-46F3-ACBE-17BC1391BD4C}.Release|Any CPU.Build.0 = Release|Any CPU - {C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674}.Release|Any CPU.Build.0 = Release|Any CPU - {F621ADD6-94E8-4A4B-998E-25B8EF15D39C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F621ADD6-94E8-4A4B-998E-25B8EF15D39C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F621ADD6-94E8-4A4B-998E-25B8EF15D39C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F621ADD6-94E8-4A4B-998E-25B8EF15D39C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {3EF210EE-D5D1-4C93-A8FA-E0DB1852BD39} = {481329D6-B8A0-491F-A398-1DF66A0FBB62} - {C3DD48CF-B8B3-40F6-9BDB-B7C7F0851674} = {481329D6-B8A0-491F-A398-1DF66A0FBB62} - {F621ADD6-94E8-4A4B-998E-25B8EF15D39C} = {481329D6-B8A0-491F-A398-1DF66A0FBB62} - EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCC2EB19-3914-489B-B1D7-B7303E0218A3} EndGlobalSection diff --git a/IRaCIS.Core.API/AnonymizeTagSetting.json b/IRaCIS.Core.API/AnonymizeTagSetting.json deleted file mode 100644 index 6576ca04a..000000000 --- a/IRaCIS.Core.API/AnonymizeTagSetting.json +++ /dev/null @@ -1,106 +0,0 @@ -{ - "needAnonymizeTag": [ - { //PatientsName - "Group": "0010", - "Element": "0010", - "ReplaceValue": "", - "Enable": true - }, - { // PatientID - "Group": "0010", - "Element": "0020", - "ReplaceValue": "", - "Enable": true - }, - { // IssuerOfPatientID - "Group": "0010", - "Element": "0021", - "ReplaceValue": "", - "Enable": true - }, - { // PatientsBirthDate - "Group": "0010", - "Element": "0030", - "ReplaceValue": "", - "Enable": true - }, - { // PatientsBirthTime - "Group": "0010", - "Element": "0032", - "ReplaceValue": "", - "Enable": false - }, - { // PatientsSex - "Group": "0010", - "Element": "0040", - "ReplaceValue": "", - "Enable": false - }, - { // OtherPatientIDs - "Group": "0010", - "Element": "1000", - "ReplaceValue": "", - "Enable": false - }, - { // OtherPatientNames - "Group": "0010", - "Element": "1001", - "ReplaceValue": "", - "Enable": false - }, - { // OtherPatientNames - "Group": "0010", - "Element": "1005", - "ReplaceValue": "", - "Enable": true - }, - { // PatientBirthName - "Group": "0010", - "Element": "1005", - "ReplaceValue": "", - "Enable": true - }, - { // PatientsAge - "Group": "0010", - "Element": "1010", - "ReplaceValue": "", - "Enable": true - }, - { // PatientsAddress - "Group": "0010", - "Element": "1040", - "ReplaceValue": "", - "Enable": true - }, - { // PatientsMothersBirthName - "Group": "0010", - "Element": "1060", - "ReplaceValue": "", - "Enable": true - }, - { - "Group": "0010", - "Element": "2150", - "ReplaceValue": "", - "Enable": true - }, - { - "Group": "0010", - "Element": "2152", - "ReplaceValue": "", - "Enable": true - }, - { - "Group": "0010", - "Element": "2154", - "ReplaceValue": "", - "Enable": true - }, - { - "Group": "0012", - "Element": "0040", - "ReplaceValue": "XXX", - "Enable": true - } - ] -} \ No newline at end of file diff --git a/IRaCIS.Core.API/Controllers/ExtraController.cs b/IRaCIS.Core.API/Controllers/ExtraController.cs index de3d78b2c..ca49c5e0b 100644 --- a/IRaCIS.Core.API/Controllers/ExtraController.cs +++ b/IRaCIS.Core.API/Controllers/ExtraController.cs @@ -1,9 +1,6 @@ using System; using System.Net.Http; using EasyCaching.Core; -using gRPC.ZHiZHUN.AuthServer.protos; -using Grpc.Net.Client; -using Grpc.Net.Client.Configuration; using IRaCIS.Application.Interfaces; using IRaCIS.Application.Contracts; using IRaCIS.Core.Application.Auth; @@ -24,6 +21,13 @@ using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Infrastructure; using System.Linq; using Microsoft.Extensions.Logging; +using MassTransit; +using Microsoft.AspNetCore.Hosting; +using Aliyun.Acs.Core.Profile; +using Aliyun.Acs.Core.Auth.Sts; +using Aliyun.Acs.Core; +using IRaCIS.Core.Application.Helper; +using Microsoft.Extensions.Options; namespace IRaCIS.Api.Controllers { @@ -203,6 +207,44 @@ namespace IRaCIS.Api.Controllers } + [HttpGet("user/GenerateSTS")] + public IResponseOutput GenerateSTS(IOptionsMonitor options ) + { + var ossOptions = options.CurrentValue; + + + IClientProfile profile = DefaultProfile.GetProfile(ossOptions.RegionId, ossOptions.AccessKeyId, ossOptions.AccessKeySecret); + DefaultAcsClient client = new DefaultAcsClient(profile); + + + // 创建一个STS请求 + AssumeRoleRequest request = new AssumeRoleRequest + { + RoleArn = ossOptions.RoleArn, // 角色ARN,需要替换为你的角色ARN + RoleSessionName = $"session-name-{NewId.NextGuid()}", // 角色会话名称,可自定义 + DurationSeconds = 900, // 令牌有效期(单位:秒),这里设置为1小时 + }; + + + AssumeRoleResponse response = client.GetAcsResponse(request); + + // 返回STS令牌信息给前端 + var stsToken = new + { + AccessKeyId = response.Credentials.AccessKeyId, + AccessKeySecret = response.Credentials.AccessKeySecret, + SecurityToken = response.Credentials.SecurityToken, + Expiration = response.Credentials.Expiration, + + Region = ossOptions.Region , + BucketName = ossOptions.BucketName , + ViewEndpoint = ossOptions.ViewEndpoint , + + }; + + return ResponseOutput.Ok(stsToken); + + } diff --git a/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs b/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs index c96d9b1c2..f8a017c5b 100644 --- a/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs +++ b/IRaCIS.Core.API/Controllers/UploadDownLoadController.cs @@ -1222,6 +1222,59 @@ namespace IRaCIS.Core.API.Controllers } + public enum UploadFileType + { + DataUpload = 1, + + DataDownload = 2, + + EmailAttachment = 3, + + EmailBodyHtml = 4, + + Other = 5 + } + + /// + /// 1:数据上传 2:导出、 3:邮件附件 4:邮件Html 通过 ----new + /// + /// + [HttpPost("SystemFile/Upload")] + [DisableRequestSizeLimit] + [DisableFormValueModelBinding] + public async Task Upload(UploadFileType fileType) + { + IResponseOutput result = null; + + switch (fileType) + { + case UploadFileType.DataUpload: + result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate, fileName)); + + break; + case UploadFileType.DataDownload: + result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.DataTemplate, fileName)); + + break; + case UploadFileType.EmailAttachment: + result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName)); + + break; + + case UploadFileType.EmailBodyHtml: + result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetSystemFileUploadPath(_hostEnvironment, StaticData.Folder.EmailTemplate, fileName)); + break; + + default: + result = await SingleFileUploadAsync((fileName) => FileStoreHelper.GetOtherFileUploadPath(_hostEnvironment, StaticData.Folder.TempFile, fileName)); + + break; + } + + return result; + + } + } #endregion diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.csproj b/IRaCIS.Core.API/IRaCIS.Core.API.csproj index c6af611a4..787cd194b 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.csproj +++ b/IRaCIS.Core.API/IRaCIS.Core.API.csproj @@ -66,33 +66,27 @@ - + + - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + + true + + + + - - - - - - - - + + + + - + @@ -105,9 +99,6 @@ - - Always - Always diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.xml b/IRaCIS.Core.API/IRaCIS.Core.API.xml index ed6960728..d07789653 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.xml +++ b/IRaCIS.Core.API/IRaCIS.Core.API.xml @@ -429,6 +429,12 @@ + + + 1:数据上传 2:导出、 3:邮件附件 4:邮件Html 通过 ----new + + + IPLimit限流 启动服务 @@ -484,113 +490,5 @@ - - Holder for reflection information generated from Protos/GrpcToken.proto - - - File descriptor for Protos/GrpcToken.proto - - - - 新增用户时需要传递数据消息, 可理解为一个类 - - - - Field number for the "id" field. - - - Field number for the "userName" field. - - - Field number for the "realName" field. - - - Field number for the "reviewerCode" field. - - - Field number for the "userTypeEnumInt" field. - - - Field number for the "userTypeShortName" field. - - - Field number for the "isAdmin" field. - - - - 新增时返回的消息格式 - - - - Field number for the "code" field. - - - Field number for the "token" field. - - - - service 用标识定义服务的,里面写对应的方法 - - - - Service descriptor - - - Client for TokenGrpcService - - - Creates a new client for TokenGrpcService - The channel to use to make remote calls. - - - Creates a new client for TokenGrpcService that uses a custom CallInvoker. - The callInvoker to use to make remote calls. - - - Protected parameterless constructor to allow creation of test doubles. - - - Protected constructor to allow creation of configured clients. - The client configuration. - - - - 获取token - - The request to send to the server. - The initial metadata to send with the call. This parameter is optional. - An optional deadline for the call. The call will be cancelled if deadline is hit. - An optional token for canceling the call. - The response received from the server. - - - - 获取token - - The request to send to the server. - The options for the call. - The response received from the server. - - - - 获取token - - The request to send to the server. - The initial metadata to send with the call. This parameter is optional. - An optional deadline for the call. The call will be cancelled if deadline is hit. - An optional token for canceling the call. - The call object. - - - - 获取token - - The request to send to the server. - The options for the call. - The call object. - - - Creates a new instance of client from given ClientBaseConfiguration. - diff --git a/IRaCIS.Core.API/NLog.config b/IRaCIS.Core.API/NLog.config deleted file mode 100644 index bf1dbbb1b..000000000 --- a/IRaCIS.Core.API/NLog.config +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/IRaCIS.Core.API/Program.cs b/IRaCIS.Core.API/Program.cs index b771b7a5f..ad2c3f425 100644 --- a/IRaCIS.Core.API/Program.cs +++ b/IRaCIS.Core.API/Program.cs @@ -53,24 +53,12 @@ namespace IRaCIS.Core.API }) .Build(); - //// Serilog SerilogExtension.AddSerilogSetup(enviromentName, host.Services); Log.Logger.Warning($"ǰ{enviromentName}"); - - NewId.SetProcessIdProvider(new CurrentProcessIdProvider()); - - - //Ŀ״̬ - await InitCache(host); - - - - - - + host.Run(); @@ -100,28 +88,7 @@ namespace IRaCIS.Core.API webBuilder.UseStartup(); }).UseSerilog() .UseServiceProviderFactory(new AutofacServiceProviderFactory()); - - - private static async Task InitCache(IHost host) - { - var _repository = host.Services.GetService(typeof(IRepository)) as IRepository; - - //ʼ ʻݣҼʻļ - await InternationalizationHelper.InitInternationlizationDataAndWatchJsonFileAsync(_repository); - - var _mediator = host.Services.GetService(typeof(IMediator)) as IMediator; - - await _mediator.Send(new AnonymizeCacheRequest()); - - await _mediator.Send(new TrialStateCacheRequest()); - - - - } - - - - + } } diff --git a/IRaCIS.Core.API/Properties/launchSettings.json b/IRaCIS.Core.API/Properties/launchSettings.json index 5993ff67d..aed031839 100644 --- a/IRaCIS.Core.API/Properties/launchSettings.json +++ b/IRaCIS.Core.API/Properties/launchSettings.json @@ -45,22 +45,7 @@ "ASPNETCORE_ENVIRONMENT": "Production" }, "applicationUrl": "http://localhost:6300" - }, - "IRaCIS.CertificateApply": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "CertificateApply" - }, - "applicationUrl": "http://localhost:6400" - }, - "IRaCIS.CenterImageDev": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "CenterImageDev" - }, - "applicationUrl": "http://localhost:6500" } + } } \ No newline at end of file diff --git a/IRaCIS.Core.API/Startup.cs b/IRaCIS.Core.API/Startup.cs index 886e443fc..21772cf98 100644 --- a/IRaCIS.Core.API/Startup.cs +++ b/IRaCIS.Core.API/Startup.cs @@ -24,6 +24,8 @@ using Invio.Extensions.Authentication.JwtBearer; using Microsoft.AspNetCore.SignalR; using IRaCIS.Core.Domain.Share; using Microsoft.AspNetCore.StaticFiles; +using IRaCIS.Core.Application.Helper; +using IRaCIS.Application.Services.BackGroundJob; namespace IRaCIS.Core.API { @@ -91,7 +93,7 @@ namespace IRaCIS.Core.API services.AddOptions().Configure( _configuration.GetSection("SystemEmailSendConfig")); services.AddOptions().Configure(_configuration.GetSection("BasicSystemConfig")); - + services.AddOptions().Configure(_configuration.GetSection("AliyunOSS")); //̬WebApi + UnifiedApiResultFilter ʡ @@ -106,17 +108,18 @@ namespace IRaCIS.Core.API services.AddSwaggerSetup(); //JWT Token ֤ services.AddJWTAuthSetup(_configuration); + + // MediatR Ϣ ¼ ӳ עhandlerӦϵ - services.AddMediatR(typeof(ConsistencyVerificationHandler).Assembly); + services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining()); // EasyCaching - services.AddEasyCachingSetup(); + services.AddEasyCachingSetup(_configuration); //services.AddDistributedMemoryCache(); // hangfire ʱ н棬Ѻ~ - //services.AddhangfireSetup(_configuration); - // QuartZ ʱ ʹhangfire ʱãҪԴ򿪣Ѿ - services.AddQuartZSetup(_configuration); + services.AddhangfireSetup(_configuration); + // ϴļ //services.AddStaticFileAuthorizationSetup(); @@ -161,7 +164,7 @@ namespace IRaCIS.Core.API } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) + public async void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //ػ app.UseLocalization(); @@ -181,7 +184,7 @@ namespace IRaCIS.Core.API app.UseLogDashboard("/LogDashboard"); //hangfire - //app.UseHangfireConfig(env); + app.UseHangfireConfig(env); ////ʱ //app.UseHttpReports(); @@ -235,6 +238,10 @@ namespace IRaCIS.Core.API endpoints.MapHub("/UploadHub"); }); + var hangfireJobService = app.ApplicationServices.GetRequiredService(); + + await hangfireJobService.InitHangfireJobTaskAsync(); + } } } diff --git a/IRaCIS.Core.API/_PipelineExtensions/Hangfire/HangfireConfig.cs b/IRaCIS.Core.API/_PipelineExtensions/Hangfire/HangfireConfig.cs deleted file mode 100644 index 48423534d..000000000 --- a/IRaCIS.Core.API/_PipelineExtensions/Hangfire/HangfireConfig.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Hangfire; -using Hangfire.Dashboard; -using IRaCIS.Application.Services.BackGroundJob; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; - -namespace IRaCIS.Core.API -{ - - - public static class HangfireConfig - { - - public static void UseHangfireConfig(this IApplicationBuilder app, IWebHostEnvironment env) - { - app.UseHangfireDashboard("/api/hangfire", new DashboardOptions() - { - //直接访问,没有带token 获取不到用户身份信息,所以这种自定义授权暂时没法使用 - //Authorization = new[] { new hangfireAuthorizationFilter() } - - //本地请求 才能看 - Authorization = new[] { new LocalRequestsOnlyAuthorizationFilter() } - - }); - - #region hangfire - //// 延迟任务执行 1秒之后执行 有时启动没运行 换成添加到队列中 - //BackgroundJob.Schedule(t => t.MemoryCacheTrialStatus(), TimeSpan.FromSeconds(1)); - ////添加到后台任务队列, - //BackgroundJob.Enqueue(t => t.MemoryCacheTrialStatus()); - - //周期性任务,1天执行一次 - - RecurringJob.AddOrUpdate(t => t.ProjectStartCache(), Cron.Daily); - - #endregion - - } - } -} diff --git a/IRaCIS.Core.API/_PipelineExtensions/HangfireConfig.cs b/IRaCIS.Core.API/_PipelineExtensions/HangfireConfig.cs new file mode 100644 index 000000000..3b9cb8b7a --- /dev/null +++ b/IRaCIS.Core.API/_PipelineExtensions/HangfireConfig.cs @@ -0,0 +1,66 @@ +using Hangfire; +using Hangfire.Dashboard; +using Hangfire.Dashboard.BasicAuthorization; +using IRaCIS.Application.Services.BackGroundJob; +using IRaCIS.Core.API.Filter; +using IRaCIS.Core.Application.Helper; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; + +namespace IRaCIS.Core.API +{ + + + public static class HangfireConfig + { + + public static void UseHangfireConfig(this IApplicationBuilder app, IWebHostEnvironment env) + { + + + app.UseHangfireDashboard("/back/hangfire", new DashboardOptions() + { + + + + Authorization = new IDashboardAuthorizationFilter[] { /*new hangfireAuthorizationFilter(),*/ + + new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions(){ + SslRedirect=false, + RequireSsl=false, + Users=new BasicAuthAuthorizationUser[]{ + new BasicAuthAuthorizationUser(){ + Login="admin", + PasswordClear="admin", + + } + } + + }) + }, + + DashboardTitle ="后台任务管理", + + + //Authorization = new BasicAuthAuthorizationFilter[] { + // new BasicAuthAuthorizationFilter(new BasicAuthAuthorizationFilterOptions(){ + // SslRedirect=false, + // RequireSsl=false, + // Users=new BasicAuthAuthorizationUser[]{ + // new BasicAuthAuthorizationUser(){ + // Login="admin", + // PasswordClear="test", + + // } + // } + + // }) + //} + + }); + + + + } + } +} \ No newline at end of file diff --git a/IRaCIS.Core.API/_ServiceExtensions/AutofacModuleSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/AutofacModuleSetup.cs index fd321596e..3435a738a 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/AutofacModuleSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/AutofacModuleSetup.cs @@ -31,10 +31,6 @@ namespace IRaCIS.Core.API containerBuilder.RegisterType().As().InstancePerLifetimeScope(); - //containerBuilder.RegisterType().As().InstancePerLifetimeScope(); - - //containerBuilder.RegisterGeneric(typeof(EFUnitOfWork<>)) - // .As(typeof(IEFUnitOfWork<>)).InstancePerLifetimeScope();//注册仓储 #endregion @@ -50,8 +46,7 @@ namespace IRaCIS.Core.API #endregion - //containerBuilder.RegisterType().As().PropertiesAutowired().InstancePerLifetimeScope(); - //containerBuilder.RegisterType().As().InstancePerLifetimeScope(); + @@ -59,22 +54,13 @@ namespace IRaCIS.Core.API containerBuilder.RegisterAssemblyTypes(application).Where(t => t.FullName.Contains("Service")) .PropertiesAutowired().AsImplementedInterfaces().EnableClassInterceptors(); - //Assembly infrastructure = Assembly.Load("IRaCIS.Core.Infra.EFCore"); - //containerBuilder.RegisterAssemblyTypes(infrastructure).AsImplementedInterfaces(); + containerBuilder.RegisterType().As().SingleInstance(); containerBuilder.RegisterType().As().InstancePerLifetimeScope(); - //containerBuilder.RegisterType().InstancePerLifetimeScope(); - //Autofac 注册拦截器 需要注意的是生成api上服务上的动态代理AOP失效 间接掉用不影响 - //containerBuilder.RegisterType(); - //containerBuilder.RegisterType(); - //containerBuilder.RegisterType(); - //containerBuilder.RegisterType().As().SingleInstance(); - - - //注册hangfire任务 依赖注入 + //注册hangfire任务 依赖注入 containerBuilder.RegisterType().As().InstancePerDependency(); diff --git a/IRaCIS.Core.API/_ServiceExtensions/EFSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/EFSetup.cs index c1d2c31cc..3a7df5742 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/EFSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/EFSetup.cs @@ -1,8 +1,12 @@ -using IRaCIS.Core.Application.Triggers; +using Hangfire.SqlServer; +using IRaCIS.Core.Application.Triggers; using IRaCIS.Core.Infra.EFCore; +using Medallion.Threading; +using Medallion.Threading.SqlServer; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using StackExchange.Redis; namespace IRaCIS.Core.API { @@ -55,6 +59,13 @@ namespace IRaCIS.Core.API }); + //注意区分 easy caching 也有 IDistributedLockProvider + services.AddSingleton(sp => + { + //var connection = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]!); + + return new SqlDistributedSynchronizationProvider(configuration.GetSection("ConnectionStrings:RemoteNew").Value); + }); //services.AddAssemblyTriggers(typeof(SubjectVisitImageDateTrigger).Assembly); } diff --git a/IRaCIS.Core.API/_ServiceExtensions/EasyCachingSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/EasyCachingSetup.cs index 7d7a28c6a..6f9e53bcc 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/EasyCachingSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/EasyCachingSetup.cs @@ -1,17 +1,26 @@ using EasyCaching.Core; +using EasyCaching.Core.Configurations; using EasyCaching.Interceptor.Castle; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace IRaCIS.Core.API { - public static class EasyCachingSetup + public static class EasyCachingSetup { - public static void AddEasyCachingSetup(this IServiceCollection services) + public static void AddEasyCachingSetup(this IServiceCollection services, IConfiguration configuration) { services.AddEasyCaching(options => { options.UseInMemory(); + + //options.UseRedis(configuration, EasyCachingConstValue.DefaultRedisName).WithMessagePack(EasyCachingConstValue.DefaultRedisName); + + }); + + //services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultRedisName); + services.ConfigureCastleInterceptor(options => options.CacheProviderName = EasyCachingConstValue.DefaultInMemoryName); } } diff --git a/IRaCIS.Core.API/_ServiceExtensions/MiniProfilerConfigure.cs b/IRaCIS.Core.API/_ServiceExtensions/MiniProfilerConfigure.cs deleted file mode 100644 index f08e27aae..000000000 --- a/IRaCIS.Core.API/_ServiceExtensions/MiniProfilerConfigure.cs +++ /dev/null @@ -1,81 +0,0 @@ -//using System; -//using Microsoft.Extensions.DependencyInjection; -//using StackExchange.Profiling.Storage; - -//namespace IRaCIS.Core.API -//{ -// public class MiniProfilerConfigure -// { -// public static void ConfigureMiniProfiler(IServiceCollection services) -// { - -// services.AddMiniProfiler(options => -// { -// // All of this is optional. You can simply call .AddMiniProfiler() for all defaults - -// // (Optional) Path to use for profiler URLs, default is /mini-profiler-resources -// options.RouteBasePath = "/profiler"; - -// //// (Optional) Control storage -// //// (default is 30 minutes in MemoryCacheStorage) -// (options.Storage as MemoryCacheStorage).CacheDuration = TimeSpan.FromMinutes(10); - -// //// (Optional) Control which SQL formatter to use, InlineFormatter is the default -// //options.SqlFormatter = new StackExchange.Profiling.SqlFormatters.InlineFormatter(); - -// //// (Optional) To control authorization, you can use the Func options: -// //// (default is everyone can access profilers) -// //options.ResultsAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler; -// //options.ResultsListAuthorize = request => MyGetUserFunction(request).CanSeeMiniProfiler; -// //// Or, there are async versions available: -// //options.ResultsAuthorizeAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfiler; -// //options.ResultsAuthorizeListAsync = async request => (await MyGetUserFunctionAsync(request)).CanSeeMiniProfilerLists; - -// //// (Optional) To control which requests are profiled, use the Func option: -// //// (default is everything should be profiled) -// //options.ShouldProfile = request => MyShouldThisBeProfiledFunction(request); - -// //// (Optional) Profiles are stored under a user ID, function to get it: -// //// (default is null, since above methods don't use it by default) -// //options.UserIdProvider = request => MyGetUserIdFunction(request); - -// //// (Optional) Swap out the entire profiler provider, if you want -// //// (default handles async and works fine for almost all applications) -// //options.ProfilerProvider = new MyProfilerProvider(); - -// //// (Optional) You can disable "Connection Open()", "Connection Close()" (and async variant) tracking. -// //// (defaults to true, and connection opening/closing is tracked) -// //options.TrackConnectionOpenClose = true; - -// //// (Optional) Use something other than the "light" color scheme. -// //// (defaults to "light") -// //options.ColorScheme = StackExchange.Profiling.ColorScheme.Auto; - -// //// The below are newer options, available in .NET Core 3.0 and above: - -// //// (Optional) You can disable MVC filter profiling -// //// (defaults to true, and filters are profiled) -// //options.EnableMvcFilterProfiling = true; -// //// ...or only save filters that take over a certain millisecond duration (including their children) -// //// (defaults to null, and all filters are profiled) -// //// options.MvcFilterMinimumSaveMs = 1.0m; - -// //// (Optional) You can disable MVC view profiling -// //// (defaults to true, and views are profiled) -// //options.EnableMvcViewProfiling = true; -// //// ...or only save views that take over a certain millisecond duration (including their children) -// //// (defaults to null, and all views are profiled) -// //// options.MvcViewMinimumSaveMs = 1.0m; - -// //// (Optional) listen to any errors that occur within MiniProfiler itself -// //// options.OnInternalError = e => MyExceptionLogger(e); - -// //// (Optional - not recommended) You can enable a heavy debug mode with stacks and tooltips when using memory storage -// //// It has a lot of overhead vs. normal profiling and should only be used with that in mind -// //// (defaults to false, debug/heavy mode is off) -// ////options.EnableDebugMode = true; -// }); -// //.AddEntityFramework(); -// } -// } -//} \ No newline at end of file diff --git a/IRaCIS.Core.API/_ServiceExtensions/QuartZSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/QuartZSetup.cs deleted file mode 100644 index 2f42e8f7c..000000000 --- a/IRaCIS.Core.API/_ServiceExtensions/QuartZSetup.cs +++ /dev/null @@ -1,45 +0,0 @@ - -using IRaCIS.Application.Services.BackGroundJob; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Quartz; - -namespace IRaCIS.Core.API -{ - public static class QuartZSetup - { - public static void AddQuartZSetup(this IServiceCollection services, IConfiguration configuration) - { - services.AddTransient(); - - services.AddQuartz(q => - { - // base quartz scheduler, job and trigger configuration - - // as of 3.3.2 this also injects scoped services (like EF DbContext) without problems - q.UseMicrosoftDependencyInjectionJobFactory(); - - // 基本Quartz调度器、作业和触发器配置 - var jobKey = new JobKey("RegularTrialWork", "regularWorkGroup"); - q.AddJob(jobKey, j => j - .WithDescription("Trial regular work") - ); - q.AddTrigger(t => t - .WithIdentity("TrialStatusTrigger") - .ForJob(jobKey) - - .WithCronSchedule("0 0 * * * ?") - .WithDescription("My regular trial work trigger") - ); - }); - - // ASP.NET Core hosting - services.AddQuartzHostedService(options => - { - // when shutting down we want jobs to complete gracefully - options.WaitForJobsToComplete = true; - }); - - } - } -} diff --git a/IRaCIS.Core.API/_ServiceExtensions/Serilog/SerilogSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/Serilog/SerilogSetup.cs index f0740dbbf..a27de1505 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/Serilog/SerilogSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/Serilog/SerilogSetup.cs @@ -21,7 +21,7 @@ namespace IRaCIS.Core.API .MinimumLevel.Override("Hangfire", LogEventLevel.Warning) .MinimumLevel.Override("System.Net.Http.HttpClient.HttpReports", LogEventLevel.Warning) .Enrich.WithClientIp() - .Enrich.WithClientAgent() + .Enrich.FromLogContext() //控制台 方便调试 问题 我们显示记录日志 时 获取上下文的ip 和用户名 用户类型 diff --git a/IRaCIS.Core.API/_ServiceExtensions/Swagger/JsonPatchDocumentFilter.cs b/IRaCIS.Core.API/_ServiceExtensions/Swagger/JsonPatchDocumentFilter.cs deleted file mode 100644 index 9f3562072..000000000 --- a/IRaCIS.Core.API/_ServiceExtensions/Swagger/JsonPatchDocumentFilter.cs +++ /dev/null @@ -1,55 +0,0 @@ -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; -using System.Collections.Generic; -using System.Linq; - -namespace IRaCIS.Core.API -{ - public class JsonPatchDocumentFilter : IDocumentFilter - { - public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) - { - var schemas = swaggerDoc.Components.Schemas.ToList(); - foreach (var item in schemas) - { - if (item.Key.StartsWith("Operation") || item.Key.StartsWith("JsonPatchDocument")) - swaggerDoc.Components.Schemas.Remove(item.Key); - } - - swaggerDoc.Components.Schemas.Add("Operation", new OpenApiSchema - { - Type = "object", - Properties = new Dictionary - { - { "op", new OpenApiSchema { Type = "string" } }, - {"value", new OpenApiSchema{ Type = "object", Nullable = true } }, - { "path", new OpenApiSchema { Type = "string" } } - } - }); - - swaggerDoc.Components.Schemas.Add("JsonPatchDocument", new OpenApiSchema - { - Type = "array", - Items = new OpenApiSchema - { - Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "Operation" } - }, - Description = "Array of operations to perform" - }); - - foreach (var path in swaggerDoc.Paths.SelectMany(p => p.Value.Operations) - .Where(p => p.Key == Microsoft.OpenApi.Models.OperationType.Patch)) - { - foreach (var item in path.Value.RequestBody.Content.Where(c => c.Key != "application/json-patch+json")) - path.Value.RequestBody.Content.Remove(item.Key); - - var response = path.Value.RequestBody.Content.SingleOrDefault(c => c.Key == "application/json-patch+json"); - - response.Value.Schema = new OpenApiSchema - { - Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "JsonPatchDocument" } - }; - } - } - } -} diff --git a/IRaCIS.Core.API/_ServiceExtensions/Swagger/SwaggerSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/Swagger/SwaggerSetup.cs index 4a16162e7..a5c53cd7f 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/Swagger/SwaggerSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/Swagger/SwaggerSetup.cs @@ -18,7 +18,6 @@ namespace IRaCIS.Core.API { public static void AddSwaggerSetup(this IServiceCollection services) { - services.AddSwaggerExamplesFromAssemblyOf(); services.AddSwaggerGen(options => { @@ -63,7 +62,6 @@ namespace IRaCIS.Core.API // 在header中添加token,传递到后台 options.OperationFilter(); - options.DocumentFilter(); // 添加登录按钮 options.AddSecurityDefinition("bearerAuth", new OpenApiSecurityScheme() diff --git a/IRaCIS.Core.API/_ServiceExtensions/hangfireSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/hangfireSetup.cs index a5dd1fc09..00b718e2c 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/hangfireSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/hangfireSetup.cs @@ -1,13 +1,12 @@ using Hangfire; using Hangfire.SqlServer; -using Hangfire.Tags.SqlServer; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using System; namespace IRaCIS.Core.API { - public static class hangfireSetup + public static class hangfireSetup { public static void AddhangfireSetup(this IServiceCollection services, IConfiguration configuration) { @@ -15,24 +14,29 @@ namespace IRaCIS.Core.API services.AddHangfire(hangFireConfig => { + + //hangFireConfig.UseInMemoryStorage(); + //指定存储介质 hangFireConfig.UseSqlServerStorage(hangFireConnStr, new SqlServerStorageOptions() { - SchemaName = "hangfire", + SchemaName = "dbo", CommandBatchMaxTimeout = TimeSpan.FromMinutes(5), SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5), QueuePollInterval = TimeSpan.Zero, UseRecommendedIsolationLevel = true, - UsePageLocksOnDequeue = true, DisableGlobalLocks = true }); - hangFireConfig.UseTagsWithSql(); //nuget引入Hangfire.Tags.SqlServer + //hangFireConfig.UseTagsWithSql(); //nuget引入Hangfire.Tags.SqlServer //.UseHangfireHttpJob(); }); - services.AddHangfireServer(); + services.AddHangfireServer(option => + { + option.Queues = new[] { "immediately_once", "default", "sys_init", "not_immediately_once" }; + }); } } diff --git a/IRaCIS.Core.API/appsettings.CenterImageDev.json b/IRaCIS.Core.API/appsettings.CenterImageDev.json deleted file mode 100644 index 948b3dacd..000000000 --- a/IRaCIS.Core.API/appsettings.CenterImageDev.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "ConnectionStrings": { - "RemoteNew": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=CenterImage_Test;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true" - }, - "BasicSystemConfig": { - - "OpenUserComplexPassword": false, - - "OpenSignDocumentBeforeWork": false, - - "OpenTrialRelationDelete": true, - - "OpenLoginLimit": false, - - "LoginMaxFailCount": 5, - - "LoginFailLockMinutes": 30 - }, - - "SystemEmailSendConfig": { - "Port": 465, - "Host": "smtp.qiye.aliyun.com", - "FromEmail": "test@extimaging.com", - "FromName": "Test_IRC", - "AuthorizationCode": "SHzyyl2021" - } - -} diff --git a/IRaCIS.Core.API/appsettings.CertificateApply.json b/IRaCIS.Core.API/appsettings.CertificateApply.json deleted file mode 100644 index 2c04ce923..000000000 --- a/IRaCIS.Core.API/appsettings.CertificateApply.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft": "Warning", - "Microsoft.Hosting.Lifetime": "Information" - } - }, - "ConnectionStrings": { - "RemoteNew": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=IRaCIS_Certificate;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true", - "Hangfire": "Server=123.56.94.154,1433\\MSSQLSERVER;Database=Hangfire_IRaCIS;User ID=sa;Password=dev123456DEV;TrustServerCertificate=true" - - }, - "BasicSystemConfig": { - - "OpenUserComplexPassword": false, - - "OpenSignDocumentBeforeWork": false, - - "OpenTrialRelationDelete": true, - - "OpenLoginLimit": false - }, - - "SystemEmailSendConfig": { - "Port": 465, - "Host": "smtp.qiye.aliyun.com", - "FromEmail": "test@extimaging.com", - "FromName": "Test_IRC", - "AuthorizationCode": "SHzyyl2021" - } - -} diff --git a/IRaCIS.Core.API/appsettings.Development.json b/IRaCIS.Core.API/appsettings.Development.json index 076ddb95f..a71d2d214 100644 --- a/IRaCIS.Core.API/appsettings.Development.json +++ b/IRaCIS.Core.API/appsettings.Development.json @@ -13,10 +13,14 @@ }, "AliyunOSS": { - "endpoint": "https://zyypacs-code.oss-cn-shanghai.aliyuncs.com", - "accessKeyId": "mpXG7Nu6zTpsDrI1", - "accessKeySecret": "yNINcEb099SkNfF6vYKaoP8TZNI3xZ", - "bucketName": "zyypacs-code" + "RegionId": "cn-shanghai", + "Endpoint": "https://oss-cn-shanghai.aliyuncs.com", + "AccessKeyId": "LTAI5tKvzs7ed3UfSpNk3xwQ", + "AccessKeySecret": "zTIceGEShlZDGnLrCFfIGFE7TXVRio", + "BucketName": "zy-sir-test-store", + "RoleArn": "acs:ram::1899121822495495:role/oss-upload", + "ViewEndpoint": "https://zy-sir-test-store.oss-cn-shanghai.aliyuncs.com", + "Region": "oss-cn-shanghai" }, "BasicSystemConfig": { @@ -30,7 +34,7 @@ "LoginMaxFailCount": 5, - "LoginFailLockMinutes":1 + "LoginFailLockMinutes": 1 }, "SystemEmailSendConfig": { @@ -38,7 +42,9 @@ "Host": "smtp.qiye.aliyun.com", "FromEmail": "test@extimaging.com", "FromName": "Test_IRC", - "AuthorizationCode": "SHzyyl2021" + "AuthorizationCode": "SHzyyl2021", + + "SiteUrl": "http://test.extimaging.com/login" } } diff --git a/IRaCIS.Core.API/appsettings.Production.json b/IRaCIS.Core.API/appsettings.Production.json index 91ca65025..442c3a8d1 100644 --- a/IRaCIS.Core.API/appsettings.Production.json +++ b/IRaCIS.Core.API/appsettings.Production.json @@ -35,7 +35,8 @@ "Host": "smtp.qiye.aliyun.com", "FromEmail": "IRC@extimaging.com", "FromName": "IRC", - "AuthorizationCode": "ExtImg@2022" + "AuthorizationCode": "ExtImg@2022", + "SiteUrl": "http://irc.extimaging.com/login" } diff --git a/IRaCIS.Core.API/appsettings.Staging.json b/IRaCIS.Core.API/appsettings.Staging.json index c40e2367e..708834b73 100644 --- a/IRaCIS.Core.API/appsettings.Staging.json +++ b/IRaCIS.Core.API/appsettings.Staging.json @@ -27,7 +27,8 @@ "Host": "smtp.qiye.aliyun.com", "FromEmail": "uat@extimaging.com", "FromName": "UAT_IRC", - "AuthorizationCode": "SHzyyl2021" + "AuthorizationCode": "SHzyyl2021", + "SiteUrl": "http://uat.extimaging.com/login" } diff --git a/IRaCIS.Core.API/appsettings.json b/IRaCIS.Core.API/appsettings.json index f142d1f51..242ea4da5 100644 --- a/IRaCIS.Core.API/appsettings.json +++ b/IRaCIS.Core.API/appsettings.json @@ -55,6 +55,26 @@ "EnableReadDeepClone": true, "EnableWriteDeepClone": false } + }, + "redis": { + "MaxRdSecond": 120, + "EnableLogging": false, + "LockMs": 5000, + "SleepMs": 300, + "dbconfig": { + "Password": "xc@123456", + "IsSsl": false, + "SslHost": null, + "ConnectionTimeout": 5000, + "AllowAdmin": true, + "Endpoints": [ + { + "Host": "47.117.164.182", + "Port": 6379 + } + ], + "Database": 0 + } } }, "IRaCISImageStore": { diff --git a/IRaCIS.Core.Application/BackGroundJob/CacheTrialStatusQuartZJob.cs b/IRaCIS.Core.Application/BackGroundJob/CacheTrialStatusQuartZJob.cs deleted file mode 100644 index e3be27479..000000000 --- a/IRaCIS.Core.Application/BackGroundJob/CacheTrialStatusQuartZJob.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; -using EasyCaching.Core; -using IRaCIS.Core.Domain; -using IRaCIS.Core.Infra.EFCore; -using IRaCIS.Core.Domain.Models; -using Microsoft.Extensions.Logging; -using Quartz; -using IRaCIS.Core.Domain.Share; - -namespace IRaCIS.Application.Services.BackGroundJob -{ - - public class CacheTrialStatusQuartZJob: IJob - { - - private readonly IRepository _trialRepository; - private readonly IEasyCachingProvider _provider; - private readonly ILogger _logger; - private readonly IRepository _systemAnonymizationRepository; - - public CacheTrialStatusQuartZJob(IRepository trialRepository, IEasyCachingProvider provider,ILogger logger, IRepository systemAnonymizationRepository) - { - _trialRepository = trialRepository; - _provider = provider; - _logger = logger; - _systemAnonymizationRepository = systemAnonymizationRepository; - } - - public async Task Execute(IJobExecutionContext context) - - { - _logger.LogInformation($"开始执行QuartZ定时任务作业"); - try - { - await MemoryCacheTrialStatus(); - - await MemoryCacheAnonymizeData(); - - } - catch (Exception e) - { - _logger.LogError($" 查询和缓存过程出现异常"+e.Message); - } - _logger.LogInformation("QuartZ定时任务作业结束"); - } - - - public async Task MemoryCacheTrialStatus() - { - var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr }) - .ToListAsync(); - - list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7))); - - } - - public async Task MemoryCacheAnonymizeData() - { - var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync(); - - _provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7)); - _provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7)); - _provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7)); - _provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7)); - } - - - - } -} \ No newline at end of file diff --git a/IRaCIS.Core.Application/BackGroundJob/IRaCISCHangfireJob.cs b/IRaCIS.Core.Application/BackGroundJob/IRaCISCHangfireJob.cs new file mode 100644 index 000000000..f62423549 --- /dev/null +++ b/IRaCIS.Core.Application/BackGroundJob/IRaCISCHangfireJob.cs @@ -0,0 +1,213 @@ +using EasyCaching.Core; +using Hangfire; +using Hangfire.Storage; +using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Application.Service; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Infrastructure; +using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace IRaCIS.Application.Services.BackGroundJob +{ + + public interface IIRaCISHangfireJob + { + + Task MemoryCacheTrialStatusAsync(); + + Task InitHangfireJobTaskAsync(); + + } + public class IRaCISCHangfireJob : IIRaCISHangfireJob + { + public static string JsonFileFolder = Path.Combine(AppContext.BaseDirectory, StaticData.Folder.Resources); + + private readonly IRepository _trialRepository; + private readonly IEasyCachingProvider _provider; + private readonly ILogger _logger; + private readonly IRepository _systemAnonymizationRepository; + private readonly IRepository _trialEmailNoticeConfigRepository; + private readonly IRepository _internationalizationRepository; + + + + public IRaCISCHangfireJob(IRepository trialRepository, ILogger logger, IEasyCachingProvider provider, IRepository trialEmailNoticeConfigRepository, IRepository internationalizationRepository, IRepository systemAnonymizationRepository) + { + _trialRepository = trialRepository; + _provider = provider; + _logger = logger; + _trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository; + _internationalizationRepository = internationalizationRepository; + _systemAnonymizationRepository = systemAnonymizationRepository; + } + + public async Task InitHangfireJobTaskAsync() + { + _logger.LogInformation("项目启动 hangfire 任务初始化 执行开始~"); + + + //项目状态 立即加载到缓存中 + await MemoryCacheTrialStatusAsync(); + + await MemoryCacheAnonymizeData(); + + + //创建项目缓存 定时任务 + HangfireJobHelper.AddOrUpdateInitCronJob("RecurringJob_Cache_TrialState", t => t.MemoryCacheTrialStatusAsync(), Cron.Daily()); + + //初始化 + + await InitInternationlizationDataAndWatchJsonFileAsync(); + + //创建邮件定时任务 + await InitSysAndTrialCronJobAsync(); + + + _logger.LogInformation("项目启动 hangfire 任务初始化 执行结束"); + } + + /// + /// 缓存项目状态 + /// + /// + public async Task MemoryCacheTrialStatusAsync() + { + + var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr }) + .ToListAsync(); + + list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7))); + + } + + public async Task MemoryCacheAnonymizeData() + { + var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync(); + + _provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7)); + _provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7)); + _provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7)); + _provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7)); + } + + + #region 国际化 初始化 + + + public async Task InitInternationlizationDataAndWatchJsonFileAsync() + { + //查询数据库的数据 + var toJsonList = await _internationalizationRepository.Where(t => t.InternationalizationType == 1).Select(t => new + { + t.Code, + t.Value, + t.ValueCN + }).ToListAsync(); + + //组织成json 文件 + + var usJsonPath = Path.Combine(JsonFileFolder, StaticData.En_US_Json); + var cnJsonPath = Path.Combine(JsonFileFolder, StaticData.Zh_CN_Json); + + + //本地静态文件国际化需要 + foreach (var tojsonItem in toJsonList) + { + StaticData.En_US_Dic[tojsonItem.Code] = tojsonItem.Value; + StaticData.Zh_CN_Dic[tojsonItem.Code] = tojsonItem.ValueCN; + } + + File.WriteAllText(usJsonPath, JsonConvert.SerializeObject(StaticData.En_US_Dic)); + File.WriteAllText(cnJsonPath, JsonConvert.SerializeObject(StaticData.Zh_CN_Dic)); + + + //监测Json文件变更 实时刷新数据 + WatchJsonFile(usJsonPath); + WatchJsonFile(cnJsonPath); + + } + + public void WatchJsonFile(string filePath) + { + if (!File.Exists(filePath)) + { + throw new BusinessValidationFailedException(StaticData.International("IRaCISCHangfireJob_FileNotFound")); + } + + FileSystemWatcher watcher = new FileSystemWatcher(Path.GetDirectoryName(filePath), Path.GetFileName(filePath)); + watcher.Changed += (sender, e) => LoadJsonFile(filePath); + watcher.EnableRaisingEvents = true; + + } + + + private void LoadJsonFile(string filePath) + { + + IConfigurationBuilder builder = new ConfigurationBuilder().AddJsonFile(filePath); + + IConfigurationRoot enConfiguration = builder.Build(); + + foreach (IConfigurationSection section in enConfiguration.GetChildren()) + { + if (filePath.Contains(StaticData.En_US_Json)) + { + StaticData.En_US_Dic[section.Key] = section.Value; + + } + else + { + StaticData.Zh_CN_Dic[section.Key] = section.Value; + } + } + } + + #endregion + + public async Task InitSysAndTrialCronJobAsync() + { + //var deleteJobIdList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr != StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend) + // .Select(t => t.TrialId + "_" + t.Id) + // .ToListAsync(); + + //foreach (var jobId in deleteJobIdList) + //{ + // HangfireJobHelper.RemoveCronJob(jobId); + //} + + + 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, t.EmailCron, t.BusinessScenarioEnum, t.TrialId }) + .ToListAsync(); + + foreach (var task in taskInfoList) + { + //利用主键作为任务Id + var jobId = $"{task.TrialId}_{task.Id}"; + + HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, task.TrialId, task.BusinessScenarioEnum, task.EmailCron); + } + + var addOrUpdateJobIdList = taskInfoList.Select(t => $"{t.TrialId}_{t.Id}").ToList(); + + var list = JobStorage.Current.GetConnection().GetRecurringJobs().ToList(); + + //项目定时任务都在default 队列 + //var dbJobIdList = JobStorage.Current.GetConnection().GetRecurringJobs().Where(t => t.Queue == "default").Select(t => t.Id).ToList(); + + //var deleteList= dbJobIdList.Except(addOrUpdateJobIdList).ToList(); + + // foreach (var jobId in deleteList) + // { + // HangfireJobHelper.RemoveCronJob(jobId); + // } + + + } + } + + +} diff --git a/IRaCIS.Core.Application/BackGroundJob/IRaCISCacheHangfireJob.cs b/IRaCIS.Core.Application/BackGroundJob/IRaCISCacheHangfireJob.cs deleted file mode 100644 index 80a3d16ac..000000000 --- a/IRaCIS.Core.Application/BackGroundJob/IRaCISCacheHangfireJob.cs +++ /dev/null @@ -1,99 +0,0 @@ -using EasyCaching.Core; -using IRaCIS.Core.Domain.Share; -using Microsoft.EntityFrameworkCore.SqlServer.Query.Internal; -using Microsoft.Extensions.Logging; - -namespace IRaCIS.Application.Services.BackGroundJob -{ - - public interface IIRaCISCacheHangfireJob - { - - Task ProjectStartCache(); - Task MemoryCacheTrialStatus(); - - Task MemoryCacheAnonymizeData(); - - Task CacheUserTypePermission(Guid? cacheUserTypeId); - } - public class IRaCISCacheHangfireJob: IIRaCISCacheHangfireJob - { - private readonly IRepository _trialRepository; - private readonly IEasyCachingProvider _provider; - private readonly ILogger _logger; - private readonly IRepository _systemAnonymizationRepository; - - private readonly IRepository _userTypeMenuRepository; - - public IRaCISCacheHangfireJob(IRepository trialRepository, - IRepository systemAnonymizationRepository, IRepository userTypeMenuRepository, - IEasyCachingProvider provider,ILogger logger) - { - _trialRepository = trialRepository; - _provider = provider; - _logger = logger; - _systemAnonymizationRepository = systemAnonymizationRepository; - _userTypeMenuRepository = userTypeMenuRepository; - } - - - public async Task ProjectStartCache() - { - _logger.LogInformation("hangfire 定时缓存项目状态任务开始~"); - try - { - await MemoryCacheTrialStatus(); - - await MemoryCacheAnonymizeData(); - - await CacheUserTypePermission(); - } - catch (Exception e) - { - _logger.LogError("hangfire 定时任务执行失败" + e.Message); - - } - - _logger.LogInformation("hangfire 定时任务执行结束"); - } - - public async Task MemoryCacheTrialStatus() - { - var list = await _trialRepository.Select(t => new { TrialId = t.Id, TrialStatusStr = t.TrialStatusStr }) - .ToListAsync(); - - list.ForEach(t => _provider.Set(t.TrialId.ToString(), t.TrialStatusStr, TimeSpan.FromDays(7))); - - } - - - - - - - - public async Task MemoryCacheAnonymizeData() - { - var systemAnonymizationList = await _systemAnonymizationRepository.Where(t => t.IsEnable).ToListAsync(); - - _provider.Set(StaticData.Anonymize.Anonymize_AddFixedFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed).ToList(), TimeSpan.FromDays(7)); - _provider.Set(StaticData.Anonymize.Anonymize_AddIRCInfoFiled, systemAnonymizationList.Where(t => t.IsAdd && t.IsFixed == false).ToList(), TimeSpan.FromDays(7)); - _provider.Set(StaticData.Anonymize.Anonymize_FixedField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed).ToList(), TimeSpan.FromDays(7)); - _provider.Set(StaticData.Anonymize.Anonymize_IRCInfoField, systemAnonymizationList.Where(t => t.IsAdd == false && t.IsFixed == false).ToList(), TimeSpan.FromDays(7)); - } - - public async Task CacheUserTypePermission(Guid? cacheUserTypeId=null) - { - - var permissionList = await _userTypeMenuRepository.Where(t => t.Menu.MenuType == "F") - .WhereIf(cacheUserTypeId != null, t => t.UserTypeId == cacheUserTypeId.Value).Select(t => new { t.UserTypeId, t.Menu.PermissionStr }).ToListAsync(); - - foreach (var userTypeGroup in permissionList.GroupBy(t => t.UserTypeId)) - { - _provider.Set($"{StaticData.CacheKey.UserTypeId}_{userTypeGroup.Key}", userTypeGroup.Select(t => t.PermissionStr).ToList(), TimeSpan.FromDays(7)); - } - } - - - } -} \ No newline at end of file diff --git a/IRaCIS.Core.Application/Helper/FileStoreHelper.cs b/IRaCIS.Core.Application/Helper/FileStoreHelper.cs index 0089d3e9a..c0797b1fe 100644 --- a/IRaCIS.Core.Application/Helper/FileStoreHelper.cs +++ b/IRaCIS.Core.Application/Helper/FileStoreHelper.cs @@ -116,6 +116,51 @@ public static class FileStoreHelper return physicalFilePath; } + + #region 修改后留存 + + + public static (string PhysicalPath, string RelativePath) GetSystemFileUploadPath(IWebHostEnvironment _hostEnvironment, string templateFolderName, string fileName) + { + var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment); + + //文件类型路径处理 + var uploadFolderPath = Path.Combine(rootPath, StaticData.Folder.SystemDataFolder, templateFolderName); + if (!Directory.Exists(uploadFolderPath)) Directory.CreateDirectory(uploadFolderPath); + + + var (trustedFileNameForFileStorage, fileRealName) = FileStoreHelper.GetStoreFileName(fileName); + + + var relativePath = $"/{StaticData.Folder.IRaCISDataFolder}/{StaticData.Folder.SystemDataFolder}/{templateFolderName}/{trustedFileNameForFileStorage}"; + + var serverFilePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage); + + return (serverFilePath, relativePath); + } + + public static (string PhysicalPath, string RelativePath) GetOtherFileUploadPath(IWebHostEnvironment _hostEnvironment, string templateFolderName, string fileName) + { + var rootPath = FileStoreHelper.GetIRaCISRootDataFolder(_hostEnvironment); + + //文件类型路径处理 + var uploadFolderPath = Path.Combine(rootPath, StaticData.Folder.OtherDataFolder, templateFolderName); + if (!Directory.Exists(uploadFolderPath)) Directory.CreateDirectory(uploadFolderPath); + + + var (trustedFileNameForFileStorage, fileRealName) = FileStoreHelper.GetStoreFileName(fileName); + + + var relativePath = $"/{StaticData.Folder.IRaCISDataFolder}/{StaticData.Folder.OtherDataFolder}/{templateFolderName}/{trustedFileNameForFileStorage}"; + + var serverFilePath = Path.Combine(uploadFolderPath, trustedFileNameForFileStorage); + + return (serverFilePath, relativePath); + } + + + #endregion + /// /// /// diff --git a/IRaCIS.Core.Application/Helper/HangfireJobHelper.cs b/IRaCIS.Core.Application/Helper/HangfireJobHelper.cs new file mode 100644 index 000000000..69eaf410d --- /dev/null +++ b/IRaCIS.Core.Application/Helper/HangfireJobHelper.cs @@ -0,0 +1,92 @@ +using Hangfire; +using IRaCIS.Core.Application.Service; +using IRaCIS.Core.Domain.Share; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NPOI.SS.Formula.Functions; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.Helper +{ + public static class HangfireJobHelper + { + + + + //public static void AddOrUpdateCronJob(string jobId, string queueName, Expression methodCall, string cron) + //{ + // RecurringJob.AddOrUpdate(jobId, queueName, methodCall, cron); + //} + + + + //添加 或者更新定时任务 Id 要唯一标识一个定义任务 + public static void AddOrUpdateCronJob(string jobId, Expression> methodCall, string cron, string queueName = "default") + { + RecurringJob.AddOrUpdate(jobId, queueName, methodCall, cron); + } + + public static void AddOrUpdateInitCronJob(string jobId, Expression> methodCall, string cron) + { + RecurringJob.AddOrUpdate(jobId, "sys_init", methodCall, cron); + } + + public static void RemoveCronJob(string jobId) + { + RecurringJob.RemoveIfExists(jobId); + + } + + + + public static void ImmediatelyOnceOnlyJob(Expression methodCall) + { + BackgroundJob.Enqueue("immediately_once", methodCall); + } + + public static void ImmediatelyOnceOnlyJob(Expression> methodCall) + { + BackgroundJob.Enqueue("immediately_once", methodCall); + } + + public static void NotImmediatelyOnceOnlyJob(Expression methodCall, TimeSpan timeSpan) + { + BackgroundJob.Schedule("not_immediately_once", methodCall, timeSpan); + } + + public static void NotImmediatelyOnceOnlyJob(Expression> methodCall, TimeSpan timeSpan) + { + BackgroundJob.Schedule("not_immediately_once", methodCall, timeSpan); + } + + + public static void AddOrUpdateTrialCronJob (string jobId, Guid trialId, EmailBusinessScenario businessScenario, string emailCron) + { + + switch (businessScenario) + { + + case EmailBusinessScenario.QCTask: + HangfireJobHelper.AddOrUpdateCronJob(jobId, t => t.SendTrialImageQCTaskEmailAsync(trialId), emailCron); + break; + case EmailBusinessScenario.QCQuestion: + HangfireJobHelper.AddOrUpdateCronJob(jobId, t => t.SendTrialQCQuestionEmailAsync(trialId), emailCron); + break; + case EmailBusinessScenario.ImageQuestion: + HangfireJobHelper.AddOrUpdateCronJob(jobId, t => t.SendTrialImageQuestionAsync(trialId), emailCron); + break; + + default: + break; + } + + } + } +} + + diff --git a/IRaCIS.Core.Application/Helper/OSSService.cs b/IRaCIS.Core.Application/Helper/OSSService.cs new file mode 100644 index 000000000..1fba59176 --- /dev/null +++ b/IRaCIS.Core.Application/Helper/OSSService.cs @@ -0,0 +1,120 @@ +using Aliyun.OSS; +using IRaCIS.Core.Infrastructure; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using NPOI.HPSF; +using SharpCompress.Common; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Security.AccessControl; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.Helper +{ + + public class AliyunOssOptions + { + public string RegionId { get; set; } + public string AccessKeyId { get; set; } + public string AccessKeySecret { get; set; } + public string EndPoint { get; set; } + public string BucketName { get; set; } + + public string RoleArn { get;set; } + + public string Region { get; set; } + + public string ViewEndpoint { get; set; } + + + } + + + public interface IOSSService + { + + } + + public class OSSService : IOSSService + { + + public AliyunOssOptions _OSSConfig { get; set; } + + public OssClient _ossClient { get; set; } + + + + public OSSService(IOptionsMonitor options) + { + var ossOptions = options.CurrentValue; + + _OSSConfig = new AliyunOssOptions() + { + RegionId = ossOptions.RegionId, + AccessKeyId = ossOptions.AccessKeyId, + AccessKeySecret = ossOptions.AccessKeySecret, + EndPoint = ossOptions.EndPoint, + BucketName = ossOptions.BucketName, + RoleArn = ossOptions.RoleArn, + Region = ossOptions.Region, + ViewEndpoint = ossOptions.ViewEndpoint + }; + + _ossClient = new OssClient(_OSSConfig.EndPoint, _OSSConfig.AccessKeyId, _OSSConfig.AccessKeySecret); + + } + + + public string UploadToOSS(string localFilePath, string oosFolderPath) + { + var localFileName = Path.GetFileName(localFilePath); + + var ossRelativePath = oosFolderPath + "/" + localFileName; + + + try + { + // 上传文件 + var result = _ossClient.PutObject(_OSSConfig.BucketName, ossRelativePath, localFilePath); + + return ossRelativePath; + } + catch (Exception ex) + { + throw new BusinessValidationFailedException("oss上传失败" + ex.Message); + + } + } + + public void DownLoadFromOSS(string ossRelativePath, string localFilePath) + { + try + { + var result = _ossClient.GetObject(_OSSConfig.BucketName, ossRelativePath); + + // 将下载的文件流保存到本地文件 + using (var fs = File.OpenWrite(localFilePath)) + { + result.Content.CopyTo(fs); + fs.Close(); + } + } + catch (Exception ex) + { + + throw new BusinessValidationFailedException("oss下载失败!" + ex.Message); + } + + + } + + + + + } + + +} diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj index 247ed6016..aa9a82bba 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj @@ -64,48 +64,44 @@ + + + + - + + + + + + true + + + true - - - - + true - - - true - - - true - - - - - - - true - - - - + + + + + + true - - - - - - - + + + + + diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index ce7fb263e..38559fb74 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -685,6 +685,27 @@ PublishLogService + + + 影像质控 + + + + + + + QC质疑 + + + + + + + 影像质疑 + + + + TrialEmailNoticeConfigService @@ -706,7 +727,7 @@ - 同步系统配置的文档到想项目中 + 同步系统配置的文档到想项目中 ---废弃 @@ -756,6 +777,27 @@ + + + 黑名单用户Id 列表 + + + + + + + 获取系统 邮件配置 勾选列表 + + + + + + + 批量勾选 传递列表每行数据,后台进行处理转换,建立关联关系 + + + + 指定资源Id,渲染Dicom检查的Jpeg预览图像 Dicom检查的Id @@ -8929,6 +8971,27 @@ TrialEmailNoticeConfigQuery 列表查询参数模型 + + 业务模块 /// + + + 业务层级 /// + + + 邮件类型 /// + + + 邮件加急类型 /// + + + 定时周期 /// + + + 邮件主题 /// + + + 附件 /// + TrialEmailNoticeConfigAddOrEdit 列表查询参数模型 @@ -9823,6 +9886,24 @@ 是否区分标准 + + 业务模块 /// + + + 业务层级 /// + + + 邮件类型 /// + + + 邮件加急类型 /// + + + 定时周期 /// + + + 邮件主题 /// + SystemBasicDataView 列表视图模型 @@ -10274,11 +10355,6 @@ TrialSiteUserSurveyAddOrEdit 列表查询参数模型 - - - 实测 标注在服务方法上 没用 - - TrialSiteEquipmentSurveyService @@ -11851,6 +11927,12 @@ 构造函数注入 + + + 缓存项目状态 + + + 统一返回前端数据包装,之前在控制器包装,现在修改为动态Api 在ResultFilter这里包装,减少重复冗余代码 diff --git a/IRaCIS.Core.Application/Service/Allocation/TaskConsistentRuleService.cs b/IRaCIS.Core.Application/Service/Allocation/TaskConsistentRuleService.cs index 1f8480a21..14ded501a 100644 --- a/IRaCIS.Core.Application/Service/Allocation/TaskConsistentRuleService.cs +++ b/IRaCIS.Core.Application/Service/Allocation/TaskConsistentRuleService.cs @@ -13,9 +13,9 @@ using IRaCIS.Core.Domain.Share; using System.Linq.Expressions; using IRaCIS.Core.Infra.EFCore.Common; using System.Linq; -using Nito.AsyncEx; using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Filter; +using Medallion.Threading; namespace IRaCIS.Core.Application.Service { @@ -31,16 +31,17 @@ namespace IRaCIS.Core.Application.Service private readonly IRepository _subjectUserRepository; private readonly IRepository _subjectRepository; private readonly IRepository _enrollRepository; + private readonly IDistributedLockProvider _distributedLockProvider; - private readonly AsyncLock _mutex = new AsyncLock(); - public TaskConsistentRuleService(IRepository visitTaskRepository, IRepository enrollRepository, IRepository taskConsistentRuleRepository, IRepository subjectUserRepository, IRepository subjectRepository) + public TaskConsistentRuleService(IRepository visitTaskRepository, IRepository enrollRepository, IRepository taskConsistentRuleRepository, IRepository subjectUserRepository, IRepository subjectRepository, IDistributedLockProvider distributedLockProvider) { _taskConsistentRuleRepository = taskConsistentRuleRepository; _visitTaskRepository = visitTaskRepository; _subjectUserRepository = subjectUserRepository; _subjectRepository = subjectRepository; _enrollRepository = enrollRepository; + _distributedLockProvider = distributedLockProvider; } /// @@ -142,7 +143,9 @@ namespace IRaCIS.Core.Application.Service //var list = query.OrderByDescending(t => t.IsHaveGeneratedTask).ToList(); - using (await _mutex.LockAsync()) + var @lock = _distributedLockProvider.CreateLock($"VisitTaskCode"); + + using (await @lock.AcquireAsync()) { int maxCodeInt = 0; @@ -293,7 +296,9 @@ namespace IRaCIS.Core.Application.Service var configDoctorUserIdList = await doctorUserIdQuery.ToListAsync(); - using (await _mutex.LockAsync()) + var @lock = _distributedLockProvider.CreateLock($"VisitTaskCode"); + + using (await @lock.AcquireAsync()) { int maxCodeInt = 0; diff --git a/IRaCIS.Core.Application/Service/Common/DTO/CommonDocumentViewModel.cs b/IRaCIS.Core.Application/Service/Common/DTO/CommonDocumentViewModel.cs index 25a9212ac..77e41901d 100644 --- a/IRaCIS.Core.Application/Service/Common/DTO/CommonDocumentViewModel.cs +++ b/IRaCIS.Core.Application/Service/Common/DTO/CommonDocumentViewModel.cs @@ -35,7 +35,7 @@ namespace IRaCIS.Core.Application.ViewModel { public CriterionType? CriterionTypeEnum { get; set; } public CommonDocumentFileType? FileTypeEnum { get; set; } - public CommonDocumentBusinessScenario? BusinessScenarioEnum { get; set; } + public EmailBusinessScenario? BusinessScenarioEnum { get; set; } public string Name { get; set; } = String.Empty; @@ -55,7 +55,7 @@ namespace IRaCIS.Core.Application.ViewModel public CriterionType? CriterionTypeEnum { get; set; } public CommonDocumentFileType FileTypeEnum { get; set; } - public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; } + public EmailBusinessScenario BusinessScenarioEnum { get; set; } //public Guid FileTypeId { get; set; } diff --git a/IRaCIS.Core.Application/Service/Common/DTO/EmailNoticeConfigViewModel.cs b/IRaCIS.Core.Application/Service/Common/DTO/EmailNoticeConfigViewModel.cs index ae2bfca4b..691b1e8bf 100644 --- a/IRaCIS.Core.Application/Service/Common/DTO/EmailNoticeConfigViewModel.cs +++ b/IRaCIS.Core.Application/Service/Common/DTO/EmailNoticeConfigViewModel.cs @@ -3,10 +3,16 @@ // 生成时间 2022-02-15 11:55:57 // 对此文件的更改可能会导致不正确的行为,并且如果重新生成代码,这些更改将会丢失。 //-------------------------------------------------------------------- +using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using Newtonsoft.Json; namespace IRaCIS.Core.Application.Contracts { + public class TrialSelectEmailNoticeConfigView : EmailNoticeConfigView + { + public bool IsHaveSelected { get; set; } + } + /// EmailNoticeConfigView 列表视图模型 public class EmailNoticeConfigView : EmailNoticeConfigAddOrEdit { @@ -19,6 +25,12 @@ namespace IRaCIS.Core.Application.Contracts + public List EmailNoticeUserList { get; set; } + + + public new List ToUserTypeList => EmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(t => t.UserType).ToList(); + public new List CopyUserTypeList => EmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(t => t.UserType).ToList(); + //[JsonIgnore] //public SystemBasicDataSelect Scenario { get; set; } ////public Guid? ScenarioParentId => Scenario.ParentId; @@ -28,17 +40,29 @@ namespace IRaCIS.Core.Application.Contracts } + public class EmailUserTypeDto + { + public UserTypeEnum UserType { get; set; } + + public EmailUserType EmailUserType { get; set; } + } + ///EmailNoticeConfigQuery 列表查询参数模型 - public class EmailNoticeConfigQuery:PageInput + public class EmailNoticeConfigQuery : PageInput { //public Guid? ScenarioId { get; set; } - public CommonDocumentBusinessScenario? BusinessScenarioEnum { get; set; } + public EmailBusinessScenario? BusinessScenarioEnum { get; set; } public bool? IsReturnRequired { get; set; } - public bool? IsUrgent { get; set; } public bool? IsEnable { get; set; } + public CriterionType? CriterionTypeEnum { get; set; } + + public Guid? TrialId { get; set; } + + public bool? IsDistinguishCriteria { get; set; } + } /// EmailNoticeConfigAddOrEdit 列表查询参数模型 @@ -47,31 +71,66 @@ namespace IRaCIS.Core.Application.Contracts public Guid? Id { get; set; } public string Code { get; set; } = String.Empty; - - public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; } + public EmailBusinessScenario BusinessScenarioEnum { get; set; } /// /// 是否区分标准 /// public bool IsDistinguishCriteria { get; set; } - - //public string AuthorizationCode { get; set; } = String.Empty; - //public Guid ScenarioId { get; set; } - //public string Title { get; set; } = String.Empty; - //public string Body { get; set; } = String.Empty; - //public string FromEmail { get; set; } = String.Empty; - //public string ReceiveEmail { get; set; } = String.Empty; - //public string CopyEmail { get; set; } = String.Empty; public bool IsReturnRequired { get; set; } - public bool IsUrgent { get; set; } public bool IsEnable { get; set; } public bool IsAutoSend { get; set; } public bool IsDeleted { get; set; } + + + + public CriterionType? CriterionTypeEnum { get; set; } + + /// 业务模块 /// + public int BusinessModuleEnum { get; set; } + + /// 业务层级 /// + public int BusinessLevelEnum { get; set; } + + /// 邮件类型 /// + public int EmailTypeEnum { get; set; } + + /// 邮件加急类型 /// + public int EmailUrgentEnum { get; set; } + public string Description { get; set; } = string.Empty; + + + /// 定时周期 /// + public string EmailCron { get; set; } = string.Empty; + + /// 邮件主题 /// + public string EmailTopic { get; set; } = string.Empty; + + public string EmailTopicCN { get; set; } = string.Empty; + + + public string AttachPath { get; set; } = string.Empty; + + public string AttachCNPath { get; set; } = string.Empty; + + public string EmailHtmlContent { get; set; } = string.Empty; + + public string EmailHtmlContentCN { get; set; } = string.Empty; + + public string AttachName { get; set; } + public string AttachNameCN { get; set; } + + + public List ToUserTypeList { get; set; } + public List CopyUserTypeList { get; set; } + } + + } diff --git a/IRaCIS.Core.Application/Service/Common/DictionaryService.cs b/IRaCIS.Core.Application/Service/Common/DictionaryService.cs index cc5bf300d..f41b6d3bc 100644 --- a/IRaCIS.Core.Application/Service/Common/DictionaryService.cs +++ b/IRaCIS.Core.Application/Service/Common/DictionaryService.cs @@ -259,7 +259,7 @@ namespace IRaCIS.Application.Services public async Task>> GetBasicDataSelect(string[] searchArray) { - var searchList = await _dicRepository.Where(t => searchArray.Contains(t.Parent.Code) && t.ParentId != null && t.IsEnable).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); + var searchList = await _dicRepository.Where(t => searchArray.Contains(t.Parent.Code) && t.ParentId != null && t.IsEnable).ProjectTo(_mapper.ConfigurationProvider,new { isEn_Us = _userInfo.IsEn_Us}).ToListAsync(); return searchList.GroupBy(t => t.ParentCode).ToDictionary(g => g.Key, g => g.OrderBy(t => t.ShowOrder).ToList()); diff --git a/IRaCIS.Core.Application/Service/Common/EmailNoticeConfigService.cs b/IRaCIS.Core.Application/Service/Common/EmailNoticeConfigService.cs index 27adfc3be..aa07c35c1 100644 --- a/IRaCIS.Core.Application/Service/Common/EmailNoticeConfigService.cs +++ b/IRaCIS.Core.Application/Service/Common/EmailNoticeConfigService.cs @@ -17,19 +17,22 @@ namespace IRaCIS.Core.Application.Contracts public class EmailNoticeConfigService : BaseService, IEmailNoticeConfigService { private readonly IRepository _emailNoticeConfigrepository; + private readonly IRepository _emailNoticeUserTypeRepository; - public EmailNoticeConfigService(IRepository repository) + public EmailNoticeConfigService(IRepository repository, IRepository emailNoticeUserTypeRepository) { _emailNoticeConfigrepository = repository; + _emailNoticeUserTypeRepository = emailNoticeUserTypeRepository; } [HttpPost] public async Task> GetEmailNoticeConfigList(EmailNoticeConfigQuery queryEmailNoticeConfig) { var emailNoticeConfigQueryable = _emailNoticeConfigrepository + .WhereIf(queryEmailNoticeConfig.IsDistinguishCriteria != null, t => t.IsDistinguishCriteria == queryEmailNoticeConfig.IsDistinguishCriteria) + .WhereIf(queryEmailNoticeConfig.CriterionTypeEnum != null, t => t.CriterionTypeEnum == queryEmailNoticeConfig.CriterionTypeEnum) .WhereIf(queryEmailNoticeConfig.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == queryEmailNoticeConfig.BusinessScenarioEnum) .WhereIf(queryEmailNoticeConfig.IsReturnRequired != null, t => t.IsReturnRequired == queryEmailNoticeConfig.IsReturnRequired) - .WhereIf(queryEmailNoticeConfig.IsUrgent != null, t => t.IsUrgent == queryEmailNoticeConfig.IsUrgent) .WhereIf(queryEmailNoticeConfig.IsEnable != null, t => t.IsEnable == queryEmailNoticeConfig.IsEnable) .ProjectTo(_mapper.ConfigurationProvider); @@ -39,10 +42,55 @@ namespace IRaCIS.Core.Application.Contracts public async Task AddOrUpdateEmailNoticeConfig(EmailNoticeConfigAddOrEdit addOrEditEmailNoticeConfig) { - - var entity = await _emailNoticeConfigrepository.InsertOrUpdateAsync(addOrEditEmailNoticeConfig, true); + if (addOrEditEmailNoticeConfig.Id == null) + { + + var entity = _mapper.Map(addOrEditEmailNoticeConfig); + + + foreach (var item in addOrEditEmailNoticeConfig.ToUserTypeList) + { + entity.EmailNoticeUserTypeList.Add(new EmailNoticeUserType() { EmailUserType = EmailUserType.To, UserType = item }); + + } + + foreach (var item in addOrEditEmailNoticeConfig.CopyUserTypeList) + { + entity.EmailNoticeUserTypeList.Add(new EmailNoticeUserType() { EmailUserType = EmailUserType.Copy, UserType = item }); + + } + + + await _emailNoticeConfigrepository.AddAsync(entity, true); + + return ResponseOutput.Ok(entity.Id.ToString()); + } + else + { + var emailNoticeConfigId = addOrEditEmailNoticeConfig.Id; + await _emailNoticeUserTypeRepository.BatchDeleteNoTrackingAsync(t => t.EmailNoticeConfigId == emailNoticeConfigId); + + + foreach (var item in addOrEditEmailNoticeConfig.ToUserTypeList) + { + await _emailNoticeUserTypeRepository.AddAsync(new EmailNoticeUserType() { EmailUserType = EmailUserType.To, UserType = item, EmailNoticeConfigId = (Guid)emailNoticeConfigId }); + + } + + foreach (var item in addOrEditEmailNoticeConfig.CopyUserTypeList) + { + await _emailNoticeUserTypeRepository.AddAsync(new EmailNoticeUserType() { EmailUserType = EmailUserType.Copy, UserType = item, EmailNoticeConfigId = (Guid)emailNoticeConfigId }); + + } + + + var entity = await _emailNoticeConfigrepository.UpdateFromDTOAsync(addOrEditEmailNoticeConfig, true); + + return ResponseOutput.Ok(entity.Id.ToString()); + + + } - return ResponseOutput.Ok(entity.Id.ToString()); } diff --git a/IRaCIS.Core.Application/Service/Common/MailService.cs b/IRaCIS.Core.Application/Service/Common/MailService.cs index 5f6e58120..7fac78714 100644 --- a/IRaCIS.Core.Application/Service/Common/MailService.cs +++ b/IRaCIS.Core.Application/Service/Common/MailService.cs @@ -6,8 +6,8 @@ using Microsoft.AspNetCore.Hosting; using IRaCIS.Core.Application.Auth; using AutoMapper; using IRaCIS.Application.Contracts; -using Nito.AsyncEx; using Microsoft.Extensions.Options; +using Medallion.Threading; namespace IRaCIS.Application.Services { @@ -54,8 +54,7 @@ namespace IRaCIS.Application.Services private readonly IRepository _userTypeRepository; private readonly IRepository _doctorTypeRepository; - - private readonly AsyncLock _mutex = new AsyncLock(); + private readonly IDistributedLockProvider _distributedLockProvider; private readonly SystemEmailSendConfig _systemEmailConfig; @@ -69,7 +68,7 @@ namespace IRaCIS.Application.Services IRepository trialRepository, IRepository userTypeRepository, IRepository doctorTypeRepository, - IMapper mapper, IOptionsMonitor systemEmailConfig) + IMapper mapper, IOptionsMonitor systemEmailConfig, IDistributedLockProvider distributedLockProvider) { _systemEmailConfig = systemEmailConfig.CurrentValue; _verificationCodeRepository = verificationCodeRepository; @@ -85,7 +84,7 @@ namespace IRaCIS.Application.Services _userTypeRepository = userTypeRepository; _doctorTypeRepository = doctorTypeRepository; - + _distributedLockProvider = distributedLockProvider; } //重置邮箱 @@ -606,7 +605,9 @@ namespace IRaCIS.Application.Services var userType = await _userTypeRepository.FirstAsync(t => t.UserTypeEnum == UserTypeEnum.IndependentReviewer); - using (await _mutex.LockAsync()) + var @lock = _distributedLockProvider.CreateLock($"UserCode"); + + using (await @lock.AcquireAsync()) { var isDoctorHaveAccount = await _userRepository.AnyAsync(t => t.DoctorId == doctorId); diff --git a/IRaCIS.Core.Application/Service/Common/_MapConfig.cs b/IRaCIS.Core.Application/Service/Common/_MapConfig.cs index 4077d674a..cf8a3a95c 100644 --- a/IRaCIS.Core.Application/Service/Common/_MapConfig.cs +++ b/IRaCIS.Core.Application/Service/Common/_MapConfig.cs @@ -20,7 +20,13 @@ namespace IRaCIS.Core.Application.Service CreateMap().ReverseMap(); CreateMap().ReverseMap(); - CreateMap(); + var trialId = Guid.Empty; + CreateMap().IncludeBase() + .ForMember(o => o.IsHaveSelected, t => t.MapFrom(u => u.TrialEmailNoticeConfigList.Any(c => c.TrialId == trialId && c.SysEmailNoticeConfigId == u.Id))) + ; + + CreateMap() + .ForMember(t => t.EmailNoticeUserList, u => u.MapFrom(c => c.EmailNoticeUserTypeList)); CreateMap(); @@ -45,7 +51,7 @@ namespace IRaCIS.Core.Application.Service CreateMap() .ForMember(o => o.ParentChildCodeEnum, t => t.MapFrom(u => u.Parent.ChildCodeEnum)) - .ForMember(o => o.Value, t => t.MapFrom(u => u.MappedValue)) + .ForMember(o => o.Value, t => t.MapFrom(u => isEn_Us? u.Value : u.ValueCN )) .ForMember(o => o.ParentCode, t => t.MapFrom(u => u.Parent.Code)); CreateMap() diff --git a/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs b/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs index 8ecdc76e8..652d381a6 100644 --- a/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs +++ b/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs @@ -36,7 +36,7 @@ namespace IRaCIS.Core.Application.ViewModel } - public class EmailUserInfoDto + public class EmailUserInfoDto { public Guid TrialEmailNoticeConfigId { get; set; } @@ -77,7 +77,7 @@ namespace IRaCIS.Core.Application.ViewModel /// /// SMTP端口 /// - public int? EmailSMTPServerPort { get; set; } + public int EmailSMTPServerPort { get; set; } /// /// 是否配置过邮箱 @@ -87,7 +87,7 @@ namespace IRaCIS.Core.Application.ViewModel public class SetTrialEmailInDto : GetTrialEmailSetOutDto { - + } public class GetTrialEmailSetInDto { @@ -100,7 +100,7 @@ namespace IRaCIS.Core.Application.ViewModel [NotDefault] public Guid TrialId { get; set; } - public CommonDocumentBusinessScenario? BusinessScenarioEnum { get; set; } + public EmailBusinessScenario? BusinessScenarioEnum { get; set; } //public CriterionType? CriterionTypeEnum { get; set; } @@ -117,51 +117,98 @@ namespace IRaCIS.Core.Application.ViewModel public Guid TrialReadingCriterionId { get; set; } - public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; } + public EmailBusinessScenario BusinessScenarioEnum { get; set; } } - /// TrialEmailNoticeConfigAddOrEdit 列表查询参数模型 - public class TrialEmailNoticeConfigAddOrEdit + public class BatchAddTrialEmailNoticeConfig { + + + public Guid? Id { get; set; } - public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; } + public EmailBusinessScenario BusinessScenarioEnum { get; set; } public string Code { get; set; } = string.Empty; - public Guid? TrialReadingCriterionId { get; set; } + public Guid TrialId { get; set; } - public string AuthorizationCode { get; set; } = string.Empty; - public string SMTPServerAddress { get; set; } = string.Empty; - - public int SMTPServerPort { get; set; } - - public CriterionType CriterionTypeEnum { get; set; } - - public string FromName { get; set; } = string.Empty; - - public string FromEmail { get; set; } = string.Empty; + public CriterionType? CriterionTypeEnum { get; set; } - public List? ToUserTypeList { get; set; } + public List ToUserTypeList { get; set; } public List CopyUserTypeList { get; set; } - - public bool IsUrgent { get; set; } - + public bool IsEnable { get; set; } public bool IsAutoSend { get; set; } public bool IsReturnRequired { get; set; } - public string FilePath { get; set; } = string.Empty; - public string FileName { get; set; } = string.Empty; + /// 业务模块 /// + public int BusinessModuleEnum { get; set; } + + /// 业务层级 /// + public int BusinessLevelEnum { get; set; } + + /// 邮件类型 /// + public int EmailTypeEnum { get; set; } + + /// 邮件加急类型 /// + public int EmailUrgentEnum { get; set; } + + /// 定时周期 /// + public string EmailCron { get; set; } = string.Empty; + + /// 邮件主题 /// + public string EmailTopic { get; set; } = string.Empty; + + public string EmailTopicCN { get; set; } = string.Empty; + + /// 附件 /// + public string AttachPath { get; set; } = string.Empty; + + public string AttachCNPath { get; set; } = string.Empty; + + public string Description { get; set; } = string.Empty; + + + public string AttachName { get; set; } = string.Empty; + public string AttachNameCN { get; set; } = string.Empty; + + + public string EmailHtmlContent { get; set; } = string.Empty; + public string EmailHtmlContentCN { get; set; } = string.Empty; + + } + + + /// TrialEmailNoticeConfigAddOrEdit 列表查询参数模型 + public class TrialEmailNoticeConfigAddOrEdit : BatchAddTrialEmailNoticeConfig + { + + public Guid? TrialReadingCriterionId { get; set; } + + + public string AuthorizationCode { get; set; } = string.Empty; + + public string SMTPServerAddress { get; set; } = string.Empty; + + public int SMTPServerPort { get; set; } + + + public string FromName { get; set; } = string.Empty; + + public string FromEmail { get; set; } = string.Empty; + + public List BlackUserIdList { get; set; } + } diff --git a/IRaCIS.Core.Application/Service/Document/EmailSendService.cs b/IRaCIS.Core.Application/Service/Document/EmailSendService.cs new file mode 100644 index 000000000..fae472eec --- /dev/null +++ b/IRaCIS.Core.Application/Service/Document/EmailSendService.cs @@ -0,0 +1,403 @@ +using DocumentFormat.OpenXml.EMMA; +using DocumentFormat.OpenXml.Spreadsheet; +using IRaCIS.Application.Contracts; +using IRaCIS.Application.Interfaces; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Core.Domain.Models; +using IRaCIS.Core.Domain.Share; +using IRaCIS.Core.Infrastructure; +using MailKit; +using Microsoft.Extensions.Options; +using Microsoft.VisualBasic; +using MimeKit; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Mail; +using System.Text; +using System.Threading.Tasks; + +namespace IRaCIS.Core.Application.Service +{ + + public interface IEmailSendService + { + Task SendEnrollOrPdEmail(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm); + Task SendTrialImageQCTaskEmailAsync(Guid trialId); + + Task SendTrialQCQuestionEmailAsync(Guid trialId); + Task SendTrialImageQuestionAsync(Guid trialId); + } + + public class EmailSendService : BaseService, IEmailSendService + { + private readonly IRepository _trialEmailNoticeConfigRepository; + + private readonly IRepository _emailNoticeConfigRepository; + + private readonly IRepository _trialRepository; + + private readonly IDictionaryService _dictionaryService; + private readonly IOptionsMonitor _SystemEmailSendConfig; + + public readonly static string EmailNamePlaceholder = "EmailNamePlaceholder"; + + public EmailSendService(IRepository trialEmailNoticeConfigRepository, IRepository emailNoticeConfigRepository, IRepository trialRepository, IOptionsMonitor systemEmailSendConfig, IDictionaryService dictionaryService) + { + _trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository; + _emailNoticeConfigRepository = emailNoticeConfigRepository; + _trialRepository = trialRepository; + _SystemEmailSendConfig = systemEmailSendConfig; + _dictionaryService = dictionaryService; + } + + //入组确认/PD确认 + + public async Task SendEnrollOrPdEmail(Guid visitTaskId, bool? isEnrollment, bool? isPDConfirm) + { + EmailBusinessScenario businessScenarioEnum; + + bool? result = null; + + if (isEnrollment != null && isPDConfirm == null) + { + businessScenarioEnum = EmailBusinessScenario.EnrollConfirmed; + + result = isEnrollment; + } + else + { + businessScenarioEnum = EmailBusinessScenario.PDConfirmed; + + result = isPDConfirm; + } + + var taskInfo = await _repository.Where(t => t.Id == visitTaskId).Select(t => new + { + t.Subject.SiteId, + t.Trial.ResearchProgramNo, + t.Subject.TrialSite.TrialSiteCode, + SubjectCode = t.Subject.Code, + t.Trial.Sponsor.SponsorName, + t.SourceSubjectVisit.VisitName, + t.TrialId, + + }).FirstNotNullAsync(); + + var isEn_us = _userInfo.IsEn_Us; + + var resultStr = isEn_us ? (result == true ? "Yes" : "No") : (result == true ? "是" : "否"); + + if (isEnrollment == true) + { + Func topicAndHtmlFunc = trialEmailConfig => + { + var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, taskInfo.ResearchProgramNo, taskInfo.SubjectCode); + + var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN, + EmailNamePlaceholder, taskInfo.ResearchProgramNo, taskInfo.SubjectCode, resultStr); + return (topicStr, htmlBodyStr, isEn_us, null); + }; + + await SendTrialEmailAsync(taskInfo.TrialId, businessScenarioEnum, topicAndHtmlFunc, taskInfo.SiteId); + } + else + { + Func topicAndHtmlFunc = trialEmailConfig => + { + var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, taskInfo.ResearchProgramNo, taskInfo.SubjectCode, taskInfo.VisitName); + + var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN, + EmailNamePlaceholder, taskInfo.ResearchProgramNo, taskInfo.SubjectCode, taskInfo.VisitName, resultStr); + + return (topicStr, htmlBodyStr, isEn_us, null); + }; + + await SendTrialEmailAsync(taskInfo.TrialId, businessScenarioEnum, topicAndHtmlFunc, taskInfo.SiteId); + } + + + } + + /// + /// 影像质控 + /// + /// + /// + public async Task SendTrialImageQCTaskEmailAsync(Guid trialId) + { + var isEn_us = false; + var trialInfo = await _repository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstNotNullAsync(); + + //找到 该项目的IQC 用户Id + var userList = await _repository.Where(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.User.FullName }).ToListAsync(); + + //判断是否任务可以领取 ,可以的话 发送邮件 + var userIdList = userList.Select(t => t.UserId).ToList(); + + foreach (var user in userList) + { + var userId = user.UserId; + + //过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id + var query = _trialRepository.Where(t => t.Id == trialId) + .Where(t => t.QCProcessEnum != TrialQCProcess.NotAudit) + .Select(t => new + { + //待领取量 + ToBeClaimedCount = t.SubjectVisitList.Where(u => u.SubmitState == SubmitStateEnum.Submitted && u.CurrentActionUserId == null && (u.PreliminaryAuditUserId == null || (u.PreliminaryAuditUserId != userId && u.ReviewAuditUserId == null))).Count(), + + //待审核通过,统计从已领取到QC提交之间的 已领取 待审核 审核中 (审核完成 领取人就会清理 所以只用查询当前领取人是自己的就好了) + ToBeReviewedCount = t.SubjectVisitList.Where(u => u.CurrentActionUserId == userId).Count() + + }); + + var sendStat = await query.FirstOrDefaultAsync(); + + //当前人 有待领取的或者有待审核的才发邮件 + if (sendStat != null && (sendStat.ToBeClaimedCount > 0 || sendStat.ToBeReviewedCount > 0)) + { + + Func topicAndHtmlFunc = trialEmailConfig => + { + var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo); + var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN, + user.FullName, DateTime.Now, sendStat.ToBeClaimedCount, sendStat.ToBeReviewedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl); + return (topicStr, htmlBodyStr, false, userId); + }; + + await SendTrialEmailAsync(trialId, EmailBusinessScenario.QCTask, topicAndHtmlFunc); + } + } + } + + /// + /// QC质疑 + /// + /// + /// + public async Task SendTrialQCQuestionEmailAsync(Guid trialId) + { + var isEn_us = false; + var trialInfo = _repository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr, t.DeclarationTypeEnumList }).FirstOrDefault(); + + //找到 该项目的IQC 用户Id + var userList = await _repository.Where(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.IQC).Select(t => new { t.UserId, t.User.FullName }).ToListAsync(); + + //判断是否任务可以领取 ,可以的话 发送邮件 + + foreach (var user in userList) + { + var userId = user.UserId; + + //过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id + var query = _trialRepository + .Where(t => t.Id == trialId) + .Select(t => new + { + ReUploadTobeDealedCount = t.SubjectVisitList.SelectMany(c => c.QCChallengeList) + .Where(u => u.CreateUserId == userId && u.IsClosed == false && u.LatestReplyUser.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator && u.ReuploadEnum == QCChanllengeReuploadEnum.CRCRequestReupload).Count(), + + //质疑待处理 发送邮件的时候 需要减去ReUploadTobeDealedCount + ToBeDealedCount = t.SubjectVisitList.SelectMany(c => c.QCChallengeList) + .Where(u => u.CreateUserId == userId && u.IsClosed == false && u.LatestReplyUser.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Count(), + }); + + var sendStat = await query.FirstOrDefaultAsync(); + + //当前人 + if (sendStat != null && (sendStat.ToBeDealedCount > 0 || sendStat.ReUploadTobeDealedCount > 0)) + { + + Func topicAndHtmlFunc = trialEmailConfig => + { + var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo); + var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN, + + user.FullName, DateTime.Now, sendStat.ToBeDealedCount - sendStat.ReUploadTobeDealedCount, sendStat.ReUploadTobeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl); + return (topicStr, htmlBodyStr, false, userId); + }; + + await SendTrialEmailAsync(trialId, EmailBusinessScenario.QCQuestion, topicAndHtmlFunc); + } + } + } + + /// + /// 影像质疑 + /// + /// + /// + public async Task SendTrialImageQuestionAsync(Guid trialId) + { + var isEn_us = false; + + var trialInfo = _repository.Where(t => t.Id == trialId).Select(t => new { t.ResearchProgramNo, t.ExperimentName, t.TrialCode, t.TrialStatusStr }).FirstOrDefault(); + + //找到 该项目的CRC 用户Id + var userList = await _repository.Where(t => t.TrialId == trialId).Where(t => t.User.UserTypeEnum == UserTypeEnum.ClinicalResearchCoordinator).Select(t => new { t.UserId, t.User.FullName }).ToListAsync(); + + //判断是否任务可以领取 ,可以的话 发送邮件 + + foreach (var user in userList) + { + var userId = user.UserId; + //过滤项目 并且 将 _userInfo.Id 换位 当前发送邮件的Id + var query = _trialRepository.Where(t => t.Id == trialId) + + .Select(t => new + { + //质疑待处理 + ToBeDealedCount = t.SubjectVisitList.Where(t => t.TrialSite.CRCUserList.Any(t => t.UserId == userId)).SelectMany(c => c.QCChallengeList) + .Where(u => u.IsClosed == false && (u.LatestReplyUser.UserTypeEnum == UserTypeEnum.IQC || u.LatestReplyUserId == null)).Count(), + + }); + + var sendStat = await query.FirstOrDefaultAsync(); + + //当前人 + if (sendStat != null && (sendStat.ToBeDealedCount > 0)) + { + + Func topicAndHtmlFunc = trialEmailConfig => + { + var topicStr = string.Format(isEn_us ? trialEmailConfig.EmailTopic : trialEmailConfig.EmailTopicCN, trialInfo.ResearchProgramNo); + var htmlBodyStr = string.Format(isEn_us ? trialEmailConfig.EmailHtmlContent : trialEmailConfig.EmailHtmlContentCN, + user.FullName, DateTime.Now, sendStat.ToBeDealedCount, _SystemEmailSendConfig.CurrentValue.SiteUrl); + return (topicStr, htmlBodyStr, isEn_us, userId); + }; + + await SendTrialEmailAsync(trialId, EmailBusinessScenario.ImageQuestion, topicAndHtmlFunc); + } + } + } + + + + + public async Task SendTrialEmailAsync(Guid trialId, EmailBusinessScenario businessScenario, Func topicAndHtmlFunc, Guid? siteId = null, Guid? trialReadingCriterionId = null) + { + //找到配置 + 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(); + + + if (trialEmailConfig == null || trialEmailConfig.IsAutoSend == false) + { + return; + } + else + { + var sendEmailConfig = new SMTPEmailConfig(); + + var (topicStr, htmlBodyStr, isEn_us, onlyToUserId) = topicAndHtmlFunc(trialEmailConfig); + + + sendEmailConfig.TopicDescription = topicStr; + sendEmailConfig.HtmlBodyStr = htmlBodyStr; + + + var blackUserIdList = trialEmailConfig.TrialEmailBlackUserList.Select(t => t.UserId).ToList(); + + + var toUserTypeEnumList = trialEmailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(c => c.UserType).ToList(); + + var copyUserTypeEnumList = trialEmailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(c => c.UserType).ToList(); + + var allUserTypeEnumList = toUserTypeEnumList.Union(copyUserTypeEnumList).Distinct().ToList(); + + var allUserList = await _repository.Where(t => t.TrialId == trialId && allUserTypeEnumList.Contains(t.User.UserTypeEnum)).Select(t => new { t.UserId, t.User.EMail, t.User.FullName, t.User.UserTypeEnum }).ToListAsync(); + + + var toUserList = allUserList.Where(t => toUserTypeEnumList.Contains(t.UserTypeEnum)) + .ToList(); + + //收件人 有CRC CRA , CRC CRA的账户要按照中心发送 + if (siteId == null && toUserTypeEnumList.Any(t => t == UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA) && onlyToUserId == null) + { + throw new BusinessValidationFailedException("当前场景收件人包含CRC CRA,但是没有siteId,请联系后端开发"); + } + if (siteId != null && toUserTypeEnumList.Any(t => t == UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA)) + { + var curentSiteUserIdList = _repository.Where(t => t.TrialId == trialId && t.SiteId == siteId).Select(t => t.UserId).ToList(); + + toUserList = toUserList.Where(t => (t.UserTypeEnum != UserTypeEnum.CRA && t.UserTypeEnum != UserTypeEnum.ClinicalResearchCoordinator) || curentSiteUserIdList.Contains(t.UserId)).ToList(); + } + + + //去除黑名单 + toUserList = toUserList.Where(t => !blackUserIdList.Contains(t.UserId)).ToList(); + + var copyUserList = allUserList.Where(t => copyUserTypeEnumList.Contains(t.UserTypeEnum)) + .Where(t => !blackUserIdList.Contains(t.UserId)).ToList(); + + if (siteId != null && copyUserTypeEnumList.Any(t => t == UserTypeEnum.ClinicalResearchCoordinator || t == UserTypeEnum.CRA)) + { + var curentSiteUserIdList = _repository.Where(t => t.TrialId == trialId && t.SiteId == siteId).Select(t => t.UserId).ToList(); + + copyUserList = copyUserList.Where(t => (t.UserTypeEnum != UserTypeEnum.CRA && t.UserTypeEnum != UserTypeEnum.ClinicalResearchCoordinator) || curentSiteUserIdList.Contains(t.UserId)).ToList(); + } + + if (onlyToUserId != null) + { + toUserList = toUserList.Where(t => t.UserId == onlyToUserId).ToList(); + } + else + { + sendEmailConfig.HtmlBodyStr = htmlBodyStr.Replace(EmailNamePlaceholder, string.Join(isEn_us ? ", " : "、", toUserList.Select(t => t.FullName).ToList())); + } + + if (toUserList.Count() == 0) + { + //---没有收件人,无法发送邮件 + throw new BusinessValidationFailedException(_localizer["TrialEmailN_NoRecipient"]); + } + + + if (trialEmailConfig.FromEmail.Contains("@") && !string.IsNullOrEmpty(trialEmailConfig.FromEmail)) + { + + sendEmailConfig.FromEmailAddress = new MimeKit.MailboxAddress(trialEmailConfig.FromName, trialEmailConfig.FromEmail); + sendEmailConfig.AuthorizationCode = trialEmailConfig.AuthorizationCode; + sendEmailConfig.UserName = trialEmailConfig.FromEmail; + + sendEmailConfig.Host = trialEmailConfig.SMTPServerAddress; + sendEmailConfig.Port = trialEmailConfig.SMTPServerPort; + } + else + { + //---项目发件邮箱配置有误,请核实 + throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidEmailConfig"]); + } + + foreach (var item in toUserList) + { + + if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail)) + { + + sendEmailConfig.ToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail)); + + } + } + foreach (var item in copyUserList) + { + + if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail)) + { + + sendEmailConfig.CopyToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail)); + + } + } + + await SendEmailHelper.SendEmailAsync(sendEmailConfig); + + } + } + + + } +} diff --git a/IRaCIS.Core.Application/Service/Document/SystemDocumentService.cs b/IRaCIS.Core.Application/Service/Document/SystemDocumentService.cs index 4d3003ad9..21480bae3 100644 --- a/IRaCIS.Core.Application/Service/Document/SystemDocumentService.cs +++ b/IRaCIS.Core.Application/Service/Document/SystemDocumentService.cs @@ -170,7 +170,7 @@ namespace IRaCIS.Core.Application.Services SignViewMinimumMinutes = sysDoc.SignViewMinimumMinutes, Name = sysDoc.Name, Path = sysDoc.Path, - FileType = sysDoc.FileType.MappedValue, + FileType = _userInfo.IsEn_Us? sysDoc.FileType.Value: sysDoc.FileType.ValueCN, UpdateTime = sysDoc.UpdateTime, FullFilePath = sysDoc.Path , diff --git a/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs b/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs index d8818be71..eb34d3eb7 100644 --- a/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs +++ b/IRaCIS.Core.Application/Service/Document/TrialDocumentService.cs @@ -60,7 +60,7 @@ namespace IRaCIS.Core.Application.Services var trialDocumentQueryable = _trialDocumentRepository.AsQueryable(true).Where(t => t.TrialId == queryTrialDocument.TrialId) .WhereIf(!string.IsNullOrEmpty(queryTrialDocument.Name), t => t.Name.Contains(queryTrialDocument.Name)) .WhereIf(queryTrialDocument.FileTypeId != null, t => t.FileTypeId == queryTrialDocument.FileTypeId) - .ProjectTo(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken }); + .ProjectTo(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken, isEn_Us=_userInfo.IsEn_Us }); return await trialDocumentQueryable.ToPagedListAsync(queryTrialDocument.PageIndex, queryTrialDocument.PageSize, queryTrialDocument.SortField, queryTrialDocument.Asc); } @@ -187,7 +187,7 @@ namespace IRaCIS.Core.Application.Services Name = needConfirmedUserType.SystemDocument.Name, Path = needConfirmedUserType.SystemDocument.Path, FileTypeId = needConfirmedUserType.SystemDocument.FileTypeId, - FileType = needConfirmedUserType.SystemDocument.FileType.MappedValue, + FileType = _userInfo.IsEn_Us? needConfirmedUserType.SystemDocument.FileType.Value: needConfirmedUserType.SystemDocument.FileType.ValueCN, UpdateTime = needConfirmedUserType.SystemDocument.UpdateTime, FullFilePath = needConfirmedUserType.SystemDocument.Path , @@ -219,7 +219,7 @@ namespace IRaCIS.Core.Application.Services Name = trialDoc.Name, Path = trialDoc.Path, FileTypeId = trialDoc.FileTypeId, - FileType = trialDoc.FileType.MappedValue, + FileType = _userInfo.IsEn_Us ? trialDoc.FileType.Value: trialDoc.FileType.ValueCN, UpdateTime = trialDoc.UpdateTime, SignViewMinimumMinutes = trialDoc.SignViewMinimumMinutes, @@ -333,7 +333,7 @@ namespace IRaCIS.Core.Application.Services Name = trialDocumentNeedConfirmedUserType.TrialDocument.Name, Path = trialDocumentNeedConfirmedUserType.TrialDocument.Path, FileTypeId = trialDocumentNeedConfirmedUserType.TrialDocument.FileTypeId, - FileType = trialDocumentNeedConfirmedUserType.TrialDocument.FileType.MappedValue, + FileType = _userInfo.IsEn_Us ? trialDocumentNeedConfirmedUserType.TrialDocument.FileType.Value : trialDocumentNeedConfirmedUserType.TrialDocument.FileType.ValueCN, UpdateTime = trialDocumentNeedConfirmedUserType.TrialDocument.UpdateTime, @@ -367,7 +367,7 @@ namespace IRaCIS.Core.Application.Services SignViewMinimumMinutes = needConfirmEdUserType.SystemDocument.SignViewMinimumMinutes, Name = needConfirmEdUserType.SystemDocument.Name, Path = needConfirmEdUserType.SystemDocument.Path, - FileType = needConfirmEdUserType.SystemDocument.FileType.MappedValue, + FileType = _userInfo.IsEn_Us ? needConfirmEdUserType.SystemDocument.FileType.Value : needConfirmEdUserType.SystemDocument.FileType.ValueCN, FileTypeId = needConfirmEdUserType.SystemDocument.FileTypeId, UpdateTime = needConfirmEdUserType.SystemDocument.UpdateTime, diff --git a/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs b/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs index 5289dea1d..7a68d55ef 100644 --- a/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs +++ b/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs @@ -32,30 +32,41 @@ namespace IRaCIS.Core.Application.Service { private readonly IRepository _trialEmailNoticeConfigRepository; + private readonly IRepository _trialEmailBlackUserRepository; + private readonly IRepository _emailNoticeConfigRepository; + private readonly IRepository _trialRepository; - private readonly IRepository _taskMedicalReviewRepository; + private readonly IRepository _visitTaskRepository; + private readonly IRepository _trialUserRepository; + private readonly IRepository _subjectRepository; + private readonly IRepository _subjectVisitRepository; - public IRepository _visitTaskRepository { get; } - public IRepository _trialUserRepository { get; } - public IRepository _subjectRepository { get; } - public IRepository _subjectVisitRepository { get; } - public TrialEmailNoticeConfigService(IRepository trialEmailNoticeConfigRepository, IRepository visitTaskRepository, + public TrialEmailNoticeConfigService( + IRepository trialEmailNoticeConfigRepository, + IRepository visitTaskRepository, IRepository trialRepository, - IRepository trialUserRepository, IRepository taskMedicalReviewRepository, IRepository subjectRepository, IRepository subjectVisitRepository) + IRepository trialUserRepository, + IRepository taskMedicalReviewRepository, + IRepository subjectRepository, + IRepository subjectVisitRepository, + IRepository trialEmailBlackUserRepository, + IRepository emailNoticeConfigRepository + ) { _trialEmailNoticeConfigRepository = trialEmailNoticeConfigRepository; _visitTaskRepository = visitTaskRepository; - this._trialRepository = trialRepository; + _trialRepository = trialRepository; _trialUserRepository = trialUserRepository; _taskMedicalReviewRepository = taskMedicalReviewRepository; _subjectRepository = subjectRepository; - _subjectVisitRepository = subjectVisitRepository; + _trialEmailBlackUserRepository = trialEmailBlackUserRepository; + _emailNoticeConfigRepository = emailNoticeConfigRepository; } /// @@ -66,7 +77,7 @@ namespace IRaCIS.Core.Application.Service [HttpPost] public async Task GetTrialEmail(GetTrialEmailSetInDto inDto) { - return await _trialRepository.Where(x => x.Id == inDto.TrialId).Select(x => new GetTrialEmailSetOutDto() + return await _trialRepository.Where(x => x.Id == inDto.TrialId, ignoreQueryFilters: true).Select(x => new GetTrialEmailSetOutDto() { TrialId = inDto.TrialId, EmailAuthorizationCode = x.EmailAuthorizationCode, @@ -76,7 +87,7 @@ namespace IRaCIS.Core.Application.Service IsConfigureEmail = x.IsConfigureEmail, EmailSMTPServerPort = x.EmailSMTPServerPort - }).FirstNotNullAsync(); + }).FirstOrDefaultAsync(); } /// @@ -94,7 +105,7 @@ namespace IRaCIS.Core.Application.Service FromEmail = inDto.EmailFromEmail, FromName = inDto.EmailFromName, SMTPServerAddress = inDto.EmailSMTPServerAddress, - SMTPServerPort = inDto.EmailSMTPServerPort.Value, + SMTPServerPort = inDto.EmailSMTPServerPort, TrialId = inDto.TrialId, }); @@ -117,7 +128,7 @@ namespace IRaCIS.Core.Application.Service FromEmail = inDto.EmailFromEmail, FromName = inDto.EmailFromName, SMTPServerAddress = inDto.EmailSMTPServerAddress, - SMTPServerPort = inDto.EmailSMTPServerPort.Value, + SMTPServerPort = inDto.EmailSMTPServerPort, }); await _trialRepository.SaveChangesAsync(); @@ -125,7 +136,7 @@ namespace IRaCIS.Core.Application.Service } /// - /// 同步系统配置的文档到想项目中 + /// 同步系统配置的文档到想项目中 ---废弃 /// /// /// @@ -139,7 +150,7 @@ namespace IRaCIS.Core.Application.Service { //只要有系统标准的文档 说明同步过了 - var trialDocCount = _trialEmailNoticeConfigRepository.Where(t =>/* t.CriterionTypeEnum == criterionTypeEnum &&*/ t.TrialId == trialId && t.TrialReadingCriterionId != null).Count(); + var trialDocCount = _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId).Count(); if (trialDocCount == 0) { @@ -148,7 +159,10 @@ namespace IRaCIS.Core.Application.Service var confirmedCriterionTypeList = list.Select(t => (CriterionType?)t.CriterionType).ToList(); - var docmentList = _repository.Where(t => confirmedCriterionTypeList.Contains(t.CriterionTypeEnum)).Select(t => new { t.Path, t.Name, t.Code, t.BusinessScenarioEnum, t.CriterionTypeEnum }).ToList(); + var docmentList = _repository.Where(t => t.BusinessScenarioEnum == EmailBusinessScenario.EnrollConfirmed || t.BusinessScenarioEnum == EmailBusinessScenario.PDConfirmed) + //.Where(t => (confirmedCriterionTypeList.Contains(t.CriterionTypeEnum)) || t.CriterionTypeEnum == null).Select(t => new { t.Path, t.Name, t.Code, t.BusinessScenarioEnum, t.CriterionTypeEnum }) + .ToList(); + foreach (var item in docmentList) @@ -157,8 +171,8 @@ namespace IRaCIS.Core.Application.Service { TrialId = trialId, TrialReadingCriterionId = list.Where(t => t.CriterionType == item.CriterionTypeEnum).FirstOrDefault()?.TrialReadingCriterionId, - FileName = item.Name, - FilePath = item.Path, + //FileName = item.Name, + //FilePath = item.Path, BusinessScenarioEnum = item.BusinessScenarioEnum, Code = item.Code }); @@ -176,6 +190,7 @@ namespace IRaCIS.Core.Application.Service + private async Task DealMedicalReviewTasKGenerateAndIsSendAsync(Guid trialId, bool? isHandSend, string pdAnswer, List taskIdList, List minUserIdList) { @@ -241,7 +256,7 @@ namespace IRaCIS.Core.Application.Service public async Task BaseBusinessScenarioSendEmailAsync(Guid visitTaskId, bool? isHandSend, EmailStoreSendMode emailStoreMode, string sendFileRelativePath) { - CommonDocumentBusinessScenario? businessScenarioEnum = null; + EmailBusinessScenario? businessScenarioEnum = null; #region 任务关联的项目配置 标准信息及配置,subject 信息 var taskInfo = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => new @@ -309,7 +324,7 @@ namespace IRaCIS.Core.Application.Service //入组确认场景 if (taskInfo.IsEnrollmentConfirm == true && taskInfo.IsEnrollementQualificationConfirm == true && taskInfo.IsBaseline == true) { - businessScenarioEnum = CommonDocumentBusinessScenario.EnrollConfirmed; + businessScenarioEnum = EmailBusinessScenario.EnrollConfirmed; } @@ -318,7 +333,7 @@ namespace IRaCIS.Core.Application.Service (taskInfo.PDState == PDStateEnum.PDProgress && taskInfo.SourceSubjectVisitId != null) || (taskInfo.SouceReadModuleId != null && taskInfo.MoudulePDState == PDStateEnum.PDProgress)) { - businessScenarioEnum = CommonDocumentBusinessScenario.PDConfirmed; + businessScenarioEnum = EmailBusinessScenario.PDConfirmed; } else { @@ -344,7 +359,7 @@ namespace IRaCIS.Core.Application.Service .Include(t => t.TrialEmailNoticeUserList).FirstOrDefaultAsync(); - if (emailConfig == null || (emailConfig.IsAutoSend == false && isHandSend==null)) + if (emailConfig == null || (emailConfig.IsAutoSend == false && isHandSend == null)) { //throw new BusinessValidationFailedException("找不到该项目标准场景下邮件的配置"); @@ -418,7 +433,7 @@ namespace IRaCIS.Core.Application.Service #region 确保 邮件Html存在 //邮件附件 - var path = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, emailConfig.FilePath); + var path = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, _userInfo.IsEn_Us ? emailConfig.AttachPath : emailConfig.AttachCNPath); if (!File.Exists(path)) { @@ -431,7 +446,7 @@ namespace IRaCIS.Core.Application.Service + Path.DirectorySeparatorChar.ToString() + "EmailTemplate" + Path.DirectorySeparatorChar.ToString() - //+ "SubjectEnrollConfirmOrPDProgress.html"; + //+ "SubjectEnrollConfirmOrPDProgress.html"; + (_userInfo.IsEn_Us ? "SubjectEnrollConfirmOrPDProgress_US.html" : "SubjectEnrollConfirmOrPDProgress.html"); #endregion @@ -439,7 +454,7 @@ namespace IRaCIS.Core.Application.Service #region 不同场景 Tile 设置 - if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed) + if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed) { sendEmailConfig.TopicDescription = _localizer["TrialEmailN_EnrollmentConfirmation", taskInfo.ResearchProgramNo, taskInfo.SubjectCode]; @@ -454,7 +469,7 @@ namespace IRaCIS.Core.Application.Service ); } } - else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed) + else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed) { sendEmailConfig.TopicDescription = _localizer["TrialEmailN_PDReport", taskInfo.ResearchProgramNo, taskInfo.SubjectCode]; @@ -464,7 +479,7 @@ namespace IRaCIS.Core.Application.Service sendEmailConfig.HtmlBodyStr = string.Format(templateInfo, - //--- 附件为疾病进展确认报告,请查收 + //--- 附件为疾病进展确认报告,请查收 _localizer["TrialEmailN_SubjectDiseaseProgression"] ); } @@ -486,7 +501,7 @@ namespace IRaCIS.Core.Application.Service //入组确认 根据每个标准配置的是否自动发送,发送邮件与否 - if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed) + if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed) { if (await _repository.Where().AnyAsync(x => x.VisitTaskId == visitTaskId && x.Answer == TargetState.Exist.GetEnumInt() && x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion)) @@ -531,7 +546,7 @@ namespace IRaCIS.Core.Application.Service } - else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed) + else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed) { @@ -629,7 +644,7 @@ namespace IRaCIS.Core.Application.Service } else { - //---发送PD 进展邮件中发现任务数据有问题! + //---发送PD 进展邮件中发现任务数据有问题! throw new BusinessValidationFailedException(_localizer["TrialEmailN_PDProgressEmailTask"]); } @@ -639,13 +654,13 @@ namespace IRaCIS.Core.Application.Service else { - //---双重有序阅片 没有定义该仲裁规则处理逻辑,请联系业务和后台开发核查! + //---双重有序阅片 没有定义该仲裁规则处理逻辑,请联系业务和后台开发核查! throw new BusinessValidationFailedException(_localizer["TrialEmailN_DoubleBlindedError"]); } } - + //屏蔽单重阅片添加 else { @@ -661,7 +676,7 @@ namespace IRaCIS.Core.Application.Service // if (taskInfo.ArbitrationRule != ArbitrationRule.None) // { - //---单重有序阅片配置有误(不应该有仲裁对象配置),请核查! + //---单重有序阅片配置有误(不应该有仲裁对象配置),请核查! // throw new BusinessValidationFailedException(_localizer["TrialEmailN_SingleBlindedSet"]); // } @@ -687,7 +702,7 @@ namespace IRaCIS.Core.Application.Service // } // else // { - //---单重有序阅片 该类型的任务不应进入此处逻辑,请联系后台开发核查! + //---单重有序阅片 该类型的任务不应进入此处逻辑,请联系后台开发核查! // throw new BusinessValidationFailedException(_localizer["TrialEmailN_SingleBlindedSequenced"]); // } @@ -697,7 +712,7 @@ namespace IRaCIS.Core.Application.Service //} //else //{ - //---有序阅片配置有误(应为单重或者双重阅片),请核查! + //---有序阅片配置有误(应为单重或者双重阅片),请核查! // throw new BusinessValidationFailedException(_localizer["TrialEmailN_BlindedSequencedReading"]); //} @@ -788,7 +803,7 @@ namespace IRaCIS.Core.Application.Service //先预先生成了邮件,发送预先生成的邮件 sendEmailConfig.EmailAttachMentConfigList.Add(new EmailAttachMentConfig() { - FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(emailConfig.FileName)}.pdf", + FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(_userInfo.IsEn_Us ? emailConfig.AttachName : emailConfig.AttachNameCN)}.pdf", FileStream = File.OpenRead(phyPath), }); @@ -812,7 +827,7 @@ namespace IRaCIS.Core.Application.Service }; - var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetSubjectEnrollConfirmOrPDEmailPath(_hostEnvironment, Path.GetFileName(path), taskInfo.TrialId, taskInfo.SiteId, taskInfo.SubjectId,true); + var (serverFilePath, relativePath, fileRealName) = FileStoreHelper.GetSubjectEnrollConfirmOrPDEmailPath(_hostEnvironment, Path.GetFileName(path), taskInfo.TrialId, taskInfo.SiteId, taskInfo.SubjectId, true); if (emailStoreMode == EmailStoreSendMode.StoreLocalSend || emailStoreMode == EmailStoreSendMode.OnlyStoreLocalNotSentEmail) { @@ -823,7 +838,7 @@ namespace IRaCIS.Core.Application.Service MiniSoftware.MiniWord.SaveAsByTemplate(wordMemoryStream, path, value); - document.LoadFromStream(wordMemoryStream,FileFormat.Docx); + document.LoadFromStream(wordMemoryStream, FileFormat.Docx); document.SaveToFile(serverFilePath, FileFormat.PDF); @@ -856,7 +871,7 @@ namespace IRaCIS.Core.Application.Service sendEmailConfig.EmailAttachMentConfigList.Add(new EmailAttachMentConfig() { - FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(emailConfig.FileName)}.pdf", + FileName = $"{taskInfo.SubjectCode}_{Path.GetFileNameWithoutExtension(_userInfo.IsEn_Us ? emailConfig.AttachName : emailConfig.AttachNameCN)}.pdf", FileStream = pdfMemoryStream }); @@ -900,19 +915,19 @@ namespace IRaCIS.Core.Application.Service //找到入组确认 或者Pd 进展 已生成任务的 访视 var subjectVisitList = await _subjectVisitRepository.Where(t => t.SubjectId == subjectId & t.CheckState == CheckStateEnum.CVPassed && (t.IsEnrollmentConfirm == true || t.PDState == PDStateEnum.PDProgress)).ToListAsync(); - if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed) + if (businessScenarioEnum == EmailBusinessScenario.EnrollConfirmed) { if (trialConfig.IsEnrollementQualificationConfirm == false) { - //---项目未配置入组确认! + //---项目未配置入组确认! return ResponseOutput.NotOk(_localizer["TrialEmailN_InCons"]); } var exisitBaseline = subjectVisitList.FirstOrDefault(t => t.IsEnrollmentConfirm); if (exisitBaseline == null) { - //---不存在配置了入组确认的并且生成任务的基线访视 + //---不存在配置了入组确认的并且生成任务的基线访视 return ResponseOutput.NotOk(_localizer["TrialEmailN_NoBaseLine"]); } else @@ -933,7 +948,7 @@ namespace IRaCIS.Core.Application.Service if (task == null) { - //---做入组确认的阅片人基线任务没有阅片完! + //---做入组确认的阅片人基线任务没有阅片完! return ResponseOutput.NotOk(_localizer["TrialEmailN_IncompBase"]); } else @@ -942,7 +957,7 @@ namespace IRaCIS.Core.Application.Service if (string.IsNullOrEmpty(filePath)) { - //---邮件手动生成失败,请联系开发核实该场景失败原因 + //---邮件手动生成失败,请联系开发核实该场景失败原因 return ResponseOutput.NotOk(_localizer["TrialEmailN_EmailFail"]); } else @@ -956,7 +971,7 @@ namespace IRaCIS.Core.Application.Service } else { - //---当前未有阅片人读完基线任务! + //---当前未有阅片人读完基线任务! return ResponseOutput.NotOk(_localizer["TrialEmailN_NoReader"]); } @@ -967,12 +982,12 @@ namespace IRaCIS.Core.Application.Service } } - else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed) + else if (businessScenarioEnum == EmailBusinessScenario.PDConfirmed) { if (trialConfig.IsPDProgressView == false) { - //---项目未配置PD进展! + //---项目未配置PD进展! return ResponseOutput.NotOk(_localizer["TrialEmailN_NoPDConfig"]); } @@ -982,7 +997,7 @@ namespace IRaCIS.Core.Application.Service if (pdSubjectVisitIdList.Count == 0) { - //---不存在配置了PD进展的并且生成任务的访视 + //---不存在配置了PD进展的并且生成任务的访视 return ResponseOutput.NotOk(_localizer["TrialEmailN_NoPDTasks"]); } @@ -1027,7 +1042,7 @@ namespace IRaCIS.Core.Application.Service } else { - //---当前受试者最新PD访视阅片任务完成状态不符合发送条件 + //---当前受试者最新PD访视阅片任务完成状态不符合发送条件 return ResponseOutput.NotOk(_localizer["TrialEmailN_PDNotFinished"]); } @@ -1040,7 +1055,7 @@ namespace IRaCIS.Core.Application.Service if (existReadModule == null) { - //---项目配置了阅片期仲裁,但是当前受试者最新PD访视没有影像学阅片期 + //---项目配置了阅片期仲裁,但是当前受试者最新PD访视没有影像学阅片期 return ResponseOutput.NotOk(_localizer["TrialEmailN_PDNoImaging"]); } else @@ -1075,7 +1090,7 @@ namespace IRaCIS.Core.Application.Service else { - //---当前受试者最新PD访视阅片期任务完成状态不符合发送条件 + //---当前受试者最新PD访视阅片期任务完成状态不符合发送条件 return ResponseOutput.NotOk(_localizer["TrialEmailN_PDPhaseNotFinished"]); } } @@ -1084,7 +1099,7 @@ namespace IRaCIS.Core.Application.Service } else { - //---未定义该仲裁规则发送业务逻辑! + //---未定义该仲裁规则发送业务逻辑! return ResponseOutput.NotOk(_localizer["TrialEmailN_NoRuleDefined"]); } } @@ -1143,7 +1158,7 @@ namespace IRaCIS.Core.Application.Service else { - //---当前项目配置,不满足双重有序阅片,不满足发送条件! + //---当前项目配置,不满足双重有序阅片,不满足发送条件! return ResponseOutput.NotOk(_localizer["TrialEmailN_NoDoubleOrder"]); } @@ -1233,7 +1248,7 @@ namespace IRaCIS.Core.Application.Service //} else { - //---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑 + //---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑 throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidTaskTypeForEmailSending"]); } @@ -1273,7 +1288,7 @@ namespace IRaCIS.Core.Application.Service //} else { - //---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑 + //---不应有 除访视、裁判、全局其他类型的任务进行发送邮件,请核查业务逻辑 throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidTaskTypeForEmailSending"]); } @@ -1311,7 +1326,7 @@ namespace IRaCIS.Core.Application.Service case CriterionType.IMWG2016: default: - //---该标准任务还未定义PD获取逻辑,联系业务和后台开发协商后补充 + //---该标准任务还未定义PD获取逻辑,联系业务和后台开发协商后补充 throw new BusinessValidationFailedException(_localizer["TrialEmailN_PDLogicNotDefined"]); } @@ -1335,19 +1350,127 @@ namespace IRaCIS.Core.Application.Service var query = _trialUserRepository.Where(t => t.TrialId == trialId, false, true).IgnoreQueryFilters().Select(t => t.User.UserTypeRole).Distinct() - .ProjectTo(_mapper.ConfigurationProvider); + .ProjectTo(_mapper.ConfigurationProvider); return await query.ToListAsync(); } + /// + /// 黑名单用户Id 列表 + /// + /// + /// + public async Task> GetTrialUserIdSelectList(Guid trialEmailNoticeConfigId) + { + + var trialEmailNoticeConfig = await _trialEmailNoticeConfigRepository.Where(t => t.Id == trialEmailNoticeConfigId).Include(t => t.TrialEmailNoticeUserList).FirstNotNullAsync(); + + var trialId = trialEmailNoticeConfig.TrialId; + + var userTypeList = trialEmailNoticeConfig.TrialEmailNoticeUserList.Select(t => t.UserType).ToList(); + + + var query = _trialUserRepository.Where(t => t.TrialId == trialId && userTypeList.Contains(t.User.UserTypeEnum), false, true).IgnoreQueryFilters() + .Select(t => new TrialSelectUser() + { + UserId = t.UserId, + UserName = t.User.UserName, + RealName = t.User.FullName, + UserTypeEnum = t.User.UserTypeEnum + }).Distinct(); + + return await query.ToListAsync(); + } + + /// + /// 获取系统 邮件配置 勾选列表 + /// + /// + /// + public async Task> GetSysEmailNoticeConfigList(EmailNoticeConfigQuery queryEmailNoticeConfig) + { + var emailNoticeConfigQueryable = _emailNoticeConfigRepository + .WhereIf(queryEmailNoticeConfig.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == queryEmailNoticeConfig.BusinessScenarioEnum) + .WhereIf(queryEmailNoticeConfig.IsReturnRequired != null, t => t.IsReturnRequired == queryEmailNoticeConfig.IsReturnRequired) + .WhereIf(queryEmailNoticeConfig.IsEnable != null, t => t.IsEnable == queryEmailNoticeConfig.IsEnable) + + .ProjectTo(_mapper.ConfigurationProvider, new { trialId = queryEmailNoticeConfig.TrialId }); + + return await emailNoticeConfigQueryable.ToPagedListAsync(queryEmailNoticeConfig.PageIndex, queryEmailNoticeConfig.PageSize, queryEmailNoticeConfig.SortField, queryEmailNoticeConfig.Asc); + } + + /// + /// 批量勾选 传递列表每行数据,后台进行处理转换,建立关联关系 + /// + /// + /// + public async Task BatchAddSysEmailConfig(List batchAddList) + { + + var first = batchAddList.First(); + var trialId = first.TrialId; + + var emailConfig = await _trialRepository.Where(t => t.Id == trialId).Select(x => new + { + TrialId = x.Id, + EmailAuthorizationCode = x.EmailAuthorizationCode, + EmailSMTPServerAddress = x.EmailSMTPServerAddress, + EmailFromEmail = x.EmailFromEmail, + EmailFromName = x.EmailFromName, + IsConfigureEmail = x.IsConfigureEmail, + EmailSMTPServerPort = x.EmailSMTPServerPort + + }).FirstNotNullAsync(); + + var list = await _repository.Where(t => t.TrialId == trialId && t.IsConfirm).Select(t => new { t.CriterionType, TrialReadingCriterionId = t.Id }).ToListAsync(); + + + var addList = _mapper.Map>(batchAddList); + + + foreach (var item in addList) + { + item.SysEmailNoticeConfigId = item.Id; + item.Id = Guid.Empty; + + item.AuthorizationCode = emailConfig.EmailAuthorizationCode; + item.FromEmail = emailConfig.EmailFromEmail; + item.SMTPServerAddress = emailConfig.EmailSMTPServerAddress; + item.FromName = emailConfig.EmailFromName; + item.SMTPServerPort = emailConfig.EmailSMTPServerPort; + item.IsAutoSend = false; + item.IsEnable = false; + + 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 })); + + item.TrialEmailNoticeUserList.AddRange(batchAddList.Where(t => t.Id == item.SysEmailNoticeConfigId) + .SelectMany(t => t.CopyUserTypeList).Select(t => new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = t })); + + + await _trialEmailNoticeConfigRepository.AddAsync(item); + + } + + await _trialEmailNoticeConfigRepository.SaveChangesAsync(); + + return ResponseOutput.Ok(); + + + } + + [HttpPost] public async Task> GetTrialEmailNoticeConfigList(TrialEmailNoticeConfigQuery inQuery) { - await SyncSystemEmainCofigDocListAsync(inQuery.TrialId); + //await SyncSystemEmainCofigDocListAsync(inQuery.TrialId); var trialEmailNoticeConfigQueryable = _trialEmailNoticeConfigRepository.Where(t => t.TrialId == inQuery.TrialId) .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) .ProjectTo(_mapper.ConfigurationProvider); @@ -1355,6 +1478,7 @@ namespace IRaCIS.Core.Application.Service return await trialEmailNoticeConfigQueryable.ToListAsync(); } + [TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })] public async Task AddOrUpdateTrialEmailNoticeConfig(TrialEmailNoticeConfigAddOrEdit addOrEditTrialEmailNoticeConfig) { @@ -1379,6 +1503,10 @@ namespace IRaCIS.Core.Application.Service } + foreach (var userid in addOrEditTrialEmailNoticeConfig.BlackUserIdList) + { + entity.TrialEmailBlackUserList.Add(new TrialEmailBlackUser() { UserId = userid }); + } await _trialEmailNoticeConfigRepository.AddAsync(entity, true); @@ -1387,10 +1515,10 @@ namespace IRaCIS.Core.Application.Service } else { + var id = (Guid)addOrEditTrialEmailNoticeConfig.Id; + await _repository.BatchDeleteAsync(t => t.TrialEmailNoticeConfigId == addOrEditTrialEmailNoticeConfig.Id); - - - var entity = (await _trialEmailNoticeConfigRepository.Where(t => t.Id == addOrEditTrialEmailNoticeConfig.Id, true, true).Include(t => t.TrialEmailNoticeUserList).FirstOrDefaultAsync()).IfNullThrowException(); + await _repository.BatchDeleteAsync(t => t.TrialEmailNoticeConfigId == addOrEditTrialEmailNoticeConfig.Id); List trialEmailNoticeUsers = new List(); @@ -1398,31 +1526,51 @@ namespace IRaCIS.Core.Application.Service foreach (var item in addOrEditTrialEmailNoticeConfig.ToUserTypeList) { - trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = item, TrialEmailNoticeConfigId = entity.Id }); + trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = item, TrialEmailNoticeConfigId = id }); } foreach (var item in addOrEditTrialEmailNoticeConfig.CopyUserTypeList) { - trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = item, TrialEmailNoticeConfigId = entity.Id }); + trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = item, TrialEmailNoticeConfigId = id }); } await _repository.AddRangeAsync(trialEmailNoticeUsers); + foreach (var userid in addOrEditTrialEmailNoticeConfig.BlackUserIdList) + { + await _trialEmailBlackUserRepository.AddAsync(new TrialEmailBlackUser() { UserId = userid, TrialEmailNoticeConfigId = id }); + + } + await _trialEmailNoticeConfigRepository.UpdateFromDTOAsync(addOrEditTrialEmailNoticeConfig); await _trialEmailNoticeConfigRepository.SaveChangesAsync(); + var jobId = $"{addOrEditTrialEmailNoticeConfig.TrialId}_{id}"; + + if (addOrEditTrialEmailNoticeConfig.IsAutoSend) + { + HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, addOrEditTrialEmailNoticeConfig.TrialId, addOrEditTrialEmailNoticeConfig.BusinessScenarioEnum, addOrEditTrialEmailNoticeConfig.EmailCron); + + } + else + { + HangfireJobHelper.RemoveCronJob(jobId); + } + return ResponseOutput.Ok(); } } + + private async Task TestEmailConfigAsync(TrialEmailNoticeConfigAddOrEdit config) { - + if (!config.FromEmail.Contains("@") || string.IsNullOrEmpty(config.FromEmail)) { @@ -1449,7 +1597,7 @@ namespace IRaCIS.Core.Application.Service throw new BusinessValidationFailedException(_localizer["TrialEmailN_InvalidSenderEmailConfig"] + ex.Message); } - + #region 人员还未加入,可以先配置邮件 历史废弃 @@ -1522,6 +1670,11 @@ namespace IRaCIS.Core.Application.Service [HttpDelete("{trialEmailNoticeConfigId:guid}")] public async Task DeleteTrialEmailNoticeConfig(Guid trialEmailNoticeConfigId) { + var trialId = await _trialEmailNoticeConfigRepository.Where(t => t.Id == trialEmailNoticeConfigId).Select(t => t.TrialId).FirstOrDefaultAsync(); + var jobId = $"{trialId}_{trialEmailNoticeConfigId}"; + + HangfireJobHelper.RemoveCronJob(jobId); + var success = await _trialEmailNoticeConfigRepository.DeleteFromQueryAsync(t => t.Id == trialEmailNoticeConfigId, true); return ResponseOutput.Ok(); diff --git a/IRaCIS.Core.Application/Service/Document/_MapConfig.cs b/IRaCIS.Core.Application/Service/Document/_MapConfig.cs index 3cec4fc79..1116a7bf1 100644 --- a/IRaCIS.Core.Application/Service/Document/_MapConfig.cs +++ b/IRaCIS.Core.Application/Service/Document/_MapConfig.cs @@ -14,12 +14,13 @@ namespace IRaCIS.Core.Application.Service var userId = Guid.Empty; var token = string.Empty; + var isEn_Us = false; CreateMap() .ForMember(d => d.FileType, u => u.MapFrom(s => s.FileType.Value)) .ForMember(d => d.FullFilePath, u => u.MapFrom(s => s.Path)); CreateMap() - .ForMember(d => d.FileType, u => u.MapFrom(s => s.FileType.MappedValue)) + .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 )); diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/DicomArchiveService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/DicomArchiveService.cs index f797c8ca4..9d9bd7cc6 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/DicomArchiveService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/DicomArchiveService.cs @@ -1,6 +1,4 @@ -using Dicom; -using Dicom.Imaging.Codec; -using EasyCaching.Core; +using EasyCaching.Core; using IRaCIS.Core.Application.Contracts.Dicom; using IRaCIS.Core.Domain.Share; using System.Text; @@ -8,10 +6,13 @@ using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Application.Helper; using Microsoft.AspNetCore.Hosting; using IRaCIS.Core.Infrastructure; +using Medallion.Threading; +using FellowOakDicom; +using FellowOakDicom.Imaging.Codec; namespace IRaCIS.Core.Application.Services { - public class DicomArchiveService :BaseService, IDicomArchiveService + public class DicomArchiveService : BaseService, IDicomArchiveService { private readonly IRepository _studyRepository; private readonly IRepository _seriesRepository; @@ -21,7 +22,7 @@ namespace IRaCIS.Core.Application.Services private readonly IWebHostEnvironment _hostEnvironment; - private static object lockCodeGenerate = new object(); + private readonly IDistributedLockProvider _distributedLockProvider; private List _instanceIdList = new List(); @@ -31,8 +32,9 @@ namespace IRaCIS.Core.Application.Services IRepository instanceRepository, IWebHostEnvironment hostEnvironment, IRepository dictionaryRepository, - IEasyCachingProvider provider) + IEasyCachingProvider provider, IDistributedLockProvider distributedLockProvider) { + _distributedLockProvider = distributedLockProvider; _hostEnvironment = hostEnvironment; _studyRepository = studyRepository; @@ -50,7 +52,7 @@ namespace IRaCIS.Core.Application.Services return success; } - + public async Task<(Guid StudyId, string StudyCode)> ArchiveDicomStreamAsync(Stream dicomStream, @@ -129,7 +131,7 @@ namespace IRaCIS.Core.Application.Services DicomStudy dicomStudy = CreateDicomStudy(dataset, addtionalInfo, out bool isStudyNeedAdd); DicomSeries dicomSeries = CreateDicomSeries(dataset, dicomStudy, out bool isSeriesNeedAdd); - DicomInstance dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries,out bool isInstanceNeedAdd); + DicomInstance dicomInstance = CreateDicomInstance(dataset, dicomStudy, dicomSeries, out bool isInstanceNeedAdd); dicomSeries.DicomStudy = dicomStudy; @@ -183,7 +185,7 @@ namespace IRaCIS.Core.Application.Services //正常保存 不做处理 await dicomFile.SaveAsync(physicalPath); } - else + else { //RLELossless 保存 await dicomFile.Clone(DicomTransferSyntax.RLELossless).SaveAsync(physicalPath); //RLELossless @@ -235,7 +237,7 @@ namespace IRaCIS.Core.Application.Services { modalityForEdit = "PET"; } - if(modality== "PT、CT") + if (modality == "PT、CT") { modalityForEdit = "PET-CT"; } @@ -282,9 +284,10 @@ namespace IRaCIS.Core.Application.Services dicomStudy.PatientBirthDate = $"{dicomStudy.PatientBirthDate[0]}{dicomStudy.PatientBirthDate[1]}{dicomStudy.PatientBirthDate[2]}{dicomStudy.PatientBirthDate[3]}-{dicomStudy.PatientBirthDate[4]}{dicomStudy.PatientBirthDate[5]}-{dicomStudy.PatientBirthDate[6]}{dicomStudy.PatientBirthDate[7]}"; } - lock (lockCodeGenerate) - { + var @lock = _distributedLockProvider.CreateLock($"StudyCode"); + using (@lock.Acquire()) + { //查询数据库获取最大的Code 没有记录则为0 var dbStudyCodeIntMax = _studyRepository.Where(s => s.TrialId == addtionalInfo.TrialId).Select(t => t.Code).DefaultIfEmpty().Max(); @@ -298,9 +301,9 @@ namespace IRaCIS.Core.Application.Services dicomStudy.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(DicomStudy)); _provider.Set($"{addtionalInfo.TrialId}_{StaticData.CacheKey.StudyMaxCode}", dicomStudy.Code, TimeSpan.FromMinutes(30)); - } + #region Setting Code old //var studyCode = _studyRepository.Where(s => s.TrialId == addtionalInfo.TrialId).Select(t => t.StudyCode).OrderByDescending(c => c).FirstOrDefault(); @@ -468,7 +471,7 @@ namespace IRaCIS.Core.Application.Services _instanceIdList.Add(instanceId); } - + return dicomInstance; } diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs index 0e3e5c184..adb1f224a 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs @@ -14,16 +14,13 @@ using IRaCIS.Core.Application.MediatR.Handlers; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; using System.Threading; -using Nito.AsyncEx; +using Medallion.Threading; namespace IRaCIS.Core.Application.Service.ImageAndDoc { [ApiExplorerSettings(GroupName = "Image")] public class StudyService : BaseService, IStudyService { - private static object lockObj = new object(); - private static readonly AsyncLock _mutex = new AsyncLock(); - private static readonly AsyncLock _mutex2 = new AsyncLock(); private readonly IEasyCachingProvider _provider; @@ -35,12 +32,12 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc private readonly IRepository _dictionaryRepository; private readonly IRepository _studyMonitorRepository; - + private readonly IDistributedLockProvider _distributedLockProvider; public StudyService(IEasyCachingProvider provider , IRepository subjectVisitRepository, IRepository dicomInstanceRepository, - IRepository dicomSeriesRepository, IRepository dicomstudyRepository, IRepository dictionaryRepository, IRepository studyMonitorRepository) + IRepository dicomSeriesRepository, IRepository dicomstudyRepository, IRepository dictionaryRepository, IRepository studyMonitorRepository, IDistributedLockProvider distributedLockProvider) { _provider = provider; _subjectVisitRepository = subjectVisitRepository; @@ -49,6 +46,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc _dicomstudyRepository = dicomstudyRepository; _dictionaryRepository = dictionaryRepository; _studyMonitorRepository = studyMonitorRepository; + _distributedLockProvider = distributedLockProvider; } @@ -160,7 +158,9 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc { var study = _mapper.Map(incommand.Study); - using (await _mutex.LockAsync()) + var @lock = _distributedLockProvider.CreateLock($"StudyCode"); + + using (await @lock.AcquireAsync()) { //查询数据库获取最大的Code 没有记录则为0 var dbStudyCodeIntMax = _dicomstudyRepository.Where(s => s.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max(); @@ -306,11 +306,11 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc } - using (await _mutex2.LockAsync()) + var @lock2 = _distributedLockProvider.CreateLock($"StudyCommit"); + + using (await @lock2.AcquireAsync()) { await _dicomInstanceRepository.SaveChangesAsync(); - - } } catch (Exception ex) @@ -826,22 +826,22 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc } result.StudyInstanceUid = studyInstanceUid; + var @lock = _distributedLockProvider.CreateLock($"StudyUpload"); - if (result.AllowReUpload || result.AllowUpload) + using (@lock.Acquire()) { - lock (lockObj) + if (result.AllowReUpload || result.AllowUpload) { _provider.Set($"StudyUid_{trialId}_{studyInstanceUid}", _userInfo.Id, TimeSpan.FromSeconds(30)); } - } - else - { - lock (lockObj) + else { _provider.Remove($"StudyUid_{trialId}_{studyInstanceUid}"); } } + + return result; } diff --git a/IRaCIS.Core.Application/Service/Institution/SiteService.cs b/IRaCIS.Core.Application/Service/Institution/SiteService.cs index ce240e222..b65b2379f 100644 --- a/IRaCIS.Core.Application/Service/Institution/SiteService.cs +++ b/IRaCIS.Core.Application/Service/Institution/SiteService.cs @@ -3,7 +3,7 @@ using IRaCIS.Application.Contracts; using IRaCIS.Core.Infra.EFCore; using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Domain.Share; -using Nito.AsyncEx; +using Medallion.Threading; namespace IRaCIS.Application.Services { @@ -12,13 +12,13 @@ namespace IRaCIS.Application.Services { private readonly IRepository _siteRepository; private readonly IRepository _trialSiteUserRepository; + private readonly IDistributedLockProvider _distributedLockProvider; - private readonly AsyncLock _mutex = new AsyncLock(); - - public SiteService(IRepository siteRepository, IRepository trialSiteUserRepository) + public SiteService(IRepository siteRepository, IRepository trialSiteUserRepository, IDistributedLockProvider distributedLockProvider) { _siteRepository = siteRepository; - this._trialSiteUserRepository = trialSiteUserRepository; + _trialSiteUserRepository = trialSiteUserRepository; + _distributedLockProvider = distributedLockProvider; } /// 分页获取研究中心列表 @@ -58,7 +58,9 @@ namespace IRaCIS.Application.Services VerifyMsg = _localizer["Site_DupName"] }; - using (await _mutex.LockAsync()) + var @lock = _distributedLockProvider.CreateLock($"SiteAdd"); + + using (await @lock.AcquireAsync()) { if (siteCommand.Id == null) { diff --git a/IRaCIS.Core.Application/Service/Management/DTO/UserTypeRoleModel.cs b/IRaCIS.Core.Application/Service/Management/DTO/UserTypeRoleModel.cs index 3a059e4bd..a68328309 100644 --- a/IRaCIS.Core.Application/Service/Management/DTO/UserTypeRoleModel.cs +++ b/IRaCIS.Core.Application/Service/Management/DTO/UserTypeRoleModel.cs @@ -12,7 +12,7 @@ namespace IRaCIS.Core.Application.Contracts public UserTypeEnum UserTypeEnum { get; set; } public List UserTypeGroupList { get; set; } = new List(); - public new List UserTypeGroupIdList => UserTypeGroupList.Select(t=>t.DictionaryId).ToList(); + public new List UserTypeGroupIdList => UserTypeGroupList.Select(t => t.DictionaryId).ToList(); } @@ -22,7 +22,7 @@ namespace IRaCIS.Core.Application.Contracts public Guid DictionaryId { get; set; } - public string GroupName { get; set; }=string.Empty; + public string GroupName { get; set; } = string.Empty; public string GroupNameCN { get; set; } = string.Empty; } @@ -36,7 +36,7 @@ namespace IRaCIS.Core.Application.Contracts } - public class UserTypeMenuAddOrEdit: UserTypeRoleAddOrEdit + public class UserTypeMenuAddOrEdit : UserTypeRoleAddOrEdit { public UserTypeEnum UserTypeEnum { get; set; } @@ -64,6 +64,16 @@ namespace IRaCIS.Core.Application.Contracts } + public class TrialSelectUser + { + public Guid UserId { get; set; } + + public string UserName { get; set; } + + public string RealName { get; set; } + + public UserTypeEnum UserTypeEnum { get; set; } + } public class TrialUserType { diff --git a/IRaCIS.Core.Application/Service/Management/UserService.cs b/IRaCIS.Core.Application/Service/Management/UserService.cs index ef581d115..8b6b968e3 100644 --- a/IRaCIS.Core.Application/Service/Management/UserService.cs +++ b/IRaCIS.Core.Application/Service/Management/UserService.cs @@ -12,6 +12,7 @@ using IRaCIS.Core.Infra.Common.Cache; using Microsoft.Identity.Client; using static IRaCIS.Core.Domain.Share.StaticData; using IRaCIS.Core.Application.ViewModel; +using Medallion.Threading; namespace IRaCIS.Application.Services { @@ -25,7 +26,7 @@ namespace IRaCIS.Application.Services private readonly IRepository _userTrialRepository; private readonly IRepository _userLogRepository; - + private readonly IDistributedLockProvider _distributedLockProvider; private readonly IMemoryCache _cache; private readonly IOptionsMonitor _verifyConfig; @@ -40,7 +41,8 @@ namespace IRaCIS.Application.Services IRepository userTrialRepository, IOptionsMonitor verifyConfig, IRepository userLogRepository - ) +, + IDistributedLockProvider distributedLockProvider) { _userLogRepository = userLogRepository; @@ -52,6 +54,7 @@ namespace IRaCIS.Application.Services _doctorRepository = doctorRepository; _userTrialRepository = userTrialRepository; _userLogRepository = userLogRepository; + _distributedLockProvider = distributedLockProvider; } @@ -504,29 +507,32 @@ namespace IRaCIS.Application.Services var saveItem = _mapper.Map(userAddModel); - saveItem.Code = await _userRepository.Select(t => t.Code).DefaultIfEmpty().MaxAsync() + 1; + var @lock = _distributedLockProvider.CreateLock($"UserAccount"); - saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User)); - - if (saveItem.IsZhiZhun) + using (await @lock.AcquireAsync()) { - saveItem.OrganizationName = AppSettings.DefaultInternalOrganizationName; + saveItem.Code = await _userRepository.Select(t => t.Code).DefaultIfEmpty().MaxAsync() + 1; + + saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User)); + + if (saveItem.IsZhiZhun) + { + saveItem.OrganizationName = AppSettings.DefaultInternalOrganizationName; + } + + + saveItem.Password = MD5Helper.Md5("123456"); + + await _userRepository.AddAsync(saveItem); + + var success = await _userRepository.SaveChangesAsync(); } - - saveItem.Password = MD5Helper.Md5("123456"); - - await _userRepository.AddAsync(saveItem); - - var success = await _userRepository.SaveChangesAsync(); - - + await _mailVerificationService.AddUserSendEmailAsync(saveItem.Id, userAddModel.BaseUrl, userAddModel.RouteUrl); - - - return ResponseOutput.Result(success, new UserAddedReturnDTO { Id = saveItem.Id, UserCode = saveItem.UserCode }); + return ResponseOutput.Ok( new UserAddedReturnDTO { Id = saveItem.Id, UserCode = saveItem.UserCode }); } diff --git a/IRaCIS.Core.Application/Service/QC/NoneDicomStudyService.cs b/IRaCIS.Core.Application/Service/QC/NoneDicomStudyService.cs index fa912838f..e6a40c3bf 100644 --- a/IRaCIS.Core.Application/Service/QC/NoneDicomStudyService.cs +++ b/IRaCIS.Core.Application/Service/QC/NoneDicomStudyService.cs @@ -5,10 +5,10 @@ //-------------------------------------------------------------------- using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Application.Filter; -using Nito.AsyncEx; using System.ComponentModel.DataAnnotations; using IRaCIS.Core.Application.Service; using IRaCIS.Core.Domain.Share; +using Medallion.Threading; namespace IRaCIS.Core.Application.Contracts { @@ -20,19 +20,19 @@ namespace IRaCIS.Core.Application.Contracts { private readonly IRepository _noneDicomStudyRepository; private readonly IRepository _noneDicomStudyFileRepository; - private readonly AsyncLock _mutex = new AsyncLock(); + private readonly IDistributedLockProvider _distributedLockProvider; private readonly QCCommon _qCCommon; public NoneDicomStudyService(IRepository noneDicomStudyRepository, QCCommon qCCommon, - IRepository noneDicomStudyFileRepository) + IRepository noneDicomStudyFileRepository, IDistributedLockProvider distributedLockProvider) { _qCCommon = qCCommon; _noneDicomStudyRepository = noneDicomStudyRepository; _noneDicomStudyFileRepository = noneDicomStudyFileRepository; - + _distributedLockProvider = distributedLockProvider; } @@ -62,7 +62,9 @@ namespace IRaCIS.Core.Application.Contracts } NoneDicomStudy? optEntity = null; - using (await _mutex.LockAsync()) + var @lock = _distributedLockProvider.CreateLock($"NoneDicomCode"); + + using (await @lock.AcquireAsync()) { if (addOrEditNoneDicomStudy.Id == Guid.Empty || addOrEditNoneDicomStudy.Id == null) { diff --git a/IRaCIS.Core.Application/Service/QC/QCOperationService.cs b/IRaCIS.Core.Application/Service/QC/QCOperationService.cs index 207e9c30c..b714730ae 100644 --- a/IRaCIS.Core.Application/Service/QC/QCOperationService.cs +++ b/IRaCIS.Core.Application/Service/QC/QCOperationService.cs @@ -10,13 +10,13 @@ using WinSCP; using Newtonsoft.Json; using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Application.Service.Inspection.DTO; -using Nito.AsyncEx; using System.ComponentModel.DataAnnotations; using IRaCIS.Core.Application.Auth; using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Application.Service; +using Medallion.Threading; namespace IRaCIS.Core.Application.Image.QA { @@ -35,8 +35,7 @@ namespace IRaCIS.Core.Application.Image.QA private readonly IRepository _trialRepository; private readonly IRepository _visitTaskRepository; private readonly IVisitTaskHelpeService _IVisitTaskHelpeService; - - private readonly AsyncLock _mutex = new AsyncLock(); + private readonly IDistributedLockProvider _distributedLockProvider; public QCOperationService(IRepository subjectVisitRepository, IRepository qcChallengeRepository, @@ -48,7 +47,8 @@ namespace IRaCIS.Core.Application.Image.QA IRepository readingClinicalDataRepository, IRepository qCChallengeDialogrepository, IRepository checkChallengeDialogrepository, - IVisitTaskHelpeService visitTaskHelpeService + IVisitTaskHelpeService visitTaskHelpeService, + IDistributedLockProvider distributedLockProvider ) { _subjectVisitRepository = subjectVisitRepository; @@ -62,6 +62,7 @@ namespace IRaCIS.Core.Application.Image.QA _trialRepository = trialRepository; this._visitTaskRepository = visitTaskRepository; _IVisitTaskHelpeService = visitTaskHelpeService; + _distributedLockProvider = distributedLockProvider; } #region QC质疑 以及回复 关闭 @@ -108,9 +109,9 @@ namespace IRaCIS.Core.Application.Image.QA var trialConfig = (await _trialRepository.Where(t => t.Id == trialId).Select(t => new { TrialId = t.Id, t.QCProcessEnum, t.IsImageConsistencyVerification }).FirstOrDefaultAsync()).IfNullThrowException(); + var @lock = _distributedLockProvider.CreateLock($"QCChallengeCode"); - - using (await _mutex.LockAsync()) + using (await @lock.AcquireAsync()) { //获取编号 var code = _qcChallengeRepository.Where(t => t.TrialId == trialId).Select(t => t.Code).DefaultIfEmpty().Max(); diff --git a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingMedicalReviewDto.cs b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingMedicalReviewDto.cs index 95784d2ff..9cb77bc89 100644 --- a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingMedicalReviewDto.cs +++ b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingMedicalReviewDto.cs @@ -262,7 +262,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto public string ImagePath { get; set; } = string.Empty; - public List FileList { get; set; } = new List(); + public List FileList { get; set; } = new List(); } @@ -310,7 +310,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto - public List FileList { get; set; } = new List(); + public List FileList { get; set; } = new List(); @@ -451,7 +451,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto public Guid TaskMedicalReviewId { get; set; } - public List FileList { get; set; } = new List(); + public List FileList { get; set; } = new List(); /// @@ -498,7 +498,7 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto public string Questioning { get; set; } = string.Empty; - public List FileList { get; set; } = new List(); + public List FileList { get; set; } = new List(); /// /// 审核建议 diff --git a/IRaCIS.Core.Application/Service/SiteSurvey/Interface/JsonPatchUserRequestExample.cs b/IRaCIS.Core.Application/Service/SiteSurvey/Interface/JsonPatchUserRequestExample.cs deleted file mode 100644 index 0fa6ff834..000000000 --- a/IRaCIS.Core.Application/Service/SiteSurvey/Interface/JsonPatchUserRequestExample.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Microsoft.AspNetCore.JsonPatch.Operations; -using Swashbuckle.AspNetCore.Filters; - -namespace IRaCIS.Core.Application.Contracts -{ - /// - /// 实测 标注在服务方法上 没用 - /// - public class JsonPatchUserRequestExample : IExamplesProvider - { - public Operation[] GetExamples() - { - return new[] - { - new Operation - { - op = "replace", - path = "/name", - value = "Gordon" - }, - new Operation - { - op = "replace", - path = "/surname", - value = "Freeman" - } - }; - } - - object IExamplesProvider.GetExamples() - { - return new[] - { - new Operation - { - op = "replace", - path = "/name", - value = "Gordon" - }, - new Operation - { - op = "replace", - path = "/surname", - value = "Freeman" - } - }; - } - } - - -} diff --git a/IRaCIS.Core.Application/Service/SiteSurvey/TrialSiteSurveyService.cs b/IRaCIS.Core.Application/Service/SiteSurvey/TrialSiteSurveyService.cs index 09a8225d9..522885748 100644 --- a/IRaCIS.Core.Application/Service/SiteSurvey/TrialSiteSurveyService.cs +++ b/IRaCIS.Core.Application/Service/SiteSurvey/TrialSiteSurveyService.cs @@ -15,6 +15,7 @@ using MailKit.Security; using MimeKit; using IRaCIS.Core.Application.Helper; using IRaCIS.Core.Application.Filter; +using Medallion.Threading; namespace IRaCIS.Core.Application.Contracts { @@ -32,24 +33,25 @@ namespace IRaCIS.Core.Application.Contracts private readonly IRepository _trialUserRepository; private readonly ITokenService _tokenService; private readonly IMailVerificationService _mailVerificationService; + private readonly IDistributedLockProvider _distributedLockProvider; public TrialSiteSurveyService(IRepository trialSiteSurveyRepository, IRepository trialUserRepository, IRepository trialSiteUserSurveyRepository, IRepository userRepository, IRepository trialSiteRepository, IRepository doctorRepository, ITokenService tokenService, - IMailVerificationService mailVerificationService) + IMailVerificationService mailVerificationService, IDistributedLockProvider distributedLockProvider) { _trialSiteSurveyRepository = trialSiteSurveyRepository; _trialSiteUserSurveyRepository = trialSiteUserSurveyRepository; _userRepository = userRepository; _trialUserRepository = trialUserRepository; _trialSiteRepository = trialSiteRepository; - this._doctorRepository = doctorRepository; + _doctorRepository = doctorRepository; _tokenService = tokenService; _mailVerificationService = mailVerificationService; + _distributedLockProvider = distributedLockProvider; } - private object lockObj { get; set; } = new object(); /// /// 发送验证码 @@ -801,7 +803,9 @@ namespace IRaCIS.Core.Application.Contracts if (sysUserInfo == null) { - lock (lockObj) + var @lock = _distributedLockProvider.CreateLock($"UserCode"); + + using (await @lock.AcquireAsync()) { var saveItem = _mapper.Map(item); @@ -902,118 +906,7 @@ namespace IRaCIS.Core.Application.Contracts - #region 废弃 - //Site 调研邀请 - public async Task SendInviteEmail(InviteEmailCommand inviteEmailCommand) - { - var trialInfo = await _repository.FirstOrDefaultAsync(t => t.Id == inviteEmailCommand.TrialId); - - - foreach (var item in inviteEmailCommand.UserList) - { - - var messageToSend = new MimeMessage(); - //发件地址 - messageToSend.From.Add(new MailboxAddress("GRR", "iracis_grr@163.com")); - //收件地址 - messageToSend.To.Add(new MailboxAddress(String.Empty, item.Email)); - //主题 - //$"[来自展影IRC] [{trialInfo.ResearchProgramNo}] 邀请信"; - messageToSend.Subject = _localizer["TrialSiteSurvey_IRCInvitation", trialInfo.ResearchProgramNo]; - - var builder = new BodyBuilder(); - - //找下系统中是否存在该用户类型的 并且邮箱 或者手机的账户 - var sysUserInfo = await _userRepository.Where(t => t.UserTypeId == item.UserTypeId && t.EMail == item.Email).Include(t => t.UserTypeRole).FirstOrDefaultAsync(); - - //int verificationCode = new Random().Next(100000, 1000000); - - //var baseApiUrl = baseUrl.Remove(baseUrl.IndexOf("#")) + "api"; - - - if (sysUserInfo == null) - { - - lock (lockObj) - { - var saveItem = _mapper.Map(item); - - saveItem.Code = _userRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1; - - saveItem.UserCode = AppSettings.GetCodeStr(saveItem.Code, nameof(User)); ; - - saveItem.UserName = saveItem.UserCode; - - saveItem.UserTypeEnum = _repository.Where(t => t.Id == saveItem.UserTypeId).Select(t => t.UserTypeEnum).First(); - - //saveItem.Password = MD5Helper.Md5(verificationCode.ToString()); - - _ = _repository.AddAsync(saveItem).Result; - - _ = _repository.SaveChangesAsync().Result; - - - sysUserInfo = saveItem; - } - - } - - - - builder.HtmlBody = @$" -
-
-
- {sysUserInfo.LastName + "/" + sysUserInfo.FirstName}: -
-
- {_localizer["TrialSiteSurvey_IRCInvitationContent", trialInfo.ResearchProgramNo]} -
- - - 查看并确认 - -
-
- "; - - - - messageToSend.Body = builder.ToMessageBody(); - - using (var smtp = new MailKit.Net.Smtp.SmtpClient()) - { - - smtp.ServerCertificateValidationCallback = (s, c, h, e) => true; - - smtp.MessageSent += (sender, args) => - { - - _ = _trialSiteUserSurveyRepository.BatchUpdateNoTrackingAsync(t => t.Id == item.Id, u => new TrialSiteUserSurvey() { IsGenerateSuccess = true, InviteState = TrialSiteUserStateEnum.HasSend, ConfirmTime = null, RejectReason = String.Empty, SystemUserId = sysUserInfo.Id, ExpireTime = DateTime.Now.AddDays(7) }).Result; - - }; - - - await smtp.ConnectAsync("smtp.163.com", 465, SecureSocketOptions.StartTls); - - - await smtp.AuthenticateAsync("iracis_grr@163.com", "XLWVQKZAEKLDWOAH"); - - - await smtp.SendAsync(messageToSend); - - - await smtp.DisconnectAsync(true); - } - - } - - - return ResponseOutput.Ok(); - } - - #endregion diff --git a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialExternalUserService.cs b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialExternalUserService.cs index 94bb318c3..309cbdd1d 100644 --- a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialExternalUserService.cs +++ b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialExternalUserService.cs @@ -16,6 +16,7 @@ using Panda.DynamicWebApi.Attributes; using IRaCIS.Core.Application.Auth; using IRaCIS.Application.Services; using IRaCIS.Core.Application.Filter; +using Medallion.Threading; namespace IRaCIS.Core.Application.Service { @@ -31,10 +32,11 @@ namespace IRaCIS.Core.Application.Service private readonly IRepository _trialSiteSurveyUserRepository; private readonly IRepository _trialSiteUserRepository; private readonly IMailVerificationService _mailVerificationService; + private readonly IDistributedLockProvider _distributedLockProvider; public TrialExternalUserService(IRepository trialExternalUseRepository, IRepository userRepository, IRepository trialUserRepository, IRepository trialSiteSurveyUserRepository, IRepository trialSiteUserRepository, - IMailVerificationService mailVerificationService) + IMailVerificationService mailVerificationService, IDistributedLockProvider distributedLockProvider) { _trialExternalUseRepository = trialExternalUseRepository; _userRepository = userRepository; @@ -43,6 +45,7 @@ namespace IRaCIS.Core.Application.Service _trialSiteUserRepository = trialSiteUserRepository; _mailVerificationService = mailVerificationService; + _distributedLockProvider = distributedLockProvider; } @@ -75,121 +78,125 @@ namespace IRaCIS.Core.Application.Service if (addOrEditTrialExternalUser.Id == null) { - var existSysUser = await _userRepository.FirstOrDefaultAsync(t => t.EMail == addOrEditTrialExternalUser.Email && t.UserTypeId == addOrEditTrialExternalUser.UserTypeId); + var @lock = _distributedLockProvider.CreateLock($"UserCode"); - if (existSysUser != null) + using (await @lock.AcquireAsync()) { - if (existSysUser.LastName != addOrEditTrialExternalUser.LastName || existSysUser.FirstName != addOrEditTrialExternalUser.FirstName) + var existSysUser = await _userRepository.FirstOrDefaultAsync(t => t.EMail == addOrEditTrialExternalUser.Email && t.UserTypeId == addOrEditTrialExternalUser.UserTypeId); + + if (existSysUser != null) { - //$"该用户在系统中的用户名为:{existSysUser.LastName + " / " + existSysUser.FirstName} 电话:{existSysUser.Phone},与填写信息存在不一致项, 请将界面信息修改为与系统一致,再进行保存", - return ResponseOutput.NotOk(_localizer["TrialExternalUser_Inconsistency", existSysUser.LastName + " / " + existSysUser.FirstName, existSysUser.Phone], new { existSysUser.LastName, existSysUser.FirstName, existSysUser.Phone, existSysUser.IsZhiZhun, existSysUser.IsTestUser }, ApiResponseCodeEnum.NeedTips); + if (existSysUser.LastName != addOrEditTrialExternalUser.LastName || existSysUser.FirstName != addOrEditTrialExternalUser.FirstName) + { + //$"该用户在系统中的用户名为:{existSysUser.LastName + " / " + existSysUser.FirstName} 电话:{existSysUser.Phone},与填写信息存在不一致项, 请将界面信息修改为与系统一致,再进行保存", + return ResponseOutput.NotOk(_localizer["TrialExternalUser_Inconsistency", existSysUser.LastName + " / " + existSysUser.FirstName, existSysUser.Phone], new { existSysUser.LastName, existSysUser.FirstName, existSysUser.Phone, existSysUser.IsZhiZhun, existSysUser.IsTestUser }, ApiResponseCodeEnum.NeedTips); + } + } - } + //处理 生成账户 - //处理 生成账户 - - if (await _trialExternalUseRepository.AnyAsync(t => - t.Email == addOrEditTrialExternalUser.Email && - t.UserTypeId == addOrEditTrialExternalUser.UserTypeId && t.TrialId == addOrEditTrialExternalUser.TrialId)) - { - //---系统已经存在与列表中填写的邮箱和用户类型相同的账户,请确认。 - return ResponseOutput.NotOk(_localizer["TrialExternalUser_EmailTypeDuplicate"]); - } + if (await _trialExternalUseRepository.AnyAsync(t => + t.Email == addOrEditTrialExternalUser.Email && + t.UserTypeId == addOrEditTrialExternalUser.UserTypeId && t.TrialId == addOrEditTrialExternalUser.TrialId)) + { + //---系统已经存在与列表中填写的邮箱和用户类型相同的账户,请确认。 + return ResponseOutput.NotOk(_localizer["TrialExternalUser_EmailTypeDuplicate"]); + } - var addEntity = _mapper.Map(addOrEditTrialExternalUser); + var addEntity = _mapper.Map(addOrEditTrialExternalUser); - await _trialExternalUseRepository.AddAsync(addEntity); + await _trialExternalUseRepository.AddAsync(addEntity); - var existUser = await _userRepository.FirstOrDefaultAsync(t => t.EMail == addOrEditTrialExternalUser.Email && t.UserTypeId == addOrEditTrialExternalUser.UserTypeId); - var trialType = await _repository.Where(t => t.Id == addOrEditTrialExternalUser.TrialId).Select(t => t.TrialType).FirstOrDefaultAsync(); + var existUser = await _userRepository.FirstOrDefaultAsync(t => t.EMail == addOrEditTrialExternalUser.Email && t.UserTypeId == addOrEditTrialExternalUser.UserTypeId); + var trialType = await _repository.Where(t => t.Id == addOrEditTrialExternalUser.TrialId).Select(t => t.TrialType).FirstOrDefaultAsync(); - if (existUser != null) - { - addEntity.IsSystemUser = true; - addEntity.SystemUserId = existUser.Id; + if (existUser != null) + { + addEntity.IsSystemUser = true; + addEntity.SystemUserId = existUser.Id; - } - else - { + } + else + { - //生成账户 并插入 + //生成账户 并插入 - var generateUser = _mapper.Map(addOrEditTrialExternalUser); + var generateUser = _mapper.Map(addOrEditTrialExternalUser); + + if (trialType == TrialType.NoneOfficial) + { + generateUser.IsTestUser = true; + } + + // 外部人员生成账号 都是外部的 + generateUser.IsZhiZhun = false; + + generateUser.Code = _userRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1; + + + generateUser.UserCode = AppSettings.GetCodeStr(generateUser.Code, nameof(User)); + + generateUser.UserName = generateUser.UserCode; + + generateUser.UserTypeEnum = _repository.Where(t => t.Id == generateUser.UserTypeId).Select(t => t.UserTypeEnum).First(); + + generateUser.Password = MD5Helper.Md5("123456"); + + generateUser.Status = UserStateEnum.Disable; + + var newAddUser = await _repository.AddAsync(generateUser); + + + addEntity.IsSystemUser = false; + addEntity.SystemUserId = newAddUser.Id; + + + existUser = newAddUser; + + } + + #region 验证用户 能否加入 + + if (trialType == TrialType.OfficialTrial || trialType == TrialType.Training) + { + + if (existUser.IsTestUser) + { + //---正式类型 、培训类型的项目 不允许加入测试用户 + throw new BusinessValidationFailedException(_localizer["TrialExternalUser_TestUserNotAllowed"]); + + } + } if (trialType == TrialType.NoneOfficial) { - generateUser.IsTestUser = true; + + if (existUser.IsTestUser == false) + { + //---测试项目 不允许加入正式用户 + throw new BusinessValidationFailedException(_localizer["TrialExternalUser_FormalUserNotAllowed"]); + } } - // 外部人员生成账号 都是外部的 - generateUser.IsZhiZhun = false; - - generateUser.Code = _userRepository.Select(t => t.Code).DefaultIfEmpty().Max() + 1; + #endregion - generateUser.UserCode = AppSettings.GetCodeStr(generateUser.Code, nameof(User)); - - generateUser.UserName = generateUser.UserCode; - - generateUser.UserTypeEnum = _repository.Where(t => t.Id == generateUser.UserTypeId).Select(t => t.UserTypeEnum).First(); - - generateUser.Password = MD5Helper.Md5("123456"); - - generateUser.Status = UserStateEnum.Disable; - - var newAddUser = await _repository.AddAsync(generateUser); + await _trialExternalUseRepository.SaveChangesAsync(); - addEntity.IsSystemUser = false; - addEntity.SystemUserId = newAddUser.Id; - - - existUser = newAddUser; - - } - - #region 验证用户 能否加入 - - if (trialType == TrialType.OfficialTrial || trialType == TrialType.Training) - { - - if (existUser.IsTestUser) + //添加的时候就发邮件 现在省略 + if (addOrEditTrialExternalUser.IsSendEmail) { - //---正式类型 、培训类型的项目 不允许加入测试用户 - throw new BusinessValidationFailedException(_localizer["TrialExternalUser_TestUserNotAllowed"]); - - } - } - - if (trialType == TrialType.NoneOfficial) - { - - if (existUser.IsTestUser == false ) - { - //---测试项目 不允许加入正式用户 - throw new BusinessValidationFailedException(_localizer["TrialExternalUser_FormalUserNotAllowed"]); - } - } - - #endregion - - - await _trialExternalUseRepository.SaveChangesAsync(); - - - //添加的时候就发邮件 现在省略 - if (addOrEditTrialExternalUser.IsSendEmail) - { - await SendExternalUserJoinEmail(new TrialExternalUserSendEmail() - { - BaseUrl = addOrEditTrialExternalUser.BaseUrl, - RouteUrl = addOrEditTrialExternalUser.RouteUrl, - TrialId = addOrEditTrialExternalUser.TrialId, - SendUsers = new List() + await SendExternalUserJoinEmail(new TrialExternalUserSendEmail() + { + BaseUrl = addOrEditTrialExternalUser.BaseUrl, + RouteUrl = addOrEditTrialExternalUser.RouteUrl, + TrialId = addOrEditTrialExternalUser.TrialId, + SendUsers = new List() { new UserEmail() { @@ -199,12 +206,13 @@ namespace IRaCIS.Core.Application.Service SystemUserId=addEntity.SystemUserId } } - }); + }); + } + + + return ResponseOutput.Ok(addEntity.Id.ToString()); } - - return ResponseOutput.Ok(addEntity.Id.ToString()); - } else { diff --git a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialService.cs b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialService.cs index 76f6cdacc..69f46a855 100644 --- a/IRaCIS.Core.Application/Service/TrialSiteUser/TrialService.cs +++ b/IRaCIS.Core.Application/Service/TrialSiteUser/TrialService.cs @@ -92,7 +92,7 @@ namespace IRaCIS.Application.Services .WhereIf(multiCriteriaSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.Criterion) == multiCriteriaSelectCount) .WhereIf(multiReviewTypeSelectCount > 0, t => t.TrialDicList.Count(t => t.KeyName == StaticData.ReviewType) == multiReviewTypeSelectCount) .WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id && t.IsDeleted == false) && t.IsDeleted == false) - .ProjectTo(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id }); + .ProjectTo(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id , isEn_Us= _userInfo.IsEn_Us }); return await query.ToPagedListAsync(searchParam.PageIndex, searchParam.PageSize, string.IsNullOrWhiteSpace(searchParam.SortField) ? "CreateTime" : searchParam.SortField, searchParam.Asc); @@ -118,7 +118,7 @@ namespace IRaCIS.Application.Services [HttpGet("{projectId:guid}")] public async Task GetTrialInfoAndLockState(Guid projectId) { - return (await _trialRepository.Where(o => o.Id == projectId).IgnoreQueryFilters().ProjectTo(_mapper.ConfigurationProvider).FirstOrDefaultAsync()).IfNullThrowException(); + return (await _trialRepository.Where(o => o.Id == projectId).IgnoreQueryFilters().ProjectTo(_mapper.ConfigurationProvider, new {isEn_Us = _userInfo.IsEn_Us }).FirstOrDefaultAsync()).IfNullThrowException(); } @@ -609,7 +609,7 @@ namespace IRaCIS.Application.Services .WhereIf(param.Status == 8, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.InviteIntoGroup)) .WhereIf(param.Status == 10, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.DoctorReading)) .WhereIf(param.Status == 14, t => t.EnrollList.Any(u => u.EnrollStatus == EnrollStatus.Finished)) - .ProjectTo(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id }); + .ProjectTo(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id, isEn_Us = _userInfo.IsEn_Us }); return await query.ToPagedListAsync(param.PageIndex, param.PageSize, string.IsNullOrWhiteSpace(param.SortField) ? "CreateTime" : param.SortField, param.Asc); @@ -644,7 +644,7 @@ namespace IRaCIS.Application.Services .WhereIf(!string.IsNullOrEmpty(searchModel.Code), o => o.TrialCode.Contains(searchModel.Code)) .WhereIf(!string.IsNullOrWhiteSpace(searchModel.Indication), o => o.Indication.Contains(searchModel.Indication)) .WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id)) - .ProjectTo(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id }); + .ProjectTo(_mapper.ConfigurationProvider, new { userTypeEnumInt = _userInfo.UserTypeEnumInt, userId = _userInfo.Id ,isEn_Us = _userInfo.IsEn_Us }); return await query.ToPagedListAsync(searchModel.PageIndex, searchModel.PageSize, string.IsNullOrWhiteSpace(searchModel.SortField) ? "CreateTime" : searchModel.SortField, searchModel.Asc); diff --git a/IRaCIS.Core.Application/Service/TrialSiteUser/_MapConfig.cs b/IRaCIS.Core.Application/Service/TrialSiteUser/_MapConfig.cs index f5861e37e..200b6f4c3 100644 --- a/IRaCIS.Core.Application/Service/TrialSiteUser/_MapConfig.cs +++ b/IRaCIS.Core.Application/Service/TrialSiteUser/_MapConfig.cs @@ -65,16 +65,17 @@ namespace IRaCIS.Core.Application.Service var userId = Guid.Empty; var userTypeEnumInt = 0; + var isEn_Us = false; CreateMap() .ForMember(x=>x.CriterionList,y=>y.MapFrom(z=>z.ReadingQuestionCriterionTrialList.Where(n=>n.IsConfirm).Select(m=>m.CriterionName))) .ForMember(d => d.DictionaryList, u => u.MapFrom(s => s.TrialDicList.Select(t => t.Dictionary).OrderBy(t => t.ShowOrder))) //.ForMember(d => d.Code, u => u.MapFrom(s => s.TrialCode)) .ForMember(d => d.Sponsor, u => u.MapFrom(s => s.Sponsor.SponsorName)) - .ForMember(d => d.Phase, u => u.MapFrom(s => s.Phase.MappedValue)) + .ForMember(d => d.Phase, u => u.MapFrom(s => isEn_Us? s.Phase.Value: s.Phase.ValueCN)) //.ForMember(d => d.DeclarationType, u => u.MapFrom(s => s.DeclarationType.MappedValue)) - .ForMember(d => d.IndicationType, u => u.MapFrom(s => s.IndicationType.MappedValue)) + .ForMember(d => d.IndicationType, u => u.MapFrom(s => isEn_Us ? s.IndicationType.Value:s.IndicationType.ValueCN)) .ForMember(d => d.CRO, u => u.MapFrom(s => s.CRO.CROName)) - .ForMember(d => d.ReviewMode, u => u.MapFrom(s => s.ReviewMode.MappedValue)) + .ForMember(d => d.ReviewMode, u => u.MapFrom(s => isEn_Us ? s.ReviewMode.Value:s.ReviewMode.ValueCN)) //.ForMember(d => d.ReviewType, u => u.MapFrom(s => s.ReviewType.Value)) .ForMember(d => d.IsLocked, u => u.MapFrom(s => s.WorkloadList.Any(u => u.DataFrom == (int)WorkLoadFromStatus.FinalConfirm))) //.ForMember(d => d.SiteCount, u => u.MapFrom(s => userTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator ? s.TrialSiteUserList.Count(k => k.UserId == userId) : s.TrialSiteList.Count())) @@ -111,7 +112,6 @@ namespace IRaCIS.Core.Application.Service .ForMember(d => d.HospitalName, u => u.MapFrom(s => s.Hospital.HospitalName)); //trial site 选择列表 subjectVisit pannel 模式添加的时候 - var isEn_Us = false; CreateMap() .ForMember(d => d.IsSelect, u => u.MapFrom(s => s.TrialSiteList.Any(k => k.TrialId == trialId))) diff --git a/IRaCIS.Core.Application/TestService.cs b/IRaCIS.Core.Application/TestService.cs index c3e953a73..46153bca6 100644 --- a/IRaCIS.Core.Application/TestService.cs +++ b/IRaCIS.Core.Application/TestService.cs @@ -3,13 +3,17 @@ using IRaCIS.Core.Application.Service; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infrastructure; +using MassTransit; +using Medallion.Threading; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using MiniExcelLibs; using System.Linq.Expressions; +using System.Reflection.Metadata; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -20,6 +24,8 @@ namespace IRaCIS.Application.Services [ApiExplorerSettings(GroupName = "Institution")] public class TestService : BaseService { + + public static int IntValue = 100; private readonly IRepository _dicRepository; private readonly IRepository _trialRepository; @@ -30,10 +36,13 @@ namespace IRaCIS.Application.Services private readonly IOptionsMonitor _basicConfig; private readonly IRepository _visitTaskRepositoryy; + private readonly IDistributedLockProvider _distributedLockProvider; - public TestService(IRepository dicRepository, IRepository trialRepository/*, IDistributedCache cache*/ + private readonly ILogger _logger; - , IOptionsMonitor systemEmailConfig, IOptionsMonitor basicConfig, IRepository visitTaskRepository) + public TestService(IRepository dicRepository, IRepository trialRepository,ILogger logger + + , IOptionsMonitor systemEmailConfig, IOptionsMonitor basicConfig, IRepository visitTaskRepository, IDistributedLockProvider distributedLockProvider) { _visitTaskRepositoryy = visitTaskRepository; @@ -42,11 +51,35 @@ namespace IRaCIS.Application.Services _dicRepository = dicRepository; _trialRepository = trialRepository; + + _distributedLockProvider= distributedLockProvider; + + _logger= logger; //_cache = cache; } + [AllowAnonymous] + public async Task TestDistributedLock( ) + { + Console.WriteLine($"我进来了当前值是:" + IntValue); + _logger.LogWarning($"我进来了当前值是:" + IntValue); + + var @lock = _distributedLockProvider.CreateLock($"UserAccount"); + + using (await @lock.AcquireAsync()) + { + await Task.Delay(4); + IntValue--; + + _logger.LogWarning( IntValue.ToString()); + Console.WriteLine(IntValue); + } + + return ResponseOutput.Ok(IntValue); + } + [AllowAnonymous] public async Task InternationazitionInit() diff --git a/IRaCIS.Core.Domain.Share/Common/EmailScenarioEnum.cs b/IRaCIS.Core.Domain.Share/Common/EmailScenarioEnum.cs index d14ccc540..b46f6ac5c 100644 --- a/IRaCIS.Core.Domain.Share/Common/EmailScenarioEnum.cs +++ b/IRaCIS.Core.Domain.Share/Common/EmailScenarioEnum.cs @@ -34,7 +34,7 @@ namespace IRaCIS.Core.Domain.Share } - public enum CommonDocumentBusinessScenario + public enum EmailBusinessScenario { EnrollConfirmed = 1, @@ -44,6 +44,12 @@ namespace IRaCIS.Core.Domain.Share Trial=3, Reviewer=4, + + QCTask = 5, + + QCQuestion = 6, + + ImageQuestion = 7 } diff --git a/IRaCIS.Core.Domain/Allocation/TaskMedicalReview.cs b/IRaCIS.Core.Domain/Allocation/TaskMedicalReview.cs index 7c77ea807..901e4c984 100644 --- a/IRaCIS.Core.Domain/Allocation/TaskMedicalReview.cs +++ b/IRaCIS.Core.Domain/Allocation/TaskMedicalReview.cs @@ -178,7 +178,7 @@ namespace IRaCIS.Core.Domain.Models /// 文件 ///
[NotMapped] - public List FileList + public List FileList { get { @@ -186,13 +186,13 @@ namespace IRaCIS.Core.Domain.Models try { - var result= JsonConvert.DeserializeObject>(this.ImagePath); - return result==null?new List() : result; + var result= JsonConvert.DeserializeObject>(this.ImagePath); + return result==null?new List() : result; } catch (Exception) { - return new List(); + return new List(); } } @@ -210,7 +210,7 @@ namespace IRaCIS.Core.Domain.Models #region 文件对象 - public class ImageInfo + public class OSSImageInfo { public string FileName { get; set; } diff --git a/IRaCIS.Core.Domain/Common/CommonDocument.cs b/IRaCIS.Core.Domain/Common/CommonDocument.cs index be9a95fa5..451b0f51c 100644 --- a/IRaCIS.Core.Domain/Common/CommonDocument.cs +++ b/IRaCIS.Core.Domain/Common/CommonDocument.cs @@ -72,7 +72,7 @@ namespace IRaCIS.Core.Domain.Models public CriterionType? CriterionTypeEnum { get; set; } public CommonDocumentFileType FileTypeEnum { get; set; } - public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; } + public EmailBusinessScenario BusinessScenarioEnum { get; set; } //[Required] diff --git a/IRaCIS.Core.Domain/Common/Dictionary.cs b/IRaCIS.Core.Domain/Common/Dictionary.cs index 6b518574a..f178c6154 100644 --- a/IRaCIS.Core.Domain/Common/Dictionary.cs +++ b/IRaCIS.Core.Domain/Common/Dictionary.cs @@ -59,9 +59,6 @@ namespace IRaCIS.Core.Domain.Models public List ChildList { get; set; } = new List(); - [NotMapped] - public string MappedValue { get; set; } - [Projectable] public string TranslateValue( string value, string valueCN,bool isCN) => isCN?valueCN:value; diff --git a/IRaCIS.Core.Domain/Common/EmailNoticeConfig.cs b/IRaCIS.Core.Domain/Common/EmailNoticeConfig.cs index dd1a99f11..74ab2ac60 100644 --- a/IRaCIS.Core.Domain/Common/EmailNoticeConfig.cs +++ b/IRaCIS.Core.Domain/Common/EmailNoticeConfig.cs @@ -16,11 +16,59 @@ namespace IRaCIS.Core.Domain.Models ///EmailNoticeConfig /// [Table("EmailNoticeConfig")] - public class EmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd,ISoftDelete + public class EmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd, ISoftDelete { + [JsonIgnore] + public List TrialEmailNoticeConfigList { get; set; } + + [JsonIgnore] + public List EmailNoticeUserTypeList { get; set; } = new List(); public string Code { get; set; } = String.Empty; - public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; } + public EmailBusinessScenario BusinessScenarioEnum { get; set; } + + /// 标准类型 /// + public CriterionType? CriterionTypeEnum { get; set; } + + /// 业务模块 /// + public int BusinessModuleEnum { get; set; } + + /// 业务层级 /// + public int BusinessLevelEnum { get; set; } + + /// 邮件类型 /// + public int EmailTypeEnum { get; set; } + + /// 邮件加急类型 /// + public int EmailUrgentEnum { get; set; } + + /// 定时周期 /// + public string EmailCron { get; set; } = string.Empty; + + /// 邮件主题 /// + public string EmailTopic { get; set; } = string.Empty; + + public string EmailTopicCN { get; set; } = string.Empty; + + /// 附件 /// + public string AttachPath { get; set; } = string.Empty; + + public string AttachCNPath { get; set; } = string.Empty; + + public string EmailHtmlContent { get; set; } = string.Empty; + + public string EmailHtmlContentCN { get; set; } = string.Empty; + + public string Description { get; set; } = string.Empty; + + + public string AttachName { get; set; } = string.Empty; + public string AttachNameCN { get; set; } = string.Empty; + + + + + /// /// 是否区分标准 @@ -34,10 +82,6 @@ namespace IRaCIS.Core.Domain.Models [Required] public bool IsReturnRequired { get; set; } - - [Required] - public bool IsUrgent { get; set; } - public bool IsAutoSend { get; set; } public bool IsEnable { get; set; } @@ -61,14 +105,21 @@ namespace IRaCIS.Core.Domain.Models public Guid? DeleteUserId { get; set; } - - - - - - - - } + + [Table("EmailNoticeUserType")] + + public class EmailNoticeUserType : Entity + { + [JsonIgnore] + public EmailNoticeConfig EmailNoticeConfig { get; set; } + + public Guid EmailNoticeConfigId { get; set; } + + + public UserTypeEnum UserType { get; set; } + + public EmailUserType EmailUserType { get; set; } + } } diff --git a/IRaCIS.Core.Domain/Document/TrialEmailNoticeConfig.cs b/IRaCIS.Core.Domain/Document/TrialEmailNoticeConfig.cs index 5b3bf06b4..2a221071d 100644 --- a/IRaCIS.Core.Domain/Document/TrialEmailNoticeConfig.cs +++ b/IRaCIS.Core.Domain/Document/TrialEmailNoticeConfig.cs @@ -12,93 +12,138 @@ using System.Linq; namespace IRaCIS.Core.Domain.Models { - /// - ///TrialEmailNoticeConfig - /// - [Table("TrialEmailNoticeConfig")] - public class TrialEmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd - { + /// + ///TrialEmailNoticeConfig + /// + [Table("TrialEmailNoticeConfig")] + public class TrialEmailNoticeConfig : Entity, IAuditUpdate, IAuditAdd, ISoftDelete + { + [JsonIgnore] - [Required] - public Guid TrialId { get; set; } - - - public string SMTPServerAddress { get; set; } = string.Empty; - - public int SMTPServerPort { get; set; } - - [Required] - public string AuthorizationCode { get; set; } = string.Empty; - - - public string FromName { get; set; } = string.Empty; - public List TrialEmailNoticeUserList { get; set; } = new List(); - - - //[Required] - - //public string ReceiveEmailsStr { get; set; } = string.Empty; - //public string CopyEmailsStr { get; set; } = string.Empty; - - //[NotMapped] - //public List ReceiveEmailList => ReceiveEmailsStr.Split('|', StringSplitOptions.RemoveEmptyEntries).Where(t => !string.IsNullOrEmpty(t)).Select(t=>t.Trim()).ToList(); - - //[NotMapped] - //public List CopyEmailList => CopyEmailsStr.Split('|', StringSplitOptions.RemoveEmptyEntries).Where(t=> !string.IsNullOrEmpty(t)).Select(t => t.Trim()).ToList(); - - - - public string FromEmail { get; set; } = string.Empty; - - [Required] - public bool IsUrgent { get; set; } - - - [Required] - public string Code { get; set; } = string.Empty; - - - - [Required] - public bool IsReturnRequired { get; set; } - - - - [Required] - public bool IsAutoSend { get; set; } - - - - public CommonDocumentBusinessScenario BusinessScenarioEnum { get; set; } - - public CriterionType? CriterionTypeEnum { get; set; } - - - public Guid? TrialReadingCriterionId { get; set; } - - [ForeignKey("TrialReadingCriterionId")] - [JsonIgnore] - public ReadingQuestionCriterionTrial TrialReadingCriterion { get; set; } + public Trial Trial { get; set; } [Required] - public string FilePath { get; set; } = string.Empty; - - [Required] - public string FileName { get; set; } = string.Empty; - - [Required] - public Guid CreateUserId { get; set; } - - [Required] - public DateTime CreateTime { get; set; } - - [Required] - public Guid UpdateUserId { get; set; } - - [Required] - public DateTime UpdateTime { get; set; } + public Guid TrialId { get; set; } - } + public string SMTPServerAddress { get; set; } = string.Empty; -} + public int SMTPServerPort { get; set; } + + [Required] + public string AuthorizationCode { get; set; } = string.Empty; + + + public string FromName { get; set; } = string.Empty; + + + public string FromEmail { get; set; } = string.Empty; + + [JsonIgnore] + public List TrialEmailNoticeUserList { get; set; } = new List(); + + public List TrialEmailBlackUserList { get; set; } = new List(); + + + /// 业务模块 /// + public int BusinessModuleEnum { get; set; } + + /// 业务层级 /// + public int BusinessLevelEnum { get; set; } + + /// 邮件类型 /// + public int EmailTypeEnum { get; set; } + + /// 邮件加急类型 /// + public int EmailUrgentEnum { get; set; } + + /// 定时周期 /// + public string EmailCron { get; set; } = string.Empty; + + /// 邮件主题 /// + public string EmailTopic { get; set; } = string.Empty; + + public string EmailTopicCN { get; set; } = string.Empty; + + /// 附件 /// + public string AttachPath { get; set; } = string.Empty; + + public string AttachCNPath { get; set; } = string.Empty; + + public string Description { get; set; } = string.Empty; + + + public string AttachName { get; set; } + public string AttachNameCN { get; set; } + + + public string EmailHtmlContent { get; set; } = string.Empty; + public string EmailHtmlContentCN { get; set; } = string.Empty; + + + + [JsonIgnore] + + public EmailNoticeConfig SysEmailNoticeConfig { get; set; } + public Guid? SysEmailNoticeConfigId { get; set; } + + + [Required] + public string Code { get; set; } = string.Empty; + + [Required] + public bool IsReturnRequired { get; set; } + [Required] + public bool IsAutoSend { get; set; } + + public bool IsEnable { get; set; } + + + public EmailBusinessScenario BusinessScenarioEnum { get; set; } + + public CriterionType? CriterionTypeEnum { get; set; } + + + public Guid? TrialReadingCriterionId { get; set; } + + [ForeignKey("TrialReadingCriterionId")] + [JsonIgnore] + public ReadingQuestionCriterionTrial TrialReadingCriterion { get; set; } + + [Required] + public Guid CreateUserId { get; set; } + + [Required] + public DateTime CreateTime { get; set; } + + [Required] + public Guid UpdateUserId { get; set; } + + [Required] + public DateTime UpdateTime { get; set; } + + public bool IsDeleted { get; set; } + + public DateTime? DeletedTime { get; set; } + + public Guid? DeleteUserId { get; set; } + + + } + + public class TrialEmailBlackUser : Entity + { + [JsonIgnore] + public TrialEmailNoticeConfig TrialEmailNoticeConfig { get; set; } + + [JsonIgnore] + public User User { get; set; } + + + public Guid TrialEmailNoticeConfigId { get; set; } + + + public Guid UserId { get; set; } + } + +} diff --git a/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj index 5cbdf014a..f9c01aaf3 100644 --- a/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj +++ b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj @@ -9,11 +9,7 @@ - - - - - + diff --git a/IRaCIS.Core.Domain/Reading/MedicalAudit/ReadingMedicalReviewDialog.cs b/IRaCIS.Core.Domain/Reading/MedicalAudit/ReadingMedicalReviewDialog.cs index c3f46259f..e00db79c7 100644 --- a/IRaCIS.Core.Domain/Reading/MedicalAudit/ReadingMedicalReviewDialog.cs +++ b/IRaCIS.Core.Domain/Reading/MedicalAudit/ReadingMedicalReviewDialog.cs @@ -113,7 +113,7 @@ namespace IRaCIS.Core.Domain.Models /// 文件 /// [NotMapped] - public List FileList + public List FileList { get { @@ -121,13 +121,13 @@ namespace IRaCIS.Core.Domain.Models try { - var result = JsonConvert.DeserializeObject>(this.ImagePath); - return result == null ? new List() : result; + var result = JsonConvert.DeserializeObject>(this.ImagePath); + return result == null ? new List() : result; } catch (Exception) { - return new List(); + return new List(); } } diff --git a/IRaCIS.Core.Domain/Trial/Trial.cs b/IRaCIS.Core.Domain/Trial/Trial.cs index 705ca584b..68f77bc56 100644 --- a/IRaCIS.Core.Domain/Trial/Trial.cs +++ b/IRaCIS.Core.Domain/Trial/Trial.cs @@ -383,7 +383,7 @@ namespace IRaCIS.Core.Domain.Models /// /// SMTP˿ /// - public int? EmailSMTPServerPort { get; set; } + public int EmailSMTPServerPort { get; set; } /// /// Ƿù diff --git a/IRaCIS.Core.Domain/Visit/SubjectVisit.cs b/IRaCIS.Core.Domain/Visit/SubjectVisit.cs index cf80c30b2..7b44926ef 100644 --- a/IRaCIS.Core.Domain/Visit/SubjectVisit.cs +++ b/IRaCIS.Core.Domain/Visit/SubjectVisit.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using IRaCIS.Core.Domain.Share; -using Microsoft.EntityFrameworkCore.Metadata.Internal; + namespace IRaCIS.Core.Domain.Models { diff --git a/IRaCIS.Core.Domain/_Config/_AppSettings.cs b/IRaCIS.Core.Domain/_Config/_AppSettings.cs index 4bda63fec..698f8a10b 100644 --- a/IRaCIS.Core.Domain/_Config/_AppSettings.cs +++ b/IRaCIS.Core.Domain/_Config/_AppSettings.cs @@ -34,7 +34,9 @@ namespace IRaCIS.Core.Domain.Share public string FromName { get; set; } - public string AuthorizationCode { get; set; } + public string AuthorizationCode { get; set; } + + public string SiteUrl { get; set; } } diff --git a/IRaCIS.Core.Domain/_Config/_StaticData.cs b/IRaCIS.Core.Domain/_Config/_StaticData.cs index daf810d2b..5bfb2f3e5 100644 --- a/IRaCIS.Core.Domain/_Config/_StaticData.cs +++ b/IRaCIS.Core.Domain/_Config/_StaticData.cs @@ -78,7 +78,7 @@ public static class StaticData public static readonly string Resources = "Resources"; public static readonly string IRaCISDataFolder = "IRaCISData"; - + public static readonly string OtherDataFolder = "OtherData"; public static readonly string TrialDataFolder = "TrialData"; public static readonly string SystemDataFolder = "SystemData"; @@ -87,6 +87,11 @@ public static class StaticData public static readonly string SignDocumentFolder = "SignDocument"; public static readonly string DataTemplate = "DataTemplate"; + public static readonly string EmailTemplate = "EmailTemplate"; + + public static readonly string CommonFile = "CommonFile"; + + public static readonly string TempFile = "TempFile"; public static readonly string NoticeAttachment = "NoticeAttachment"; diff --git a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs index 3720a409d..068df0e6d 100644 --- a/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs +++ b/IRaCIS.Core.Infra.EFCore/Context/IRaCISDBContext.cs @@ -123,14 +123,14 @@ namespace IRaCIS.Core.Infra.EFCore modelBuilder.Entity().HasMany(t => t.ChildList).WithOne(t => t.Parent); modelBuilder.Entity().HasMany(t => t.EarlierSubjectUserList).WithOne(t => t.OrignalSubjectUser); - if (_userInfo.IsEn_Us) - { - modelBuilder.Entity().Property(t => t.MappedValue).HasColumnName(nameof(Domain.Models.Dictionary.Value)); - } - else - { - modelBuilder.Entity().Property(t => t.MappedValue).HasColumnName(nameof(Domain.Models.Dictionary.ValueCN)); - } + //if (_userInfo.IsEn_Us) + //{ + // modelBuilder.Entity().Property(t => t.MappedValue).HasColumnName(nameof(Domain.Models.Dictionary.Value)); + //} + //else + //{ + // modelBuilder.Entity().Property(t => t.MappedValue).HasColumnName(nameof(Domain.Models.Dictionary.ValueCN)); + //} //遍历实体模型手动配置 @@ -513,7 +513,8 @@ namespace IRaCIS.Core.Infra.EFCore public virtual DbSet UserLog { get; set; } - + public virtual DbSet EmailNoticeUserType { get; set; } + public virtual DbSet TrialEmailBlackUser { get; set; } #region 废弃 diff --git a/IRaCIS.Core.Infra.EFCore/EntityConfigration/ClinicalFromConfigration.cs b/IRaCIS.Core.Infra.EFCore/EntityConfigration/ClinicalFromConfigration.cs deleted file mode 100644 index 98b711e7a..000000000 --- a/IRaCIS.Core.Infra.EFCore/EntityConfigration/ClinicalFromConfigration.cs +++ /dev/null @@ -1,27 +0,0 @@ -using IRaCIS.Core.Domain.Models; -using Microsoft.EntityFrameworkCore.Metadata.Builders; -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace IRaCIS.Core.Infra.EFCore.EntityConfigration -{ - //public class ClinicalFromConfigration : IEntityTypeConfiguration - //{ - - - // public void Configure(EntityTypeBuilder builder) - // { - // builder - // .HasOne(s => s.ReadingClinicalData) - // .WithMany(c => c.ClinicalFormList) - // .HasForeignKey(s => new { s.SubjectId, s.ReadingId }) - // .HasPrincipalKey(c => new { c.SubjectId, c.ReadingId }); - // } - - - //} -} diff --git a/IRaCIS.Core.Infra.EFCore/EntityConfigration/DoctorConfigration.cs b/IRaCIS.Core.Infra.EFCore/EntityConfigration/DoctorConfigration.cs index bac14118a..a0d0f1744 100644 --- a/IRaCIS.Core.Infra.EFCore/EntityConfigration/DoctorConfigration.cs +++ b/IRaCIS.Core.Infra.EFCore/EntityConfigration/DoctorConfigration.cs @@ -26,31 +26,17 @@ namespace IRaCIS.Core.Infra.EFCore.EntityConfigration } - //public class DoctorTaskConfigration : IEntityTypeConfiguration - //{ - // public void Configure(EntityTypeBuilder builder) - // { - // builder - // .HasOne(dd => dd.DoctorUser) - // .WithMany(p => p.VisitTaskList) - // .HasForeignKey(dd => dd.DoctorUserId); - - - // } - - - //} - public class DictionaryConfigration : IEntityTypeConfiguration { public void Configure(EntityTypeBuilder builder) { - builder.Property(e => e.MappedValue).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore); - builder.Property(e => e.MappedValue).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore); + + //builder.Property(e => e.MappedValue).Metadata.SetBeforeSaveBehavior(PropertySaveBehavior.Ignore); + // builder.Property(e => e.MappedValue).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore); } } diff --git a/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj b/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj index df6df308d..ccebbacad 100644 --- a/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj +++ b/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj @@ -17,13 +17,13 @@ - - - + + - - + + + diff --git a/IRaCIS.Core.Infrastructure/Extention/RequestExtension.cs b/IRaCIS.Core.Infrastructure/Extention/RequestExtension.cs deleted file mode 100644 index 1aecdeb67..000000000 --- a/IRaCIS.Core.Infrastructure/Extention/RequestExtension.cs +++ /dev/null @@ -1,158 +0,0 @@ -using Microsoft.AspNetCore.Http; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace IRaCIS.Core.Infrastructure.Extention -{ - public static class HttpContextExtension - { - - public static T GetService(this HttpContext context) where T : class - { - return context.RequestServices.GetService(typeof(T)) as T; - } - - - public static string GetUserIp(this HttpContext context) - { - string realIP = null; - string forwarded = null; - string remoteIpAddress = context.Connection.RemoteIpAddress.ToString(); - if (context.Request.Headers.ContainsKey("X-Real-IP")) - { - realIP = context.Request.Headers["X-Real-IP"].ToString(); - if (realIP != remoteIpAddress) - { - remoteIpAddress = realIP; - } - } - if (context.Request.Headers.ContainsKey("X-Forwarded-For")) - { - forwarded = context.Request.Headers["X-Forwarded-For"].ToString(); - if (forwarded != remoteIpAddress) - { - remoteIpAddress = forwarded; - } - } - return remoteIpAddress; - } - - - - /// - /// 获取Request值 - /// - /// - /// - /// - public static string Request(this HttpContext context, string parameter) - { - try - { - if (context == null) - return null; - if (context.Request.Method == "POST") - return context.Request.Form[parameter].ToString(); - else - return context.Request.Query[parameter].ToString(); - } - catch (System.Exception ex) - { - Console.Write(ex.Message + ex.InnerException); - return context.RequestString(parameter); - } - } - - public static T Request(this HttpContext context, string parameter) where T : class - { - return context.RequestString(parameter)?.DeserializeObject(); - } - public static string RequestString(this HttpContext context, string parameter) - { - string requestParam = context.GetRequestParameters(); - if (string.IsNullOrEmpty(requestParam)) return null; - Dictionary keyValues = requestParam.DeserializeObject>(); - if (keyValues == null || keyValues.Count == 0) return null; - if (keyValues.TryGetValue(parameter, out object value)) - { - if (value == null) return null; - if (value.GetType() == typeof(string)) - { - return value?.ToString(); - } - return value.Serialize(); - } - return null; - } - /// - /// 是否为ajax请求 - /// - /// - /// - public static bool IsAjaxRequest(this HttpContext context) - { - return context.Request("X-Requested-With") == "XMLHttpRequest" - || (context.Request.Headers != null - && context.Request.Headers["X-Requested-With"] == "XMLHttpRequest"); - } - - public static UserAgent GetAgentType(this HttpContext context) - { - string agent = context.Request.Headers["User-Agent"].ToString().ToLower(); - - if (agent.Contains("ios") || agent.Contains("ipod") || agent.Contains("ipad")) - { - return UserAgent.IOS; - } - if (agent.Contains("windows")) - { - return UserAgent.Windows; - } - return UserAgent.Android; - - } - - /// - /// 获取请求的参数 - /// net core 2.0已增加回读方法 context.Request.EnableRewind(); - /// - /// - /// - /// - - public static string GetRequestParameters(this HttpContext context) - { - if (context.Request.Body == null || !context.Request.Body.CanRead || !context.Request.Body.CanSeek) - return null; - if (context.Request.Body.Length == 0) - return null; - if (context.Request.Body.Position > 0) - context.Request.Body.Position = 0; - - string prarameters = null; - var bodyStream = context.Request.Body; - - using (var buffer = new MemoryStream()) - { - bodyStream.CopyToAsync(buffer); - buffer.Position = 0L; - bodyStream.Position = 0L; - using (var reader = new StreamReader(buffer, Encoding.UTF8)) - { - buffer.Seek(0, SeekOrigin.Begin); - prarameters = reader.ReadToEnd(); - } - } - return prarameters; - } - } - public enum UserAgent - { - IOS = 0, - Android = 1, - Windows = 2, - Linux - } -} diff --git a/IRaCIS.Core.Infrastructure/Helper/IPHelper.cs b/IRaCIS.Core.Infrastructure/Helper/IPHelper.cs deleted file mode 100644 index c8827eab0..000000000 --- a/IRaCIS.Core.Infrastructure/Helper/IPHelper.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Linq; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Http; - -namespace IRaCIS.Core.Infrastructure -{ - public class IPHelper - { - /// - /// 是否为ip - /// - /// - /// - public static bool IsIP(string ip) - { - return Regex.IsMatch(ip, @"^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$"); - } - - public static string GetIP(HttpRequest request) - { - if (request == null) - { - return ""; - } - - string ip = request.Headers["X-Real-IP"].FirstOrDefault(); - if (string.IsNullOrEmpty(ip)) - { - ip = request.Headers["X-Forwarded-For"].FirstOrDefault(); - } - if (string.IsNullOrEmpty(ip)) - { - ip = request.HttpContext?.Connection?.RemoteIpAddress?.ToString(); - } - if (string.IsNullOrEmpty(ip) || !IsIP(ip)) - { - ip = "127.0.0.1"; - } - - return ip; - } - } -} \ No newline at end of file diff --git a/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj b/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj index 152693792..9976f5251 100644 --- a/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj +++ b/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj @@ -9,13 +9,12 @@ - - - - - - - + + + + + + diff --git a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs index b0ae8448b..0b6e8ea93 100644 --- a/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs +++ b/IRaCIS.Core.Infrastructure/_IRaCIS/Output/ResponseOutput.cs @@ -169,7 +169,7 @@ namespace IRaCIS.Core.Infrastructure.Extention public static IResponseOutput DBNotExistIfNUll(object businessObject) { - return new ResponseOutput().NotOk("The business object{businessObject.GetType().Name} does not exist in the database, or was deleted by someone else, or an incorrect parameter query caused"); + return new ResponseOutput().NotOk($"The business object{businessObject.GetType().Name} does not exist in the database, or was deleted by someone else, or an incorrect parameter query caused"); } diff --git a/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj b/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj index 5f49abc87..16b11378d 100644 --- a/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj +++ b/IRaCIS.Core.Test/IRaCIS.Core.Test.csproj @@ -15,7 +15,6 @@ - all